We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Save phone number received from login.gov
### Issue description

For the user profile feature, we will need phone number from login.gov and need it to appear on the connected Contact object. We should save the phone number both the user and connected contact as soon as we get it, but only if the phone number isn't already filled in. Users can update the phone number as needed in our system and we should trust if they already have a phone number filled in manually then it is probably a better one to contact them on anyways. 

### Acceptance criteria

- [ ] Save phone number from login.gov to a user's Contact
- [ ] If phone number is already filled in for the associated contact, update the user and leave the contact alone
- [ ] On saving contact, if contact has a related user with no phone number, update user
- [ ] Update unit tests

### Additional context

_No response_

### Links to other issues

blocks: #1807 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/registrar/models/contact.py`
Content:
```
1 from django.db import models
2 
3 from .utility.time_stamped_model import TimeStampedModel
4 
5 from phonenumber_field.modelfields import PhoneNumberField  # type: ignore
6 
7 
8 class Contact(TimeStampedModel):
9     """Contact information follows a similar pattern for each contact."""
10 
11     user = models.OneToOneField(
12         "registrar.User",
13         null=True,
14         blank=True,
15         on_delete=models.SET_NULL,
16     )
17 
18     first_name = models.CharField(
19         null=True,
20         blank=True,
21         verbose_name="first name",
22         db_index=True,
23     )
24     middle_name = models.CharField(
25         null=True,
26         blank=True,
27     )
28     last_name = models.CharField(
29         null=True,
30         blank=True,
31         verbose_name="last name",
32         db_index=True,
33     )
34     title = models.CharField(
35         null=True,
36         blank=True,
37         verbose_name="title / role",
38     )
39     email = models.EmailField(
40         null=True,
41         blank=True,
42         db_index=True,
43         max_length=320,
44     )
45     phone = PhoneNumberField(
46         null=True,
47         blank=True,
48         db_index=True,
49     )
50 
51     def _get_all_relations(self):
52         """Returns an array of all fields which are relations"""
53         return [f.name for f in self._meta.get_fields() if f.is_relation]
54 
55     def has_more_than_one_join(self, expected_relation):
56         """Helper for finding whether an object is joined more than once.
57         expected_relation is the one relation with one expected join"""
58         # all_relations is the list of all_relations (from contact) to be checked for existing joins
59         all_relations = self._get_all_relations()
60         return any(self._has_more_than_one_join_per_relation(rel, expected_relation) for rel in all_relations)
61 
62     def _has_more_than_one_join_per_relation(self, relation, expected_relation):
63         """Helper for finding whether an object is joined more than once."""
64         # threshold is the number of related objects that are acceptable
65         # when determining if related objects exist. threshold is 0 for most
66         # relationships. if the relationship is expected_relation, we know that
67         # there is already exactly 1 acceptable relationship (the one we are
68         # attempting to delete), so the threshold is 1
69         threshold = 1 if relation == expected_relation else 0
70 
71         # Raise a KeyError if rel is not a defined field on the db_obj model
72         # This will help catch any errors in relation passed.
73         if relation not in [field.name for field in self._meta.get_fields()]:
74             raise KeyError(f"{relation} is not a defined field on the {self._meta.model_name} model.")
75 
76         # if attr rel in db_obj is not None, then test if reference object(s) exist
77         if getattr(self, relation) is not None:
78             field = self._meta.get_field(relation)
79             if isinstance(field, models.OneToOneField):
80                 # if the rel field is a OneToOne field, then we have already
81                 # determined that the object exists (is not None)
82                 # so return True unless the relation being tested is the expected_relation
83                 is_not_expected_relation = relation != expected_relation
84                 return is_not_expected_relation
85             elif isinstance(field, models.ForeignObjectRel):
86                 # if the rel field is a ManyToOne or ManyToMany, then we need
87                 # to determine if the count of related objects is greater than
88                 # the threshold
89                 return getattr(self, relation).count() > threshold
90         return False
91 
92     def get_formatted_name(self):
93         """Returns the contact's name in Western order."""
94         names = [n for n in [self.first_name, self.middle_name, self.last_name] if n]
95         return " ".join(names) if names else "Unknown"
96 
97     def has_contact_info(self):
98         return bool(self.title or self.email or self.phone)
99 
100     def save(self, *args, **kwargs):
101         # Call the parent class's save method to perform the actual save
102         super().save(*args, **kwargs)
103 
104         # Update the related User object's first_name and last_name
105         if self.user and (not self.user.first_name or not self.user.last_name):
106             self.user.first_name = self.first_name
107             self.user.last_name = self.last_name
108             self.user.save()
109 
110     def __str__(self):
111         if self.first_name or self.last_name:
112             return self.get_formatted_name()
113         elif self.email:
114             return self.email
115         elif self.pk:
116             return str(self.pk)
117         else:
118             return ""
119
```

Path: `src/djangooidc/backends.py`
Content:
```
1 # coding: utf-8
2 from __future__ import unicode_literals
3 
4 import logging
5 
6 from django.conf import settings
7 from django.contrib.auth import get_user_model
8 from django.contrib.auth.backends import ModelBackend
9 from django.utils import timezone
10 
11 logger = logging.getLogger(__name__)
12 
13 
14 class OpenIdConnectBackend(ModelBackend):
15     """
16     This backend checks a previously performed OIDC authentication.
17     If it is OK and the user already exists in the database, it is returned.
18     If it is OK and user does not exist in the database, it is created and
19         returned unless setting OIDC_CREATE_UNKNOWN_USER is False.
20     In all other cases, None is returned.
21     """
22 
23     def authenticate(self, request, **kwargs):
24         logger.debug("kwargs %s" % kwargs)
25         user = None
26         if not kwargs or "sub" not in kwargs.keys():
27             return user
28 
29         UserModel = get_user_model()
30         username = self.clean_username(kwargs["sub"])
31 
32         # Some OP may actually choose to withhold some information, so we must
33         # test if it is present
34         openid_data = {"last_login": timezone.now()}
35         openid_data["first_name"] = kwargs.get("given_name", "")
36         openid_data["last_name"] = kwargs.get("family_name", "")
37         openid_data["email"] = kwargs.get("email", "")
38         openid_data["phone"] = kwargs.get("phone", "")
39 
40         # Note that this could be accomplished in one try-except clause, but
41         # instead we use get_or_create when creating unknown users since it has
42         # built-in safeguards for multiple threads.
43         if getattr(settings, "OIDC_CREATE_UNKNOWN_USER", True):
44             args = {
45                 UserModel.USERNAME_FIELD: username,
46                 # defaults _will_ be updated, these are not fallbacks
47                 "defaults": openid_data,
48             }
49 
50             user, created = UserModel.objects.get_or_create(**args)
51 
52             if not created:
53                 # If user exists, update existing user
54                 self.update_existing_user(user, args["defaults"])
55             else:
56                 # If user is created, configure the user
57                 user = self.configure_user(user, **kwargs)
58         else:
59             try:
60                 user = UserModel.objects.get_by_natural_key(username)
61             except UserModel.DoesNotExist:
62                 return None
63         # run this callback for a each login
64         user.on_each_login()
65         return user
66 
67     def update_existing_user(self, user, kwargs):
68         """Update other fields without overwriting first_name and last_name.
69         Overwrite first_name and last_name if not empty string"""
70 
71         for key, value in kwargs.items():
72             # Check if the key is not first_name or last_name or value is not empty string
73             if key not in ["first_name", "last_name"] or value:
74                 setattr(user, key, value)
75         user.save()
76 
77     def clean_username(self, username):
78         """
79         Performs any cleaning on the "username" prior to using it to get or
80         create the user object.  Returns the cleaned username.
81         """
82         return username
83 
84     def configure_user(self, user, **kwargs):
85         """
86         Configures a user after creation and returns the updated user.
87         """
88         user.set_unusable_password()
89         return user
90
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/djangooidc/backends.py b/src/djangooidc/backends.py
--- a/src/djangooidc/backends.py
+++ b/src/djangooidc/backends.py
@@ -65,13 +65,31 @@
         return user
 
     def update_existing_user(self, user, kwargs):
-        """Update other fields without overwriting first_name and last_name.
-        Overwrite first_name and last_name if not empty string"""
+        """
+        Update user fields without overwriting certain fields.
+
+        Args:
+            user: User object to be updated.
+            kwargs: Dictionary containing fields to update and their new values.
 
+        Note:
+            This method updates user fields while preserving the values of 'first_name',
+            'last_name', and 'phone' fields, unless specific conditions are met.
+
+            - 'first_name', 'last_name' or 'phone' will be updated if the provided value is not empty.
+        """
+
+        fields_to_check = ["first_name", "last_name", "phone"]
+
+        # Iterate over fields to update
         for key, value in kwargs.items():
-            # Check if the key is not first_name or last_name or value is not empty string
-            if key not in ["first_name", "last_name"] or value:
+            # Check if the field is not 'first_name', 'last_name', or 'phone',
+            # or if it's 'first_name' or 'last_name' or 'phone' and the provided value is not empty
+            if key not in fields_to_check or (key in fields_to_check and value):
+                # Update the corresponding attribute of the user object
                 setattr(user, key, value)
+
+        # Save the user object with the updated fields
         user.save()
 
     def clean_username(self, username):
diff --git a/src/registrar/models/contact.py b/src/registrar/models/contact.py
--- a/src/registrar/models/contact.py
+++ b/src/registrar/models/contact.py
@@ -101,11 +101,23 @@
         # Call the parent class's save method to perform the actual save
         super().save(*args, **kwargs)
 
-        # Update the related User object's first_name and last_name
-        if self.user and (not self.user.first_name or not self.user.last_name):
-            self.user.first_name = self.first_name
-            self.user.last_name = self.last_name
-            self.user.save()
+        if self.user:
+            updated = False
+
+            # Update first name and last name if necessary
+            if not self.user.first_name or not self.user.last_name:
+                self.user.first_name = self.first_name
+                self.user.last_name = self.last_name
+                updated = True
+
+            # Update phone if necessary
+            if not self.user.phone:
+                self.user.phone = self.phone
+                updated = True
+
+            # Save user if any updates were made
+            if updated:
+                self.user.save()
 
     def __str__(self):
         if self.first_name or self.last_name:

{"golden_diff": "diff --git a/src/djangooidc/backends.py b/src/djangooidc/backends.py\n--- a/src/djangooidc/backends.py\n+++ b/src/djangooidc/backends.py\n@@ -65,13 +65,31 @@\n         return user\n \n     def update_existing_user(self, user, kwargs):\n-        \"\"\"Update other fields without overwriting first_name and last_name.\n-        Overwrite first_name and last_name if not empty string\"\"\"\n+        \"\"\"\n+        Update user fields without overwriting certain fields.\n+\n+        Args:\n+            user: User object to be updated.\n+            kwargs: Dictionary containing fields to update and their new values.\n \n+        Note:\n+            This method updates user fields while preserving the values of 'first_name',\n+            'last_name', and 'phone' fields, unless specific conditions are met.\n+\n+            - 'first_name', 'last_name' or 'phone' will be updated if the provided value is not empty.\n+        \"\"\"\n+\n+        fields_to_check = [\"first_name\", \"last_name\", \"phone\"]\n+\n+        # Iterate over fields to update\n         for key, value in kwargs.items():\n-            # Check if the key is not first_name or last_name or value is not empty string\n-            if key not in [\"first_name\", \"last_name\"] or value:\n+            # Check if the field is not 'first_name', 'last_name', or 'phone',\n+            # or if it's 'first_name' or 'last_name' or 'phone' and the provided value is not empty\n+            if key not in fields_to_check or (key in fields_to_check and value):\n+                # Update the corresponding attribute of the user object\n                 setattr(user, key, value)\n+\n+        # Save the user object with the updated fields\n         user.save()\n \n     def clean_username(self, username):\ndiff --git a/src/registrar/models/contact.py b/src/registrar/models/contact.py\n--- a/src/registrar/models/contact.py\n+++ b/src/registrar/models/contact.py\n@@ -101,11 +101,23 @@\n         # Call the parent class's save method to perform the actual save\n         super().save(*args, **kwargs)\n \n-        # Update the related User object's first_name and last_name\n-        if self.user and (not self.user.first_name or not self.user.last_name):\n-            self.user.first_name = self.first_name\n-            self.user.last_name = self.last_name\n-            self.user.save()\n+        if self.user:\n+            updated = False\n+\n+            # Update first name and last name if necessary\n+            if not self.user.first_name or not self.user.last_name:\n+                self.user.first_name = self.first_name\n+                self.user.last_name = self.last_name\n+                updated = True\n+\n+            # Update phone if necessary\n+            if not self.user.phone:\n+                self.user.phone = self.phone\n+                updated = True\n+\n+            # Save user if any updates were made\n+            if updated:\n+                self.user.save()\n \n     def __str__(self):\n         if self.first_name or self.last_name:\n", "issue": "Save phone number received from login.gov\n### Issue description\n\nFor the user profile feature, we will need phone number from login.gov and need it to appear on the connected Contact object. We should save the phone number both the user and connected contact as soon as we get it, but only if the phone number isn't already filled in. Users can update the phone number as needed in our system and we should trust if they already have a phone number filled in manually then it is probably a better one to contact them on anyways. \n\n### Acceptance criteria\n\n- [ ] Save phone number from login.gov to a user's Contact\n- [ ] If phone number is already filled in for the associated contact, update the user and leave the contact alone\n- [ ] On saving contact, if contact has a related user with no phone number, update user\n- [ ] Update unit tests\n\n### Additional context\n\n_No response_\n\n### Links to other issues\n\nblocks: #1807 \n", "before_files": [{"content": "from django.db import models\n\nfrom .utility.time_stamped_model import TimeStampedModel\n\nfrom phonenumber_field.modelfields import PhoneNumberField  # type: ignore\n\n\nclass Contact(TimeStampedModel):\n    \"\"\"Contact information follows a similar pattern for each contact.\"\"\"\n\n    user = models.OneToOneField(\n        \"registrar.User\",\n        null=True,\n        blank=True,\n        on_delete=models.SET_NULL,\n    )\n\n    first_name = models.CharField(\n        null=True,\n        blank=True,\n        verbose_name=\"first name\",\n        db_index=True,\n    )\n    middle_name = models.CharField(\n        null=True,\n        blank=True,\n    )\n    last_name = models.CharField(\n        null=True,\n        blank=True,\n        verbose_name=\"last name\",\n        db_index=True,\n    )\n    title = models.CharField(\n        null=True,\n        blank=True,\n        verbose_name=\"title / role\",\n    )\n    email = models.EmailField(\n        null=True,\n        blank=True,\n        db_index=True,\n        max_length=320,\n    )\n    phone = PhoneNumberField(\n        null=True,\n        blank=True,\n        db_index=True,\n    )\n\n    def _get_all_relations(self):\n        \"\"\"Returns an array of all fields which are relations\"\"\"\n        return [f.name for f in self._meta.get_fields() if f.is_relation]\n\n    def has_more_than_one_join(self, expected_relation):\n        \"\"\"Helper for finding whether an object is joined more than once.\n        expected_relation is the one relation with one expected join\"\"\"\n        # all_relations is the list of all_relations (from contact) to be checked for existing joins\n        all_relations = self._get_all_relations()\n        return any(self._has_more_than_one_join_per_relation(rel, expected_relation) for rel in all_relations)\n\n    def _has_more_than_one_join_per_relation(self, relation, expected_relation):\n        \"\"\"Helper for finding whether an object is joined more than once.\"\"\"\n        # threshold is the number of related objects that are acceptable\n        # when determining if related objects exist. threshold is 0 for most\n        # relationships. if the relationship is expected_relation, we know that\n        # there is already exactly 1 acceptable relationship (the one we are\n        # attempting to delete), so the threshold is 1\n        threshold = 1 if relation == expected_relation else 0\n\n        # Raise a KeyError if rel is not a defined field on the db_obj model\n        # This will help catch any errors in relation passed.\n        if relation not in [field.name for field in self._meta.get_fields()]:\n            raise KeyError(f\"{relation} is not a defined field on the {self._meta.model_name} model.\")\n\n        # if attr rel in db_obj is not None, then test if reference object(s) exist\n        if getattr(self, relation) is not None:\n            field = self._meta.get_field(relation)\n            if isinstance(field, models.OneToOneField):\n                # if the rel field is a OneToOne field, then we have already\n                # determined that the object exists (is not None)\n                # so return True unless the relation being tested is the expected_relation\n                is_not_expected_relation = relation != expected_relation\n                return is_not_expected_relation\n            elif isinstance(field, models.ForeignObjectRel):\n                # if the rel field is a ManyToOne or ManyToMany, then we need\n                # to determine if the count of related objects is greater than\n                # the threshold\n                return getattr(self, relation).count() > threshold\n        return False\n\n    def get_formatted_name(self):\n        \"\"\"Returns the contact's name in Western order.\"\"\"\n        names = [n for n in [self.first_name, self.middle_name, self.last_name] if n]\n        return \" \".join(names) if names else \"Unknown\"\n\n    def has_contact_info(self):\n        return bool(self.title or self.email or self.phone)\n\n    def save(self, *args, **kwargs):\n        # Call the parent class's save method to perform the actual save\n        super().save(*args, **kwargs)\n\n        # Update the related User object's first_name and last_name\n        if self.user and (not self.user.first_name or not self.user.last_name):\n            self.user.first_name = self.first_name\n            self.user.last_name = self.last_name\n            self.user.save()\n\n    def __str__(self):\n        if self.first_name or self.last_name:\n            return self.get_formatted_name()\n        elif self.email:\n            return self.email\n        elif self.pk:\n            return str(self.pk)\n        else:\n            return \"\"\n", "path": "src/registrar/models/contact.py"}, {"content": "# coding: utf-8\nfrom __future__ import unicode_literals\n\nimport logging\n\nfrom django.conf import settings\nfrom django.contrib.auth import get_user_model\nfrom django.contrib.auth.backends import ModelBackend\nfrom django.utils import timezone\n\nlogger = logging.getLogger(__name__)\n\n\nclass OpenIdConnectBackend(ModelBackend):\n    \"\"\"\n    This backend checks a previously performed OIDC authentication.\n    If it is OK and the user already exists in the database, it is returned.\n    If it is OK and user does not exist in the database, it is created and\n        returned unless setting OIDC_CREATE_UNKNOWN_USER is False.\n    In all other cases, None is returned.\n    \"\"\"\n\n    def authenticate(self, request, **kwargs):\n        logger.debug(\"kwargs %s\" % kwargs)\n        user = None\n        if not kwargs or \"sub\" not in kwargs.keys():\n            return user\n\n        UserModel = get_user_model()\n        username = self.clean_username(kwargs[\"sub\"])\n\n        # Some OP may actually choose to withhold some information, so we must\n        # test if it is present\n        openid_data = {\"last_login\": timezone.now()}\n        openid_data[\"first_name\"] = kwargs.get(\"given_name\", \"\")\n        openid_data[\"last_name\"] = kwargs.get(\"family_name\", \"\")\n        openid_data[\"email\"] = kwargs.get(\"email\", \"\")\n        openid_data[\"phone\"] = kwargs.get(\"phone\", \"\")\n\n        # Note that this could be accomplished in one try-except clause, but\n        # instead we use get_or_create when creating unknown users since it has\n        # built-in safeguards for multiple threads.\n        if getattr(settings, \"OIDC_CREATE_UNKNOWN_USER\", True):\n            args = {\n                UserModel.USERNAME_FIELD: username,\n                # defaults _will_ be updated, these are not fallbacks\n                \"defaults\": openid_data,\n            }\n\n            user, created = UserModel.objects.get_or_create(**args)\n\n            if not created:\n                # If user exists, update existing user\n                self.update_existing_user(user, args[\"defaults\"])\n            else:\n                # If user is created, configure the user\n                user = self.configure_user(user, **kwargs)\n        else:\n            try:\n                user = UserModel.objects.get_by_natural_key(username)\n            except UserModel.DoesNotExist:\n                return None\n        # run this callback for a each login\n        user.on_each_login()\n        return user\n\n    def update_existing_user(self, user, kwargs):\n        \"\"\"Update other fields without overwriting first_name and last_name.\n        Overwrite first_name and last_name if not empty string\"\"\"\n\n        for key, value in kwargs.items():\n            # Check if the key is not first_name or last_name or value is not empty string\n            if key not in [\"first_name\", \"last_name\"] or value:\n                setattr(user, key, value)\n        user.save()\n\n    def clean_username(self, username):\n        \"\"\"\n        Performs any cleaning on the \"username\" prior to using it to get or\n        create the user object.  Returns the cleaned username.\n        \"\"\"\n        return username\n\n    def configure_user(self, user, **kwargs):\n        \"\"\"\n        Configures a user after creation and returns the updated user.\n        \"\"\"\n        user.set_unusable_password()\n        return user\n", "path": "src/djangooidc/backends.py"}], "after_files": [{"content": "from django.db import models\n\nfrom .utility.time_stamped_model import TimeStampedModel\n\nfrom phonenumber_field.modelfields import PhoneNumberField  # type: ignore\n\n\nclass Contact(TimeStampedModel):\n    \"\"\"Contact information follows a similar pattern for each contact.\"\"\"\n\n    user = models.OneToOneField(\n        \"registrar.User\",\n        null=True,\n        blank=True,\n        on_delete=models.SET_NULL,\n    )\n\n    first_name = models.CharField(\n        null=True,\n        blank=True,\n        verbose_name=\"first name\",\n        db_index=True,\n    )\n    middle_name = models.CharField(\n        null=True,\n        blank=True,\n    )\n    last_name = models.CharField(\n        null=True,\n        blank=True,\n        verbose_name=\"last name\",\n        db_index=True,\n    )\n    title = models.CharField(\n        null=True,\n        blank=True,\n        verbose_name=\"title / role\",\n    )\n    email = models.EmailField(\n        null=True,\n        blank=True,\n        db_index=True,\n        max_length=320,\n    )\n    phone = PhoneNumberField(\n        null=True,\n        blank=True,\n        db_index=True,\n    )\n\n    def _get_all_relations(self):\n        \"\"\"Returns an array of all fields which are relations\"\"\"\n        return [f.name for f in self._meta.get_fields() if f.is_relation]\n\n    def has_more_than_one_join(self, expected_relation):\n        \"\"\"Helper for finding whether an object is joined more than once.\n        expected_relation is the one relation with one expected join\"\"\"\n        # all_relations is the list of all_relations (from contact) to be checked for existing joins\n        all_relations = self._get_all_relations()\n        return any(self._has_more_than_one_join_per_relation(rel, expected_relation) for rel in all_relations)\n\n    def _has_more_than_one_join_per_relation(self, relation, expected_relation):\n        \"\"\"Helper for finding whether an object is joined more than once.\"\"\"\n        # threshold is the number of related objects that are acceptable\n        # when determining if related objects exist. threshold is 0 for most\n        # relationships. if the relationship is expected_relation, we know that\n        # there is already exactly 1 acceptable relationship (the one we are\n        # attempting to delete), so the threshold is 1\n        threshold = 1 if relation == expected_relation else 0\n\n        # Raise a KeyError if rel is not a defined field on the db_obj model\n        # This will help catch any errors in relation passed.\n        if relation not in [field.name for field in self._meta.get_fields()]:\n            raise KeyError(f\"{relation} is not a defined field on the {self._meta.model_name} model.\")\n\n        # if attr rel in db_obj is not None, then test if reference object(s) exist\n        if getattr(self, relation) is not None:\n            field = self._meta.get_field(relation)\n            if isinstance(field, models.OneToOneField):\n                # if the rel field is a OneToOne field, then we have already\n                # determined that the object exists (is not None)\n                # so return True unless the relation being tested is the expected_relation\n                is_not_expected_relation = relation != expected_relation\n                return is_not_expected_relation\n            elif isinstance(field, models.ForeignObjectRel):\n                # if the rel field is a ManyToOne or ManyToMany, then we need\n                # to determine if the count of related objects is greater than\n                # the threshold\n                return getattr(self, relation).count() > threshold\n        return False\n\n    def get_formatted_name(self):\n        \"\"\"Returns the contact's name in Western order.\"\"\"\n        names = [n for n in [self.first_name, self.middle_name, self.last_name] if n]\n        return \" \".join(names) if names else \"Unknown\"\n\n    def has_contact_info(self):\n        return bool(self.title or self.email or self.phone)\n\n    def save(self, *args, **kwargs):\n        # Call the parent class's save method to perform the actual save\n        super().save(*args, **kwargs)\n\n        if self.user:\n            updated = False\n\n            # Update first name and last name if necessary\n            if not self.user.first_name or not self.user.last_name:\n                self.user.first_name = self.first_name\n                self.user.last_name = self.last_name\n                updated = True\n\n            # Update phone if necessary\n            if not self.user.phone:\n                self.user.phone = self.phone\n                updated = True\n\n            # Save user if any updates were made\n            if updated:\n                self.user.save()\n\n    def __str__(self):\n        if self.first_name or self.last_name:\n            return self.get_formatted_name()\n        elif self.email:\n            return self.email\n        elif self.pk:\n            return str(self.pk)\n        else:\n            return \"\"\n", "path": "src/registrar/models/contact.py"}, {"content": "# coding: utf-8\nfrom __future__ import unicode_literals\n\nimport logging\n\nfrom django.conf import settings\nfrom django.contrib.auth import get_user_model\nfrom django.contrib.auth.backends import ModelBackend\nfrom django.utils import timezone\n\nlogger = logging.getLogger(__name__)\n\n\nclass OpenIdConnectBackend(ModelBackend):\n    \"\"\"\n    This backend checks a previously performed OIDC authentication.\n    If it is OK and the user already exists in the database, it is returned.\n    If it is OK and user does not exist in the database, it is created and\n        returned unless setting OIDC_CREATE_UNKNOWN_USER is False.\n    In all other cases, None is returned.\n    \"\"\"\n\n    def authenticate(self, request, **kwargs):\n        logger.debug(\"kwargs %s\" % kwargs)\n        user = None\n        if not kwargs or \"sub\" not in kwargs.keys():\n            return user\n\n        UserModel = get_user_model()\n        username = self.clean_username(kwargs[\"sub\"])\n\n        # Some OP may actually choose to withhold some information, so we must\n        # test if it is present\n        openid_data = {\"last_login\": timezone.now()}\n        openid_data[\"first_name\"] = kwargs.get(\"given_name\", \"\")\n        openid_data[\"last_name\"] = kwargs.get(\"family_name\", \"\")\n        openid_data[\"email\"] = kwargs.get(\"email\", \"\")\n        openid_data[\"phone\"] = kwargs.get(\"phone\", \"\")\n\n        # Note that this could be accomplished in one try-except clause, but\n        # instead we use get_or_create when creating unknown users since it has\n        # built-in safeguards for multiple threads.\n        if getattr(settings, \"OIDC_CREATE_UNKNOWN_USER\", True):\n            args = {\n                UserModel.USERNAME_FIELD: username,\n                # defaults _will_ be updated, these are not fallbacks\n                \"defaults\": openid_data,\n            }\n\n            user, created = UserModel.objects.get_or_create(**args)\n\n            if not created:\n                # If user exists, update existing user\n                self.update_existing_user(user, args[\"defaults\"])\n            else:\n                # If user is created, configure the user\n                user = self.configure_user(user, **kwargs)\n        else:\n            try:\n                user = UserModel.objects.get_by_natural_key(username)\n            except UserModel.DoesNotExist:\n                return None\n        # run this callback for a each login\n        user.on_each_login()\n        return user\n\n    def update_existing_user(self, user, kwargs):\n        \"\"\"\n        Update user fields without overwriting certain fields.\n\n        Args:\n            user: User object to be updated.\n            kwargs: Dictionary containing fields to update and their new values.\n\n        Note:\n            This method updates user fields while preserving the values of 'first_name',\n            'last_name', and 'phone' fields, unless specific conditions are met.\n\n            - 'first_name', 'last_name' or 'phone' will be updated if the provided value is not empty.\n        \"\"\"\n\n        fields_to_check = [\"first_name\", \"last_name\", \"phone\"]\n\n        # Iterate over fields to update\n        for key, value in kwargs.items():\n            # Check if the field is not 'first_name', 'last_name', or 'phone',\n            # or if it's 'first_name' or 'last_name' or 'phone' and the provided value is not empty\n            if key not in fields_to_check or (key in fields_to_check and value):\n                # Update the corresponding attribute of the user object\n                setattr(user, key, value)\n\n        # Save the user object with the updated fields\n        user.save()\n\n    def clean_username(self, username):\n        \"\"\"\n        Performs any cleaning on the \"username\" prior to using it to get or\n        create the user object.  Returns the cleaned username.\n        \"\"\"\n        return username\n\n    def configure_user(self, user, **kwargs):\n        \"\"\"\n        Configures a user after creation and returns the updated user.\n        \"\"\"\n        user.set_unusable_password()\n        return user\n", "path": "src/djangooidc/backends.py"}]}