diff --git a/src/djangooidc/views.py b/src/djangooidc/views.py index ab81ccff1..b887b7a14 100644 --- a/src/djangooidc/views.py +++ b/src/djangooidc/views.py @@ -99,8 +99,11 @@ def login_callback(request): return CLIENT.create_authn_request(request.session) user = authenticate(request=request, **userinfo) if user: + # Set the verification type + user.set_user_verification_type() login(request, user) logger.info("Successfully logged in user %s" % user) + # Clear the flag if the exception is not caught request.session.pop("redirect_attempted", None) return redirect(request.session.get("next", "/")) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 6869df94a..dd016b470 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -508,7 +508,7 @@ class MyUserAdmin(BaseUserAdmin): ("Important dates", {"fields": ("last_login", "date_joined")}), ) - readonly_fields = ("verification_type") + readonly_fields = ("verification_type",) # Hide Username (uuid), Groups and Permissions # Q: Now that we're using Groups and Permissions, @@ -516,7 +516,7 @@ class MyUserAdmin(BaseUserAdmin): analyst_fieldsets = ( ( None, - {"fields": ("password", "status")}, + {"fields": ("password", "status", "verification_type")}, ), ("Personal Info", {"fields": ("first_name", "last_name", "email")}), ( @@ -636,11 +636,14 @@ class MyUserAdmin(BaseUserAdmin): return [] def get_readonly_fields(self, request, obj=None): + readonly_fields = list(self.readonly_fields) + if request.user.has_perm("registrar.full_access_permission"): - return () # No read-only fields for all access users - # Return restrictive Read-only fields for analysts and - # users who might not belong to groups - return self.analyst_readonly_fields + return readonly_fields + else: + # Return restrictive Read-only fields for analysts and + # users who might not belong to groups + return self.analyst_readonly_fields class HostIPInline(admin.StackedInline): diff --git a/src/registrar/fixtures_users.py b/src/registrar/fixtures_users.py index 99fe4910e..4c2b85233 100644 --- a/src/registrar/fixtures_users.py +++ b/src/registrar/fixtures_users.py @@ -6,6 +6,7 @@ from registrar.models import ( User, UserGroup, ) +from registrar.models.verified_by_staff import VerifiedByStaff fake = Faker() logger = logging.getLogger(__name__) @@ -187,6 +188,9 @@ class UserFixture: logger.info(f"Going to load {len(users)} users in group {group_name}") for user_data in users: try: + + # TODO - Add the fixture user to the VerifiedByStaff table + # (To track how this user was verified) user, _ = User.objects.get_or_create(username=user_data["username"]) user.is_superuser = False user.first_name = user_data["first_name"] diff --git a/src/registrar/migrations/0085_user_verification_type.py b/src/registrar/migrations/0085_user_verification_type.py new file mode 100644 index 000000000..2790ea3b7 --- /dev/null +++ b/src/registrar/migrations/0085_user_verification_type.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.10 on 2024-04-19 21:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("registrar", "0084_create_groups_v11"), + ] + + operations = [ + migrations.AddField( + model_name="user", + name="verification_type", + field=models.CharField( + blank=True, + choices=[ + ("grandfathered", "Legacy user"), + ("verified_by_staff", "Verified by staff"), + ("regular", "Verified by Login.gov"), + ("invited", "Invited by a domain manager"), + ], + help_text="The means through which this user was verified", + null=True, + ), + ), + ] diff --git a/src/registrar/models/user.py b/src/registrar/models/user.py index c69672100..9320a80ff 100644 --- a/src/registrar/models/user.py +++ b/src/registrar/models/user.py @@ -60,7 +60,7 @@ class User(AbstractUser): ) verification_type = models.CharField( - choices=VerificationTypeChoices, + choices=VerificationTypeChoices.choices, null=True, blank=True, help_text="The means through which this user was verified", @@ -115,19 +115,19 @@ class User(AbstractUser): @classmethod - def get_existing_user_from_uuid(cls, uuid): + def existing_user(cls, uuid): existing_user = None try: existing_user = cls.objects.get(username=uuid) if existing_user and UserDomainRole.objects.filter(user=existing_user).exists(): - return (False, existing_user) + return False except cls.DoesNotExist: # Do nothing when the user is not found, as we're checking for existence. pass except Exception as err: raise err - return (True, existing_user) + return True @classmethod def needs_identity_verification(cls, email, uuid): @@ -136,14 +136,14 @@ class User(AbstractUser): # An existing user who is a domain manager of a domain (that is, # they have an entry in UserDomainRole for their User) - user_exists, existing_user = cls.existing_user(uuid) + user_exists = cls.existing_user(uuid) if not user_exists: return False # The user needs identity verification if they don't meet # any special criteria, i.e. we are validating them "regularly" - existing_user.verification_type = cls.get_verification_type_from_email(email) - return existing_user.verification_type == cls.VerificationTypeChoices.REGULAR + verification_type = cls.get_verification_type_from_email(email) + return verification_type == cls.VerificationTypeChoices.REGULAR @classmethod def get_verification_type_from_email(cls, email, invitation_status=DomainInvitation.DomainInvitationStatus.INVITED): @@ -167,11 +167,11 @@ class User(AbstractUser): return verification_type - def user_verification_type(self, check_if_user_exists=False): + def set_user_verification_type(self): if self.verification_type is None: # Would need to check audit log retrieved = DomainInvitation.DomainInvitationStatus.RETRIEVED - user_exists, _ = self.existing_user(self.username) + user_exists = self.existing_user(self.username) verification_type = self.get_verification_type_from_email(self.email, invitation_status=retrieved) # This should check if the type is unknown, use check_if_user_exists?