Files

116 lines
3.4 KiB
Python
Raw Permalink Normal View History

2022-03-13 13:33:19 -04:00
import logging
2022-07-03 10:43:59 -04:00
from typing import Callable, Optional, TYPE_CHECKING, Union
2022-03-13 13:33:19 -04:00
2021-09-02 20:50:01 +01:00
from django.contrib import auth
2021-09-03 11:29:26 +01:00
from django.contrib.auth.models import User
2022-03-13 13:33:19 -04:00
from django.http.request import HttpRequest
from django.utils.timezone import now
from rest_framework.request import Request as DRFRequest
2022-07-03 10:43:59 -04:00
from rest_framework.response import Response
2021-09-02 17:27:07 +01:00
2022-02-17 18:47:04 +00:00
from .models.profile import Profile
2021-09-02 20:50:01 +01:00
logger = logging.getLogger(__name__)
2021-09-02 20:50:01 +01:00
if TYPE_CHECKING:
2022-02-17 18:47:04 +00:00
from .models.github import GitHubUser
2021-09-02 20:50:01 +01:00
2022-02-20 09:21:38 -05:00
2021-09-02 20:50:01 +01:00
class AnonymousUser(auth.models.AnonymousUser):
profile: Profile
2022-02-20 09:21:38 -05:00
2021-09-17 10:22:46 +01:00
if TYPE_CHECKING:
2022-02-20 09:21:38 -05:00
2021-09-17 10:22:46 +01:00
class Request(DRFRequest):
user: Union[User, AnonymousUser]
profile: Profile
2022-02-20 09:21:38 -05:00
2021-09-17 10:22:46 +01:00
else:
Request = DRFRequest
2021-09-02 17:27:07 +01:00
2022-02-20 09:21:38 -05:00
2022-07-03 10:43:59 -04:00
def disable_csrf(
2025-03-04 17:54:52 +00:00
get_response: Callable[[HttpRequest], Response],
2022-07-03 10:43:59 -04:00
) -> Callable[[HttpRequest], Response]:
def middleware(request: HttpRequest) -> Response:
2021-09-02 17:52:17 +01:00
setattr(request, "_dont_enforce_csrf_checks", True)
return get_response(request)
return middleware
2022-02-20 09:21:38 -05:00
2022-07-03 10:43:59 -04:00
def set_user_profile(
2025-03-04 17:54:52 +00:00
get_response: Callable[[HttpRequest], Response],
2022-07-03 10:43:59 -04:00
) -> Callable[[Request], Response]:
2021-09-02 17:27:07 +01:00
"""
2021-09-02 22:03:34 +01:00
Makes sure that `request.profile` is always available, even for anonymous users.
2021-09-02 17:27:07 +01:00
"""
2022-07-03 10:43:59 -04:00
def middleware(request: Request) -> Response:
user_agent = request.headers.get("User-Agent")
# Avoid creating profiles for SSR or bots
if user_agent is None or (
"node" in user_agent
or "undici" in user_agent
or "Next.js Middleware" in user_agent
or "python-requests" in user_agent
or "curl" in user_agent
or "YandexRenderResourcesBot" in user_agent
2022-02-20 09:21:38 -05:00
):
request.profile = Profile()
return get_response(request)
2021-09-03 11:29:26 +01:00
profile: Optional[Profile] = None
2021-09-02 17:27:07 +01:00
2021-09-03 11:29:26 +01:00
# Use the user's profile if they're logged in
2021-09-02 17:27:07 +01:00
if not request.user.is_anonymous:
2021-09-03 11:29:26 +01:00
profile = Profile.objects.filter(user=request.user).first()
2021-09-02 17:27:07 +01:00
2021-09-03 11:29:26 +01:00
# Otherwise, use their session profile
2021-09-02 17:27:07 +01:00
if not profile:
2021-09-03 11:29:26 +01:00
id = request.session.get("profile_id")
2021-09-02 20:50:01 +01:00
2021-09-03 11:29:26 +01:00
if isinstance(id, int):
profile = Profile.objects.filter(id=id).first()
2024-03-13 23:04:20 +09:00
if profile is not None:
profile_user = User.objects.filter(profile=profile).first()
2021-09-02 17:27:07 +01:00
2024-03-13 23:04:20 +09:00
if profile_user and request.user.is_anonymous:
request.user = profile_user
2021-09-03 11:29:26 +01:00
# If we still don't have a profile, create a new one
if not profile:
profile = Profile()
# And attach it to the logged-in user, if there is one
if not request.user.is_anonymous:
assert Profile.objects.filter(user=request.user).first() is None
profile.user = request.user
profile.save()
request.session["profile_id"] = profile.id
# More info to help identify why we are creating so many profiles...
x_forwarded_for = request.headers.get("X-Forwarded-For", "n/a")
logger.debug(
"Made new profile: User-Agent: %s, IP: %s, name: %s, request path: %s",
user_agent,
x_forwarded_for,
profile,
request.path,
)
2021-09-02 17:27:07 +01:00
2021-09-02 23:11:59 +01:00
if profile.user is None and not request.user.is_anonymous:
profile.user = request.user
2021-09-02 17:27:07 +01:00
profile.last_request_date = now()
profile.save()
2021-09-03 11:29:26 +01:00
request.profile = profile
2021-09-02 22:03:34 +01:00
2021-09-02 17:27:07 +01:00
return get_response(request)
2021-09-03 11:29:26 +01:00
2021-09-02 17:27:07 +01:00
return middleware