This commit is contained in:
zandercymatics 2024-05-14 13:49:43 -06:00
parent 54c532f3b2
commit f55d0a655a
No known key found for this signature in database
GPG key ID: FF4636ABEC9682B7
10 changed files with 38 additions and 43 deletions

View file

@ -50,7 +50,7 @@ class OpenIdConnectBackend(ModelBackend):
user, created = UserModel.objects.get_or_create(**args) user, created = UserModel.objects.get_or_create(**args)
if created: if created and request is not None:
request.session["is_new_user"] = True request.session["is_new_user"] = True
if not created: if not created:
@ -63,7 +63,8 @@ class OpenIdConnectBackend(ModelBackend):
try: try:
user = UserModel.objects.get_by_natural_key(username) user = UserModel.objects.get_by_natural_key(username)
except UserModel.DoesNotExist: except UserModel.DoesNotExist:
request.session["is_new_user"] = True if request is not None:
request.session["is_new_user"] = True
return None return None
# run this callback for a each login # run this callback for a each login
user.on_each_login() user.on_each_login()

View file

@ -46,4 +46,3 @@ class ContactForm(forms.Form):
label="Phone", label="Phone",
error_messages={"invalid": "Enter a valid 10-digit phone number.", "required": "Enter your phone number."}, error_messages={"invalid": "Enter a valid 10-digit phone number.", "required": "Enter your phone number."},
) )

View file

@ -202,6 +202,7 @@ NameserverFormset = formset_factory(
validate_max=True, validate_max=True,
) )
# TODO - refactor, wait until daves PR # TODO - refactor, wait until daves PR
class ContactForm(forms.ModelForm): class ContactForm(forms.ModelForm):
"""Form for updating contacts.""" """Form for updating contacts."""

View file

@ -150,7 +150,7 @@ class OrganizationContactForm(RegistrarForm):
"""Require something to be selected when this is a federal agency.""" """Require something to be selected when this is a federal agency."""
federal_agency = self.cleaned_data.get("federal_agency", None) federal_agency = self.cleaned_data.get("federal_agency", None)
# need the domain request object to know if this is federal # need the domain request object to know if this is federal
if self.domain_request is None: if hasattr(self, "domain_request") and self.domain_request is None:
# hmm, no saved domain request object?, default require the agency # hmm, no saved domain request object?, default require the agency
if not federal_agency: if not federal_agency:
# no answer was selected # no answer was selected

View file

@ -3,6 +3,7 @@ from django.db import models
from .utility.time_stamped_model import TimeStampedModel from .utility.time_stamped_model import TimeStampedModel
from phonenumber_field.modelfields import PhoneNumberField # type: ignore from phonenumber_field.modelfields import PhoneNumberField # type: ignore
class Contact(TimeStampedModel): class Contact(TimeStampedModel):
"""Contact information follows a similar pattern for each contact.""" """Contact information follows a similar pattern for each contact."""

View file

@ -280,4 +280,4 @@ def from_database(form_class, obj):
"""Returns a dict of form field values gotten from `obj`.""" """Returns a dict of form field values gotten from `obj`."""
if obj is None: if obj is None:
return {} return {}
return {name: getattr(obj, name) for name in form_class.declared_fields.keys()} # type: ignore return {name: getattr(obj, name) for name in form_class.declared_fields.keys()} # type: ignore

View file

@ -1,17 +1,20 @@
""" """
Contains middleware used in settings.py Contains middleware used in settings.py
""" """
from urllib.parse import urlparse, urlunparse, parse_qs, urlencode from urllib.parse import urlparse, urlunparse, parse_qs, urlencode
from django.urls import reverse from django.urls import reverse
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from waffle.decorators import flag_is_active from waffle.decorators import flag_is_active
class CheckUserProfileMiddleware: class CheckUserProfileMiddleware:
""" """
Checks if the current user has finished_setup = False. Checks if the current user has finished_setup = False.
If they do, redirect them to the setup page regardless of where they are in If they do, redirect them to the setup page regardless of where they are in
the application. the application.
""" """
def __init__(self, get_response): def __init__(self, get_response):
self.get_response = get_response self.get_response = get_response
@ -21,7 +24,7 @@ class CheckUserProfileMiddleware:
return response return response
def process_view(self, request, view_func, view_args, view_kwargs): def process_view(self, request, view_func, view_args, view_kwargs):
# Check that the user is "opted-in" to the profile feature flag # Check that the user is "opted-in" to the profile feature flag
has_profile_feature_flag = flag_is_active(request, "profile_feature") has_profile_feature_flag = flag_is_active(request, "profile_feature")
@ -32,10 +35,7 @@ class CheckUserProfileMiddleware:
# Check if setup is not finished # Check if setup is not finished
finished_setup = hasattr(request.user, "finished_setup") and request.user.finished_setup finished_setup = hasattr(request.user, "finished_setup") and request.user.finished_setup
if request.user.is_authenticated and not finished_setup: if request.user.is_authenticated and not finished_setup:
setup_page = reverse( setup_page = reverse("finish-contact-profile-setup", kwargs={"pk": request.user.contact.pk})
"finish-contact-profile-setup",
kwargs={"pk": request.user.contact.pk}
)
logout_page = reverse("logout") logout_page = reverse("logout")
excluded_pages = [ excluded_pages = [
setup_page, setup_page,
@ -52,7 +52,7 @@ class CheckUserProfileMiddleware:
# Don't redirect on excluded pages (such as the setup page itself) # Don't redirect on excluded pages (such as the setup page itself)
if not any(request.path.startswith(page) for page in excluded_pages): if not any(request.path.startswith(page) for page in excluded_pages):
# Preserve the original query parameters, and coerce them into a dict # Preserve the original query parameters, and coerce them into a dict
query_params = parse_qs(request.META['QUERY_STRING']) query_params = parse_qs(request.META["QUERY_STRING"])
if custom_redirect is not None: if custom_redirect is not None:
# Set the redirect value to our redirect location # Set the redirect value to our redirect location
@ -65,7 +65,6 @@ class CheckUserProfileMiddleware:
setup_page_parts[4] = urlencode(query_params) setup_page_parts[4] = urlencode(query_params)
# Reassemble the URL # Reassemble the URL
setup_page = urlunparse(setup_page_parts) setup_page = urlunparse(setup_page_parts)
# Redirect to the setup page # Redirect to the setup page
return HttpResponseRedirect(setup_page) return HttpResponseRedirect(setup_page)
@ -88,4 +87,4 @@ class NoCacheMiddleware:
def __call__(self, request): def __call__(self, request):
response = self.get_response(request) response = self.get_response(request)
response["Cache-Control"] = "no-cache" response["Cache-Control"] = "no-cache"
return response return response

View file

@ -20,6 +20,7 @@ logger = logging.getLogger(__name__)
class BaseContactView(ContactPermissionView): class BaseContactView(ContactPermissionView):
"""Provides a base view for the contact object. On get, the contact """Provides a base view for the contact object. On get, the contact
is saved in the session and on self.object.""" is saved in the session and on self.object."""
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
"""Sets the current contact in cache, defines the current object as self.object """Sets the current contact in cache, defines the current object as self.object
then returns render_to_response""" then returns render_to_response"""
@ -56,6 +57,7 @@ class BaseContactView(ContactPermissionView):
class ContactFormBaseView(BaseContactView, FormMixin): class ContactFormBaseView(BaseContactView, FormMixin):
"""Adds a FormMixin to BaseContactView, and handles post""" """Adds a FormMixin to BaseContactView, and handles post"""
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
"""Form submission posts to this view. """Form submission posts to this view.
@ -78,8 +80,9 @@ class ContactFormBaseView(BaseContactView, FormMixin):
class ContactProfileSetupView(ContactFormBaseView): class ContactProfileSetupView(ContactFormBaseView):
"""This view forces the user into providing additional details that """This view forces the user into providing additional details that
we may have missed from Login.gov""" we may have missed from Login.gov"""
template_name = "finish_contact_setup.html" template_name = "finish_contact_setup.html"
form_class = ContactForm form_class = ContactForm
model = Contact model = Contact
@ -99,22 +102,23 @@ class ContactProfileSetupView(ContactFormBaseView):
- COMPLETE_SETUP: Indicates that we want to navigate BACK_TO_SELF, but the subsequent - COMPLETE_SETUP: Indicates that we want to navigate BACK_TO_SELF, but the subsequent
redirect after the next POST should be either HOME or TO_SPECIFIC_PAGE redirect after the next POST should be either HOME or TO_SPECIFIC_PAGE
""" """
HOME = "home" HOME = "home"
BACK_TO_SELF = "back_to_self" BACK_TO_SELF = "back_to_self"
COMPLETE_SETUP = "complete_setup" COMPLETE_SETUP = "complete_setup"
TO_SPECIFIC_PAGE = "domain_request" TO_SPECIFIC_PAGE = "domain_request"
# TODO - refactor # TODO - refactor
@waffle_flag('profile_feature') @waffle_flag("profile_feature")
@method_decorator(csrf_protect) @method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
""" """
Handles dispatching of the view, applying CSRF protection and checking the 'profile_feature' flag. Handles dispatching of the view, applying CSRF protection and checking the 'profile_feature' flag.
This method sets the redirect type based on the 'redirect' query parameter, This method sets the redirect type based on the 'redirect' query parameter,
defaulting to BACK_TO_SELF if not provided. defaulting to BACK_TO_SELF if not provided.
It updates the session with the redirect view name if the redirect type is TO_SPECIFIC_PAGE. It updates the session with the redirect view name if the redirect type is TO_SPECIFIC_PAGE.
Returns: Returns:
HttpResponse: The response generated by the parent class's dispatch method. HttpResponse: The response generated by the parent class's dispatch method.
""" """
@ -140,7 +144,7 @@ class ContactProfileSetupView(ContactFormBaseView):
self.RedirectType.HOME, self.RedirectType.HOME,
self.RedirectType.COMPLETE_SETUP, self.RedirectType.COMPLETE_SETUP,
self.RedirectType.BACK_TO_SELF, self.RedirectType.BACK_TO_SELF,
self.RedirectType.TO_SPECIFIC_PAGE self.RedirectType.TO_SPECIFIC_PAGE,
] ]
if redirect_type not in default_redirects: if redirect_type not in default_redirects:
self.redirect_type = self.RedirectType.TO_SPECIFIC_PAGE self.redirect_type = self.RedirectType.TO_SPECIFIC_PAGE
@ -154,8 +158,8 @@ class ContactProfileSetupView(ContactFormBaseView):
""" """
Returns a URL string based on the current value of self.redirect_type. Returns a URL string based on the current value of self.redirect_type.
Depending on self.redirect_type, constructs a base URL and appends a Depending on self.redirect_type, constructs a base URL and appends a
'redirect' query parameter. Handles different redirection types such as 'redirect' query parameter. Handles different redirection types such as
HOME, BACK_TO_SELF, COMPLETE_SETUP, and TO_SPECIFIC_PAGE. HOME, BACK_TO_SELF, COMPLETE_SETUP, and TO_SPECIFIC_PAGE.
Returns: Returns:
@ -178,13 +182,11 @@ class ContactProfileSetupView(ContactFormBaseView):
base_url = reverse(desired_view) base_url = reverse(desired_view)
except NoReverseMatch as err: except NoReverseMatch as err:
logger.error(err) logger.error(err)
logger.error( logger.error("ContactProfileSetupView -> get_redirect_url -> Could not find specified page.")
"ContactProfileSetupView -> get_redirect_url -> Could not find specified page."
)
base_url = reverse("home") base_url = reverse("home")
case _: case _:
base_url = reverse("home") base_url = reverse("home")
# Quote cleans up the value so that it can be used in a url # Quote cleans up the value so that it can be used in a url
query_params["redirect"] = quote(self.redirect_type) query_params["redirect"] = quote(self.redirect_type)
@ -231,27 +233,24 @@ class ContactProfileSetupView(ContactFormBaseView):
return self.form_invalid(form) return self.form_invalid(form)
def form_valid(self, form): def form_valid(self, form):
completed_states = [ completed_states = [self.RedirectType.TO_SPECIFIC_PAGE, self.RedirectType.HOME]
self.RedirectType.TO_SPECIFIC_PAGE,
self.RedirectType.HOME
]
if self.redirect_type in completed_states: if self.redirect_type in completed_states:
self.request.user.finished_setup = True self.request.user.finished_setup = True
self.request.user.save() self.request.user.save()
to_database(form=form, obj=self.object) to_database(form=form, obj=self.object)
self._update_session_with_contact() self._update_session_with_contact()
return super().form_valid(form) return super().form_valid(form)
def get_initial(self): def get_initial(self):
"""The initial value for the form (which is a formset here).""" """The initial value for the form (which is a formset here)."""
db_object = from_database(form_class=self.form_class, obj=self.object) db_object = from_database(form_class=self.form_class, obj=self.object)
return db_object return db_object
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context["email_sublabel_text"] = self._email_sublabel_text() context["email_sublabel_text"] = self._email_sublabel_text()
@ -259,7 +258,7 @@ class ContactProfileSetupView(ContactFormBaseView):
context["confirm_changes"] = True context["confirm_changes"] = True
return context return context
def _email_sublabel_text(self): def _email_sublabel_text(self):
"""Returns the lengthy sublabel for the email field""" """Returns the lengthy sublabel for the email field"""
help_url = public_site_url("help/account-management/#get-help-with-login.gov") help_url = public_site_url("help/account-management/#get-help-with-login.gov")

View file

@ -819,4 +819,3 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView):
duplicates = [item for item, count in object_dict.items() if count > 1] duplicates = [item for item, count in object_dict.items() if count > 1]
return duplicates return duplicates

View file

@ -341,7 +341,6 @@ class ContactPermission(PermissionsLoginMixin):
if not self.request.user.is_authenticated: if not self.request.user.is_authenticated:
return False return False
given_contact_pk = self.kwargs["pk"] given_contact_pk = self.kwargs["pk"]
# Grab the user in the DB to do a full object comparision, not just on ids # Grab the user in the DB to do a full object comparision, not just on ids
@ -351,13 +350,10 @@ class ContactPermission(PermissionsLoginMixin):
if current_user.contact.pk != given_contact_pk: if current_user.contact.pk != given_contact_pk:
# Don't allow users to modify other users profiles # Don't allow users to modify other users profiles
return False return False
# Check if the object at the id we're searching on actually exists # Check if the object at the id we're searching on actually exists
requested_user_exists = User.objects.filter(pk=current_user.pk).exists() requested_user_exists = User.objects.filter(pk=current_user.pk).exists()
requested_contact_exists = Contact.objects.filter( requested_contact_exists = Contact.objects.filter(user=current_user.pk, pk=given_contact_pk).exists()
user=current_user.pk,
pk=given_contact_pk
).exists()
if not requested_user_exists or not requested_contact_exists: if not requested_user_exists or not requested_contact_exists:
return False return False