Exemple #1
0
    def test_combined_serializer(self):
        projects = [self.project, self.create_project()]
        alert_rule = self.create_alert_rule(projects=projects)
        issue_rule = self.create_issue_alert_rule(
            data={
                "project": self.project,
                "name": "Issue Rule Test",
                "conditions": [],
                "actions": [],
                "actionMatch": "all",
            })
        other_alert_rule = self.create_alert_rule()

        result = serialize([alert_rule, issue_rule, other_alert_rule],
                           serializer=CombinedRuleSerializer())

        self.assert_alert_rule_serialized(alert_rule, result[0])
        assert result[1]["id"] == str(issue_rule.id)
        self.assert_alert_rule_serialized(other_alert_rule, result[2])
    def get(self, request, organization):
        """
        Fetches alert rules and legacy rules for an organization
        """
        project_ids = self.get_requested_project_ids(request) or None
        if project_ids == {-1}:  # All projects for org:
            project_ids = Project.objects.filter(
                organization=organization).values_list("id", flat=True)
        elif project_ids is None:  # All projects for user
            org_team_list = Team.objects.filter(
                organization=organization).values_list("id", flat=True)
            user_team_list = OrganizationMemberTeam.objects.filter(
                organizationmember__user=request.user,
                team__in=org_team_list).values_list("team", flat=True)
            project_ids = Project.objects.filter(
                teams__in=user_team_list).values_list("id", flat=True)

        teams = set(request.GET.getlist("team", []))
        team_filter_query = None
        if teams:
            # do normal teams lookup based on request params
            verified_ids = set()
            unassigned = None
            if "unassigned" in teams:
                teams.remove("unassigned")
                unassigned = Q(owner_id=None)

            if "myteams" in teams:
                teams.remove("myteams")
                if is_active_superuser(request):
                    # retrieve all teams within the organization
                    myteams = Team.objects.filter(
                        organization=organization,
                        status=TeamStatus.VISIBLE).values_list("id", flat=True)
                    verified_ids.update(myteams)
                else:
                    myteams = [t.id for t in request.access.teams]
                    verified_ids.update(myteams)

            for team_id in teams:  # Verify each passed Team id is numeric
                if type(team_id) is not int and not team_id.isdigit():
                    return Response(f"Invalid Team ID: {team_id}",
                                    status=status.HTTP_400_BAD_REQUEST)
            teams.update(verified_ids)

            teams = Team.objects.filter(id__in=teams)
            for team in teams:
                if team.id in verified_ids:
                    continue

                if not request.access.has_team_access(team):
                    return Response(
                        f"Error: You do not have permission to access {team.name}",
                        status=status.HTTP_400_BAD_REQUEST,
                    )
            team_filter_query = Q(
                owner_id__in=teams.values_list("actor_id", flat=True))
            if unassigned:
                team_filter_query = team_filter_query | unassigned

        alert_rules = AlertRule.objects.fetch_for_organization(
            organization, project_ids)
        if not features.has("organizations:performance-view", organization):
            # Filter to only error alert rules
            alert_rules = alert_rules.filter(
                snuba_query__dataset=Dataset.Events.value)
        issue_rules = Rule.objects.filter(
            status__in=[RuleStatus.ACTIVE, RuleStatus.INACTIVE],
            project__in=project_ids)
        name = request.GET.get("name", None)
        if name:
            alert_rules = alert_rules.filter(Q(name__icontains=name))
            issue_rules = issue_rules.filter(Q(label__icontains=name))

        if team_filter_query:
            alert_rules = alert_rules.filter(team_filter_query)
            issue_rules = issue_rules.filter(team_filter_query)

        expand = request.GET.getlist("expand", [])
        if "latestIncident" in expand:
            alert_rules = alert_rules.annotate(incident_id=Coalesce(
                Subquery(
                    Incident.objects.filter(alert_rule=OuterRef(
                        "pk")).order_by("-date_started").values("id")[:1]),
                Value("-1"),
            ))

        is_asc = request.GET.get("asc", False) == "1"
        sort_key = request.GET.getlist("sort", ["date_added"])
        rule_sort_key = [
            "label" if x == "name" else x for x in sort_key
        ]  # Rule's don't share the same field name for their title/label/name...so we account for that here.
        case_insensitive = sort_key == ["name"]

        if "incident_status" in sort_key:
            alert_rules = alert_rules.annotate(incident_status=Coalesce(
                Subquery(
                    Incident.objects.filter(alert_rule=OuterRef(
                        "pk")).order_by("-date_started").values("status")[:1]),
                Value(-1, output_field=IntegerField()),
            ))
            issue_rules = issue_rules.annotate(
                incident_status=Value(-2, output_field=IntegerField()))

        if "date_triggered" in sort_key:
            far_past_date = Value(datetime.min, output_field=DateTimeField())
            alert_rules = alert_rules.annotate(date_triggered=Coalesce(
                Subquery(
                    Incident.objects.filter(alert_rule=OuterRef("pk")).
                    order_by("-date_started").values("date_started")[:1]),
                far_past_date,
            ), )
            issue_rules = issue_rules.annotate(date_triggered=far_past_date)
        alert_rule_intermediary = CombinedQuerysetIntermediary(
            alert_rules, sort_key)
        rule_intermediary = CombinedQuerysetIntermediary(
            issue_rules, rule_sort_key)
        return self.paginate(
            request,
            paginator_cls=CombinedQuerysetPaginator,
            on_results=lambda x: serialize(
                x, request.user, CombinedRuleSerializer(expand=expand)),
            default_per_page=25,
            intermediaries=[alert_rule_intermediary, rule_intermediary],
            desc=not is_asc,
            cursor_cls=StringCursor if case_insensitive else Cursor,
            case_insensitive=case_insensitive,
        )
    def get(self, request, organization):
        """
        Fetches alert rules and legacy rules for an organization
        """
        project_ids = self.get_requested_project_ids(request) or None
        if project_ids == {-1}:  # All projects for org:
            project_ids = Project.objects.filter(
                organization=organization).values_list("id", flat=True)
        elif project_ids is None:  # All projects for user
            org_team_list = Team.objects.filter(
                organization=organization).values_list("id", flat=True)
            user_team_list = OrganizationMemberTeam.objects.filter(
                organizationmember__user=request.user,
                team__in=org_team_list).values_list("team", flat=True)
            project_ids = Project.objects.filter(
                teams__in=user_team_list).values_list("id", flat=True)

        teams = request.GET.getlist("team", [])
        team_filter_query = None
        if len(teams) > 0:
            try:
                teams_query, unassigned = parse_team_params(
                    request, organization, teams)
            except InvalidParams as err:
                return Response(str(err), status=status.HTTP_400_BAD_REQUEST)

            team_filter_query = Q(
                owner_id__in=teams_query.values_list("actor_id", flat=True))
            if unassigned:
                team_filter_query = team_filter_query | Q(owner_id=None)

        alert_rules = AlertRule.objects.fetch_for_organization(
            organization, project_ids)
        if not features.has("organizations:performance-view", organization):
            # Filter to only error alert rules
            alert_rules = alert_rules.filter(
                snuba_query__dataset=Dataset.Events.value)
        issue_rules = Rule.objects.filter(
            status__in=[RuleStatus.ACTIVE, RuleStatus.INACTIVE],
            project__in=project_ids)
        name = request.GET.get("name", None)
        if name:
            alert_rules = alert_rules.filter(Q(name__icontains=name))
            issue_rules = issue_rules.filter(Q(label__icontains=name))

        if team_filter_query:
            alert_rules = alert_rules.filter(team_filter_query)
            issue_rules = issue_rules.filter(team_filter_query)

        expand = request.GET.getlist("expand", [])
        if "latestIncident" in expand:
            alert_rules = alert_rules.annotate(incident_id=Coalesce(
                Subquery(
                    Incident.objects.filter(alert_rule=OuterRef(
                        "pk")).order_by("-date_started").values("id")[:1]),
                Value("-1"),
            ))

        is_asc = request.GET.get("asc", False) == "1"
        sort_key = request.GET.getlist("sort", ["date_added"])
        rule_sort_key = [
            "label" if x == "name" else x for x in sort_key
        ]  # Rule's don't share the same field name for their title/label/name...so we account for that here.
        case_insensitive = sort_key == ["name"]

        if "incident_status" in sort_key:
            alert_rules = alert_rules.annotate(incident_status=Coalesce(
                Subquery(
                    Incident.objects.filter(alert_rule=OuterRef(
                        "pk")).order_by("-date_started").values("status")[:1]),
                Value(-1, output_field=IntegerField()),
            ))
            issue_rules = issue_rules.annotate(
                incident_status=Value(-2, output_field=IntegerField()))

        if "date_triggered" in sort_key:
            far_past_date = Value(datetime.min, output_field=DateTimeField())
            alert_rules = alert_rules.annotate(date_triggered=Coalesce(
                Subquery(
                    Incident.objects.filter(alert_rule=OuterRef("pk")).
                    order_by("-date_started").values("date_started")[:1]),
                far_past_date,
            ), )
            issue_rules = issue_rules.annotate(date_triggered=far_past_date)
        alert_rule_intermediary = CombinedQuerysetIntermediary(
            alert_rules, sort_key)
        rule_intermediary = CombinedQuerysetIntermediary(
            issue_rules, rule_sort_key)
        return self.paginate(
            request,
            paginator_cls=CombinedQuerysetPaginator,
            on_results=lambda x: serialize(
                x, request.user, CombinedRuleSerializer(expand=expand)),
            default_per_page=25,
            intermediaries=[alert_rule_intermediary, rule_intermediary],
            desc=not is_asc,
            cursor_cls=StringCursor if case_insensitive else Cursor,
            case_insensitive=case_insensitive,
        )