Ejemplo n.º 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
Ejemplo n.º 2
0
    def test_unfurl_discover_multi_y_axis(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&yAxis=count_unique%28user%29&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",
                "organizations:chart-unfurls",
            ]
        ):
            unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)

        assert unfurls[url] == build_discover_attachment(
            title=args["query"].get("name"), chart_url="chart-url"
        )
        assert len(mock_generate_chart.mock_calls) == 1
        chart_data = mock_generate_chart.call_args[0][1]

        assert len(chart_data["stats"]["count()"]["data"]) == 288
        assert len(chart_data["stats"]["count_unique(user)"]["data"]) == 288
Ejemplo n.º 3
0
def has_discover_links(links: List[str]) -> bool:
    for link in links:
        link_type, _ = match_link(link)
        if link_type == LinkType.DISCOVER:
            return True

    return False
Ejemplo n.º 4
0
    def test_unfurl_discover(self, mock_generate_chart):
        project1 = self.create_project(organization=self.org)
        min_ago = iso_format(before_now(minutes=1))
        self.store_event(data={
            "fingerprint": ["group2"],
            "timestamp": min_ago
        },
                         project_id=project1.id)
        self.store_event(data={
            "fingerprint": ["group2"],
            "timestamp": min_ago
        },
                         project_id=project1.id)

        url = f"https://sentry.io/organizations/{self.org.slug}/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&project={project1.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:chart-unfurls"):
            unfurls = link_handlers[link_type].fn(self.request,
                                                  self.integration, links)

        assert unfurls[url] == build_discover_attachment(
            title=args["query"].get("name"), chart_url="chart-url")
        assert len(mock_generate_chart.mock_calls) == 1
Ejemplo n.º 5
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",
                "organizations:chart-unfurls",
        ]):
            unfurls = link_handlers[link_type].fn(self.request,
                                                  self.integration, links,
                                                  self.user)

        assert unfurls[url] == build_discover_attachment(
            title=args["query"].get("name"), chart_url="chart-url")
        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
Ejemplo n.º 6
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"]
Ejemplo n.º 7
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
Ejemplo n.º 8
0
def test_match_link(url, expected):
    assert match_link(url) == expected
Ejemplo n.º 9
0
    def test_unfurl_discover_short_url(self, mock_generate_chart):
        query = {
            "fields": [
                "message", "event.type", "project", "user.display",
                "count_unique(user)"
            ],
            "query":
            "message:[first,second]",
            "yAxis":
            "count_unique(user)",
            "display":
            "top5",
            "topEvents":
            2,
        }
        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={
                "message": "first",
                "fingerprint": ["group2"],
                "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/?id={saved_query.id}&statsPeriod=24h&project={self.project.id}"
        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

        # Line chart expected since yAxis is count_unique(user)
        assert mock_generate_chart.call_args[0][
            0] == ChartType.SLACK_DISCOVER_TOP5_PERIOD_LINE
        chart_data = mock_generate_chart.call_args[0][1]
        assert chart_data["seriesName"] == "count_unique(user)"
        # 2 + 1 cause of Other
        assert len(chart_data["stats"].keys()) == 2
        first_key = list(chart_data["stats"].keys())[0]
        assert len(chart_data["stats"][first_key]["data"]) == 288
Ejemplo n.º 10
0
    def on_link_shared(
        self,
        request: Request,
        slack_request: SlackRequest,
    ) -> Optional[Response]:
        matches: Dict[LinkType, List[UnfurlableUrl]] = defaultdict(list)
        links_seen = set()

        integration = slack_request.integration
        data = slack_request.data.get("event")

        # An unfurl may have multiple links to unfurl
        for item in data["links"]:
            try:
                url = item["url"]
                slack_shared_link = parse_link(url)
            except Exception as e:
                logger.error("slack.parse-link-error", extra={"error": str(e)})
                continue

            # We would like to track what types of links users are sharing, but
            # it's a little difficult to do in Sentry because we filter requests
            # from Slack bots. Instead we just log to Kibana.
            logger.info("slack.link-shared",
                        extra={"slack_shared_link": slack_shared_link})
            link_type, args = match_link(url)

            # Link can't be unfurled
            if link_type is None or args is None:
                continue

            if (link_type == LinkType.DISCOVER
                    and not slack_request.has_identity and features.has(
                        "organizations:chart-unfurls",
                        slack_request.integration.organizations.all()[0],
                        actor=request.user,
                    )):
                analytics.record(
                    "integrations.slack.chart_unfurl",
                    organization_id=integration.organizations.all()[0].id,
                    unfurls_count=0,
                )
                self.prompt_link(data, slack_request, integration)
                return self.respond()

            # Don't unfurl the same thing multiple times
            seen_marker = hash(json.dumps((link_type, args), sort_keys=True))
            if seen_marker in links_seen:
                continue

            links_seen.add(seen_marker)
            matches[link_type].append(UnfurlableUrl(url=url, args=args))

        if not matches:
            return None

        # Unfurl each link type
        results: Dict[str, Any] = {}
        for link_type, unfurl_data in matches.items():
            results.update(link_handlers[link_type].fn(request, integration,
                                                       unfurl_data,
                                                       slack_request.user))

        if not results:
            return None

        access_token = self._get_access_token(integration)

        payload = {
            "token": access_token,
            "channel": data["channel"],
            "ts": data["message_ts"],
            "unfurls": json.dumps(results),
        }

        client = SlackClient()
        try:
            client.post("/chat.unfurl", data=payload)
        except ApiError as e:
            logger.error("slack.event.unfurl-error",
                         extra={"error": str(e)},
                         exc_info=True)

        return self.respond()
Ejemplo n.º 11
0
def has_discover_links(links: list[str]) -> bool:
    return any(match_link(link)[0] == LinkType.DISCOVER for link in links)
Ejemplo n.º 12
0
    def on_link_shared(self, request: Request, integration: Integration,
                       token: str, data: Mapping[str,
                                                 Any]) -> Optional[Response]:
        matches: Dict[LinkType, List[UnfurlableUrl]] = defaultdict(list)
        links_seen = set()

        # An unfurl may have multiple links to unfurl
        for item in data["links"]:
            try:
                # We would like to track what types of links users are sharing,
                # but it's a little difficult to do in sentry since we filter
                # requests from Slack bots. Instead we just log to Kibana
                logger.info(
                    "slack.link-shared",
                    extra={"slack_shared_link": parse_link(item["url"])})
            except Exception as e:
                logger.error("slack.parse-link-error", extra={"error": str(e)})

            link_type, args = match_link(item["url"])

            # Link can't be unfurled
            if link_type is None or args is None:
                continue

            # Don't unfurl the same thing multiple times
            seen_marker = hash(json.dumps((link_type, args), sort_keys=True))
            if seen_marker in links_seen:
                continue

            links_seen.add(seen_marker)
            matches[link_type].append(UnfurlableUrl(url=item["url"],
                                                    args=args))

        if not matches:
            return None

        # Unfurl each link type
        results: Dict[str, Any] = {}
        for link_type, unfurl_data in matches.items():
            results.update(link_handlers[link_type].fn(request, integration,
                                                       unfurl_data))

        if not results:
            return None

        access_token = self._get_access_token(integration)

        payload = {
            "token": access_token,
            "channel": data["channel"],
            "ts": data["message_ts"],
            "unfurls": json.dumps(results),
        }

        client = SlackClient()
        try:
            client.post("/chat.unfurl", data=payload)
        except ApiError as e:
            logger.error("slack.event.unfurl-error",
                         extra={"error": str(e)},
                         exc_info=True)

        return self.respond()