-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
chore(slack): reorganize unfurl SLOs #102500
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
|
|
||
| import logging | ||
| from collections import defaultdict | ||
| from collections.abc import Mapping, MutableMapping | ||
| from collections.abc import Mapping | ||
| from typing import Any | ||
|
|
||
| import orjson | ||
|
|
@@ -31,6 +31,7 @@ | |
| from sentry.integrations.slack.unfurl.types import LinkType, UnfurlableUrl | ||
| from sentry.integrations.slack.views.link_identity import build_linking_url | ||
| from sentry.organizations.services.organization import organization_service | ||
| from sentry.organizations.services.organization.model import RpcOrganization | ||
|
|
||
| from .base import SlackDMEndpoint | ||
| from .command import LINK_FROM_CHANNEL_MESSAGE | ||
|
|
@@ -159,108 +160,135 @@ def on_message(self, request: Request, slack_request: SlackDMRequest) -> Respons | |
|
|
||
| return self.respond() | ||
|
|
||
| def on_link_shared(self, request: Request, slack_request: SlackDMRequest) -> bool: | ||
| """Returns true on success""" | ||
| matches: MutableMapping[LinkType, list[UnfurlableUrl]] = defaultdict(list) | ||
| def _get_unfurlable_links( | ||
| self, | ||
| request: Request, | ||
| slack_request: SlackDMRequest, | ||
| data: dict[str, Any], | ||
| organization: RpcOrganization | None, | ||
| logger_params: dict[str, Any], | ||
| ) -> dict[LinkType, list[UnfurlableUrl]]: | ||
| matches: dict[LinkType, list[UnfurlableUrl]] = defaultdict(list) | ||
| links_seen = set() | ||
|
|
||
| data = slack_request.data.get("event", {}) | ||
|
|
||
| logger_params = { | ||
| "integration_id": slack_request.integration.id, | ||
| "team_id": slack_request.team_id, | ||
| "channel_id": slack_request.channel_id, | ||
| "user_id": slack_request.user_id, | ||
| "channel": slack_request.channel_id, | ||
| **data, | ||
| } | ||
|
|
||
| # An unfurl may have multiple links to unfurl | ||
| for item in data.get("links", []): | ||
| try: | ||
| url = item["url"] | ||
| except Exception: | ||
| _logger.exception("parse-link-error", extra={**logger_params, "url": url}) | ||
| continue | ||
|
|
||
| link_type, args = match_link(url) | ||
|
|
||
| # Link can't be unfurled | ||
| if link_type is None or args is None: | ||
| continue | ||
|
|
||
| ois = integration_service.get_organization_integrations( | ||
| integration_id=slack_request.integration.id, limit=1 | ||
| ) | ||
| organization_id = ois[0].organization_id if len(ois) > 0 else None | ||
| organization_context = ( | ||
| organization_service.get_organization_by_id( | ||
| id=organization_id, user_id=None, include_projects=False, include_teams=False | ||
| ) | ||
| if organization_id | ||
| else None | ||
| ) | ||
| organization = organization_context.organization if organization_context else None | ||
| logger_params["organization_id"] = organization_id | ||
|
|
||
| if ( | ||
| organization | ||
| and link_type == LinkType.DISCOVER | ||
| and not slack_request.has_identity | ||
| and features.has("organizations:discover-basic", organization, actor=request.user) | ||
| ): | ||
| with MessagingInteractionEvent( | ||
| interaction_type=MessagingInteractionType.PROCESS_SHARED_LINK, | ||
| spec=SlackMessagingSpec(), | ||
| ).capture() as lifecycle: | ||
| try: | ||
| analytics.record( | ||
| SlackIntegrationChartUnfurl( | ||
| organization_id=organization.id, | ||
| unfurls_count=0, | ||
| ) | ||
| url = item["url"] | ||
| except Exception: | ||
| lifecycle.record_failure("Failed to parse link", extra={**logger_params}) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This try/except is sort of weird. Realistically, this should only ever be a key error, and we can probably handle it a bit more gracefully with a |
||
| continue | ||
|
|
||
| link_type, args = match_link(url) | ||
|
|
||
| # Link can't be unfurled | ||
| if link_type is None or args is None: | ||
| lifecycle.record_halt("Unfurlable link", extra={"url": url}) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Cannot unfurl: misleading halt message under None conditionsThe halt message "Unfurlable link" is misleading. This message is recorded when
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bruh |
||
| continue | ||
|
|
||
| if ( | ||
| organization | ||
| and link_type == LinkType.DISCOVER | ||
| and not slack_request.has_identity | ||
| and features.has( | ||
| "organizations:discover-basic", organization, actor=request.user | ||
| ) | ||
| except Exception as e: | ||
| sentry_sdk.capture_exception(e) | ||
| ): | ||
| try: | ||
| analytics.record( | ||
| SlackIntegrationChartUnfurl( | ||
| organization_id=organization.id, | ||
| unfurls_count=0, | ||
| ) | ||
| ) | ||
| except Exception as e: | ||
GabeVillalobos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| sentry_sdk.capture_exception(e) | ||
|
|
||
| self.prompt_link(slack_request) | ||
| return True | ||
| self.prompt_link(slack_request) | ||
| lifecycle.record_halt("Discover link requires identity", extra={"url": url}) | ||
| return {} | ||
|
|
||
| # Don't unfurl the same thing multiple times | ||
| seen_marker = hash(orjson.dumps((link_type, list(args))).decode()) | ||
| if seen_marker in links_seen: | ||
| continue | ||
| # Don't unfurl the same thing multiple times | ||
| seen_marker = hash(orjson.dumps((link_type, list(args))).decode()) | ||
| if seen_marker in links_seen: | ||
| continue | ||
|
|
||
| links_seen.add(seen_marker) | ||
| matches[link_type].append(UnfurlableUrl(url=url, args=args)) | ||
| links_seen.add(seen_marker) | ||
| matches[link_type].append(UnfurlableUrl(url=url, args=args)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Missing return: unfurlable links None instead of dictThe method |
||
|
|
||
| if not matches: | ||
| return False | ||
| return matches | ||
|
|
||
| # Unfurl each link type | ||
| results: MutableMapping[str, Any] = {} | ||
| def _unfurl_links( | ||
| self, slack_request: SlackDMRequest, matches: dict[LinkType, list[UnfurlableUrl]] | ||
| ) -> dict[str, Any]: | ||
| results: dict[str, Any] = {} | ||
| for link_type, unfurl_data in matches.items(): | ||
| results.update( | ||
| link_handlers[link_type].fn( | ||
| request, | ||
| slack_request.integration, | ||
| unfurl_data, | ||
| slack_request.user, | ||
| slack_request.integration, unfurl_data, slack_request.user | ||
| ) | ||
| ) | ||
|
|
||
| if not results: | ||
| return False | ||
|
|
||
| # XXX(isabella): we use our message builders to create the blocks for each link to be | ||
| # unfurled, so the original result will include the fallback text string, however, the | ||
| # unfurl endpoint does not accept fallback text. | ||
| for link_info in results.values(): | ||
| if "text" in link_info: | ||
| del link_info["text"] | ||
|
|
||
| payload = {"channel": data["channel"], "ts": data["message_ts"], "unfurls": results} | ||
| return results | ||
|
|
||
| def on_link_shared(self, request: Request, slack_request: SlackDMRequest) -> bool: | ||
| """Returns true on success""" | ||
|
|
||
| data = slack_request.data.get("event", {}) | ||
|
|
||
| ois = integration_service.get_organization_integrations( | ||
| integration_id=slack_request.integration.id, limit=1 | ||
| ) | ||
| organization_id = ois[0].organization_id if len(ois) > 0 else None | ||
| organization_context = ( | ||
| organization_service.get_organization_by_id( | ||
| id=organization_id, | ||
| user_id=None, | ||
| include_projects=False, | ||
| include_teams=False, | ||
| ) | ||
| if organization_id | ||
| else None | ||
| ) | ||
| organization = organization_context.organization if organization_context else None | ||
|
|
||
| logger_params = { | ||
| "integration_id": slack_request.integration.id, | ||
| "team_id": slack_request.team_id, | ||
| "channel_id": slack_request.channel_id, | ||
| "user_id": slack_request.user_id, | ||
| "channel": slack_request.channel_id, | ||
| "organization_id": organization_id, | ||
| **data, | ||
| } | ||
|
|
||
| # An unfurl may have multiple links to unfurl | ||
| matches = self._get_unfurlable_links( | ||
| request, slack_request, data, organization, logger_params | ||
| ) | ||
| if not matches: | ||
| return False | ||
|
|
||
| # Unfurl each link type | ||
| results = self._unfurl_links(slack_request, matches) | ||
| if not results: | ||
| return False | ||
|
|
||
| with MessagingInteractionEvent( | ||
| interaction_type=MessagingInteractionType.UNFURL_LINK, | ||
| spec=SlackMessagingSpec(), | ||
| ).capture() as lifecycle: | ||
| payload = {"channel": data["channel"], "ts": data["message_ts"], "unfurls": results} | ||
| client = SlackSdkClient(integration_id=slack_request.integration.id) | ||
| try: | ||
| client.chat_unfurl( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.