Coverage for apps / core / middleware.py: 100%
29 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 00:40 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 00:40 +0000
1import re
4class DeviceDetectionMiddleware:
5 """Middleware to detect legacy browsers that can't run modern React.
7 Sets request.is_legacy_device = True for browsers that need the legacy frontend:
8 - iOS < 11 (Safari lacks ES6 module support)
9 - Internet Explorer (all versions)
10 - Edge Legacy (non-Chromium, pre-2020)
11 - Chrome < 60
12 - Firefox < 55
14 Note: Actual redirects are handled by Nginx for performance (see nginx/nginx.conf).
15 This middleware provides the detection flag for use in views/templates if needed.
16 """
18 # Pattern to match iOS version from user agent
19 IOS_PATTERN = re.compile(r'(?:iPhone|iPad|iPod).*OS (\d+)_')
21 # Pattern to match Chrome version
22 CHROME_PATTERN = re.compile(r'Chrome/(\d+)\.')
24 # Pattern to match Firefox version
25 FIREFOX_PATTERN = re.compile(r'Firefox/(\d+)\.')
27 def __init__(self, get_response):
28 self.get_response = get_response
30 def __call__(self, request):
31 request.is_legacy_device = self._is_legacy_device(request)
32 return self.get_response(request)
34 def _is_legacy_device(self, request):
35 """Check if the request is from a browser that can't run modern React."""
36 user_agent = request.META.get('HTTP_USER_AGENT', '')
37 if not user_agent:
38 return False
40 # iOS < 11
41 match = self.IOS_PATTERN.search(user_agent)
42 if match:
43 return int(match.group(1)) < 11
45 # Internet Explorer
46 if 'MSIE ' in user_agent or 'Trident/' in user_agent:
47 return True
49 # Edge Legacy (non-Chromium)
50 if 'Edge/' in user_agent and 'Edg/' not in user_agent:
51 return True
53 # Chrome < 60
54 if 'Chrome/' in user_agent and 'Edg' not in user_agent and 'OPR/' not in user_agent:
55 match = self.CHROME_PATTERN.search(user_agent)
56 if match and int(match.group(1)) < 60:
57 return True
59 # Firefox < 55
60 match = self.FIREFOX_PATTERN.search(user_agent)
61 if match and int(match.group(1)) < 55:
62 return True
64 return False