107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
import re
|
|
|
|
from django.conf import settings
|
|
from django.http import HttpResponseRedirect
|
|
|
|
|
|
class EnforceLoginMiddleware:
|
|
"""
|
|
Middleware class which requires the user to be authenticated for all urls except
|
|
those defined in PUBLIC_URLS in settings.py. PUBLIC_URLS should be a tuple of regular
|
|
expressions for the urls you want anonymous users to have access to. If PUBLIC_URLS
|
|
is not defined, it falls back to LOGIN_URL or failing that '/accounts/login/'.
|
|
Requests for urls not matching PUBLIC_URLS get redirected to LOGIN_URL with next set
|
|
to original path of the unauthenticated request.
|
|
Any urls statically served by django are excluded from this check. To enforce the same
|
|
validation on these set SERVE_STATIC_TO_PUBLIC to False.
|
|
"""
|
|
|
|
def __init__(self, get_response):
|
|
self.get_response = get_response
|
|
self.login_url = getattr(settings, "LOGIN_URL", "/accounts/login/")
|
|
|
|
if hasattr(settings, "PUBLIC_URLS"):
|
|
public_urls = [re.compile(url) for url in settings.PUBLIC_URLS]
|
|
else:
|
|
public_urls = [re.compile("^%s/?$" % (self.login_url[1:]))]
|
|
|
|
self.public_urls = tuple(public_urls)
|
|
|
|
def __call__(self, request):
|
|
# Check if user needs to be redirected to login
|
|
redirect_response = self.check_login(request)
|
|
if redirect_response:
|
|
return redirect_response
|
|
|
|
return self.get_response(request)
|
|
|
|
def check_login(self, request):
|
|
"""
|
|
Redirect anonymous users to login_url from non public urls
|
|
"""
|
|
try:
|
|
if request.user.is_anonymous:
|
|
for url in self.public_urls:
|
|
if url.match(request.path[1:]):
|
|
return None
|
|
return HttpResponseRedirect(
|
|
"%s?next=%s" % (self.login_url, request.path)
|
|
)
|
|
except AttributeError:
|
|
return HttpResponseRedirect("%s?next=%s" % (self.login_url, request.path))
|
|
return None
|
|
|
|
|
|
class DetectDevice:
|
|
"""
|
|
Middleware to detect the device type from user agent string.
|
|
"""
|
|
|
|
def __init__(self, get_response):
|
|
self.get_response = get_response
|
|
|
|
def __call__(self, request):
|
|
request.device = self.detect_device(request)
|
|
return self.get_response(request)
|
|
|
|
def detect_device(self, request):
|
|
device = {}
|
|
|
|
ua = request.META.get("HTTP_USER_AGENT", "").lower()
|
|
|
|
if "iphone" in ua:
|
|
match = re.search(r"iphone os (\d)", ua)
|
|
if match:
|
|
device["iphone"] = "iphone" + match.group(1)
|
|
else:
|
|
device["iphone"] = "iphone"
|
|
|
|
if "ipad" in ua:
|
|
device["ipad"] = "ipad"
|
|
|
|
if "android" in ua:
|
|
match = re.search(r"android (\d\.\d)", ua)
|
|
if match:
|
|
version = match.group(1).replace(".", "")
|
|
device["android"] = "android" + version
|
|
else:
|
|
device["android"] = "android"
|
|
|
|
if "blackberry" in ua:
|
|
device["blackberry"] = "blackberry"
|
|
|
|
if "windows phone os 7" in ua:
|
|
device["winphone7"] = "winphone7"
|
|
|
|
if "iemobile" in ua:
|
|
device["winmo"] = "winmo"
|
|
|
|
if not device:
|
|
# either desktop, or something we don't care about.
|
|
device["baseline"] = "baseline"
|
|
|
|
# spits out device names for CSS targeting, to be applied to <html> or <body>.
|
|
device["classes"] = " ".join(v for (k, v) in device.items())
|
|
|
|
return device
|