File tree Expand file tree Collapse file tree 3 files changed +42
-12
lines changed
Expand file tree Collapse file tree 3 files changed +42
-12
lines changed Original file line number Diff line number Diff line change 11from __future__ import annotations
22
3- from urllib .parse import urlencode
4-
53from allauth .account .adapter import DefaultAccountAdapter
64from allauth .exceptions import ImmediateHttpResponse
75from allauth .socialaccount .models import SocialLogin
119from django .http import HttpResponseRedirect
1210from django .urls import reverse
1311
12+ from allauth_2fa .utils import get_next_query_string
1413from allauth_2fa .utils import user_has_valid_totp_device
1514
1615
@@ -45,16 +44,9 @@ def get_2fa_authenticate_url(self, request: HttpRequest) -> str:
4544 redirect_url = reverse ("two-factor-authenticate" )
4645
4746 # Add "next" parameter to the URL if possible.
48- # If the view function smells like a class-based view, we can interrogate it.
49- if getattr (request .resolver_match .func , "view_class" , None ):
50- view = request .resolver_match .func .view_class ()
51- view .request = request
52- success_url = view .get_success_url ()
53- query_params = request .GET .copy ()
54- if success_url :
55- query_params [view .redirect_field_name ] = success_url
56- if query_params :
57- redirect_url += f"?{ urlencode (query_params )} "
47+ query_string = get_next_query_string (request )
48+ if query_string :
49+ redirect_url += query_string
5850
5951 return redirect_url
6052
Original file line number Diff line number Diff line change 66from urllib .parse import urlencode
77
88import qrcode
9+ from django .http import HttpRequest
910from django_otp .models import Device
1011from qrcode .image .svg import SvgPathImage
1112
@@ -35,3 +36,29 @@ def user_has_valid_totp_device(user) -> bool:
3536 if not user .is_authenticated :
3637 return False
3738 return user .totpdevice_set .filter (confirmed = True ).exists ()
39+
40+
41+ def get_next_query_string (request : HttpRequest ) -> str | None :
42+ """
43+ Get the query string (including the prefix `?`) to
44+ redirect to after a successful POST.
45+
46+ If a query string can't be determined, returns None.
47+ """
48+ # If the view function smells like a class-based view,
49+ # we can interrogate it.
50+ try :
51+ view = request .resolver_match .func .view_class ()
52+ redirect_field_name = view .redirect_field_name
53+ except AttributeError :
54+ # Interrogation failed :(
55+ return None
56+
57+ view .request = request
58+ query_params = request .GET .copy ()
59+ success_url = view .get_success_url ()
60+ if success_url :
61+ query_params [redirect_field_name ] = success_url
62+ if query_params :
63+ return f"?{ urlencode (query_params )} "
64+ return None
Original file line number Diff line number Diff line change 55
66import pytest
77from allauth .account .signals import user_logged_in
8+ from allauth .account .views import PasswordResetFromKeyView
89from django .conf import settings
910from django .contrib .auth import get_user_model
1011from django .contrib .auth .models import AbstractUser
2021from pytest_django .asserts import assertRedirects
2122
2223from allauth_2fa import views
24+ from allauth_2fa .adapter import OTPAdapter
2325from allauth_2fa .middleware import BaseRequire2FAMiddleware
2426
2527from . import forms as forms_overrides
@@ -393,3 +395,12 @@ def test_forms_override(
393395 settings_key : f"{ custom_form_cls .__module__ } .{ custom_form_cls .__qualname__ } " ,
394396 }
395397 assert view .get_form_class () is custom_form_cls
398+
399+
400+ @pytest .mark .parametrize ("view_cls" , [PasswordResetFromKeyView ])
401+ def test_view_missing_attribute (request , view_cls ) -> None :
402+ # Ensure we're testing a view that's missing the attribute.
403+ assert hasattr (view_cls (), "get_redirect_field_name" ) is False
404+
405+ # Ensure the function doesn't fail when the attribute is missing.
406+ assert OTPAdapter ().get_2fa_authenticate_url (request ) is not None
You can’t perform that action at this time.
0 commit comments