NDOJ/judge/middleware.py

181 lines
6 KiB
Python
Raw Normal View History

2023-02-13 22:44:04 +00:00
import time
import logging
2023-03-07 07:19:45 +00:00
import random
import json
from datetime import datetime
2023-02-13 22:44:04 +00:00
2020-01-21 06:35:58 +00:00
from django.conf import settings
2023-01-24 03:08:11 +00:00
from django.http import HttpResponseRedirect, Http404
2020-01-21 06:35:58 +00:00
from django.urls import Resolver404, resolve, reverse
from django.utils.http import urlquote
2023-01-24 02:36:44 +00:00
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import ObjectDoesNotExist
2023-01-27 23:25:41 +00:00
from django.utils.translation import gettext as _
2023-01-24 02:36:44 +00:00
from judge.models import Organization
2023-01-27 23:25:41 +00:00
from judge.utils.views import generic_message
2020-01-21 06:35:58 +00:00
2023-02-04 16:34:41 +00:00
USED_DOMAINS = ["www"]
2023-05-15 05:01:53 +00:00
URL_NAMES_BYPASS_SUBDOMAIN = ["submission_source_file"]
2023-02-04 16:34:41 +00:00
2020-01-21 06:35:58 +00:00
class ShortCircuitMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
try:
2022-05-14 17:57:27 +00:00
callback, args, kwargs = resolve(
request.path_info, getattr(request, "urlconf", None)
)
2020-01-21 06:35:58 +00:00
except Resolver404:
callback, args, kwargs = None, None, None
2022-05-14 17:57:27 +00:00
if getattr(callback, "short_circuit_middleware", False):
2020-01-21 06:35:58 +00:00
return callback(request, *args, **kwargs)
return self.get_response(request)
class DMOJLoginMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user.is_authenticated:
profile = request.profile = request.user.profile
2022-05-14 17:57:27 +00:00
login_2fa_path = reverse("login_2fa")
if (
profile.is_totp_enabled
and not request.session.get("2fa_passed", False)
and request.path not in (login_2fa_path, reverse("auth_logout"))
and not request.path.startswith(settings.STATIC_URL)
):
return HttpResponseRedirect(
login_2fa_path + "?next=" + urlquote(request.get_full_path())
)
2020-01-21 06:35:58 +00:00
else:
request.profile = None
return self.get_response(request)
class DMOJImpersonationMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user.is_impersonate:
request.no_profile_update = True
request.profile = request.user.profile
return self.get_response(request)
class ContestMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
profile = request.profile
if profile:
profile.update_contest()
request.participation = profile.current_contest
request.in_contest = request.participation is not None
2022-05-14 17:57:27 +00:00
request.contest_mode = request.session.get("contest_mode", True)
2020-01-21 06:35:58 +00:00
else:
request.in_contest = False
request.participation = None
2022-01-10 11:13:46 +00:00
request.in_contest_mode = request.in_contest and request.contest_mode
2020-01-21 06:35:58 +00:00
return self.get_response(request)
2022-12-18 09:31:31 +00:00
class DarkModeMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if "darkmode" in request.GET:
return HttpResponseRedirect(
reverse("toggle_darkmode") + "?next=" + urlquote(request.path)
)
2022-12-20 08:24:24 +00:00
return self.get_response(request)
2023-01-24 02:36:44 +00:00
class SubdomainMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
2023-01-31 05:19:30 +00:00
request.organization = None
if not settings.USE_SUBDOMAIN:
return self.get_response(request)
2023-01-24 02:36:44 +00:00
domain = request.get_host()
site = get_current_site(request).domain
2023-02-04 16:34:41 +00:00
subdomain = domain[: len(domain) - len(site)].lower()
if len(subdomain) <= 1:
return self.get_response(request)
subdomain = subdomain[:-1]
2023-05-15 05:01:53 +00:00
if (
subdomain in USED_DOMAINS
or resolve(request.path).url_name in URL_NAMES_BYPASS_SUBDOMAIN
):
2023-02-04 16:34:41 +00:00
return self.get_response(request)
try:
organization = Organization.objects.get(slug=subdomain)
if request.profile and organization in request.profile.organizations.all():
request.organization = organization
else:
if request.profile:
return generic_message(
request,
_("No permission"),
_("You need to join this group first"),
status=404,
)
if not request.GET.get("next", None):
return HttpResponseRedirect(
reverse("auth_login") + "?next=" + urlquote(request.path)
)
except ObjectDoesNotExist:
return generic_message(
request,
_("No such group"),
_("No such group"),
status=404,
)
2023-01-24 02:36:44 +00:00
return self.get_response(request)
2023-02-13 22:44:04 +00:00
class SlowRequestMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
2023-03-07 07:19:45 +00:00
logger = logging.getLogger("judge.request_time")
logger_slow = logging.getLogger("judge.slow_request")
2023-02-13 22:44:04 +00:00
start_time = time.time()
response = self.get_response(request)
2023-03-13 06:23:06 +00:00
if response.status_code == 200:
2023-04-05 22:07:02 +00:00
try:
response_time = time.time() - start_time
url_name = resolve(request.path).url_name
message = {
"url_name": url_name,
"response_time": response_time * 1000,
"profile": request.user.username,
"date": datetime.now().strftime("%Y/%m/%d"),
"url": request.build_absolute_uri(),
"method": request.method,
}
if response_time > 9:
logger_slow.info(json.dumps(message))
if random.random() < 0.1:
logger.info(json.dumps(message))
except Exception:
pass
2023-02-13 22:44:04 +00:00
return response