Browse Source

feat(apple-crash-report): Apple crash report URL specifies project (#12544)

Support fetching apple crash reports by event_id and project.
This is required to use Snuba for event details as we won't have
database ids.
Lyn Nagara 6 years ago
parent
commit
bdf0cd9833

+ 7 - 11
src/sentry/api/endpoints/event_apple_crash_report.py

@@ -9,33 +9,29 @@ try:
 except ImportError:
     from django.http import HttpResponse, StreamingHttpResponse
 
-from sentry.api.base import Endpoint
-from sentry.api.bases.group import GroupPermission
+from sentry.api.bases.project import ProjectEndpoint
 from sentry.api.exceptions import ResourceDoesNotExist
 from sentry.models import Event
 from sentry.lang.native.applecrashreport import AppleCrashReport
 from sentry.utils.safe import get_path
 
 
-class EventAppleCrashReportEndpoint(Endpoint):
-    permission_classes = (GroupPermission, )
+class EventAppleCrashReportEndpoint(ProjectEndpoint):
 
-    def get(self, request, event_id):
+    def get(self, request, project, event_id):
         """
-        Retrieve an Apple Crash Report from and event
+        Retrieve an Apple Crash Report from an event
         `````````````````````````````````````````````
 
         This endpoint returns the an apple crash report for a specific event.
-        The event ID is the event as it appears in the Sentry database
-        and not the event ID that is reported by the client upon submission.
+        The event ID is either the event as it appears in the Sentry database
+        or the event ID that is reported by the client upon submission.
         This works only if the event.platform == cocoa
         """
-        event = Event.objects.from_event_id(event_id, project_id=None)
+        event = Event.objects.from_event_id(event_id, project_id=project.id)
         if event is None:
             raise ResourceDoesNotExist
 
-        self.check_object_permissions(request, event.group)
-
         Event.objects.bind_nodes([event], 'data')
 
         if event.platform not in ('cocoa', 'native'):

+ 5 - 5
src/sentry/api/urls.py

@@ -868,6 +868,11 @@ urlpatterns = patterns(
         EventGroupingInfoEndpoint.as_view(),
         name='sentry-api-0-event-grouping-info'
     ),
+    url(
+        r'^projects/(?P<organization_slug>[^\/]+)/(?P<project_slug>[^\/]+)/events/(?P<event_id>[\w-]+)/apple-crash-report$',
+        EventAppleCrashReportEndpoint.as_view(),
+        name='sentry-api-0-event-apple-crash-report'
+    ),
     url(
         r'^projects/(?P<organization_slug>[^\/]+)/(?P<project_slug>[^\/]+)/events/(?P<event_id>[\w-]+)/attachments/$',
         EventAttachmentsEndpoint.as_view(),
@@ -1236,11 +1241,6 @@ urlpatterns = patterns(
         EventDetailsEndpoint.as_view(),
         name='sentry-api-0-event-details'
     ),
-    url(
-        r'^events/(?P<event_id>\d+)/apple-crash-report$',
-        EventAppleCrashReportEndpoint.as_view(),
-        name='sentry-api-0-event-apple-crash-report'
-    ),
 
     # Sentry Apps
     url(

+ 1 - 0
src/sentry/static/sentry/app/components/events/interfaces/crashContent.jsx

@@ -24,6 +24,7 @@ class CrashContent extends React.Component {
     return stackView === 'raw' ? (
       <RawExceptionContent
         eventId={event.id}
+        projectId={group.project.slug}
         type={stackType}
         values={exception.values}
         platform={event.platform}

+ 11 - 4
src/sentry/static/sentry/app/components/events/interfaces/rawExceptionContent.jsx

@@ -5,7 +5,10 @@ import LoadingIndicator from 'app/components/loadingIndicator';
 import LoadingError from 'app/components/loadingError';
 import ClippedBox from 'app/components/clippedBox';
 
+import SentryTypes from 'app/sentryTypes';
 import withApi from 'app/utils/withApi';
+import withOrganization from 'app/utils/withOrganization';
+import {t} from 'app/locale';
 
 class RawExceptionContent extends React.Component {
   static propTypes = {
@@ -13,7 +16,9 @@ class RawExceptionContent extends React.Component {
     type: PropTypes.oneOf(['original', 'minified']),
     platform: PropTypes.string,
     eventId: PropTypes.string,
+    projectId: PropTypes.string.isRequired,
     values: PropTypes.array.isRequired,
+    organization: SentryTypes.Organization.isRequired,
   };
 
   constructor(props) {
@@ -43,8 +48,10 @@ class RawExceptionContent extends React.Component {
   }
 
   getAppleCrashReportEndpoint() {
-    const minified = this.props.type == 'minified';
-    return `/events/${this.props.eventId}/apple-crash-report?minified=${minified}`;
+    const {type, organization, projectId, eventId} = this.props;
+
+    const minified = type == 'minified';
+    return `/projects/${organization.slug}/${projectId}/events/${eventId}/apple-crash-report?minified=${minified}`;
   }
 
   fetchAppleCrashReport() {
@@ -98,7 +105,7 @@ class RawExceptionContent extends React.Component {
               }
               className="btn btn-default btn-sm pull-right"
             >
-              Download
+              {t('Download')}
             </a>
           );
         }
@@ -116,4 +123,4 @@ class RawExceptionContent extends React.Component {
   }
 }
 
-export default withApi(RawExceptionContent);
+export default withApi(withOrganization(RawExceptionContent));