Skip to content

Commit

Permalink
fix: allow creating integration configurations where deleted versions…
Browse files Browse the repository at this point in the history
… exist (#2531)
  • Loading branch information
matthewelwell authored Jul 27, 2023
1 parent 721957a commit 3430829
Show file tree
Hide file tree
Showing 22 changed files with 190 additions and 82 deletions.
7 changes: 4 additions & 3 deletions api/integrations/amplitude/serializers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from rest_framework import serializers

from integrations.amplitude.models import AmplitudeConfiguration
from integrations.common.serializers import (
BaseEnvironmentIntegrationModelSerializer,
)


class AmplitudeConfigurationSerializer(serializers.ModelSerializer):
class AmplitudeConfigurationSerializer(BaseEnvironmentIntegrationModelSerializer):
class Meta:
model = AmplitudeConfiguration
fields = ("id", "api_key")
4 changes: 2 additions & 2 deletions api/integrations/amplitude/views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from integrations.amplitude.models import AmplitudeConfiguration
from integrations.amplitude.serializers import AmplitudeConfigurationSerializer
from integrations.common.views import IntegrationCommonViewSet
from integrations.common.views import EnvironmentIntegrationCommonViewSet


class AmplitudeConfigurationViewSet(IntegrationCommonViewSet):
class AmplitudeConfigurationViewSet(EnvironmentIntegrationCommonViewSet):
serializer_class = AmplitudeConfigurationSerializer
pagination_class = None # set here to ensure documentation is correct
model_class = AmplitudeConfiguration
2 changes: 1 addition & 1 deletion api/integrations/common/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ class BaseEnvironmentIntegrationModelSerializer(_BaseIntegrationModelSerializer)


class BaseProjectIntegrationModelSerializer(_BaseIntegrationModelSerializer):
one_to_one_field_name = "project"
one_to_one_field_name = "project_id"
32 changes: 31 additions & 1 deletion api/integrations/common/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.exceptions import (
NotFound,
Expand All @@ -7,9 +8,10 @@

from environments.models import Environment
from environments.permissions.constants import VIEW_ENVIRONMENT
from projects.permissions import VIEW_PROJECT


class IntegrationCommonViewSet(viewsets.ModelViewSet):
class EnvironmentIntegrationCommonViewSet(viewsets.ModelViewSet):
serializer_class = None
pagination_class = None # set here to ensure documentation is correct
model_class = None
Expand Down Expand Up @@ -52,3 +54,31 @@ def get_environment_from_request(self):
Get environment object from URL parameters in request.
"""
return Environment.objects.get(api_key=self.kwargs["environment_api_key"])


class ProjectIntegrationBaseViewSet(viewsets.ModelViewSet):
serializer_class = None
pagination_class = None
model_class = None

def get_queryset(self):
if getattr(self, "swagger_fake_view", False):
return self.model_class.objects.none()

project = get_object_or_404(
self.request.user.get_permitted_projects(VIEW_PROJECT),
pk=self.kwargs["project_pk"],
)
return self.model_class.objects.filter(project=project)

def perform_create(self, serializer):
project_id = self.kwargs["project_pk"]
if self.model_class.objects.filter(project_id=project_id).exists():
raise ValidationError(
f"{self.model_class.__name__} for this project already exists."
)
serializer.save(project_id=project_id)

def perform_update(self, serializer):
project_id = self.kwargs["project_pk"]
serializer.save(project_id=project_id)
33 changes: 3 additions & 30 deletions api/integrations/datadog/views.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,8 @@
from rest_framework import viewsets
from rest_framework.exceptions import ValidationError
from rest_framework.generics import get_object_or_404

from integrations.common.views import ProjectIntegrationBaseViewSet
from integrations.datadog.models import DataDogConfiguration
from integrations.datadog.serializers import DataDogConfigurationSerializer
from projects.permissions import VIEW_PROJECT


class DataDogConfigurationViewSet(viewsets.ModelViewSet):
class DataDogConfigurationViewSet(ProjectIntegrationBaseViewSet):
serializer_class = DataDogConfigurationSerializer
pagination_class = None # set here to ensure documentation is correct

def get_queryset(self):
if getattr(self, "swagger_fake_view", False):
return DataDogConfiguration.objects.none()

project = get_object_or_404(
self.request.user.get_permitted_projects(VIEW_PROJECT),
pk=self.kwargs["project_pk"],
)
return DataDogConfiguration.objects.filter(project=project)

def perform_create(self, serializer):
project_id = self.kwargs["project_pk"]
if DataDogConfiguration.objects.filter(project_id=project_id).exists():
raise ValidationError(
"DataDogConfiguration for this project already exist."
)

serializer.save(project_id=project_id)

def perform_update(self, serializer):
project_id = self.kwargs["project_pk"]
serializer.save(project_id=project_id)
model_class = DataDogConfiguration
4 changes: 2 additions & 2 deletions api/integrations/dynatrace/views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from integrations.common.views import IntegrationCommonViewSet
from integrations.common.views import EnvironmentIntegrationCommonViewSet
from integrations.dynatrace.models import DynatraceConfiguration
from integrations.dynatrace.serializers import DynatraceConfigurationSerializer


class DynatraceConfigurationViewSet(IntegrationCommonViewSet):
class DynatraceConfigurationViewSet(EnvironmentIntegrationCommonViewSet):
serializer_class = DynatraceConfigurationSerializer
pagination_class = None # set here to ensure documentation is correct
model_class = DynatraceConfiguration
4 changes: 2 additions & 2 deletions api/integrations/heap/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from integrations.common.views import IntegrationCommonViewSet
from integrations.common.views import EnvironmentIntegrationCommonViewSet
from integrations.heap.models import HeapConfiguration
from integrations.heap.serializers import HeapConfigurationSerializer


class HeapConfigurationViewSet(IntegrationCommonViewSet):
class HeapConfigurationViewSet(EnvironmentIntegrationCommonViewSet):
serializer_class = HeapConfigurationSerializer
model_class = HeapConfiguration
4 changes: 2 additions & 2 deletions api/integrations/mixpanel/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from integrations.common.views import IntegrationCommonViewSet
from integrations.common.views import EnvironmentIntegrationCommonViewSet
from integrations.mixpanel.models import MixpanelConfiguration
from integrations.mixpanel.serializers import MixpanelConfigurationSerializer


class MixpanelConfigurationViewSet(IntegrationCommonViewSet):
class MixpanelConfigurationViewSet(EnvironmentIntegrationCommonViewSet):
serializer_class = MixpanelConfigurationSerializer
model_class = MixpanelConfiguration
33 changes: 3 additions & 30 deletions api/integrations/new_relic/views.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,8 @@
from rest_framework import viewsets
from rest_framework.exceptions import ValidationError
from rest_framework.generics import get_object_or_404

from integrations.common.views import ProjectIntegrationBaseViewSet
from integrations.new_relic.models import NewRelicConfiguration
from integrations.new_relic.serializers import NewRelicConfigurationSerializer
from projects.permissions import VIEW_PROJECT


class NewRelicConfigurationViewSet(viewsets.ModelViewSet):
class NewRelicConfigurationViewSet(ProjectIntegrationBaseViewSet):
serializer_class = NewRelicConfigurationSerializer
pagination_class = None # set here to ensure documentation is correct

def get_queryset(self):
if getattr(self, "swagger_fake_view", False):
return NewRelicConfiguration.objects.none()

project = get_object_or_404(
self.request.user.get_permitted_projects(VIEW_PROJECT),
pk=self.kwargs["project_pk"],
)
return NewRelicConfiguration.objects.filter(project=project)

def perform_create(self, serializer):
project_id = self.kwargs["project_pk"]
if NewRelicConfiguration.objects.filter(project_id=project_id).exists():
raise ValidationError(
"NewRelicConfiguration for this project already exist."
)

serializer.save(project_id=project_id)

def perform_update(self, serializer):
project_id = self.kwargs["project_pk"]
serializer.save(project_id=project_id)
model_class = NewRelicConfiguration
4 changes: 2 additions & 2 deletions api/integrations/rudderstack/views.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from integrations.common.views import IntegrationCommonViewSet
from integrations.common.views import EnvironmentIntegrationCommonViewSet
from integrations.rudderstack.models import RudderstackConfiguration
from integrations.rudderstack.serializers import (
RudderstackConfigurationSerializer,
)


class RudderstackConfigurationViewSet(IntegrationCommonViewSet):
class RudderstackConfigurationViewSet(EnvironmentIntegrationCommonViewSet):
serializer_class = RudderstackConfigurationSerializer
pagination_class = None # set here to ensure documentation is correct
model_class = RudderstackConfiguration
4 changes: 2 additions & 2 deletions api/integrations/segment/views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from integrations.common.views import IntegrationCommonViewSet
from integrations.common.views import EnvironmentIntegrationCommonViewSet
from integrations.segment.models import SegmentConfiguration
from integrations.segment.serializers import SegmentConfigurationSerializer


class SegmentConfigurationViewSet(IntegrationCommonViewSet):
class SegmentConfigurationViewSet(EnvironmentIntegrationCommonViewSet):
serializer_class = SegmentConfigurationSerializer
pagination_class = None # set here to ensure documentation is correct
model_class = SegmentConfiguration
4 changes: 2 additions & 2 deletions api/integrations/slack/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from slack_sdk.oauth import AuthorizeUrlGenerator

from environments.models import Environment
from integrations.common.views import IntegrationCommonViewSet
from integrations.common.views import EnvironmentIntegrationCommonViewSet
from integrations.slack.models import SlackConfiguration, SlackEnvironment
from integrations.slack.serializers import (
SlackChannelListQueryParamSerializer,
Expand Down Expand Up @@ -58,7 +58,7 @@ def list(self, request, *args, **kwargs):
return Response(serializer.data)


class SlackEnvironmentViewSet(IntegrationCommonViewSet):
class SlackEnvironmentViewSet(EnvironmentIntegrationCommonViewSet):
serializer_class = SlackEnvironmentSerializer
pagination_class = None # set here to ensure documentation is correct
model_class = SlackEnvironment
Expand Down
4 changes: 2 additions & 2 deletions api/integrations/webhook/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from integrations.common.views import IntegrationCommonViewSet
from integrations.common.views import EnvironmentIntegrationCommonViewSet
from integrations.webhook.models import WebhookConfiguration
from integrations.webhook.serializers import WebhookConfigurationSerializer


class WebhookConfigurationViewSet(IntegrationCommonViewSet):
class WebhookConfigurationViewSet(EnvironmentIntegrationCommonViewSet):
serializer_class = WebhookConfigurationSerializer
model_class = WebhookConfiguration
12 changes: 12 additions & 0 deletions api/tests/unit/integrations/amplitude/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import pytest

from integrations.amplitude.models import AmplitudeConfiguration


@pytest.fixture()
def deleted_amplitude_integration(environment):
amplitude_configuration = AmplitudeConfiguration.objects.create(
environment=environment, api_key="some-key"
)
amplitude_configuration.delete()
return amplitude_configuration
40 changes: 40 additions & 0 deletions api/tests/unit/integrations/amplitude/test_unit_amplitude_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import json

from django.urls import reverse
from rest_framework import status


def test_create_amplitude_integration(environment, admin_client):
# Given
url = reverse(
"api-v1:environments:integrations-amplitude-list", args=[environment.api_key]
)

# When
response = admin_client.post(
path=url,
data=json.dumps({"api_key": "some-key"}),
content_type="application/json",
)

# Then
assert response.status_code == status.HTTP_201_CREATED


def test_create_amplitude_integration_in_environment_with_deleted_integration(
environment, admin_client, deleted_amplitude_integration
):
# Given
url = reverse(
"api-v1:environments:integrations-amplitude-list", args=[environment.api_key]
)

# When
response = admin_client.post(
path=url,
data=json.dumps({"api_key": "some-key"}),
content_type="application/json",
)

# Then
assert response.status_code == status.HTTP_201_CREATED
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_base_project_integration_model_serializer_save_updates_existing_if_soft
serializer.is_valid(raise_exception=True)

# When
serializer.save(project=project)
serializer.save(project_id=project.id)

# Then
updated_webhook_config = DataDogConfiguration.objects.filter(
Expand Down
Empty file.
12 changes: 12 additions & 0 deletions api/tests/unit/integrations/datadog/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import pytest

from integrations.datadog.models import DataDogConfiguration


@pytest.fixture()
def deleted_datadog_configuration(project):
configuration = DataDogConfiguration.objects.create(
project=project, api_key="some-key"
)
configuration.delete()
return configuration
27 changes: 27 additions & 0 deletions api/tests/unit/integrations/datadog/test_unit_datadog_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import json

from django.urls import reverse
from rest_framework import status


def test_create_datadog_configuration_in_project_with_deleted_configuration(
admin_client, project, deleted_datadog_configuration
):
# Given
url = reverse("api-v1:projects:integrations-datadog-list", args=[project.id])

api_key, base_url = "some-key", "https://api.newrelic.com/"

# When
response = admin_client.post(
path=url,
data=json.dumps({"api_key": api_key, "base_url": base_url}),
content_type="application/json",
)

# Then
assert response.status_code == status.HTTP_201_CREATED

response_json = response.json()
assert response_json["api_key"] == api_key
assert response_json["base_url"] == base_url
Empty file.
12 changes: 12 additions & 0 deletions api/tests/unit/integrations/newrelic/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import pytest

from integrations.new_relic.models import NewRelicConfiguration


@pytest.fixture()
def deleted_newrelic_configuration(project):
configuration = NewRelicConfiguration.objects.create(
project=project, api_key="some-key"
)
configuration.delete()
return configuration
28 changes: 28 additions & 0 deletions api/tests/unit/integrations/newrelic/test_unit_newrelic_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import json

from django.urls import reverse
from rest_framework import status


def test_create_newrelic_configuration_in_project_with_deleted_configuration(
admin_client, project, deleted_newrelic_configuration
):
# Given
url = reverse("api-v1:projects:integrations-new-relic-list", args=[project.id])

api_key, base_url, app_id = "some-key", "https://api.newrelic.com/", "1"

# When
response = admin_client.post(
path=url,
data=json.dumps({"api_key": api_key, "base_url": base_url, "app_id": app_id}),
content_type="application/json",
)

# Then
assert response.status_code == status.HTTP_201_CREATED

response_json = response.json()
assert response_json["api_key"] == api_key
assert response_json["base_url"] == base_url
assert response_json["app_id"] == app_id

0 comments on commit 3430829

Please sign in to comment.