diff --git a/src/sentry/api/endpoints/event_attachments.py b/src/sentry/api/endpoints/event_attachments.py index af532c419a76..9d206ffff8a1 100644 --- a/src/sentry/api/endpoints/event_attachments.py +++ b/src/sentry/api/endpoints/event_attachments.py @@ -1,3 +1,4 @@ +from drf_spectacular.utils import OpenApiParameter, extend_schema from rest_framework.request import Request from rest_framework.response import Response @@ -8,29 +9,59 @@ from sentry.api.bases.project import ProjectEndpoint from sentry.api.paginator import OffsetPaginator from sentry.api.serializers import serialize +from sentry.api.serializers.models.eventattachment import EventAttachmentSerializerResponse +from sentry.apidocs.constants import RESPONSE_FORBIDDEN, RESPONSE_NOT_FOUND, RESPONSE_UNAUTHORIZED +from sentry.apidocs.examples.event_attachment_examples import EventAttachmentExamples +from sentry.apidocs.parameters import CursorQueryParam, EventParams, GlobalParams +from sentry.apidocs.utils import inline_sentry_response_serializer from sentry.models.eventattachment import EventAttachment, event_attachment_screenshot_filter from sentry.search.utils import tokenize_query from sentry.services import eventstore +EVENT_ATTACHMENTS_QUERY_PARAM = OpenApiParameter( + name="query", + location="query", + required=False, + type=str, + description=( + "Filter the attachments by name (substring match) or by attachment kind. " + "Use `is:screenshot` to restrict the results to screenshot attachments." + ), +) + +@extend_schema(tags=["Events"]) @cell_silo_endpoint class EventAttachmentsEndpoint(ProjectEndpoint): owner = ApiOwner.OWNERS_INGEST publish_status = { - "GET": ApiPublishStatus.PRIVATE, + "GET": ApiPublishStatus.PUBLIC, } + @extend_schema( + operation_id="List an Event's Attachments", + parameters=[ + GlobalParams.ORG_ID_OR_SLUG, + GlobalParams.PROJECT_ID_OR_SLUG, + EventParams.EVENT_ID, + EVENT_ATTACHMENTS_QUERY_PARAM, + CursorQueryParam, + ], + responses={ + 200: inline_sentry_response_serializer( + "ListEventAttachmentsResponse", list[EventAttachmentSerializerResponse] + ), + 401: RESPONSE_UNAUTHORIZED, + 403: RESPONSE_FORBIDDEN, + 404: RESPONSE_NOT_FOUND, + }, + examples=EventAttachmentExamples.LIST_EVENT_ATTACHMENTS, + ) def get(self, request: Request, project, event_id) -> Response: """ - Retrieve attachments for an event - ````````````````````````````````` + Retrieve a list of attachments uploaded for a given event. - :pparam string organization_id_or_slug: the id or slug of the organization the - issues belong to. - :pparam string project_id_or_slug: the id or slug of the project the event - belongs to. - :pparam string event_id: the id of the event. - :auth: required + Requires the `event-attachments` organization feature. """ if not features.has( "organizations:event-attachments", project.organization, actor=request.user diff --git a/tests/apidocs/endpoints/events/test_event_attachments.py b/tests/apidocs/endpoints/events/test_event_attachments.py new file mode 100644 index 000000000000..644114198706 --- /dev/null +++ b/tests/apidocs/endpoints/events/test_event_attachments.py @@ -0,0 +1,42 @@ +from django.test.client import RequestFactory +from django.urls import reverse + +from fixtures.apidocs_test_case import APIDocsTestCase +from sentry.models.eventattachment import EventAttachment +from sentry.testutils.helpers.datetime import before_now + + +class ProjectEventAttachmentsDocs(APIDocsTestCase): + def setUp(self) -> None: + event = self.store_event( + data={"fingerprint": ["group1"], "timestamp": before_now(minutes=1).isoformat()}, + project_id=self.project.id, + ) + EventAttachment.objects.create( + project_id=event.project_id, + event_id=event.event_id, + type="event.attachment", + name="hello.png", + content_type="image/png", + size=18, + sha1="d3f299af02d6abbe92dd8368bab781824a9702ed", + blob_path=":File contents here", + ) + + self.url = reverse( + "sentry-api-0-event-attachments", + kwargs={ + "organization_id_or_slug": self.project.organization.slug, + "project_id_or_slug": self.project.slug, + "event_id": event.event_id, + }, + ) + + self.login_as(user=self.user) + + def test_get(self) -> None: + with self.feature("organizations:event-attachments"): + response = self.client.get(self.url) + request = RequestFactory().get(self.url) + + self.validate_schema(request, response)