diff --git a/api/custom_auth/serializers.py b/api/custom_auth/serializers.py index 11bd80828a6b..aabf01eff74a 100644 --- a/api/custom_auth/serializers.py +++ b/api/custom_auth/serializers.py @@ -52,8 +52,9 @@ class Meta(UserCreateSerializer.Meta): "is_active", "marketing_consent_given", "key", + "uuid", ) - read_only_fields = ("is_active",) + read_only_fields = ("is_active", "uuid") write_only_fields = ("sign_up_type",) extra_kwargs = { "email": { diff --git a/api/sales_dashboard/templates/sales_dashboard/organisation.html b/api/sales_dashboard/templates/sales_dashboard/organisation.html index cfe0610039a1..f0e7563a973f 100644 --- a/api/sales_dashboard/templates/sales_dashboard/organisation.html +++ b/api/sales_dashboard/templates/sales_dashboard/organisation.html @@ -156,6 +156,7 @@

{{user.email}} {{ user.date_joined }} {{ user.last_login }} + {{ user.uuid }} {% endfor %} diff --git a/api/tests/unit/custom_auth/test_unit_custom_auth_views.py b/api/tests/unit/custom_auth/test_unit_custom_auth_views.py new file mode 100644 index 000000000000..09b6d45de632 --- /dev/null +++ b/api/tests/unit/custom_auth/test_unit_custom_auth_views.py @@ -0,0 +1,22 @@ +from django.urls import reverse +from rest_framework import status +from rest_framework.test import APIClient + +from users.models import FFAdminUser + + +def test_get_current_user(staff_user: FFAdminUser, staff_client: APIClient) -> None: + # Given + url = reverse("api-v1:custom_auth:ffadminuser-me") + + # When + response = staff_client.get(url) + + # Then + assert response.status_code == status.HTTP_200_OK + + response_json = response.json() + assert response_json["email"] == staff_user.email + assert response_json["first_name"] == staff_user.first_name + assert response_json["last_name"] == staff_user.last_name + assert response_json["uuid"] == str(staff_user.uuid) diff --git a/api/tests/unit/features/test_unit_features_views.py b/api/tests/unit/features/test_unit_features_views.py index 0226d4b1a615..07defe5e8766 100644 --- a/api/tests/unit/features/test_unit_features_views.py +++ b/api/tests/unit/features/test_unit_features_views.py @@ -140,6 +140,7 @@ def test_remove_owners_only_remove_specified_owners( "first_name": user_3.first_name, "last_name": user_3.last_name, "last_login": None, + "uuid": mock.ANY, } @@ -1565,6 +1566,7 @@ def test_add_owners_adds_owner( "first_name": staff_user.first_name, "last_name": staff_user.last_name, "last_login": None, + "uuid": mock.ANY, } assert json_response["owners"][1] == { "id": admin_user.id, @@ -1572,6 +1574,7 @@ def test_add_owners_adds_owner( "first_name": admin_user.first_name, "last_name": admin_user.last_name, "last_login": None, + "uuid": mock.ANY, } diff --git a/api/users/admin.py b/api/users/admin.py index 85663231e8fd..4ce68597736a 100644 --- a/api/users/admin.py +++ b/api/users/admin.py @@ -44,6 +44,7 @@ class CustomUserAdmin(UserAdmin): "is_staff", "is_active", "date_joined", + "uuid", ) list_filter = ( @@ -57,6 +58,7 @@ class CustomUserAdmin(UserAdmin): "username", "first_name", "last_name", + "uuid", ) inlines = [UserOrganisationInline] diff --git a/api/users/migrations/0037_add_uuid_field_to_user_model.py b/api/users/migrations/0037_add_uuid_field_to_user_model.py new file mode 100644 index 000000000000..f5eb30f549e8 --- /dev/null +++ b/api/users/migrations/0037_add_uuid_field_to_user_model.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.25 on 2024-08-12 14:21 +from django.apps.registry import Apps +from django.db import migrations, models +import uuid + +from django.db.backends.base.schema import BaseDatabaseSchemaEditor + + +def set_default_uuids(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> None: + user_model = apps.get_model("users", "FFAdminUser") + + users = list(user_model.objects.all()) + for user in users: + user.uuid = uuid.uuid4() + + user_model.objects.bulk_update(users, fields=["uuid"]) + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0036_create_hubspot_lead'), + ] + + operations = [ + migrations.AddField( + model_name='ffadminuser', + name='uuid', + field=models.UUIDField(default=uuid.uuid4), + ), + migrations.RunPython(set_default_uuids, reverse_code=migrations.RunPython.noop), + migrations.AlterField( + model_name='ffadminuser', + name='uuid', + field=models.UUIDField(default=uuid.uuid4, editable=False, unique=True), + ), + ] diff --git a/api/users/models.py b/api/users/models.py index e2e272c3ba3a..3c458e3b0e94 100644 --- a/api/users/models.py +++ b/api/users/models.py @@ -1,5 +1,6 @@ import logging import typing +import uuid from datetime import timedelta from django.conf import settings @@ -112,6 +113,8 @@ class FFAdminUser(LifecycleModel, AbstractUser): choices=SignUpType.choices, max_length=100, blank=True, null=True ) + uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + USERNAME_FIELD = "email" REQUIRED_FIELDS = ["first_name", "last_name", "sign_up_type"] diff --git a/api/users/serializers.py b/api/users/serializers.py index d7fef9200201..858ae491a2ba 100644 --- a/api/users/serializers.py +++ b/api/users/serializers.py @@ -44,7 +44,7 @@ class UserFullSerializer(serializers.ModelSerializer): class Meta: model = FFAdminUser - fields = ("id", "email", "first_name", "last_name", "organisations") + fields = ("id", "email", "first_name", "last_name", "organisations", "uuid") class UserLoginSerializer(serializers.ModelSerializer): @@ -57,7 +57,7 @@ class UserListSerializer(serializers.ModelSerializer): role = serializers.SerializerMethodField(read_only=True) join_date = serializers.SerializerMethodField(read_only=True) - default_fields = ("id", "email", "first_name", "last_name", "last_login") + default_fields = ("id", "email", "first_name", "last_name", "last_login", "uuid") organisation_users_fields = ( "role", "date_joined", @@ -134,12 +134,14 @@ class UserPermissionGroupSerializerDetail(UserPermissionGroupSerializer): class CustomCurrentUserSerializer(DjoserUserSerializer): auth_type = serializers.CharField(read_only=True) is_superuser = serializers.BooleanField(read_only=True) + uuid = serializers.UUIDField(read_only=True) class Meta(DjoserUserSerializer.Meta): fields = DjoserUserSerializer.Meta.fields + ( "auth_type", "is_superuser", "date_joined", + "uuid", )