diff --git a/api/audit/serializers.py b/api/audit/serializers.py index a936a137fe1e..e4de2d68bb48 100644 --- a/api/audit/serializers.py +++ b/api/audit/serializers.py @@ -2,14 +2,14 @@ from audit.models import AuditLog from environments.serializers import EnvironmentSerializerLight -from projects.serializers import ProjectListSerializer +from projects.serializers import ProjectSerializer from users.serializers import UserListSerializer class AuditLogSerializer(serializers.ModelSerializer): author = UserListSerializer() environment = EnvironmentSerializerLight() - project = ProjectListSerializer() + project = ProjectSerializer() class Meta: model = AuditLog diff --git a/api/environments/serializers.py b/api/environments/serializers.py index 19609da9be4d..86d8e72d894e 100644 --- a/api/environments/serializers.py +++ b/api/environments/serializers.py @@ -10,7 +10,7 @@ ReadOnlyIfNotValidPlanMixin, ) from projects.models import Project -from projects.serializers import ProjectListSerializer +from projects.serializers import ProjectSerializer from util.drf_writable_nested.serializers import ( DeleteBeforeUpdateWritableNestedModelSerializer, ) @@ -18,7 +18,7 @@ class EnvironmentSerializerFull(serializers.ModelSerializer): feature_states = FeatureStateSerializerFull(many=True) - project = ProjectListSerializer() + project = ProjectSerializer() class Meta: model = Environment @@ -86,16 +86,6 @@ def get_project(self, validated_data: dict = None) -> Project: ) -class EnvironmentRetrieveSerializerWithMetadata(EnvironmentSerializerWithMetadata): - total_segment_overrides = serializers.IntegerField() - - class Meta(EnvironmentSerializerWithMetadata.Meta): - fields = EnvironmentSerializerWithMetadata.Meta.fields + ( - "total_segment_overrides", - ) - read_only_fields = ("total_segment_overrides",) - - class CreateUpdateEnvironmentSerializer( ReadOnlyIfNotValidPlanMixin, EnvironmentSerializerWithMetadata ): diff --git a/api/environments/views.py b/api/environments/views.py index e23209558273..34129decf3ad 100644 --- a/api/environments/views.py +++ b/api/environments/views.py @@ -3,7 +3,6 @@ import logging -from django.db.models import Count from django.utils.decorators import method_decorator from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema @@ -42,7 +41,6 @@ CloneEnvironmentSerializer, CreateUpdateEnvironmentSerializer, EnvironmentAPIKeySerializer, - EnvironmentRetrieveSerializerWithMetadata, EnvironmentSerializerWithMetadata, WebhookSerializer, ) @@ -75,8 +73,6 @@ def get_serializer_class(self): return DeleteAllTraitKeysSerializer if self.action == "clone": return CloneEnvironmentSerializer - if self.action == "retrieve": - return EnvironmentRetrieveSerializerWithMetadata elif self.action in ("create", "update", "partial_update"): return CreateUpdateEnvironmentSerializer return EnvironmentSerializerWithMetadata @@ -102,20 +98,12 @@ def get_queryset(self): return ( self.request.master_api_key.organisation.projects.environments.all() ) - return self.request.user.get_permitted_environments( "VIEW_ENVIRONMENT", project=project ) # Permission class handles validation of permissions for other actions - queryset = Environment.objects.all() - - if self.action == "retrieve": - queryset = queryset.annotate( - total_segment_overrides=Count("feature_segments") - ) - - return queryset + return Environment.objects.all() def perform_create(self, serializer): environment = serializer.save() diff --git a/api/organisations/views.py b/api/organisations/views.py index 998a16373857..e15c5a53c58d 100644 --- a/api/organisations/views.py +++ b/api/organisations/views.py @@ -49,7 +49,7 @@ PermissionModelSerializer, UserObjectPermissionsSerializer, ) -from projects.serializers import ProjectListSerializer +from projects.serializers import ProjectSerializer from users.serializers import UserIdSerializer from webhooks.mixins import TriggerSampleWebhookMixin from webhooks.webhooks import WebhookType @@ -118,7 +118,7 @@ def create(self, request, **kwargs): def projects(self, request, pk): organisation = self.get_object() projects = organisation.projects.all() - return Response(ProjectListSerializer(projects, many=True).data) + return Response(ProjectSerializer(projects, many=True).data) @action(detail=True, methods=["POST"]) def invite(self, request, pk): diff --git a/api/projects/serializers.py b/api/projects/serializers.py index db474b67e52b..10914a5fa1ff 100644 --- a/api/projects/serializers.py +++ b/api/projects/serializers.py @@ -12,7 +12,7 @@ from users.serializers import UserListSerializer, UserPermissionGroupSerializer -class ProjectListSerializer(serializers.ModelSerializer): +class ProjectSerializer(serializers.ModelSerializer): migration_status = serializers.SerializerMethodField( help_text="Edge migration status of the project; can be one of: " + ", ".join([k.value for k in ProjectIdentityMigrationStatus]) @@ -39,8 +39,10 @@ class Meta: def get_migration_status(self, obj: Project) -> str: if not settings.PROJECT_METADATA_TABLE_NAME_DYNAMO: migration_status = ProjectIdentityMigrationStatus.NOT_APPLICABLE.value + elif obj.is_edge_project_by_default: migration_status = ProjectIdentityMigrationStatus.MIGRATION_COMPLETED.value + else: migration_status = IdentityMigrator(obj.id).migration_status.value @@ -56,28 +58,6 @@ def get_use_edge_identities(self, obj: Project) -> bool: ) -class ProjectRetrieveSerializer(ProjectListSerializer): - total_features = serializers.IntegerField() - total_segments = serializers.IntegerField() - - class Meta(ProjectListSerializer.Meta): - fields = ProjectListSerializer.Meta.fields + ( - "max_segments_allowed", - "max_features_allowed", - "max_segment_overrides_allowed", - "total_features", - "total_segments", - ) - - read_only_fields = ( - "max_segments_allowed", - "max_features_allowed", - "max_segment_overrides_allowed", - "total_features", - "total_segments", - ) - - class CreateUpdateUserProjectPermissionSerializer( CreateUpdateUserPermissionSerializerABC ): diff --git a/api/projects/tests/test_serializers.py b/api/projects/tests/test_serializers.py index 079b87106175..13bb9d00b025 100644 --- a/api/projects/tests/test_serializers.py +++ b/api/projects/tests/test_serializers.py @@ -4,13 +4,10 @@ from django.utils import timezone from environments.dynamodb.types import ProjectIdentityMigrationStatus -from projects.serializers import ( - ProjectListSerializer, - ProjectRetrieveSerializer, -) +from projects.serializers import ProjectSerializer -def test_ProjectListSerializer_get_migration_status_returns_migration_not_applicable_if_not_configured( +def test_ProjectSerializer_get_migration_status_returns_migration_not_applicable_if_not_configured( mocker, project, settings ): # Given @@ -19,7 +16,7 @@ def test_ProjectListSerializer_get_migration_status_returns_migration_not_applic "projects.serializers.IdentityMigrator", autospec=True ) - serializer = ProjectListSerializer() + serializer = ProjectSerializer() # When migration_status = serializer.get_migration_status(project) @@ -29,7 +26,7 @@ def test_ProjectListSerializer_get_migration_status_returns_migration_not_applic mocked_identity_migrator.assert_not_called() -def test_ProjectListSerializer_get_migration_status_returns_migration_completed_for_new_projects( +def test_ProjectSerializer_get_migration_status_returns_migration_completed_for_new_projects( mocker, project, settings ): # Given @@ -39,7 +36,7 @@ def test_ProjectListSerializer_get_migration_status_returns_migration_completed_ "projects.serializers.IdentityMigrator", autospec=True ) - serializer = ProjectListSerializer() + serializer = ProjectSerializer() # When migration_status = serializer.get_migration_status(project) @@ -49,7 +46,7 @@ def test_ProjectListSerializer_get_migration_status_returns_migration_completed_ mocked_identity_migrator.assert_not_called() -def test_ProjectListSerializer_get_migration_status_calls_migrator_with_correct_arguments_for_old_projects( +def test_ProjectSerializer_get_migration_status_calls_migrator_with_correct_arguments_for_old_projects( mocker, project, settings ): # Given @@ -60,7 +57,7 @@ def test_ProjectListSerializer_get_migration_status_calls_migrator_with_correct_ settings.EDGE_RELEASE_DATETIME = timezone.now() - serializer = ProjectListSerializer() + serializer = ProjectSerializer() # When migration_status = serializer.get_migration_status(project) @@ -81,32 +78,9 @@ def test_ProjectListSerializer_get_migration_status_calls_migrator_with_correct_ (ProjectIdentityMigrationStatus.NOT_APPLICABLE.value, False), ], ) -def test_ProjectListSerializer_get_use_edge_identities( - project, migration_status, expected -): +def test_ProjectSerializer_get_use_edge_identities(project, migration_status, expected): # Given - serializer = ProjectListSerializer(context={"migration_status": migration_status}) - - # When/Then - assert expected is serializer.get_use_edge_identities(project) - - -@pytest.mark.parametrize( - "migration_status, expected", - [ - (ProjectIdentityMigrationStatus.MIGRATION_COMPLETED.value, True), - (ProjectIdentityMigrationStatus.MIGRATION_IN_PROGRESS.value, False), - (ProjectIdentityMigrationStatus.MIGRATION_NOT_STARTED.value, False), - (ProjectIdentityMigrationStatus.NOT_APPLICABLE.value, False), - ], -) -def test_ProjectRetrieveSerializer_get_use_edge_identities( - project, migration_status, expected -): - # Given - serializer = ProjectRetrieveSerializer( - context={"migration_status": migration_status} - ) + serializer = ProjectSerializer(context={"migration_status": migration_status}) # When/Then assert expected is serializer.get_use_edge_identities(project) diff --git a/api/projects/views.py b/api/projects/views.py index 1c11040b195b..4a47707406a8 100644 --- a/api/projects/views.py +++ b/api/projects/views.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals from django.conf import settings -from django.db.models import Count, Q from django.utils.decorators import method_decorator from drf_yasg import openapi from drf_yasg.utils import no_body, swagger_auto_schema @@ -45,8 +44,7 @@ CreateUpdateUserProjectPermissionSerializer, ListUserPermissionGroupProjectPermissionSerializer, ListUserProjectPermissionSerializer, - ProjectListSerializer, - ProjectRetrieveSerializer, + ProjectSerializer, ) @@ -72,11 +70,7 @@ ), ) class ProjectViewSet(viewsets.ModelViewSet): - def get_serializer_class(self): - if self.action == "retrieve": - return ProjectRetrieveSerializer - return ProjectListSerializer - + serializer_class = ProjectSerializer permission_classes = [ProjectPermissions | MasterAPIKeyProjectPermissions] pagination_class = None @@ -99,20 +93,6 @@ def get_queryset(self): if project_uuid: queryset = queryset.filter(uuid=project_uuid) - if self.action == "retrieve": - queryset = queryset.annotate( - total_features=Count( - "features", - filter=Q(features__deleted_at__isnull=True), - distinct=True, - ), - total_segments=Count( - "segments", - filter=Q(segments__deleted_at__isnull=True), - distinct=True, - ), - ) - return queryset def perform_create(self, serializer): diff --git a/api/tests/unit/projects/test_unit_projects_views.py b/api/tests/unit/projects/test_unit_projects_views.py deleted file mode 100644 index bfe94af39dfa..000000000000 --- a/api/tests/unit/projects/test_unit_projects_views.py +++ /dev/null @@ -1,75 +0,0 @@ -import pytest -from django.urls import reverse -from pytest_lazyfixture import lazy_fixture -from rest_framework import status - -from projects.models import Project - -list_url = reverse("api-v1:projects:project-list") -PROJECT_NAME = "Test project" - - -@pytest.mark.parametrize( - "client", (lazy_fixture("admin_client"), lazy_fixture("master_api_key_client")) -) -def test_get_project_list_data(client, organisation): - # Given - hide_disabled_flags = False - enable_dynamo_db = False - prevent_flag_defaults = True - enable_realtime_updates = False - only_allow_lower_case_feature_names = True - - Project.objects.create( - name=PROJECT_NAME, - organisation=organisation, - hide_disabled_flags=hide_disabled_flags, - enable_dynamo_db=enable_dynamo_db, - prevent_flag_defaults=prevent_flag_defaults, - enable_realtime_updates=enable_realtime_updates, - only_allow_lower_case_feature_names=only_allow_lower_case_feature_names, - ) - - # When - response = client.get(list_url) - - # Then - assert response.status_code == status.HTTP_200_OK - assert response.json()[0]["name"] == PROJECT_NAME - assert response.json()[0]["hide_disabled_flags"] is hide_disabled_flags - assert response.json()[0]["enable_dynamo_db"] is enable_dynamo_db - assert response.json()[0]["prevent_flag_defaults"] is prevent_flag_defaults - assert response.json()[0]["enable_realtime_updates"] is enable_realtime_updates - assert ( - response.json()[0]["only_allow_lower_case_feature_names"] - is only_allow_lower_case_feature_names - ) - assert "max_segments_allowed" not in response.json()[0].keys() - assert "max_features_allowed" not in response.json()[0].keys() - assert "max_segment_overrides_allowed" not in response.json()[0].keys() - assert "total_features" not in response.json()[0].keys() - assert "total_segments" not in response.json()[0].keys() - - -@pytest.mark.parametrize( - "client", (lazy_fixture("admin_client"), lazy_fixture("master_api_key_client")) -) -def test_get_project_data_by_id(client, organisation): - # Given - project = Project.objects.create( - name=PROJECT_NAME, - organisation=organisation, - ) - url = reverse("api-v1:projects:project-detail", args=[project.id]) - - # When - response = client.get(url) - - # Then - assert response.status_code == status.HTTP_200_OK - assert response.json()["name"] == PROJECT_NAME - assert response.json()["max_segments_allowed"] == 100 - assert response.json()["max_features_allowed"] == 400 - assert response.json()["max_segment_overrides_allowed"] == 100 - assert response.json()["total_features"] == 0 - assert response.json()["total_segments"] == 0