Пример #1
0
    def test_unfurl_discover_html_escaped(self, mock_generate_chart):
        min_ago = iso_format(before_now(minutes=1))
        self.store_event(data={
            "fingerprint": ["group2"],
            "timestamp": min_ago
        },
                         project_id=self.project.id)
        self.store_event(data={
            "fingerprint": ["group2"],
            "timestamp": min_ago
        },
                         project_id=self.project.id)

        url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&project={self.project.id}&query=&sort=-timestamp&statsPeriod=24h"
        link_type, args = match_link(url)

        if not args or not link_type:
            raise Exception("Missing link_type/args")

        links = [
            UnfurlableUrl(url=url, args=args),
        ]

        with self.feature(["organizations:discover-basic"]):
            unfurls = link_handlers[link_type].fn(self.request,
                                                  self.integration, links,
                                                  self.user)

        assert (unfurls[url] == SlackDiscoverMessageBuilder(
            title=args["query"].get("name"), chart_url="chart-url").build())
        assert len(mock_generate_chart.mock_calls) == 1
        chart_data = mock_generate_chart.call_args[0][1]
        assert chart_data["seriesName"] == "count()"
        assert len(chart_data["stats"]["data"]) == 288
Пример #2
0
    def test_unfurl_discover_short_url_without_project_ids(
            self, mock_generate_chart):
        query = {
            "fields":
            ["title", "event.type", "project", "user.display", "timestamp"],
            "query":
            "",
            "yAxis":
            "count_unique(users)",
        }
        saved_query = DiscoverSavedQuery.objects.create(
            organization=self.organization,
            created_by=self.user,
            name="Test query",
            query=query,
            version=2,
        )
        saved_query.set_projects([self.project.id])

        min_ago = iso_format(before_now(minutes=1))
        self.store_event(data={
            "fingerprint": ["group2"],
            "timestamp": min_ago
        },
                         project_id=self.project.id)
        self.store_event(data={
            "fingerprint": ["group2"],
            "timestamp": min_ago
        },
                         project_id=self.project.id)

        url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?id={saved_query.id}&statsPeriod=24h"
        link_type, args = match_link(url)

        if not args or not link_type:
            raise Exception("Missing link_type/args")

        links = [
            UnfurlableUrl(url=url, args=args),
        ]

        with self.feature([
                "organizations:discover",
                "organizations:discover-basic",
        ]):
            unfurls = link_handlers[link_type].fn(self.request,
                                                  self.integration, links,
                                                  self.user)

        assert (unfurls[url] == SlackDiscoverMessageBuilder(
            title=args["query"].get("name"), chart_url="chart-url").build())
        assert len(mock_generate_chart.mock_calls) == 1

        assert mock_generate_chart.call_args[0][
            0] == ChartType.SLACK_DISCOVER_TOTAL_PERIOD
        chart_data = mock_generate_chart.call_args[0][1]
        assert chart_data["seriesName"] == "count_unique(users)"
        assert len(chart_data["stats"]["data"]) == 288
Пример #3
0
    def test_unfurl_world_map(self, mock_generate_chart):
        min_ago = iso_format(before_now(minutes=1))
        self.store_event(
            data={
                "fingerprint": ["group2"],
                "timestamp": min_ago,
                "user": {
                    "geo": {
                        "country_code": "CA",
                        "region": "Canada"
                    }
                },
            },
            project_id=self.project.id,
        )
        self.store_event(
            data={
                "fingerprint": ["group2"],
                "timestamp": min_ago,
                "user": {
                    "geo": {
                        "country_code": "AU",
                        "region": "Australia"
                    }
                },
            },
            project_id=self.project.id,
        )

        url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?display=worldmap&field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&project={self.project.id}&query=&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29"
        link_type, args = match_link(url)

        if not args or not link_type:
            raise Exception("Missing link_type/args")

        links = [
            UnfurlableUrl(url=url, args=args),
        ]

        with self.feature(["organizations:discover-basic"]):
            unfurls = link_handlers[link_type].fn(self.request,
                                                  self.integration, links,
                                                  self.user)

        assert (unfurls[url] == SlackDiscoverMessageBuilder(
            title=args["query"].get("name"), chart_url="chart-url").build())
        assert len(mock_generate_chart.mock_calls) == 1

        assert mock_generate_chart.call_args[0][
            0] == ChartType.SLACK_DISCOVER_WORLDMAP
        chart_data = mock_generate_chart.call_args[0][1]
        assert chart_data["seriesName"] == "count()"
        assert len(chart_data["stats"]["data"]) == 2
        assert sorted(x["geo.country_code"]
                      for x in chart_data["stats"]["data"]) == ["AU", "CA"]
Пример #4
0
    def test_top_daily_events_renders_bar_chart(self, mock_generate_chart):
        min_ago = iso_format(before_now(minutes=1))
        self.store_event(
            data={
                "message": "first",
                "fingerprint": ["group1"],
                "timestamp": min_ago
            },
            project_id=self.project.id,
        )
        self.store_event(
            data={
                "message": "second",
                "fingerprint": ["group2"],
                "timestamp": min_ago
            },
            project_id=self.project.id,
        )

        url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?field=message&field=event.type&field=count()&name=All+Events&query=message:[first,second]&sort=-count&statsPeriod=24h&display=dailytop5&topEvents=2"
        link_type, args = match_link(url)

        if not args or not link_type:
            raise Exception("Missing link_type/args")

        links = [
            UnfurlableUrl(url=url, args=args),
        ]

        with self.feature([
                "organizations:discover",
                "organizations:discover-basic",
        ]):
            unfurls = link_handlers[link_type].fn(self.request,
                                                  self.integration, links,
                                                  self.user)

        assert (unfurls[url] == SlackDiscoverMessageBuilder(
            title=args["query"].get("name"), chart_url="chart-url").build())
        assert len(mock_generate_chart.mock_calls) == 1

        assert mock_generate_chart.call_args[0][
            0] == ChartType.SLACK_DISCOVER_TOP5_DAILY
        chart_data = mock_generate_chart.call_args[0][1]
        assert chart_data["seriesName"] == "count()"
        assert len(chart_data["stats"].keys()) == 2
        first_key = list(chart_data["stats"].keys())[0]
        # Two buckets
        assert len(chart_data["stats"][first_key]["data"]) == 2
Пример #5
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