def get(self, request, wizard_hash):
        """
        This opens a page where with an active session fill stuff into the cache
        Redirects to organization whenever cache has been deleted
        """
        context = {
            'hash': wizard_hash
        }
        key = '%s%s' % (SETUP_WIZARD_CACHE_KEY, wizard_hash)

        wizard_data = default_cache.get(key)
        if wizard_data is None:
            return self.redirect_to_org(request)

        orgs = client.get(
            reverse('sentry-api-0-organizations'), request=request)

        filled_projects = []

        for org in orgs.data:
            projects = client.get(reverse('sentry-api-0-organization-projects', kwargs={
                'organization_slug': org.get('slug')
            }), request=request)
            for project in projects.data:
                if project.get('status') == 'deleted':
                    continue  # skip if project has been deleted
                enriched_project = project
                enriched_project['organization'] = org
                keys = client.get(reverse('sentry-api-0-project-keys', kwargs={
                    'organization_slug': org.get('slug'),
                    'project_slug': project.get('slug')
                }), request=request)
                enriched_project['keys'] = keys.data
                filled_projects.append(enriched_project)

        # Fetching or creating a token
        token = None
        tokens = [
            x for x in ApiToken.objects.filter(user=request.user).all()
            if 'project:releases' in x.get_scopes()
        ]
        if not tokens:
            token = ApiToken.objects.create(
                user=request.user,
                scope_list=['project:releases'],
                refresh_token=None,
                expires_at=None,
            )
        else:
            token = tokens[0]

        result = {
            'apiKeys': serialize(token),
            'projects': filled_projects
        }

        key = '%s%s' % (SETUP_WIZARD_CACHE_KEY, wizard_hash)
        default_cache.set(key, result, SETUP_WIZARD_CACHE_TIMEOUT)

        return render_to_response('sentry/setup-wizard.html', context, request)
Exemple #2
0
def react_plugin_config(plugin, project, request):
    response = client.get(
        u"/projects/{}/{}/plugins/{}/".format(project.organization.slug, project.slug, plugin.slug),
        request=request,
    )

    return mark_safe(
        """
    <div id="ref-plugin-config"></div>
    <script>
    $(function(){
        ReactDOM.render(React.createFactory(SentryApp.PluginConfig)({
            project: %s,
            organization: %s,
            data: %s
        }), document.getElementById('ref-plugin-config'));
    });
    </script>
    """
        % (
            json.dumps_htmlsafe(serialize(project, request.user)),
            json.dumps_htmlsafe(serialize(project.organization, request.user)),
            json.dumps_htmlsafe(response.data),
        )
    )
    def handle(self, request, organization, team, project, slug):
        try:
            plugin = plugins.get(slug)
        except KeyError:
            return self.redirect(reverse('sentry-manage-project', args=[project.organization.slug, project.slug]))

        if not plugin.can_configure_for_project(project):
            return self.redirect(reverse('sentry-manage-project', args=[project.organization.slug, project.slug]))

        react_plugin = None
        is_enabled = plugin.is_enabled(project)
        if isinstance(plugin, IssueTrackingPlugin2) or isinstance(plugin, NotificationPlugin):
            view = None
            response = client.get('/projects/{}/{}/plugins/{}/'.format(
                organization.slug,
                project.slug,
                slug,
            ), request=request)
            react_plugin = response.data
        else:
            view = plugin.configure(request=request, project=project)
            if isinstance(view, HttpResponse):
                return view

        context = {
            'page': 'plugin',
            'title': plugin.get_title(),
            'view': view,
            'plugin': plugin,
            'plugin_is_enabled': is_enabled,
            'react_plugin': react_plugin,
        }

        return self.respond('sentry/projects/plugins/configure.html', context)
    def get(self, request: Request, group) -> Response:
        """
        Retrieve the Oldest Event for an Issue
        ``````````````````````````````````````

        Retrieves the details of the oldest event for an issue.

        :pparam string group_id: the ID of the issue
        """

        environments = [e.name for e in get_environments(request, group.project.organization)]

        event = group.get_oldest_event_for_environments(environments)

        if not event:
            return Response({"detail": "No events found for group"}, status=404)

        try:
            return client.get(
                f"/projects/{event.organization.slug}/{event.project.slug}/events/{event.event_id}/",
                request=request,
                data={"environment": environments, "group_id": event.group_id},
            )
        except client.ApiError as e:
            return Response(e.body, status=e.status_code)
Exemple #5
0
def react_plugin_config(plugin, project, request):
    response = client.get(
        f"/projects/{project.organization.slug}/{project.slug}/plugins/{plugin.slug}/",
        request=request,
    )
    nonce = ""
    if hasattr(request, "csp_nonce"):
        nonce = f' nonce="{request.csp_nonce}"'

    # Pretty sure this is not in use, and if it is, it has been broken since
    # https://github.com/getsentry/sentry/pull/13578/files#diff-d17d91cc629f5f2e4582adb6e52d426f654452b751da97bafa25160b78566438L206
    return mark_safe("""
    <div id="ref-plugin-config"></div>
    <script%s>
      window.__onSentryInit = window.__onSentryInit || [];
      window.__onSentryInit.push({
        name: 'renderReact',
        component: 'PluginConfig',
        container: '#ref-plugin-config',
        props: {
            project: %s,
            organization: %s,
            data: %s
        },
      });
    </script>
    """ % (
        nonce,
        json.dumps_htmlsafe(serialize(project, request.user)),
        json.dumps_htmlsafe(serialize(project.organization, request.user)),
        json.dumps_htmlsafe(response.data),
    ))
Exemple #6
0
def react_plugin_config(plugin, project, request):
    response = client.get(
        f"/projects/{project.organization.slug}/{project.slug}/plugins/{plugin.slug}/",
        request=request,
    )
    nonce = ""
    if hasattr(request, "csp_nonce"):
        nonce = f' nonce="{request.csp_nonce}"'

    return mark_safe("""
    <div id="ref-plugin-config"></div>
    <script%s>
    $(function(){
        ReactDOM.render(React.createFactory(SentryApp.PluginConfig)({
            project: %s,
            organization: %s,
            data: %s
        }), document.getElementById('ref-plugin-config'));
    });
    </script>
    """ % (
        nonce,
        json.dumps_htmlsafe(serialize(project, request.user)),
        json.dumps_htmlsafe(serialize(project.organization, request.user)),
        json.dumps_htmlsafe(response.data),
    ))
Exemple #7
0
    def get(self, request: Request, group) -> Response:
        """
        Retrieve the Latest Event for an Issue
        ``````````````````````````````````````

        Retrieves the details of the latest event for an issue.

        :pparam string group_id: the ID of the issue
        """
        environments = [
            e.name
            for e in get_environments(request, group.project.organization)
        ]

        event = group.get_latest_event_for_environments(environments)

        if not event:
            return Response({"detail": "No events found for group"},
                            status=404)

        collapse = request.GET.getlist("collapse", [])
        if "stacktraceOnly" in collapse:
            return Response(serialize(event, request.user, EventSerializer()))

        try:
            return client.get(
                f"/projects/{event.organization.slug}/{event.project.slug}/events/{event.event_id}/",
                request=request,
                data={
                    "environment": environments,
                    "group_id": event.group_id
                },
            )
        except client.ApiError as e:
            return Response(e.body, status=e.status_code)
Exemple #8
0
    def get(self, request, group):
        """
        Retrieve the Latest Event for an Issue
        ``````````````````````````````````````

        Retrieves the details of the latest event for an issue.

        :pparam string group_id: the ID of the issue
        """
        environments = [
            e.name
            for e in get_environments(request, group.project.organization)
        ]

        event = group.get_latest_event_for_environments(environments)

        if not event:
            return Response({"detail": "No events found for group"},
                            status=404)

        try:
            return client.get(
                u"/projects/{}/{}/events/{}/".format(event.organization.slug,
                                                     event.project.slug,
                                                     event.event_id),
                request=request,
            )
        except client.ApiError as e:
            return Response(e.body, status=e.status_code)
    def get(self, request, group):
        """
        Retrieve the Oldest Event for an Issue
        ``````````````````````````````````````

        Retrieves the details of the oldest event for an issue.

        :pparam string group_id: the ID of the issue
        """

        environments = [e.name for e in get_environments(request, group.project.organization)]

        event = group.get_oldest_event_for_environments(environments)

        if not event:
            return Response({'detail': 'No events found for group'}, status=404)

        try:
            return client.get(u'/projects/{}/{}/events/{}/'.format(
                event.organization.slug,
                event.project.slug,
                event.event_id
            ), request=request)
        except client.ApiError as e:
            return Response(e.body, status=e.status_code)
def react_plugin_config(plugin, project, request):
    response = client.get(
        '/projects/{}/{}/plugins/{}/'.format(
            project.organization.slug,
            project.slug,
            plugin.slug,
        ),
        request=request
    )

    return mark_safe(
        """
    <div id="ref-plugin-config"></div>
    <script>
    $(function(){
        ReactDOM.render(React.createFactory(Sentry.PluginConfig)({
            project: %s,
            organization: %s,
            data: %s
        }), document.getElementById('ref-plugin-config'));
    });
    </script>
    """ % (
            json.dumps_htmlsafe(serialize(project, request.user)),
            json.dumps_htmlsafe(serialize(project.organization, request.user)),
            json.dumps_htmlsafe(response.data)
        )
    )
    def get(self, request, group):
        """
        Retrieve the latest event

        Return details on the latest event for this group.

            {method} {path}

        """
        event = group.get_latest_event()

        return client.get("/events/{}/".format(event.id), request.user, request.auth)
    def get(self, request, group):
        """
        Retrieve the latest sample for an aggregate

        Return details on the latest sample for this aggregate.

            {method} {path}

        """
        event = group.get_latest_event()

        return client.get('/events/{}/'.format(event.id), request.user, request.auth)
Exemple #13
0
    def get(self, request, group):
        """
        Retrieve the latest sample for an aggregate

        Return details on the latest sample for this aggregate.

            {method} {path}

        """
        event = group.get_latest_event()

        try:
            return client.get('/events/{}/'.format(event.id), request.user, request.auth)
        except client.ApiError as e:
            return Response(e.body, status=e.status)
Exemple #14
0
    def get(self, request, group):
        """
        Retrieve the latest sample for an aggregate

        Return details on the latest sample for this aggregate.

            {method} {path}

        """
        event = group.get_latest_event()

        try:
            return client.get('/events/{}/'.format(event.id), request.user, request.auth)
        except client.ApiError as e:
            return Response(e.body, status=e.status_code)
Exemple #15
0
    def post(self, request):
        """
        Authenticate a user

        Authenticate a user using the provided credentials.

            curl -X {method} -u PUBLIC_KEY:SECRET_KEY {path}

        """
        if not request.user.is_authenticated():
            return Response(status=400)

        # Must use the real request object that Django knows about
        login(request._request, request.user)

        return client.get('/users/me/', request.user, request.auth)
    def get(self, request, group):
        """
        Latest Sample
        `````````````

        Retrieves the details of the latest sample for an aggregate.

        :pparam string group_id: the ID of the group to get the latest sample of.
        """
        event = group.get_latest_event()
        if not event:
            return Response({'detail': 'No events found for group'}, status=404)

        try:
            return client.get('/events/{}/'.format(event.id), request=request)
        except client.ApiError as e:
            return Response(e.body, status=e.status_code)
    def get(self, request, group):
        """
        Retrieve Latest Event
        `````````````````````

        Retrieves the details of the latest event for an issue.

        :pparam string group_id: the ID of the issue
        """
        event = group.get_latest_event()
        if not event:
            return Response({'detail': 'No events found for group'}, status=404)

        try:
            return client.get(u'/events/{}/'.format(event.id), request=request)
        except client.ApiError as e:
            return Response(e.body, status=e.status_code)
Exemple #18
0
    def get(self, request, group):
        """
        Retrieve the Latest Event for an Issue
        ``````````````````````````````````````

        Retrieves the details of the latest event for an issue.

        :pparam string group_id: the ID of the issue
        """
        event = group.get_latest_event()
        if not event:
            return Response({'detail': 'No events found for group'}, status=404)

        try:
            return client.get(u'/events/{}/'.format(event.id), request=request)
        except client.ApiError as e:
            return Response(e.body, status=e.status_code)
Exemple #19
0
    def handle(self, request, organization, team, project, slug):
        try:
            plugin = plugins.get(slug)
        except KeyError:
            return self.redirect(
                reverse('sentry-manage-project',
                        args=[project.organization.slug, project.slug]))

        if not plugin.can_configure_for_project(project):
            return self.redirect(
                reverse('sentry-manage-project',
                        args=[project.organization.slug, project.slug]))

        react_plugin = None
        is_enabled = plugin.is_enabled(project)
        if isinstance(plugin, IssueTrackingPlugin2) or isinstance(
                plugin, NotificationPlugin):
            view = None
            response = client.get('/projects/{}/{}/plugins/{}/'.format(
                organization.slug,
                project.slug,
                slug,
            ),
                                  request=request)
            react_plugin = response.data
        else:
            view = plugin.configure(request=request, project=project)
            if isinstance(view, HttpResponse):
                return view

        context = {
            'page': 'plugin',
            'title': plugin.get_title(),
            'view': view,
            'plugin': plugin,
            'plugin_is_enabled': is_enabled,
            'react_plugin': react_plugin,
        }

        return self.respond('sentry/projects/plugins/configure.html', context)
Exemple #20
0
    def get(self, request):
        """
        Retrieve an aggregate

        Return details on an individual aggregate specified by query parameters.

            {method} {path}?shareId=mnIX

        """
        share_id = request.GET.get('shareId')
        if share_id:
            try:
                group = Group.from_share_id(share_id)
            except Group.DoesNotExist:
                group = None
        else:
            group = None

        if not group:
            return Response({'detail': 'No groups found'}, status=404)

        return client.get('/groups/{}/'.format(group.id), request.user, request.auth)
Exemple #21
0
    def post(self, request):
        """
        Authenticate a User
        ```````````````````

        This endpoint authenticates a user using the provided credentials
        through a regular HTTP basic auth system.  The response contains
        cookies that need to be sent with further requests that require
        authentication.

        This is primarily used internally in Sentry.

        Common example::

            curl -X ###METHOD### -u username:password ###URL###
        """
        if not request.user.is_authenticated():
            return Response(status=400)

        # Must use the real request object that Django knows about
        login(request._request, request.user)

        return client.get('/users/me/', request.user, request.auth)
Exemple #22
0
    def post(self, request):
        """
        Authenticate a User
        ```````````````````

        This endpoint authenticates a user using the provided credentials
        through a regular HTTP basic auth system.  The response contains
        cookies that need to be sent with further requests that require
        authentication.

        This is primarily used internally in Sentry.

        Common example::

            curl -X ###METHOD### -u username:password ###URL###
        """
        if not request.user.is_authenticated():
            return Response(status=400)

        # Must use the real request object that Django knows about
        login(request._request, request.user)

        return client.get('/users/me/', request=request)
    def get(self, request):
        """
        Retrieve an aggregate

        Return details on an individual aggregate specified by query parameters.

            {method} {path}?shareId=mnIX

        """
        share_id = request.GET.get('shareId')
        if share_id:
            try:
                group = Group.from_share_id(share_id)
            except Group.DoesNotExist:
                group = None
        else:
            group = None

        if not group:
            return Response({'detail': 'No groups found'}, status=404)

        return client.get('/groups/{}/'.format(group.id), request.user,
                          request.auth)
    def get(self, request, group):
        event = group.get_latest_event()

        return client.get('/events/{}/'.format(event.id), request.user,
                          request.auth)
    def get(self, request, group):
        event = group.get_latest_event()

        return client.get('/events/{}/'.format(event.id), request.user, request.auth)
Exemple #26
0
def unfurl_discover(data, integration,
                    links: List[UnfurlableUrl]) -> UnfurledUrl:
    orgs_by_slug = {org.slug: org for org in integration.organizations.all()}
    unfurls = {}

    for link in links:
        org_slug = link.args["org_slug"]
        org = orgs_by_slug.get(org_slug)

        # If the link shared is an org w/o the slack integration do not unfurl
        if not org:
            continue
        if not features.has("organizations:chart-unfurls", org):
            continue

        params = link.args["query"]
        query_id = params.get("id", None)

        saved_query = {}
        if query_id:
            try:
                response = client.get(
                    auth=ApiKey(organization=org, scope_list=["org:read"]),
                    path=
                    f"/organizations/{org_slug}/discover/saved/{query_id}/",
                )

            except Exception as exc:
                logger.error(
                    "Failed to load saved query for unfurl: %s",
                    str(exc),
                    exc_info=True,
                )
            else:
                saved_query = response.data

        # Override params from Discover Saved Query if they aren't in the URL
        params.setlist(
            "order",
            params.getlist("sort") or to_list(saved_query.get("orderby")))
        params.setlist(
            "name",
            params.getlist("name") or to_list(saved_query.get("name")))
        params.setlist(
            "yAxis",
            params.getlist("yAxis")
            or to_list(saved_query.get("yAxis", "count()")))
        params.setlist(
            "field",
            params.getlist("field") or to_list(saved_query.get("fields")))

        # Only override if key doesn't exist since we want to account for
        # an intermediate state where the query could have been cleared
        if "query" not in params:
            params.setlist(
                "query",
                params.getlist("query") or to_list(saved_query.get("query")))

        display_mode = str(
            params.get("display") or saved_query.get("display", "default"))

        if "daily" in display_mode:
            params.setlist("interval", ["1d"])
        if "top5" in display_mode:
            params.setlist("topEvents", [f"{TOP_N}"])

        try:
            resp = client.get(
                auth=ApiKey(organization=org, scope_list=["org:read"]),
                path=f"/organizations/{org_slug}/events-stats/",
                params=params,
            )
        except Exception as exc:
            logger.error(
                "Failed to load events-stats for unfurl: %s",
                str(exc),
                exc_info=True,
            )
            continue

        chart_data = {"seriesName": params.get("yAxis"), "stats": resp.data}

        style = display_modes.get(display_mode, display_modes["default"])

        try:
            url = generate_chart(style, chart_data)
        except RuntimeError as exc:
            logger.error(
                "Failed to generate chat for discover unfurl: %s",
                str(exc),
                exc_info=True,
            )
            continue

        unfurls[link.url] = build_discover_attachment(
            title=link.args["query"].get("name", "Dashboards query"),
            chart_url=url,
        )

    return unfurls
Exemple #27
0
def unfurl_discover(
    data: HttpRequest,
    integration: Integration,
    links: List[UnfurlableUrl],
    user: Optional["User"],
) -> UnfurledUrl:
    orgs_by_slug = {org.slug: org for org in integration.organizations.all()}
    unfurls = {}

    for link in links:
        org_slug = link.args["org_slug"]
        org = orgs_by_slug.get(org_slug)

        # If the link shared is an org w/o the slack integration do not unfurl
        if not org:
            continue
        if not features.has("organizations:discover-basic", org):
            continue

        params = link.args["query"]
        query_id = params.get("id", None)

        saved_query = {}
        if query_id:
            try:
                response = client.get(
                    auth=ApiKey(organization=org, scope_list=["org:read"]),
                    path=f"/organizations/{org_slug}/discover/saved/{query_id}/",
                )

            except Exception as exc:
                logger.error(
                    f"Failed to load saved query for unfurl: {exc}",
                    exc_info=True,
                )
            else:
                saved_query = response.data

        # Override params from Discover Saved Query if they aren't in the URL
        params.setlist(
            "order",
            params.getlist("sort")
            or (to_list(saved_query.get("orderby")) if saved_query.get("orderby") else []),
        )
        params.setlist("name", params.getlist("name") or to_list(saved_query.get("name")))

        fields = params.getlist("field") or to_list(saved_query.get("fields"))
        # Mimic Discover to pick the first aggregate as the yAxis option if
        # one isn't specified.
        axis_options = [field for field in fields if is_aggregate(field)] + [DEFAULT_AXIS_OPTION]
        params.setlist(
            "yAxis", params.getlist("yAxis") or to_list(saved_query.get("yAxis", axis_options[0]))
        )
        params.setlist("field", params.getlist("field") or to_list(saved_query.get("fields")))

        params.setlist(
            "project",
            params.getlist("project")
            or (to_list(saved_query.get("project")) if saved_query.get("project") else []),
        )

        # Only override if key doesn't exist since we want to account for
        # an intermediate state where the query could have been cleared
        if "query" not in params:
            params.setlist(
                "query", params.getlist("query") or to_list(saved_query.get("query", ""))
            )

        display_mode = str(params.get("display") or saved_query.get("display", "default"))

        if "daily" in display_mode:
            params.setlist("interval", ["1d"])

        if "top5" in display_mode:
            params.setlist(
                "topEvents",
                params.getlist("topEvents") or to_list(saved_query.get("topEvents", f"{TOP_N}")),
            )

            y_axis = params.getlist("yAxis")[0]
            if display_mode != "dailytop5":
                display_mode = get_top5_display_mode(y_axis)

        else:
            # topEvents param persists in the URL in some cases, we want to discard
            # it if it's not a top n display type.
            params.pop("topEvents", None)

        if "previous" in display_mode:
            stats_period = params.getlist("statsPeriod", [DEFAULT_PERIOD])[0]
            parsed_period = parse_stats_period(stats_period)
            if parsed_period and parsed_period <= timedelta(days=MAX_PERIOD_DAYS_INCLUDE_PREVIOUS):
                stats_period = get_double_period(stats_period)
                params.setlist("statsPeriod", [stats_period])

        endpoint = "events-stats/"
        if "worldmap" in display_mode:
            endpoint = "events-geo/"
            params.setlist("field", params.getlist("yAxis"))
            params.pop("sort", None)

        try:
            resp = client.get(
                auth=ApiKey(organization=org, scope_list=["org:read"]),
                user=user,
                path=f"/organizations/{org_slug}/{endpoint}",
                params=params,
            )
        except Exception as exc:
            logger.error(
                f"Failed to load {endpoint} for unfurl: {exc}",
                exc_info=True,
            )
            continue

        chart_data = {"seriesName": params.get("yAxis"), "stats": resp.data}

        style = display_modes.get(display_mode, display_modes["default"])

        try:
            url = generate_chart(style, chart_data)
        except RuntimeError as exc:
            logger.error(
                f"Failed to generate chart for discover unfurl: {exc}",
                exc_info=True,
            )
            continue

        unfurls[link.url] = SlackDiscoverMessageBuilder(
            title=link.args["query"].get("name", "Dashboards query"),
            chart_url=url,
        ).build()

    analytics.record(
        "integrations.slack.chart_unfurl",
        organization_id=integration.organizations.all()[0].id,
        user_id=user.id if user else None,
        unfurls_count=len(unfurls),
    )

    return unfurls
Exemple #28
0
def unfurl_discover(data, integration,
                    links: List[UnfurlableUrl]) -> UnfurledUrl:
    orgs_by_slug = {org.slug: org for org in integration.organizations.all()}
    unfurls = {}

    for link in links:
        org_slug = link.args["org_slug"]
        org = orgs_by_slug.get(org_slug)

        # If the link shared is an org w/o the slack integration do not unfurl
        if not org:
            continue
        if not features.has("organizations:chart-unfurls", org):
            continue

        params = link.args["query"]
        params.setlist("order", params.get("sort"))
        display_mode = str(link.args["query"].get("display", "default"))

        if "daily" in display_mode:
            params.setlist("interval", ["1d"])
        if "top5" in display_mode:
            params.setlist("topEvents", [f"{TOP_N}"])

        try:
            resp = client.get(
                auth=ApiKey(organization=org, scope_list=["org:read"]),
                path=f"/organizations/{org_slug}/events-stats/",
                params=params,
            )
        except Exception as exc:
            logger.error(
                "Failed to load events-stats for unfurl: %s",
                str(exc),
                exc_info=True,
            )
            continue

        chart_data = {
            "seriesName": link.args["query"].get("yAxis", "count()"),
            "stats": resp.data
        }

        style = display_modes.get(display_mode, display_modes["default"])

        try:
            url = generate_chart(style, chart_data)
        except RuntimeError as exc:
            logger.error(
                "Failed to generate chat for discover unfurl: %s",
                str(exc),
                exc_info=True,
            )
            continue

        unfurls[link.url] = build_discover_attachment(
            title=link.args["query"].get("name", "Dashboards query"),
            chart_url=url,
        )

    return unfurls