def test_unfurl_discover(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", "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 chart_data["seriesName"] == "count()" assert len(chart_data["stats"]["data"]) == 288
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
def test_top_events_url_param(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=top5&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", "organizations:chart-unfurls", "organizations:discover-top-events", ] ): 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_TOP5_PERIOD 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] assert len(chart_data["stats"][first_key]["data"]) == 288
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
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
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: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")) if saved_query.get("orderby") else []), ) 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"))) 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: if features.has("organizations:discover-top-events", org): params.setlist( "topEvents", params.getlist("topEvents") or to_list(saved_query.get("topEvents", f"{TOP_N}")), ) else: params.setlist("topEvents", [f"{TOP_N}"]) 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]) try: resp = client.get( auth=ApiKey(organization=org, scope_list=["org:read"]), user=user, 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 chart 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, ) 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