mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-06 09:45:23 +02:00
removed user-contact connection
This commit is contained in:
parent
694cfa543b
commit
6361369953
22 changed files with 129 additions and 418 deletions
|
@ -5,12 +5,3 @@ class RegistrarConfig(AppConfig):
|
|||
"""Configure signal handling for our registrar Django application."""
|
||||
|
||||
name = "registrar"
|
||||
|
||||
def ready(self):
|
||||
"""Runs when all Django applications have been loaded.
|
||||
|
||||
We use it here to load signals that connect related models.
|
||||
"""
|
||||
# noqa here because we are importing something to make the signals
|
||||
# get registered, but not using what we import
|
||||
from . import signals # noqa
|
||||
|
|
|
@ -4,7 +4,7 @@ from .domain import (
|
|||
NameserverFormset,
|
||||
DomainSecurityEmailForm,
|
||||
DomainOrgNameAddressForm,
|
||||
ContactForm,
|
||||
UserForm,
|
||||
AuthorizingOfficialContactForm,
|
||||
DomainDnssecForm,
|
||||
DomainDsdataFormset,
|
||||
|
|
|
@ -16,7 +16,7 @@ from registrar.utility.errors import (
|
|||
SecurityEmailErrorCodes,
|
||||
)
|
||||
|
||||
from ..models import Contact, DomainInformation, Domain
|
||||
from ..models import Contact, DomainInformation, Domain, User
|
||||
from .common import (
|
||||
ALGORITHM_CHOICES,
|
||||
DIGEST_TYPE_CHOICES,
|
||||
|
@ -203,6 +203,63 @@ NameserverFormset = formset_factory(
|
|||
)
|
||||
|
||||
|
||||
class UserForm(forms.ModelForm):
|
||||
"""Form for updating contacts."""
|
||||
|
||||
email = forms.EmailField(max_length=None)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["first_name", "middle_name", "last_name", "title", "email", "phone"]
|
||||
widgets = {
|
||||
"first_name": forms.TextInput,
|
||||
"middle_name": forms.TextInput,
|
||||
"last_name": forms.TextInput,
|
||||
"title": forms.TextInput,
|
||||
"email": forms.EmailInput,
|
||||
"phone": RegionalPhoneNumberWidget,
|
||||
}
|
||||
|
||||
# the database fields have blank=True so ModelForm doesn't create
|
||||
# required fields by default. Use this list in __init__ to mark each
|
||||
# of these fields as required
|
||||
required = ["first_name", "last_name", "title", "email", "phone"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# take off maxlength attribute for the phone number field
|
||||
# which interferes with out input_with_errors template tag
|
||||
self.fields["phone"].widget.attrs.pop("maxlength", None)
|
||||
|
||||
# Define a custom validator for the email field with a custom error message
|
||||
email_max_length_validator = MaxLengthValidator(320, message="Response must be less than 320 characters.")
|
||||
self.fields["email"].validators.append(email_max_length_validator)
|
||||
|
||||
for field_name in self.required:
|
||||
self.fields[field_name].required = True
|
||||
|
||||
# Set custom form label
|
||||
self.fields["middle_name"].label = "Middle name (optional)"
|
||||
|
||||
# Set custom error messages
|
||||
self.fields["first_name"].error_messages = {"required": "Enter your first name / given name."}
|
||||
self.fields["last_name"].error_messages = {"required": "Enter your last name / family name."}
|
||||
self.fields["title"].error_messages = {
|
||||
"required": "Enter your title or role in your organization (e.g., Chief Information Officer)"
|
||||
}
|
||||
self.fields["email"].error_messages = {
|
||||
"required": "Enter your email address in the required format, like name@example.com."
|
||||
}
|
||||
self.fields["phone"].error_messages["required"] = "Enter your phone number."
|
||||
self.domainInfo = None
|
||||
|
||||
def set_domain_info(self, domainInfo):
|
||||
"""Set the domain information for the form.
|
||||
The form instance is associated with the contact itself. In order to access the associated
|
||||
domain information object, this needs to be set in the form by the view."""
|
||||
self.domainInfo = domainInfo
|
||||
|
||||
|
||||
class ContactForm(forms.ModelForm):
|
||||
"""Form for updating contacts."""
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django import forms
|
||||
|
||||
from registrar.models.contact import Contact
|
||||
from registrar.models.user import User
|
||||
|
||||
from django.core.validators import MaxLengthValidator
|
||||
from phonenumber_field.widgets import RegionalPhoneNumberWidget
|
||||
|
@ -13,7 +13,7 @@ class UserProfileForm(forms.ModelForm):
|
|||
redirect = forms.CharField(widget=forms.HiddenInput(), required=False)
|
||||
|
||||
class Meta:
|
||||
model = Contact
|
||||
model = User
|
||||
fields = ["first_name", "middle_name", "last_name", "title", "email", "phone"]
|
||||
widgets = {
|
||||
"first_name": forms.TextInput,
|
||||
|
|
|
@ -65,13 +65,6 @@ class Command(BaseCommand):
|
|||
|
||||
resourcename = f"{table_name}Resource"
|
||||
|
||||
# if table_name is Contact, clean the table first
|
||||
# User table is loaded before Contact, and signals create
|
||||
# rows in Contact table which break the import, so need
|
||||
# to be cleaned again before running import on Contact table
|
||||
if table_name == "Contact":
|
||||
self.clean_table(table_name)
|
||||
|
||||
# Define the directory and the pattern for csv filenames
|
||||
tmp_dir = "tmp"
|
||||
pattern = f"{table_name}_"
|
||||
|
|
|
@ -8,13 +8,6 @@ from phonenumber_field.modelfields import PhoneNumberField # type: ignore
|
|||
class Contact(TimeStampedModel):
|
||||
"""
|
||||
Contact information follows a similar pattern for each contact.
|
||||
|
||||
This model uses signals [as defined in [signals.py](../../src/registrar/signals.py)].
|
||||
When a new user is created through Login.gov, a contact object will be created and
|
||||
associated on the `user` field.
|
||||
|
||||
If the `user` object already exists, the underlying user object
|
||||
will be updated if any updates are made to it through Login.gov.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -23,10 +23,6 @@ class User(AbstractUser):
|
|||
A custom user model that performs identically to the default user model
|
||||
but can be customized later.
|
||||
|
||||
This model uses signals [as defined in [signals.py](../../src/registrar/signals.py)].
|
||||
When a new user is created through Login.gov, a contact object will be created and
|
||||
associated on the contacts `user` field.
|
||||
|
||||
If the `user` object already exists, said user object
|
||||
will be updated if any updates are made to it through Login.gov.
|
||||
"""
|
||||
|
@ -113,15 +109,11 @@ class User(AbstractUser):
|
|||
Tracks if the user finished their profile setup or not. This is so
|
||||
we can globally enforce that new users provide additional account information before proceeding.
|
||||
"""
|
||||
|
||||
# Change this to self once the user and contact objects are merged.
|
||||
# For now, since they are linked, lets test on the underlying contact object.
|
||||
user_info = self.contact # noqa
|
||||
user_values = [
|
||||
user_info.first_name,
|
||||
user_info.last_name,
|
||||
user_info.title,
|
||||
user_info.phone,
|
||||
self.first_name,
|
||||
self.last_name,
|
||||
self.title,
|
||||
self.phone,
|
||||
]
|
||||
return None not in user_values
|
||||
|
||||
|
@ -169,8 +161,13 @@ class User(AbstractUser):
|
|||
"""Return count of ineligible requests"""
|
||||
return self.domain_requests_created.filter(status=DomainRequest.DomainRequestStatus.INELIGIBLE).count()
|
||||
|
||||
def get_formatted_name(self):
|
||||
"""Returns the contact's name in Western order."""
|
||||
names = [n for n in [self.first_name, self.middle_name, self.last_name] if n]
|
||||
return " ".join(names) if names else "Unknown"
|
||||
|
||||
def has_contact_info(self):
|
||||
return bool(self.contact.title or self.contact.email or self.contact.phone)
|
||||
return bool(self.title or self.email or self.phone)
|
||||
|
||||
@classmethod
|
||||
def needs_identity_verification(cls, email, uuid):
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
import logging
|
||||
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from .models import User, Contact
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def handle_profile(sender, instance, **kwargs):
|
||||
"""Method for when a User is saved.
|
||||
|
||||
A first time registrant may have been invited, so we'll search for a matching
|
||||
Contact record, by email address, and associate them, if possible.
|
||||
|
||||
A first time registrant may not have a matching Contact, so we'll create one,
|
||||
copying the contact values we received from Login.gov in order to initialize it.
|
||||
|
||||
During subsequent login, a User record may be updated with new data from Login.gov,
|
||||
but in no case will we update contact values on an existing Contact record.
|
||||
"""
|
||||
|
||||
first_name = getattr(instance, "first_name", "")
|
||||
middle_name = getattr(instance, "middle_name", "")
|
||||
last_name = getattr(instance, "last_name", "")
|
||||
email = getattr(instance, "email", "")
|
||||
phone = getattr(instance, "phone", "")
|
||||
title = getattr(instance, "title", "")
|
||||
|
||||
is_new_user = kwargs.get("created", False)
|
||||
|
||||
if is_new_user:
|
||||
contacts = Contact.objects.filter(email=email)
|
||||
else:
|
||||
contacts = Contact.objects.filter(user=instance)
|
||||
|
||||
if len(contacts) == 0: # no matching contact
|
||||
Contact.objects.create(
|
||||
user=instance,
|
||||
first_name=first_name,
|
||||
middle_name=middle_name,
|
||||
last_name=last_name,
|
||||
email=email,
|
||||
phone=phone,
|
||||
title=title,
|
||||
)
|
||||
|
||||
if len(contacts) >= 1 and is_new_user: # a matching contact
|
||||
contacts[0].user = instance
|
||||
contacts[0].save()
|
||||
|
||||
if len(contacts) > 1: # multiple matches
|
||||
logger.warning(
|
||||
"There are multiple Contacts with the same email address."
|
||||
f" Picking #{contacts[0].id} for User #{instance.id}."
|
||||
)
|
|
@ -12,37 +12,24 @@
|
|||
|
||||
{% if user.has_contact_info %}
|
||||
{# Title #}
|
||||
{% if user.title or user.contact.title %}
|
||||
{% if user.contact.title %}
|
||||
{{ user.contact.title }}
|
||||
{% else %}
|
||||
{{ user.title }}
|
||||
{% endif %}
|
||||
{% if user.title %}
|
||||
{{ user.title }}
|
||||
<br>
|
||||
{% else %}
|
||||
None<br>
|
||||
{% endif %}
|
||||
{# Email #}
|
||||
{% if user.email or user.contact.email %}
|
||||
{% if user.contact.email %}
|
||||
{{ user.contact.email }}
|
||||
{% include "admin/input_with_clipboard.html" with field=user invisible_input_field=True %}
|
||||
{% else %}
|
||||
{{ user.email }}
|
||||
{% include "admin/input_with_clipboard.html" with field=user invisible_input_field=True %}
|
||||
{% endif %}
|
||||
{% if user.email %}
|
||||
{{ user.email }}
|
||||
{% include "admin/input_with_clipboard.html" with field=user invisible_input_field=True %}
|
||||
<br class="admin-icon-group__br">
|
||||
{% else %}
|
||||
None<br>
|
||||
{% endif %}
|
||||
|
||||
{# Phone #}
|
||||
{% if user.phone or user.contact.phone %}
|
||||
{% if user.contact.phone %}
|
||||
{{ user.contact.phone }}
|
||||
{% else %}
|
||||
{{ user.phone }}
|
||||
{% endif %}
|
||||
{% if user.phone %}
|
||||
{{ user.phone }}
|
||||
<br>
|
||||
{% else %}
|
||||
None<br>
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
{# Conditionally display profile #}
|
||||
{% if not has_profile_feature_flag %}
|
||||
{% url 'domain-your-contact-information' pk=domain.id as url %}
|
||||
{% include "includes/summary_item.html" with title='Your contact information' value=request.user.contact contact='true' edit_link=url editable=domain.is_editable %}
|
||||
{% include "includes/summary_item.html" with title='Your contact information' value=request.user contact='true' edit_link=url editable=domain.is_editable %}
|
||||
{% endif %}
|
||||
|
||||
{% url 'domain-security-email' pk=domain.id as url %}
|
||||
|
|
|
@ -77,11 +77,11 @@
|
|||
</fieldset>
|
||||
<div>
|
||||
|
||||
<button type="submit" name="contact_setup_save_button" class="usa-button ">
|
||||
<button type="submit" name="user_setup_save_button" class="usa-button ">
|
||||
Save
|
||||
</button>
|
||||
{% if user_finished_setup and going_to_specific_page %}
|
||||
<button type="submit" name="contact_setup_submit_button" class="usa-button usa-button--outline">
|
||||
<button type="submit" name="user_setup_submit_button" class="usa-button usa-button--outline">
|
||||
{{redirect_button_text }}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
</h3>
|
||||
<div class="usa-summary-box__text">
|
||||
<ul>
|
||||
<li>Full name: <b>{{ user.contact.get_formatted_name }}</b></li>
|
||||
<li>Full name: <b>{{ user.get_formatted_name }}</b></li>
|
||||
<li>Organization email: <b>{{ user.email }}</b></li>
|
||||
<li>Title or role in your organization: <b>{{ user.contact.title }}</b></li>
|
||||
<li>Phone: <b>{{ user.contact.phone.as_national }}</b></li>
|
||||
<li>Title or role in your organization: <b>{{ user.title }}</b></li>
|
||||
<li>Phone: <b>{{ user.phone.as_national }}</b></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -810,6 +810,8 @@ def create_superuser():
|
|||
user = User.objects.create_user(
|
||||
username="superuser",
|
||||
email="admin@example.com",
|
||||
first_name="first",
|
||||
last_name="last",
|
||||
is_staff=True,
|
||||
password=p,
|
||||
)
|
||||
|
@ -826,6 +828,8 @@ def create_user():
|
|||
user = User.objects.create_user(
|
||||
username="staffuser",
|
||||
email="staff@example.com",
|
||||
first_name="first",
|
||||
last_name="last",
|
||||
is_staff=True,
|
||||
password=p,
|
||||
)
|
||||
|
|
|
@ -242,15 +242,11 @@ class TestDomainAdmin(MockEppLib, WebTest):
|
|||
username="MrMeoward",
|
||||
first_name="Meoward",
|
||||
last_name="Jones",
|
||||
email="meoward.jones@igorville.gov",
|
||||
phone="(555) 123 12345",
|
||||
title="Treat inspector",
|
||||
)
|
||||
|
||||
# Due to the relation between User <==> Contact,
|
||||
# the underlying contact has to be modified this way.
|
||||
_creator.contact.email = "meoward.jones@igorville.gov"
|
||||
_creator.contact.phone = "(555) 123 12345"
|
||||
_creator.contact.title = "Treat inspector"
|
||||
_creator.contact.save()
|
||||
|
||||
# Create a fake domain request
|
||||
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW, user=_creator)
|
||||
domain_request.approve()
|
||||
|
@ -2067,15 +2063,11 @@ class TestDomainRequestAdmin(MockEppLib):
|
|||
username="MrMeoward",
|
||||
first_name="Meoward",
|
||||
last_name="Jones",
|
||||
email="meoward.jones@igorville.gov",
|
||||
phone="(555) 123 12345",
|
||||
title="Treat inspector",
|
||||
)
|
||||
|
||||
# Due to the relation between User <==> Contact,
|
||||
# the underlying contact has to be modified this way.
|
||||
_creator.contact.email = "meoward.jones@igorville.gov"
|
||||
_creator.contact.phone = "(555) 123 12345"
|
||||
_creator.contact.title = "Treat inspector"
|
||||
_creator.contact.save()
|
||||
|
||||
# Create a fake domain request
|
||||
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW, user=_creator)
|
||||
|
||||
|
@ -2092,11 +2084,11 @@ class TestDomainRequestAdmin(MockEppLib):
|
|||
|
||||
# == Check for the creator == #
|
||||
|
||||
# Check for the right title, email, and phone number in the response.
|
||||
# Check for the right title and phone number in the response.
|
||||
# Email will appear more than once
|
||||
expected_creator_fields = [
|
||||
# Field, expected value
|
||||
("title", "Treat inspector"),
|
||||
("email", "meoward.jones@igorville.gov"),
|
||||
("phone", "(555) 123 12345"),
|
||||
]
|
||||
self.test_helper.assert_response_contains_distinct_values(response, expected_creator_fields)
|
||||
|
@ -3103,15 +3095,11 @@ class TestDomainInformationAdmin(TestCase):
|
|||
username="MrMeoward",
|
||||
first_name="Meoward",
|
||||
last_name="Jones",
|
||||
email="meoward.jones@igorville.gov",
|
||||
phone="(555) 123 12345",
|
||||
title="Treat inspector",
|
||||
)
|
||||
|
||||
# Due to the relation between User <==> Contact,
|
||||
# the underlying contact has to be modified this way.
|
||||
_creator.contact.email = "meoward.jones@igorville.gov"
|
||||
_creator.contact.phone = "(555) 123 12345"
|
||||
_creator.contact.title = "Treat inspector"
|
||||
_creator.contact.save()
|
||||
|
||||
# Create a fake domain request
|
||||
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW, user=_creator)
|
||||
domain_request.approve()
|
||||
|
@ -3133,13 +3121,12 @@ class TestDomainInformationAdmin(TestCase):
|
|||
|
||||
# == Check for the creator == #
|
||||
|
||||
# Check for the right title, email, and phone number in the response.
|
||||
# Check for the right title and phone number in the response.
|
||||
# We only need to check for the end tag
|
||||
# (Otherwise this test will fail if we change classes, etc)
|
||||
expected_creator_fields = [
|
||||
# Field, expected value
|
||||
("title", "Treat inspector"),
|
||||
("email", "meoward.jones@igorville.gov"),
|
||||
("phone", "(555) 123 12345"),
|
||||
]
|
||||
self.test_helper.assert_response_contains_distinct_values(response, expected_creator_fields)
|
||||
|
@ -4067,8 +4054,8 @@ class TestContactAdmin(TestCase):
|
|||
self.assertEqual(readonly_fields, expected_fields)
|
||||
|
||||
def test_change_view_for_joined_contact_five_or_less(self):
|
||||
"""Create a contact, join it to 4 domain requests. The 5th join will be a user.
|
||||
Assert that the warning on the contact form lists 5 joins."""
|
||||
"""Create a contact, join it to 4 domain requests. 5th join is user.
|
||||
Assert that the warning on the contact form lists 4 joins."""
|
||||
with less_console_noise():
|
||||
self.client.force_login(self.superuser)
|
||||
|
||||
|
@ -4099,17 +4086,17 @@ class TestContactAdmin(TestCase):
|
|||
"<li>Joined to DomainRequest: <a href='/admin/registrar/"
|
||||
f"domainrequest/{domain_request4.pk}/change/'>city4.gov</a></li>"
|
||||
"<li>Joined to User: <a href='/admin/registrar/"
|
||||
f"user/{self.staffuser.pk}/change/'>staff@example.com</a></li>"
|
||||
f"user/{self.staffuser.pk}/change/'>first last staff@example.com</a></li>"
|
||||
"</ul>",
|
||||
)
|
||||
|
||||
def test_change_view_for_joined_contact_five_or_more(self):
|
||||
"""Create a contact, join it to 5 domain requests. The 6th join will be a user.
|
||||
"""Create a contact, join it to 5 domain requests. 6th join is user.
|
||||
Assert that the warning on the contact form lists 5 joins and a '1 more' ellispsis."""
|
||||
with less_console_noise():
|
||||
self.client.force_login(self.superuser)
|
||||
# Create an instance of the model
|
||||
# join it to 5 domain requests. The 6th join will be a user.
|
||||
# join it to 6 domain requests.
|
||||
contact, _ = Contact.objects.get_or_create(user=self.staffuser)
|
||||
domain_request1 = completed_domain_request(submitter=contact, name="city1.gov")
|
||||
domain_request2 = completed_domain_request(submitter=contact, name="city2.gov")
|
||||
|
|
|
@ -1209,24 +1209,14 @@ class TestUser(TestCase):
|
|||
# test with a user with contact info defined
|
||||
self.assertTrue(self.user.has_contact_info())
|
||||
# test with a user without contact info defined
|
||||
self.user.contact.title = None
|
||||
self.user.contact.email = None
|
||||
self.user.contact.phone = None
|
||||
self.user.title = None
|
||||
self.user.email = None
|
||||
self.user.phone = None
|
||||
self.assertFalse(self.user.has_contact_info())
|
||||
|
||||
|
||||
class TestContact(TestCase):
|
||||
def setUp(self):
|
||||
self.email_for_invalid = "intern@igorville.gov"
|
||||
self.invalid_user, _ = User.objects.get_or_create(
|
||||
username=self.email_for_invalid,
|
||||
email=self.email_for_invalid,
|
||||
first_name="",
|
||||
last_name="",
|
||||
phone="",
|
||||
)
|
||||
self.invalid_contact, _ = Contact.objects.get_or_create(user=self.invalid_user)
|
||||
|
||||
self.email = "mayor@igorville.gov"
|
||||
self.user, _ = User.objects.get_or_create(
|
||||
email=self.email, first_name="Jeff", last_name="Lebowski", phone="123456789"
|
||||
|
@ -1242,87 +1232,6 @@ class TestContact(TestCase):
|
|||
Contact.objects.all().delete()
|
||||
User.objects.all().delete()
|
||||
|
||||
def test_saving_contact_updates_user_first_last_names_and_phone(self):
|
||||
"""When a contact is updated, we propagate the changes to the linked user if it exists."""
|
||||
|
||||
# User and Contact are created and linked as expected.
|
||||
# An empty User object should create an empty contact.
|
||||
self.assertEqual(self.invalid_contact.first_name, "")
|
||||
self.assertEqual(self.invalid_contact.last_name, "")
|
||||
self.assertEqual(self.invalid_contact.phone, "")
|
||||
self.assertEqual(self.invalid_user.first_name, "")
|
||||
self.assertEqual(self.invalid_user.last_name, "")
|
||||
self.assertEqual(self.invalid_user.phone, "")
|
||||
|
||||
# Manually update the contact - mimicking production (pre-existing data)
|
||||
self.invalid_contact.first_name = "Joey"
|
||||
self.invalid_contact.last_name = "Baloney"
|
||||
self.invalid_contact.phone = "123456789"
|
||||
self.invalid_contact.save()
|
||||
|
||||
# Refresh the user object to reflect the changes made in the database
|
||||
self.invalid_user.refresh_from_db()
|
||||
|
||||
# Updating the contact's first and last names propagate to the user
|
||||
self.assertEqual(self.invalid_contact.first_name, "Joey")
|
||||
self.assertEqual(self.invalid_contact.last_name, "Baloney")
|
||||
self.assertEqual(self.invalid_contact.phone, "123456789")
|
||||
self.assertEqual(self.invalid_user.first_name, "Joey")
|
||||
self.assertEqual(self.invalid_user.last_name, "Baloney")
|
||||
self.assertEqual(self.invalid_user.phone, "123456789")
|
||||
|
||||
def test_saving_contact_does_not_update_user_first_last_names_and_phone(self):
|
||||
"""When a contact is updated, we avoid propagating the changes to the linked user if it already has a value"""
|
||||
|
||||
# User and Contact are created and linked as expected
|
||||
self.assertEqual(self.contact.first_name, "Jeff")
|
||||
self.assertEqual(self.contact.last_name, "Lebowski")
|
||||
self.assertEqual(self.contact.phone, "123456789")
|
||||
self.assertEqual(self.user.first_name, "Jeff")
|
||||
self.assertEqual(self.user.last_name, "Lebowski")
|
||||
self.assertEqual(self.user.phone, "123456789")
|
||||
|
||||
self.contact.first_name = "Joey"
|
||||
self.contact.last_name = "Baloney"
|
||||
self.contact.phone = "987654321"
|
||||
self.contact.save()
|
||||
|
||||
# Refresh the user object to reflect the changes made in the database
|
||||
self.user.refresh_from_db()
|
||||
|
||||
# Updating the contact's first and last names propagate to the user
|
||||
self.assertEqual(self.contact.first_name, "Joey")
|
||||
self.assertEqual(self.contact.last_name, "Baloney")
|
||||
self.assertEqual(self.contact.phone, "987654321")
|
||||
self.assertEqual(self.user.first_name, "Jeff")
|
||||
self.assertEqual(self.user.last_name, "Lebowski")
|
||||
self.assertEqual(self.user.phone, "123456789")
|
||||
|
||||
def test_saving_contact_does_not_update_user_email(self):
|
||||
"""When a contact's email is updated, the change is not propagated to the user."""
|
||||
self.contact.email = "joey.baloney@diaperville.com"
|
||||
self.contact.save()
|
||||
|
||||
# Refresh the user object to reflect the changes made in the database
|
||||
self.user.refresh_from_db()
|
||||
|
||||
# Updating the contact's email does not propagate
|
||||
self.assertEqual(self.contact.email, "joey.baloney@diaperville.com")
|
||||
self.assertEqual(self.user.email, "mayor@igorville.gov")
|
||||
|
||||
def test_saving_contact_does_not_update_user_email_when_none(self):
|
||||
"""When a contact's email is updated, and the first/last name is none,
|
||||
the change is not propagated to the user."""
|
||||
self.invalid_contact.email = "joey.baloney@diaperville.com"
|
||||
self.invalid_contact.save()
|
||||
|
||||
# Refresh the user object to reflect the changes made in the database
|
||||
self.invalid_user.refresh_from_db()
|
||||
|
||||
# Updating the contact's email does not propagate
|
||||
self.assertEqual(self.invalid_contact.email, "joey.baloney@diaperville.com")
|
||||
self.assertEqual(self.invalid_user.email, "intern@igorville.gov")
|
||||
|
||||
def test_has_more_than_one_join(self):
|
||||
"""Test the Contact model method, has_more_than_one_join"""
|
||||
# test for a contact which has one user defined
|
||||
|
@ -1334,6 +1243,7 @@ class TestContact(TestCase):
|
|||
|
||||
def test_has_contact_info(self):
|
||||
"""Test that has_contact_info properly returns"""
|
||||
self.contact.title = "Title"
|
||||
# test with a contact with contact info defined
|
||||
self.assertTrue(self.contact.has_contact_info())
|
||||
# test with a contact without contact info defined
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
from django.test import TestCase
|
||||
from django.contrib.auth import get_user_model
|
||||
from registrar.models import Contact
|
||||
|
||||
|
||||
class TestUserPostSave(TestCase):
|
||||
def setUp(self):
|
||||
self.username = "test_user"
|
||||
self.first_name = "First"
|
||||
self.last_name = "Last"
|
||||
self.email = "info@example.com"
|
||||
self.phone = "202-555-0133"
|
||||
|
||||
self.preferred_first_name = "One"
|
||||
self.preferred_last_name = "Two"
|
||||
self.preferred_email = "front_desk@example.com"
|
||||
self.preferred_phone = "202-555-0134"
|
||||
|
||||
def test_user_created_without_matching_contact(self):
|
||||
"""Expect 1 Contact containing data copied from User."""
|
||||
self.assertEqual(len(Contact.objects.all()), 0)
|
||||
user = get_user_model().objects.create(
|
||||
username=self.username,
|
||||
first_name=self.first_name,
|
||||
last_name=self.last_name,
|
||||
email=self.email,
|
||||
phone=self.phone,
|
||||
)
|
||||
actual = Contact.objects.get(user=user)
|
||||
self.assertEqual(actual.first_name, self.first_name)
|
||||
self.assertEqual(actual.last_name, self.last_name)
|
||||
self.assertEqual(actual.email, self.email)
|
||||
self.assertEqual(actual.phone, self.phone)
|
||||
|
||||
def test_user_created_with_matching_contact(self):
|
||||
"""Expect 1 Contact associated, but with no data copied from User."""
|
||||
self.assertEqual(len(Contact.objects.all()), 0)
|
||||
Contact.objects.create(
|
||||
first_name=self.preferred_first_name,
|
||||
last_name=self.preferred_last_name,
|
||||
email=self.email, # must be the same, to find the match!
|
||||
phone=self.preferred_phone,
|
||||
)
|
||||
user = get_user_model().objects.create(
|
||||
username=self.username,
|
||||
first_name=self.first_name,
|
||||
last_name=self.last_name,
|
||||
email=self.email,
|
||||
)
|
||||
actual = Contact.objects.get(user=user)
|
||||
self.assertEqual(actual.first_name, self.preferred_first_name)
|
||||
self.assertEqual(actual.last_name, self.preferred_last_name)
|
||||
self.assertEqual(actual.email, self.email)
|
||||
self.assertEqual(actual.phone, self.preferred_phone)
|
||||
|
||||
def test_user_updated_without_matching_contact(self):
|
||||
"""Expect 1 Contact containing data copied from User."""
|
||||
# create the user
|
||||
self.assertEqual(len(Contact.objects.all()), 0)
|
||||
user = get_user_model().objects.create(username=self.username, first_name="", last_name="", email="", phone="")
|
||||
# delete the contact
|
||||
Contact.objects.all().delete()
|
||||
self.assertEqual(len(Contact.objects.all()), 0)
|
||||
# modify the user
|
||||
user.username = self.username
|
||||
user.first_name = self.first_name
|
||||
user.last_name = self.last_name
|
||||
user.email = self.email
|
||||
user.phone = self.phone
|
||||
user.save()
|
||||
# test
|
||||
actual = Contact.objects.get(user=user)
|
||||
self.assertEqual(actual.first_name, self.first_name)
|
||||
self.assertEqual(actual.last_name, self.last_name)
|
||||
self.assertEqual(actual.email, self.email)
|
||||
self.assertEqual(actual.phone, self.phone)
|
||||
|
||||
def test_user_updated_with_matching_contact(self):
|
||||
"""Expect 1 Contact associated, but with no data copied from User."""
|
||||
# create the user
|
||||
self.assertEqual(len(Contact.objects.all()), 0)
|
||||
user = get_user_model().objects.create(
|
||||
username=self.username,
|
||||
first_name=self.first_name,
|
||||
last_name=self.last_name,
|
||||
email=self.email,
|
||||
phone=self.phone,
|
||||
)
|
||||
# modify the user
|
||||
user.first_name = self.preferred_first_name
|
||||
user.last_name = self.preferred_last_name
|
||||
user.email = self.preferred_email
|
||||
user.phone = self.preferred_phone
|
||||
user.save()
|
||||
# test
|
||||
actual = Contact.objects.get(user=user)
|
||||
self.assertEqual(actual.first_name, self.first_name)
|
||||
self.assertEqual(actual.last_name, self.last_name)
|
||||
self.assertEqual(actual.email, self.email)
|
||||
self.assertEqual(actual.phone, self.phone)
|
|
@ -57,12 +57,10 @@ class TestWithUser(MockEppLib):
|
|||
last_name = "Last"
|
||||
email = "info@example.com"
|
||||
phone = "8003111234"
|
||||
self.user = get_user_model().objects.create(
|
||||
username=username, first_name=first_name, last_name=last_name, email=email, phone=phone
|
||||
)
|
||||
title = "test title"
|
||||
self.user.contact.title = title
|
||||
self.user.contact.save()
|
||||
self.user = get_user_model().objects.create(
|
||||
username=username, first_name=first_name, last_name=last_name, title=title, email=email, phone=phone
|
||||
)
|
||||
|
||||
username_regular_incomplete = "test_regular_user_incomplete"
|
||||
username_other_incomplete = "test_other_user_incomplete"
|
||||
|
@ -560,7 +558,7 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
|||
self.assertContains(finish_setup_page, "Enter your phone number.")
|
||||
|
||||
# Check for the name of the save button
|
||||
self.assertContains(finish_setup_page, "contact_setup_save_button")
|
||||
self.assertContains(finish_setup_page, "user_setup_save_button")
|
||||
|
||||
# Add a phone number
|
||||
finish_setup_form = finish_setup_page.form
|
||||
|
@ -598,7 +596,7 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
|||
self.assertContains(finish_setup_page, "Enter your phone number.")
|
||||
|
||||
# Check for the name of the save button
|
||||
self.assertContains(finish_setup_page, "contact_setup_save_button")
|
||||
self.assertContains(finish_setup_page, "user_setup_save_button")
|
||||
|
||||
# Add a phone number
|
||||
finish_setup_form = finish_setup_page.form
|
||||
|
@ -613,7 +611,7 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
|||
|
||||
# Submit the form using the specific submit button to execute the redirect
|
||||
completed_setup_page = self._submit_form_webtest(
|
||||
finish_setup_form, follow=True, name="contact_setup_submit_button"
|
||||
finish_setup_form, follow=True, name="user_setup_submit_button"
|
||||
)
|
||||
self.assertEqual(completed_setup_page.status_code, 200)
|
||||
|
||||
|
|
|
@ -1478,8 +1478,8 @@ class TestDomainContactInformation(TestDomainOverview):
|
|||
|
||||
def test_domain_your_contact_information_content(self):
|
||||
"""Logged-in user's contact information appears on the page."""
|
||||
self.user.contact.first_name = "Testy"
|
||||
self.user.contact.save()
|
||||
self.user.first_name = "Testy"
|
||||
self.user.save()
|
||||
page = self.app.get(reverse("domain-your-contact-information", kwargs={"pk": self.domain.id}))
|
||||
self.assertContains(page, "Testy")
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ from registrar.models.utility.contact_error import ContactError
|
|||
from registrar.views.utility.permission_views import UserDomainRolePermissionDeleteView
|
||||
|
||||
from ..forms import (
|
||||
ContactForm,
|
||||
UserForm,
|
||||
AuthorizingOfficialContactForm,
|
||||
DomainOrgNameAddressForm,
|
||||
DomainAddUserForm,
|
||||
|
@ -573,7 +573,7 @@ class DomainYourContactInformationView(DomainFormBaseView):
|
|||
"""Domain your contact information editing view."""
|
||||
|
||||
template_name = "domain_your_contact_information.html"
|
||||
form_class = ContactForm
|
||||
form_class = UserForm
|
||||
|
||||
@waffle_flag("!profile_feature") # type: ignore
|
||||
def dispatch(self, request, *args, **kwargs): # type: ignore
|
||||
|
@ -582,7 +582,7 @@ class DomainYourContactInformationView(DomainFormBaseView):
|
|||
def get_form_kwargs(self, *args, **kwargs):
|
||||
"""Add domain_info.submitter instance to make a bound form."""
|
||||
form_kwargs = super().get_form_kwargs(*args, **kwargs)
|
||||
form_kwargs["instance"] = self.request.user.contact
|
||||
form_kwargs["instance"] = self.request.user
|
||||
return form_kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
|
|
|
@ -9,9 +9,6 @@ from django.http import QueryDict
|
|||
from django.views.generic.edit import FormMixin
|
||||
from registrar.forms.user_profile import UserProfileForm, FinishSetupProfileForm
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from registrar.models import (
|
||||
Contact,
|
||||
)
|
||||
from registrar.models.user import User
|
||||
from registrar.models.utility.generic_helper import replace_url_queryparams
|
||||
from registrar.views.utility.permission_views import UserProfilePermissionView
|
||||
|
@ -25,7 +22,7 @@ class UserProfileView(UserProfilePermissionView, FormMixin):
|
|||
Base View for the User Profile. Handles getting and setting the User Profile
|
||||
"""
|
||||
|
||||
model = Contact
|
||||
model = User
|
||||
template_name = "profile.html"
|
||||
form_class = UserProfileForm
|
||||
base_view_name = "user-profile"
|
||||
|
@ -57,6 +54,7 @@ class UserProfileView(UserProfilePermissionView, FormMixin):
|
|||
def get_context_data(self, **kwargs):
|
||||
"""Extend get_context_data to include has_profile_feature_flag"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
logger.info("UserProfileView::get_context_data")
|
||||
# This is a django waffle flag which toggles features based off of the "flag" table
|
||||
context["has_profile_feature_flag"] = flag_is_active(self.request, "profile_feature")
|
||||
|
||||
|
@ -123,9 +121,7 @@ class UserProfileView(UserProfilePermissionView, FormMixin):
|
|||
def get_object(self, queryset=None):
|
||||
"""Override get_object to return the logged-in user's contact"""
|
||||
self.user = self.request.user # get the logged in user
|
||||
if hasattr(self.user, "contact"): # Check if the user has a contact instance
|
||||
return self.user.contact
|
||||
return None
|
||||
return self.user
|
||||
|
||||
|
||||
class FinishProfileSetupView(UserProfileView):
|
||||
|
@ -134,7 +130,7 @@ class FinishProfileSetupView(UserProfileView):
|
|||
|
||||
template_name = "finish_profile_setup.html"
|
||||
form_class = FinishSetupProfileForm
|
||||
model = Contact
|
||||
model = User
|
||||
|
||||
base_view_name = "finish-user-profile-setup"
|
||||
|
||||
|
@ -160,11 +156,11 @@ class FinishProfileSetupView(UserProfileView):
|
|||
# Get the current form and validate it
|
||||
if form.is_valid():
|
||||
self.redirect_page = False
|
||||
if "contact_setup_save_button" in request.POST:
|
||||
if "user_setup_save_button" in request.POST:
|
||||
# Logic for when the 'Save' button is clicked, which indicates
|
||||
# user should stay on this page
|
||||
self.redirect_page = False
|
||||
elif "contact_setup_submit_button" in request.POST:
|
||||
elif "user_setup_submit_button" in request.POST:
|
||||
# Logic for when the other button is clicked, which indicates
|
||||
# the user should be taken to the redirect page
|
||||
self.redirect_page = True
|
||||
|
|
|
@ -4,7 +4,7 @@ import abc # abstract base class
|
|||
|
||||
from django.views.generic import DetailView, DeleteView, TemplateView
|
||||
from registrar.models import Domain, DomainRequest, DomainInvitation
|
||||
from registrar.models.contact import Contact
|
||||
from registrar.models.user import User
|
||||
from registrar.models.user_domain_role import UserDomainRole
|
||||
|
||||
from .mixins import (
|
||||
|
@ -154,9 +154,9 @@ class UserProfilePermissionView(UserProfilePermission, DetailView, abc.ABC):
|
|||
"""
|
||||
|
||||
# DetailView property for what model this is viewing
|
||||
model = Contact
|
||||
model = User
|
||||
# variable name in template context for the model object
|
||||
context_object_name = "contact"
|
||||
context_object_name = "user"
|
||||
|
||||
# Abstract property enforces NotImplementedError on an attribute.
|
||||
@property
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue