Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/sentry/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
TeamAlertsTriggeredTotalsEndpoint,
)
from sentry.insights.endpoints.starred_segments import InsightsStarredSegmentsEndpoint
from sentry.integrations.api.endpoints.data_forwarding_index import DataForwardingIndexEndpoint
from sentry.integrations.api.endpoints.doc_integration_avatar import DocIntegrationAvatarEndpoint
from sentry.integrations.api.endpoints.doc_integration_details import DocIntegrationDetailsEndpoint
from sentry.integrations.api.endpoints.doc_integrations_index import DocIntegrationsEndpoint
Expand Down Expand Up @@ -1403,6 +1404,12 @@ def create_group_urls(name_prefix: str) -> list[URLPattern | URLResolver]:
OrganizationCodeMappingCodeOwnersEndpoint.as_view(),
name="sentry-api-0-organization-code-mapping-codeowners",
),
# Data Forwarding
re_path(
r"^(?P<organization_id_or_slug>[^/]+)/forwarding/$",
DataForwardingIndexEndpoint.as_view(),
name="sentry-api-0-organization-forwarding",
),
re_path(
r"^(?P<organization_id_or_slug>[^/]+)/codeowners-associations/$",
OrganizationCodeOwnersAssociationsEndpoint.as_view(),
Expand Down
97 changes: 97 additions & 0 deletions src/sentry/integrations/api/endpoints/data_forwarding_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from django.utils.decorators import method_decorator
from django.views.decorators.cache import never_cache
from drf_spectacular.utils import extend_schema
from rest_framework import status
from rest_framework.request import Request
from rest_framework.response import Response

from sentry import audit_log
from sentry.api.api_owners import ApiOwner
from sentry.api.api_publish_status import ApiPublishStatus
from sentry.api.base import region_silo_endpoint
from sentry.api.bases.organization import OrganizationEndpoint, OrganizationPermission
from sentry.api.paginator import OffsetPaginator
from sentry.api.serializers import serialize
from sentry.apidocs.constants import RESPONSE_BAD_REQUEST, RESPONSE_FORBIDDEN
from sentry.apidocs.parameters import GlobalParams
from sentry.integrations.api.serializers.rest_framework.data_forwarder import (
DataForwarderSerializer,
)
from sentry.integrations.models.data_forwarder import DataForwarder
from sentry.organizations.services.organization.model import RpcUserOrganizationContext
from sentry.web.decorators import set_referrer_policy


class OrganizationDataForwardingDetailsPermission(OrganizationPermission):
scope_map = {
"GET": ["org:read"],
"POST": ["org:write"],
}


@region_silo_endpoint
@extend_schema(tags=["Integrations"])
class DataForwardingIndexEndpoint(OrganizationEndpoint):
owner = ApiOwner.INTEGRATIONS
publish_status = {
"GET": ApiPublishStatus.PRIVATE,
"POST": ApiPublishStatus.PRIVATE,
}
permission_classes = (OrganizationDataForwardingDetailsPermission,)

@extend_schema(
operation_id="Retrieve Data Forwarding Configurations for an Organization",
parameters=[GlobalParams.ORG_ID_OR_SLUG],
responses={
200: DataForwarderSerializer,
},
)
@set_referrer_policy("strict-origin-when-cross-origin")
@method_decorator(never_cache)
def get(self, request: Request, organization_context: RpcUserOrganizationContext) -> Response:
queryset = DataForwarder.objects.filter(
organization_id=organization_context.organization.id
)

return self.paginate(
request=request,
queryset=queryset,
on_results=lambda x: serialize(x, request.user),
paginator_cls=OffsetPaginator,
)

@extend_schema(
operation_id="Create a Data Forwarding Configuration for an Organization",
parameters=[GlobalParams.ORG_ID_OR_SLUG],
request=DataForwarderSerializer,
responses={
201: DataForwarderSerializer,
400: RESPONSE_BAD_REQUEST,
403: RESPONSE_FORBIDDEN,
},
)
@set_referrer_policy("strict-origin-when-cross-origin")
@method_decorator(never_cache)
def post(self, request: Request, organization_context: RpcUserOrganizationContext) -> Response:
data = request.data.copy()
data["organization_id"] = organization_context.organization.id

serializer = DataForwarderSerializer(data=data)
if serializer.is_valid():
data_forwarder = serializer.save()

self.create_audit_entry(
request=request,
organization=organization_context.organization,
target_object=data_forwarder.id,
event=audit_log.get_event_id("DATA_FORWARDER_ADD"),
data={
"provider": data_forwarder.provider,
"organization_id": data_forwarder.organization_id,
},
)

return self.respond(
serialize(data_forwarder, request.user), status=status.HTTP_201_CREATED
)
return self.respond(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Loading