def _get_actions(self, request: Request, group): project = group.project action_list = [] for plugin in plugins.for_project(project, version=1): if is_plugin_deprecated(plugin, project): continue results = safe_execute(plugin.actions, request, group, action_list, _with_transaction=False) if not results: continue action_list = results for plugin in plugins.for_project(project, version=2): if is_plugin_deprecated(plugin, project): continue for action in (safe_execute( plugin.get_actions, request, group, _with_transaction=False) or ()): action_list.append(action) return action_list
def _get_available_issue_plugins(self, request, group): project = group.project plugin_issues = [] for plugin in plugins.for_project(project, version=1): if isinstance(plugin, IssueTrackingPlugin2): if is_plugin_deprecated(plugin, project): continue plugin_issues = safe_execute( plugin.plugin_issues, request, group, plugin_issues, _with_transaction=False ) return plugin_issues
def get_annotations(group, request=None): project = group.project annotation_list = [] for plugin in plugins.for_project(project, version=2): if is_plugin_deprecated(plugin, project): continue for value in (safe_execute( plugin.get_annotations, group=group, _with_transaction=False) or ()): annotation = safe_execute(Annotation, _with_transaction=False, **value) if annotation: annotation_list.append(annotation) return annotation_list
def handle(self, request: Request, organization, project, group_id, slug) -> Response: group = get_object_or_404(Group, pk=group_id, project=project) try: plugin = plugins.get(slug) if is_plugin_deprecated(plugin, project): raise Http404("Plugin not found") except KeyError: raise Http404("Plugin not found") GroupMeta.objects.populate_cache([group]) response = plugin.get_view_response(request, group) if response: return response redirect = request.META.get("HTTP_REFERER", "") if not is_safe_url(redirect, allowed_hosts=(request.get_host(), )): redirect = f"/{organization.slug}/{group.project.slug}/" return HttpResponseRedirect(redirect)
def get_attrs(self, item_list, user): from sentry.integrations import IntegrationFeatures from sentry.models import PlatformExternalIssue from sentry.plugins.base import plugins GroupMeta.objects.populate_cache(item_list) # Note that organization is necessary here for use in `_get_permalink` to avoid # making unnecessary queries. prefetch_related_objects(item_list, "project__organization") if user.is_authenticated and item_list: bookmarks = set( GroupBookmark.objects.filter( user=user, group__in=item_list).values_list("group_id", flat=True)) seen_groups = dict( GroupSeen.objects.filter(user=user, group__in=item_list).values_list( "group_id", "last_seen")) subscriptions = self._get_subscriptions(item_list, user) else: bookmarks = set() seen_groups = {} subscriptions = defaultdict(lambda: (False, False, None)) assignees = { a.group_id: a.assigned_actor() for a in GroupAssignee.objects.filter(group__in=item_list) } resolved_assignees = ActorTuple.resolve_dict(assignees) ignore_items = { g.group_id: g for g in GroupSnooze.objects.filter(group__in=item_list) } resolved_item_list = [ i for i in item_list if i.status == GroupStatus.RESOLVED ] if resolved_item_list: release_resolutions = { i[0]: i[1:] for i in GroupResolution.objects.filter( group__in=resolved_item_list).values_list( "group", "type", "release__version", "actor_id") } # due to our laziness, and django's inability to do a reasonable join here # we end up with two queries commit_results = list( Commit.objects.extra( select={"group_id": "sentry_grouplink.group_id"}, tables=["sentry_grouplink"], where=[ "sentry_grouplink.linked_id = sentry_commit.id", "sentry_grouplink.group_id IN ({})".format(", ".join( str(i.id) for i in resolved_item_list)), "sentry_grouplink.linked_type = %s", "sentry_grouplink.relationship = %s", ], params=[ int(GroupLink.LinkedType.commit), int(GroupLink.Relationship.resolves) ], )) commit_resolutions = { i.group_id: d for i, d in zip(commit_results, serialize( commit_results, user)) } else: release_resolutions = {} commit_resolutions = {} actor_ids = {r[-1] for r in release_resolutions.values()} actor_ids.update(r.actor_id for r in ignore_items.values()) if actor_ids: users = list(User.objects.filter(id__in=actor_ids, is_active=True)) actors = {u.id: d for u, d in zip(users, serialize(users, user))} else: actors = {} share_ids = dict( GroupShare.objects.filter(group__in=item_list).values_list( "group_id", "uuid")) result = {} seen_stats = self._get_seen_stats(item_list, user) annotations_by_group_id = defaultdict(list) organization_id_list = list( {item.project.organization_id for item in item_list}) # if no groups, then we can't proceed but this seems to be a valid use case if not item_list: return {} if len(organization_id_list) > 1: # this should never happen but if it does we should know about it logger.warning( "Found multiple organizations for groups: %s, with orgs: %s" % ([item.id for item in item_list], organization_id_list)) # should only have 1 org at this point organization_id = organization_id_list[0] authorized = self._is_authorized(user, organization_id) # find all the integration installs that have issue tracking for integration in Integration.objects.filter( organizations=organization_id): if not (integration.has_feature(IntegrationFeatures.ISSUE_BASIC) or integration.has_feature(IntegrationFeatures.ISSUE_SYNC)): continue install = integration.get_installation(organization_id) local_annotations_by_group_id = (safe_execute( install.get_annotations_for_group_list, group_list=item_list, _with_transaction=False, ) or {}) merge_list_dictionaries(annotations_by_group_id, local_annotations_by_group_id) # find the external issues for sentry apps and add them in local_annotations_by_group_id = (safe_execute( PlatformExternalIssue.get_annotations_for_group_list, group_list=item_list, _with_transaction=False, ) or {}) merge_list_dictionaries(annotations_by_group_id, local_annotations_by_group_id) snuba_stats = self._get_group_snuba_stats(item_list, seen_stats) for item in item_list: active_date = item.active_at or item.first_seen annotations = [] annotations.extend(annotations_by_group_id[item.id]) # add the annotations for plugins # note that the model GroupMeta where all the information is stored is already cached at the top of this function # so these for loops doesn't make a bunch of queries for plugin in plugins.for_project(project=item.project, version=1): if is_plugin_deprecated(plugin, item.project): continue safe_execute(plugin.tags, None, item, annotations, _with_transaction=False) for plugin in plugins.for_project(project=item.project, version=2): annotations.extend( safe_execute(plugin.get_annotations, group=item, _with_transaction=False) or ()) resolution_actor = None resolution_type = None resolution = release_resolutions.get(item.id) if resolution: resolution_type = "release" resolution_actor = actors.get(resolution[-1]) if not resolution: resolution = commit_resolutions.get(item.id) if resolution: resolution_type = "commit" ignore_item = ignore_items.get(item.id) if ignore_item: ignore_actor = actors.get(ignore_item.actor_id) else: ignore_actor = None result[item] = { "id": item.id, "assigned_to": resolved_assignees.get(item.id), "is_bookmarked": item.id in bookmarks, "subscription": subscriptions[item.id], "has_seen": seen_groups.get(item.id, active_date) > active_date, "annotations": annotations, "ignore_until": ignore_item, "ignore_actor": ignore_actor, "resolution": resolution, "resolution_type": resolution_type, "resolution_actor": resolution_actor, "share_id": share_ids.get(item.id), "authorized": authorized, } result[item]["is_unhandled"] = bool( snuba_stats.get(item.id, {}).get("unhandled")) if seen_stats: result[item].update(seen_stats.get(item, {})) return result