Пример #1
0
    def get_attrs(self, item_list, user):
        from sentry.api.serializers import GroupSerializer

        groups = list(
            Group.objects.filter(
                id__in=set([i.group_id for i in item_list if i.group_id])))
        serialized_groups = {}
        if groups:
            serialized_groups = {
                d["id"]: d
                for d in serialize(
                    groups,
                    user,
                    GroupSerializer(environment_func=self.environment_func),
                )
            }

        attrs = super(UserReportWithGroupSerializer,
                      self).get_attrs(item_list, user)
        for item in item_list:
            attrs[item].update({
                "group":
                serialized_groups[six.text_type(item.group_id)]
                if item.group_id else None
            })
        return attrs
Пример #2
0
    def put(self, request, group):
        """
        Update an Issue
        ```````````````

        Updates an individual issues's attributes.  Only the attributes
        submitted are modified.

        :pparam string issue_id: the ID of the group to retrieve.
        :param string status: the new status for the issue.  Valid values
                              are ``"resolved"``, ``resolvedInNextRelease``,
                              ``"unresolved"``, and ``"ignored"``.
        :param string assignedTo: the actor id (or username) of the user or team that should be
                                  assigned to this issue.
        :param boolean hasSeen: in case this API call is invoked with a user
                                context this allows changing of the flag
                                that indicates if the user has seen the
                                event.
        :param boolean isBookmarked: in case this API call is invoked with a
                                     user context this allows changing of
                                     the bookmark flag.
        :param boolean isSubscribed:
        :param boolean isPublic: sets the issue to public or private.
        :auth: required
        """
        discard = request.data.get("discard")

        # TODO(dcramer): we need to implement assignedTo in the bulk mutation
        # endpoint
        try:
            response = client.put(
                path=u"/projects/{}/{}/issues/".format(
                    group.project.organization.slug, group.project.slug),
                params={"id": group.id},
                data=request.data,
                request=request,
            )
        except client.ApiError as e:
            return Response(e.body, status=e.status_code)

        # if action was discard, there isn't a group to serialize anymore
        if discard:
            return response

        # we need to fetch the object against as the bulk mutation endpoint
        # only returns a delta, and object mutation returns a complete updated
        # entity.
        # TODO(dcramer): we should update the API and have this be an explicit
        # flag (or remove it entirely) so that delta's are the primary response
        # for mutation.
        group = Group.objects.get(id=group.id)

        serialized = serialize(
            group,
            request.user,
            GroupSerializer(environment_func=self._get_environment_func(
                request, group.project.organization_id)),
        )

        return Response(serialized, status=response.status_code)
Пример #3
0
    def get_attrs(self, item_list, user):
        from sentry.api.serializers import GroupSerializer

        # TODO(dcramer); assert on relations
        attrs = super(OrganizationActivitySerializer,
                      self).get_attrs(item_list, user)

        groups = {
            d["id"]: d
            for d in serialize(
                set([i.group for i in item_list if i.group_id]),
                user,
                GroupSerializer(environment_func=self.environment_func),
            )
        }

        projects = {
            d["id"]: d
            for d in serialize(set(i.project for i in item_list), user)
        }

        for item in item_list:
            attrs[item]["issue"] = groups[six.text_type(
                item.group_id)] if item.group_id else None
            attrs[item]["project"] = projects[six.text_type(item.project_id)]
        return attrs
Пример #4
0
    def get(self, request: Request, team) -> Response:
        """
        Return the oldest issues owned by a team
        """
        limit = min(100, int(request.GET.get("limit", 10)))
        environments = [
            e.id for e in get_environments(request, team.organization)
        ]
        group_environment_filter = (Q(
            groupenvironment__environment_id=environments[0])
                                    if environments else Q())

        group_list = list(
            Group.objects.filter_to_team(team).filter(
                group_environment_filter,
                status=GroupStatus.UNRESOLVED,
                last_seen__gt=datetime.now() - timedelta(days=90),
            ).order_by("first_seen")[:limit])

        return Response(
            serialize(
                group_list,
                request.user,
                GroupSerializer(environment_func=self._get_environment_func(
                    request, team.organization_id)),
            ))
Пример #5
0
    def get_attrs(self, item_list, user):
        from sentry.api.serializers import GroupSerializer

        # TODO(dcramer); assert on relations
        attrs = super().get_attrs(item_list, user)

        groups = {
            d["id"]: d
            for d in serialize(
                {i.group
                 for i in item_list if i.group_id},
                user,
                GroupSerializer(environment_func=self.environment_func),
            )
        }

        projects = {
            d["id"]: d
            for d in serialize({i.project
                                for i in item_list}, user)
        }

        for item in item_list:
            attrs[item]["issue"] = groups[str(
                item.group_id)] if item.group_id else None
            attrs[item]["project"] = projects[str(item.project_id)]
        return attrs
Пример #6
0
    def get(self, request: Request, team) -> Response:
        """
        Return the oldest issues owned by a team
        """
        limit = min(100, int(request.GET.get("limit", 10)))
        group_list = list(
            Group.objects.filter_to_team(team).filter(
                status=GroupStatus.UNRESOLVED).order_by("first_seen")[:limit])

        return Response(
            serialize(
                group_list,
                request.user,
                GroupSerializer(environment_func=self._get_environment_func(
                    request, team.organization_id)),
            ))
Пример #7
0
    def get(self, request, team):
        """
        Return a list of the trending groups for a given team.

        The resulting query will find groups which have been seen since the
        cutoff date, and then sort those by score, returning the highest scoring
        groups first.
        """
        minutes = int(request.GET.get('minutes', 15))
        limit = min(100, int(request.GET.get('limit', 10)))

        project_list = Project.objects.get_for_user(user=request.user, team=team)

        project_dict = dict((p.id, p) for p in project_list)

        cutoff = timedelta(minutes=minutes)
        cutoff_dt = timezone.now() - cutoff

        if get_db_engine('default') == 'sqlite':
            sort_value = 'times_seen'
        else:
            sort_value = 'score'

        group_list = list(
            Group.objects.filter(
                project__in=project_dict.keys(),
                status=GroupStatus.UNRESOLVED,
                last_seen__gte=cutoff_dt,
            ).extra(
                select={'sort_value': sort_value},
            ).order_by('-{}'.format(sort_value))[:limit]
        )

        for group in group_list:
            group._project_cache = project_dict.get(group.project_id)

        return Response(
            serialize(
                group_list,
                request.user,
                GroupSerializer(
                    environment_func=self._get_environment_func(
                        request, team.organization_id)
                )
            )
        )
Пример #8
0
    def get_attrs(self, item_list, user):
        from sentry.api.serializers import GroupSerializer

        # TODO(dcramer); assert on relations
        groups = {
            d["id"]: d
            for d in serialize(
                set(i.group for i in item_list if i.group_id),
                user,
                GroupSerializer(environment_func=self.environment_func),
            )
        }

        attrs = super(UserReportWithGroupSerializer, self).get_attrs(item_list, user)
        for item in item_list:
            attrs[item].update(
                {"group": groups[six.text_type(item.group_id)] if item.group_id else None}
            )
        return attrs
Пример #9
0
    def get(self, request, team):
        """
        Return a list of the newest groups for a given team.

        The resulting query will find groups which have been seen since the
        cutoff date, and then sort those by score, returning the highest scoring
        groups first.
        """
        minutes = int(request.GET.get("minutes", 15))
        limit = min(100, int(request.GET.get("limit", 10)))

        project_list = Project.objects.get_for_user(user=request.user, team=team)

        project_dict = {p.id: p for p in project_list}

        cutoff = timedelta(minutes=minutes)
        cutoff_dt = timezone.now() - cutoff

        sort_value = "score"
        group_list = list(
            Group.objects.filter(
                project__in=project_dict.keys(),
                status=GroupStatus.UNRESOLVED,
                active_at__gte=cutoff_dt,
            )
            .extra(select={"sort_value": sort_value})
            .order_by(f"-{sort_value}", "-first_seen")[:limit]
        )

        for group in group_list:
            group._project_cache = project_dict.get(group.project_id)

        return Response(
            serialize(
                group_list,
                request.user,
                GroupSerializer(
                    environment_func=self._get_environment_func(request, team.organization_id)
                ),
            )
        )
Пример #10
0
    def put(self, request: Request, group) -> Response:
        """
        Update an Issue
        ```````````````

        Updates an individual issue's attributes. Only the attributes submitted
        are modified.

        :pparam string issue_id: the ID of the group to retrieve.
        :param string status: the new status for the issue.  Valid values
                              are ``"resolved"``, ``resolvedInNextRelease``,
                              ``"unresolved"``, and ``"ignored"``.
        :param string assignedTo: the user or team that should be assigned to
                                  this issue. Can be of the form ``"<user_id>"``,
                                  ``"user:<user_id>"``, ``"<username>"``,
                                  ``"<user_primary_email>"``, or ``"team:<team_id>"``.
        :param string assignedBy: ``"suggested_assignee"`` | ``"assignee_selector"``
        :param boolean hasSeen: in case this API call is invoked with a user
                                context this allows changing of the flag
                                that indicates if the user has seen the
                                event.
        :param boolean isBookmarked: in case this API call is invoked with a
                                     user context this allows changing of
                                     the bookmark flag.
        :param boolean isSubscribed:
        :param boolean isPublic: sets the issue to public or private.
        :auth: required
        """
        try:
            discard = request.data.get("discard")
            project = group.project
            search_fn = functools.partial(prep_search, self, request, project)
            response = update_groups(request, [group.id], [project],
                                     project.organization_id, search_fn)
            # if action was discard, there isn't a group to serialize anymore
            # if response isn't 200, return the response update_groups gave us (i.e. helpful error)
            # instead of serializing the updated group
            if discard or response.status_code != 200:
                return response

            # we need to fetch the object against as the bulk mutation endpoint
            # only returns a delta, and object mutation returns a complete updated
            # entity.
            # TODO(dcramer): we should update the API and have this be an explicit
            # flag (or remove it entirely) so that delta's are the primary response
            # for mutation.
            group = Group.objects.get(id=group.id)

            serialized = serialize(
                group,
                request.user,
                GroupSerializer(environment_func=self._get_environment_func(
                    request, group.project.organization_id)),
            )
            return Response(serialized, status=response.status_code)
        except client.ApiError as e:
            logging.error(
                "group_details:put client.ApiError",
                exc_info=True,
            )
            return Response(e.body, status=e.status_code)
        except Exception:
            raise
Пример #11
0
    def get(self, request, group):
        """
        Retrieve an Issue
        `````````````````

        Return details on an individual issue. This returns the basic stats for
        the issue (title, last seen, first seen), some overall numbers (number
        of comments, user reports) as well as the summarized event data.

        :pparam string issue_id: the ID of the issue to retrieve.
        :auth: required
        """
        # TODO(dcramer): handle unauthenticated/public response
        data = serialize(
            group, request.user,
            GroupSerializer(environment_func=self._get_environment_func(
                request, group.project.organization_id)))

        # TODO: these probably should be another endpoint
        activity = self._get_activity(request, group, num=100)
        seen_by = self._get_seen_by(request, group)

        first_release = group.get_first_release()

        if first_release is not None:
            last_release = group.get_last_release()
        else:
            last_release = None

        action_list = self._get_actions(request, group)

        if first_release:
            first_release = self._get_release_info(request, group,
                                                   first_release)
        if last_release:
            last_release = self._get_release_info(request, group, last_release)

        try:
            environment_id = self._get_environment_id_from_request(
                request, group.project.organization_id)
        except Environment.DoesNotExist:
            get_range = lambda model, keys, start, end, **kwargs: \
                {k: tsdb.make_series(0, start, end) for k in keys}
            tags = []
            user_reports = UserReport.objects.none()

        else:
            get_range = functools.partial(tsdb.get_range,
                                          environment_id=environment_id)
            tags = tagstore.get_group_tag_keys(group.project_id,
                                               group.id,
                                               environment_id,
                                               limit=100)
            if environment_id is None:
                user_reports = UserReport.objects.filter(group=group)
            else:
                user_reports = UserReport.objects.filter(
                    group=group, environment_id=environment_id)

        now = timezone.now()
        hourly_stats = tsdb.rollup(
            get_range(
                model=tsdb.models.group,
                keys=[group.id],
                end=now,
                start=now - timedelta(days=1),
            ), 3600)[group.id]
        daily_stats = tsdb.rollup(
            get_range(
                model=tsdb.models.group,
                keys=[group.id],
                end=now,
                start=now - timedelta(days=30),
            ), 3600 * 24)[group.id]

        participants = list(
            User.objects.filter(
                groupsubscription__is_active=True,
                groupsubscription__group=group,
            ))

        data.update({
            'firstRelease':
            first_release,
            'lastRelease':
            last_release,
            'activity':
            serialize(activity, request.user),
            'seenBy':
            seen_by,
            'participants':
            serialize(participants, request.user),
            'pluginActions':
            action_list,
            'pluginIssues':
            self._get_available_issue_plugins(request, group),
            'pluginContexts':
            self._get_context_plugins(request, group),
            'userReportCount':
            user_reports.count(),
            'tags':
            sorted(serialize(tags, request.user), key=lambda x: x['name']),
            'stats': {
                '24h': hourly_stats,
                '30d': daily_stats,
            }
        })

        # the current release is the 'latest seen' release within the
        # environment even if it hasnt affected this issue

        try:
            environment = self._get_environment_from_request(
                request,
                group.project.organization_id,
            )
        except Environment.DoesNotExist:
            environment = None

        if environment is not None:
            try:
                current_release = GroupRelease.objects.filter(
                    group_id=group.id,
                    environment=environment.name,
                    release_id=ReleaseEnvironment.objects.filter(
                        release_id__in=ReleaseProject.objects.filter(
                            project_id=group.project_id).values_list(
                                'release_id', flat=True),
                        organization_id=group.project.organization_id,
                        environment_id=environment.id,
                    ).order_by('-first_seen').values_list('release_id',
                                                          flat=True)[:1],
                )[0]
            except IndexError:
                current_release = None

            data.update({
                'currentRelease':
                serialize(current_release, request.user,
                          GroupReleaseWithStatsSerializer())
            })

        return Response(data)
Пример #12
0
    def put(self, request, group):
        """
        Update an Issue
        ```````````````

        Updates an individual issue's attributes. Only the attributes submitted
        are modified.

        :pparam string issue_id: the ID of the group to retrieve.
        :param string status: the new status for the issue.  Valid values
                              are ``"resolved"``, ``resolvedInNextRelease``,
                              ``"unresolved"``, and ``"ignored"``.
        :param string assignedTo: the user or team that should be assigned to
                                  this issue. Can be of the form ``"<user_id>"``,
                                  ``"user:<user_id>"``, ``"<username>"``,
                                  ``"<user_primary_email>"``, or ``"team:<team_id>"``.
        :param boolean hasSeen: in case this API call is invoked with a user
                                context this allows changing of the flag
                                that indicates if the user has seen the
                                event.
        :param boolean isBookmarked: in case this API call is invoked with a
                                     user context this allows changing of
                                     the bookmark flag.
        :param boolean isSubscribed:
        :param boolean isPublic: sets the issue to public or private.
        :auth: required
        """
        try:
            discard = request.data.get("discard")

            # TODO(dcramer): we need to implement assignedTo in the bulk mutation
            # endpoint
            response = client.put(
                path=
                f"/projects/{group.project.organization.slug}/{group.project.slug}/issues/",
                params={"id": group.id},
                data=request.data,
                request=request,
            )

            # if action was discard, there isn't a group to serialize anymore
            if discard:
                return response

            # we need to fetch the object against as the bulk mutation endpoint
            # only returns a delta, and object mutation returns a complete updated
            # entity.
            # TODO(dcramer): we should update the API and have this be an explicit
            # flag (or remove it entirely) so that delta's are the primary response
            # for mutation.
            group = Group.objects.get(id=group.id)

            serialized = serialize(
                group,
                request.user,
                GroupSerializer(environment_func=self._get_environment_func(
                    request, group.project.organization_id)),
            )
            return Response(serialized, status=response.status_code)
        except client.ApiError as e:
            logging.error(
                "group_details:put client.ApiError",
                exc_info=True,
            )
            metrics.incr(
                "workflowslo.http_response",
                sample_rate=1.0,
                tags={
                    "status": e.status_code,
                    "detail": "group_details:put:client.ApiError"
                },
            )
            return Response(e.body, status=e.status_code)
        except Exception:
            metrics.incr(
                "group.update.http_response",
                sample_rate=1.0,
                tags={
                    "status": 500,
                    "detail": "group_details:put:Exception"
                },
            )
            raise
Пример #13
0
    def get(self, request, group):
        """
        Retrieve an Issue
        `````````````````

        Return details on an individual issue. This returns the basic stats for
        the issue (title, last seen, first seen), some overall numbers (number
        of comments, user reports) as well as the summarized event data.

        :pparam string issue_id: the ID of the issue to retrieve.
        :auth: required
        """
        # TODO(dcramer): handle unauthenticated/public response

        # TODO(jess): This can be removed when tagstore v2 is deprecated
        use_snuba = request.GET.get("enable_snuba") == "1"
        environments = get_environments(request, group.project.organization)
        environment_ids = [e.id for e in environments]

        if use_snuba:
            # WARNING: the rest of this endpoint relies on this serializer
            # populating the cache SO don't move this :)
            data = serialize(
                group, request.user,
                GroupSerializerSnuba(environment_ids=environment_ids))
        else:
            # TODO(jess): This is just to ensure we're not breaking the old
            # issue page somehow -- non-snuba tagstore versions will raise
            # if more than one env is passed
            if environments:
                environments = environments[:1]
                environment_ids = environment_ids[:1]

            data = serialize(
                group,
                request.user,
                GroupSerializer(
                    # Just in case multiple envs are passed, let's make
                    # sure we're using the same one for all the stats
                    environment_func=lambda: environments[0]
                    if environments else None),
            )

        # TODO: these probably should be another endpoint
        activity = self._get_activity(request, group, num=100)
        seen_by = self._get_seen_by(request, group)

        first_release = group.get_first_release()

        if first_release is not None:
            last_release = group.get_last_release()
        else:
            last_release = None

        action_list = self._get_actions(request, group)

        if first_release:
            first_release = self._get_release_info(request, group,
                                                   first_release)
        if last_release:
            last_release = self._get_release_info(request, group, last_release)

        get_range = functools.partial(tsdb.get_range,
                                      environment_ids=environment_ids)

        tags = tagstore.get_group_tag_keys(group.project_id,
                                           group.id,
                                           environment_ids,
                                           limit=100)
        if not environment_ids:
            user_reports = UserReport.objects.filter(group=group)
        else:
            user_reports = UserReport.objects.filter(
                group=group, environment_id__in=environment_ids)

        now = timezone.now()
        hourly_stats = tsdb.rollup(
            get_range(model=tsdb.models.group,
                      keys=[group.id],
                      end=now,
                      start=now - timedelta(days=1)),
            3600,
        )[group.id]
        daily_stats = tsdb.rollup(
            get_range(model=tsdb.models.group,
                      keys=[group.id],
                      end=now,
                      start=now - timedelta(days=30)),
            3600 * 24,
        )[group.id]

        participants = list(
            User.objects.filter(groupsubscription__is_active=True,
                                groupsubscription__group=group))

        data.update({
            "firstRelease":
            first_release,
            "lastRelease":
            last_release,
            "activity":
            serialize(activity, request.user),
            "seenBy":
            seen_by,
            "participants":
            serialize(participants, request.user),
            "pluginActions":
            action_list,
            "pluginIssues":
            self._get_available_issue_plugins(request, group),
            "pluginContexts":
            self._get_context_plugins(request, group),
            "userReportCount":
            user_reports.count(),
            "tags":
            sorted(serialize(tags, request.user), key=lambda x: x["name"]),
            "stats": {
                "24h": hourly_stats,
                "30d": daily_stats
            },
        })

        # the current release is the 'latest seen' release within the
        # environment even if it hasnt affected this issue
        if environments:
            try:
                current_release = GroupRelease.objects.filter(
                    group_id=group.id,
                    environment__in=[env.name for env in environments],
                    release_id=ReleaseEnvironment.objects.filter(
                        release_id__in=ReleaseProject.objects.filter(
                            project_id=group.project_id).values_list(
                                "release_id", flat=True),
                        organization_id=group.project.organization_id,
                        environment_id__in=environment_ids,
                    ).order_by("-first_seen").values_list("release_id",
                                                          flat=True)[:1],
                )[0]
            except IndexError:
                current_release = None

            data.update({
                "currentRelease":
                serialize(current_release, request.user,
                          GroupReleaseWithStatsSerializer())
            })

        return Response(data)