Example #1
0
    def test_team_actors_to_user_ids(self):
        team1 = self.create_team()
        team2 = self.create_team()
        team3 = self.create_team()  # team with no active members
        users = [self.create_user() for i in range(0, 8)]

        self.create_member(user=users[0], organization=self.organization, teams=[team1])
        self.create_member(user=users[1], organization=self.organization, teams=[team1])
        self.create_member(user=users[2], organization=self.organization, teams=[team1])
        self.create_member(user=users[3], organization=self.organization, teams=[team1, team2])
        self.create_member(user=users[4], organization=self.organization, teams=[team2, self.team])
        self.create_member(user=users[5], organization=self.organization, teams=[team2])

        # Inactive member
        member6 = self.create_member(
            user=users[6], organization=self.organization, teams=[team2, team3]
        )
        team_member6 = OrganizationMemberTeam.objects.filter(organizationmember_id=member6.id)
        for team_member in team_member6:
            team_member.update(is_active=False)
        # Member without teams
        self.create_member(user=users[7], organization=self.organization, teams=[])

        team_actors = [
            ActorTuple(team1.id, Team),
            ActorTuple(team2.id, Team),
            ActorTuple(team3.id, Team),
        ]
        user_ids = [user.id for user in users]

        assert team_actors_to_user_ids(team_actors, user_ids) == {
            team1.id: {users[0].id, users[1].id, users[2].id, users[3].id},
            team2.id: {users[3].id, users[4].id, users[5].id},
        }
Example #2
0
    def test_get_owners_when_codeowners_and_issueowners_exists(self):
        self.team = self.create_team(
            organization=self.organization, slug="tiger-team", members=[self.user]
        )
        self.team2 = self.create_team(
            organization=self.organization, slug="dolphin-team", members=[self.user]
        )
        self.project = self.create_project(
            organization=self.organization, teams=[self.team, self.team2]
        )
        self.code_mapping = self.create_code_mapping(project=self.project)

        rule_a = Rule(Matcher("path", "*.py"), [Owner("team", self.team.slug)])
        rule_b = Rule(Matcher("path", "src/*"), [Owner("user", self.user.email)])
        rule_c = Rule(Matcher("path", "*.py"), [Owner("team", self.team2.slug)])

        ProjectOwnership.objects.create(
            project_id=self.project.id, schema=dump_schema([rule_a, rule_b]), fallthrough=True
        )

        self.create_codeowners(
            self.project, self.code_mapping, raw="*.py @tiger-team", schema=dump_schema([rule_c])
        )

        self.assert_ownership_equals(
            ProjectOwnership.get_owners(
                self.project.id, {"stacktrace": {"frames": [{"filename": "api/foo.py"}]}}
            ),
            (
                [ActorTuple(self.team.id, Team), ActorTuple(self.team2.id, Team)],
                [rule_a, rule_c],
            ),
        )
 def test_basic(self):
     owners = [
         Owner("user", self.user.email),
         Owner("team", self.team.slug)
     ]
     assert resolve_actors(owners, self.project.id) == {
         owners[0]: ActorTuple(self.user.id, User),
         owners[1]: ActorTuple(self.team.id, Team),
     }
Example #4
0
    def test_build_events_by_actor(self):
        events = self.team1_events + self.team2_events + self.user4_events

        events_by_actor = {
            ActorTuple(self.team1.id, Team): set(self.team1_events),
            ActorTuple(self.team2.id, Team): set(self.team2_events),
            ActorTuple(self.user3.id, User): set(self.team1_events),
            ActorTuple(self.user4.id, User): set(self.user4_events),
        }
        assert build_events_by_actor(self.project.id, events, self.user_ids) == events_by_actor
Example #5
0
    def test_users(self):
        actor = ActorTuple(self.user.id, User)
        result = extract_user_ids_from_mentions(self.organization.id, [actor])
        assert result["users"] == {self.user.id}
        assert result["team_users"] == set()

        other_user = self.create_user()
        result = extract_user_ids_from_mentions(
            self.organization.id,
            [actor, ActorTuple(other_user.id, User)])
        assert result["users"] == {self.user.id, other_user.id}
        assert result["team_users"] == set()
Example #6
0
    def test_convert_actors_to_user_set(self):
        user1 = self.create_user()
        user2 = self.create_user()
        user3 = self.create_user()
        user4 = self.create_user()

        team1 = self.create_team()
        team2 = self.create_team()

        self.create_member(user=user1,
                           organization=self.organization,
                           teams=[team1])
        self.create_member(user=user2,
                           organization=self.organization,
                           teams=[team2])
        self.create_member(user=user3,
                           organization=self.organization,
                           teams=[team1, team2])
        self.create_member(user=user4,
                           organization=self.organization,
                           teams=[])

        team1_events = {
            self.create_event(self.project.id),
            self.create_event(self.project.id),
            self.create_event(self.project.id),
            self.create_event(self.project.id),
        }
        team2_events = {
            self.create_event(self.project.id),
            self.create_event(self.project.id),
            self.create_event(self.project.id),
            self.create_event(self.project.id),
        }
        user4_events = {
            self.create_event(self.project.id),
            self.create_event(self.project.id)
        }
        events_by_actor = {
            ActorTuple(team1.id, Team): team1_events,
            ActorTuple(team2.id, Team): team2_events,
            ActorTuple(user3.id, User): team1_events.union(team2_events),
            ActorTuple(user4.id, User): user4_events,
        }
        user_by_events = {
            user1.id: team1_events,
            user2.id: team2_events,
            user3.id: team1_events.union(team2_events),
            user4.id: user4_events,
        }
        assert convert_actors_to_users(events_by_actor,
                                       user_by_events.keys()) == user_by_events
Example #7
0
def resolve_actors(owners, project_id):
    """Convert a list of Owner objects into a dictionary
    of {Owner: Actor} pairs. Actors not identified are returned
    as None."""
    from sentry.models import ActorTuple
    from sentry.models import User, Team

    if not owners:
        return {}

    users, teams = [], []
    owners_lookup = {}

    for owner in owners:
        # teams aren't technical case insensitive, but teams also
        # aren't allowed to have non-lowercase in slugs, so
        # this kinda works itself out correctly since they won't match
        owners_lookup[(owner.type, owner.identifier.lower())] = owner
        if owner.type == "user":
            users.append(owner)
        elif owner.type == "team":
            teams.append(owner)

    actors = {}
    if users:
        actors.update(
            {
                ("user", email.lower()): ActorTuple(u_id, User)
                for u_id, email in User.objects.filter(
                    reduce(operator.or_, [Q(emails__email__iexact=o.identifier) for o in users]),
                    # We don't require verified emails
                    # emails__is_verified=True,
                    is_active=True,
                    sentry_orgmember_set__organizationmemberteam__team__projectteam__project_id=project_id,
                )
                .distinct()
                .values_list("id", "emails__email")
            }
        )

    if teams:
        actors.update(
            {
                ("team", slug): ActorTuple(t_id, Team)
                for t_id, slug in Team.objects.filter(
                    slug__in=[o.identifier for o in teams], projectteam__project_id=project_id
                ).values_list("id", "slug")
            }
        )

    return {o: actors.get((o.type, o.identifier.lower())) for o in owners}
    def test_get_owners_when_codeowners_exists_and_no_issueowners(self):
        # This case will never exist bc we create a ProjectOwnership record if none exists when creating a ProjectCodeOwner record.
        # We have this testcase for potential corrupt data.
        self.team = self.create_team(organization=self.organization,
                                     slug="tiger-team",
                                     members=[self.user])
        self.code_mapping = self.create_code_mapping(project=self.project)

        rule_a = Rule(Matcher("path", "*.js"), [Owner("team", self.team.slug)])

        self.create_codeowners(
            self.project,
            self.code_mapping,
            raw="*.js @tiger-team",
            schema=dump_schema([rule_a]),
        )
        self.assert_ownership_equals(
            ProjectOwnership.get_owners(
                self.project.id,
                {"stacktrace": {
                    "frames": [{
                        "filename": "src/foo.js"
                    }]
                }}),
            (
                [ActorTuple(self.team.id, Team)],
                [rule_a],
            ),
        )
Example #9
0
def get_owners(
    project: Project, event: Optional["Event"] = None
) -> Iterable[Union["Team", "User"]]:
    """Given a project and an event, decide which users and teams are the owners."""

    if event:
        owners, _ = ProjectOwnership.get_owners(project.id, event.data)
    else:
        owners = ProjectOwnership.Everyone

    if not owners:
        outcome = "empty"
        recipients = set()

    elif owners == ProjectOwnership.Everyone:
        outcome = "everyone"
        recipients = User.objects.filter(id__in=project.member_set.values_list("user", flat=True))

    else:
        outcome = "match"
        recipients = ActorTuple.resolve_many(owners)

    metrics.incr(
        "features.owners.send_to",
        tags={"organization": project.organization_id, "outcome": outcome},
        skip_internal=True,
    )
    return recipients
Example #10
0
    def to_internal_value(self, data):
        if not data:
            return None

        try:
            actor = ActorTuple.from_actor_identifier(data)
        except Exception:
            raise serializers.ValidationError(
                "Could not parse actor. Format should be `type:id` where type is `team` or `user`."
            )
        try:
            obj = actor.resolve()
        except (Team.DoesNotExist, User.DoesNotExist):
            raise serializers.ValidationError(
                f"{actor.type.__name__} does not exist")

        if actor.type == Team:
            if obj.organization != self.context["organization"]:
                raise serializers.ValidationError(
                    "Team is not a member of this organization")
        elif actor.type == User:
            if not OrganizationMember.objects.filter(
                    organization=self.context["organization"],
                    user=obj).exists():
                raise serializers.ValidationError(
                    "User is not a member of this organization")
        return actor
Example #11
0
    def test_teams(self):
        member_user = self.create_user()
        self.create_member(user=member_user,
                           organization=self.organization,
                           role="member",
                           teams=[self.team])
        actor = ActorTuple(self.team.id, Team)
        result = extract_user_ids_from_mentions(self.organization.id, [actor])
        assert result["users"] == set()
        assert result["team_users"] == {self.user.id, member_user.id}

        # Explicitly mentioned users shouldn't be included in team_users
        result = extract_user_ids_from_mentions(
            self.organization.id, [ActorTuple(member_user.id, User), actor])
        assert result["users"] == {member_user.id}
        assert result["team_users"] == {self.user.id}
Example #12
0
    def get_autoassign_owners(cls, project_id, data, limit=2):
        """
        Get the auto-assign owner for a project if there are any.

        Returns a tuple of (auto_assignment_enabled, list_of_owners).
        """
        with metrics.timer("projectownership.get_autoassign_owners"):
            ownership = cls.get_ownership_cached(project_id)
            if not ownership:
                return False, []

            rules = cls._matching_ownership_rules(ownership, project_id, data)
            if not rules:
                return ownership.auto_assignment, []

            # We want the last matching rule to take the most precedence.
            owners = [owner for rule in rules for owner in rule.owners]
            owners.reverse()
            actors = {
                key: val
                for key, val in resolve_actors({owner
                                                for owner in owners},
                                               project_id).items() if val
            }
            actors = [actors[owner] for owner in owners
                      if owner in actors][:limit]

            # Can happen if the ownership rule references a user/team that no longer
            # is assigned to the project or has been removed from the org.
            if not actors:
                return ownership.auto_assignment, []

            from sentry.models import ActorTuple

            return ownership.auto_assignment, ActorTuple.resolve_many(actors)
Example #13
0
    def to_internal_value(self, data):
        if not data:
            return None

        try:
            return ActorTuple.from_actor_identifier(data)
        except Exception:
            raise serializers.ValidationError("Unknown actor input")
Example #14
0
    def get_autoassign_owners(cls, project_id, data, limit=2):
        """
        Get the auto-assign owner for a project if there are any.

        We combine the schemas from IssueOwners and CodeOwners.

        Returns a tuple of (auto_assignment_enabled, list_of_owners, assigned_by_codeowners: boolean).
        """
        from sentry.models import ProjectCodeOwners

        with metrics.timer("projectownership.get_autoassign_owners"):
            ownership = cls.get_ownership_cached(project_id)
            codeowners = ProjectCodeOwners.get_codeowners_cached(project_id)
            assigned_by_codeowners = False
            if not (ownership or codeowners):
                return False, [], assigned_by_codeowners

            if not ownership:
                ownership = cls(project_id=project_id)

            ownership_rules = cls._matching_ownership_rules(
                ownership, project_id, data)
            codeowners_rules = (cls._matching_ownership_rules(
                codeowners, project_id, data) if codeowners else [])

            if not (codeowners_rules or ownership_rules):
                return ownership.auto_assignment, [], assigned_by_codeowners

            ownership_actors = cls._find_actors(project_id, ownership_rules,
                                                limit)
            codeowners_actors = cls._find_actors(project_id, codeowners_rules,
                                                 limit)

            # Can happen if the ownership rule references a user/team that no longer
            # is assigned to the project or has been removed from the org.
            if not (ownership_actors or codeowners_actors):
                return ownership.auto_assignment, [], assigned_by_codeowners

            # Ownership rules take precedence over codeowner rules.
            actors = [*ownership_actors, *codeowners_actors][:limit]

            # Only the first item in the list is used for assignment, the rest are just used to suggest suspect owners.
            # So if ownership_actors is empty, it will be assigned by codeowners_actors
            if len(ownership_actors) == 0:
                assigned_by_codeowners = True

            from sentry.models import ActorTuple

            return (
                ownership.auto_assignment,
                ActorTuple.resolve_many(actors),
                assigned_by_codeowners,
            )
Example #15
0
 def validate_owner(self, owner):
     # owner should be team:id or user:id
     try:
         actor = ActorTuple.from_actor_identifier(owner)
     except serializers.ValidationError:
         raise serializers.ValidationError(
             "Could not parse owner. Format should be `type:id` where type is `team` or `user`."
         )
     try:
         if actor.resolve():
             return actor
     except (User.DoesNotExist, Team.DoesNotExist):
         raise serializers.ValidationError(
             "Could not resolve owner to existing team or user.")
 def test_abs_path_when_filename_present(self):
     frame = {
         "filename": "computer.cpp",
         "abs_path": "C:\\My\\Path\\computer.cpp",
     }
     rule = Rule(Matcher("path", "*My\\Path*"),
                 [Owner("team", self.team.slug)])
     ProjectOwnership.objects.create(project_id=self.project.id,
                                     schema=dump_schema([rule]),
                                     fallthrough=True)
     assert ProjectOwnership.get_owners(
         self.project.id, {"stacktrace": {
             "frames": [frame]
         }}) == ([ActorTuple(self.team.id, Team)], [rule])
def self_subscribe_and_assign_issue(acting_user, group):
    # Used during issue resolution to assign to acting user
    # returns None if the user didn't elect to self assign on resolution
    # or the group is assigned already, otherwise returns Actor
    # representation of current user
    if acting_user:
        GroupSubscription.objects.subscribe(
            user=acting_user,
            group=group,
            reason=GroupSubscriptionReason.status_change)
        self_assign_issue = UserOption.objects.get_value(
            user=acting_user, key="self_assign_issue", default="0")
        if self_assign_issue == "1" and not group.assignee_set.exists():
            return ActorTuple(type=User, id=acting_user.id)
Example #18
0
    def test_transfer_to_organization_alert_rules(self):
        from_org = self.create_organization()
        from_user = self.create_user()
        self.create_member(user=from_user,
                           role="member",
                           organization=from_org)
        team = self.create_team(organization=from_org)
        to_org = self.create_organization()
        to_team = self.create_team(organization=to_org)
        to_user = self.create_user()
        self.create_member(user=to_user, role="member", organization=to_org)

        project = self.create_project(teams=[team])

        # should lose their owners
        alert_rule = self.create_alert_rule(
            organization=self.organization,
            projects=[project],
            owner=ActorTuple.from_actor_identifier(f"team:{team.id}"),
        )
        rule1 = Rule.objects.create(label="another test rule",
                                    project=project,
                                    owner=team.actor)
        rule2 = Rule.objects.create(label="rule4",
                                    project=project,
                                    owner=from_user.actor)

        # should keep their owners
        rule3 = Rule.objects.create(label="rule2",
                                    project=project,
                                    owner=to_team.actor)
        rule4 = Rule.objects.create(label="rule3",
                                    project=project,
                                    owner=to_user.actor)

        project.transfer_to(organization=to_org)

        alert_rule.refresh_from_db()
        rule1.refresh_from_db()
        rule2.refresh_from_db()
        rule3.refresh_from_db()
        rule4.refresh_from_db()
        assert alert_rule.organization_id == to_org.id
        assert alert_rule.owner is None
        assert rule1.owner is None
        assert rule2.owner is None

        assert rule3.owner is not None
        assert rule4.owner is not None
Example #19
0
def build_events_by_actor(project_id, events, user_ids):
    """
    build_events_by_actor(project_id: Int, events: Set(Events), user_ids: Set[Int]) -> Map[Actor, Set(Events)]
    """
    events_by_actor = defaultdict(set)
    for event in events:
        # TODO(LB): I Know this is inefficient.
        # ProjectOwnership.get_owners is O(n) queries and I'm doing that O(len(events)) times
        # I will create a follow-up PR to address this method's efficiency problem
        # Just wanted to make as few changes as possible for now.
        actors, __ = ProjectOwnership.get_owners(project_id, event.data)
        if actors == ProjectOwnership.Everyone:
            actors = [ActorTuple(user_id, User) for user_id in user_ids]
        for actor in actors:
            events_by_actor[actor].add(event)
    return events_by_actor
Example #20
0
    def test_get_owners_basic(self):
        rule_a = Rule(Matcher("path", "*.py"), [Owner("team", self.team.slug)])
        rule_b = Rule(Matcher("path", "src/*"), [Owner("user", self.user.email)])

        ProjectOwnership.objects.create(
            project_id=self.project.id, schema=dump_schema([rule_a, rule_b]), fallthrough=True
        )

        # No data matches
        assert ProjectOwnership.get_owners(self.project.id, {}) == (ProjectOwnership.Everyone, None)

        # Match only rule_a
        self.assert_ownership_equals(
            ProjectOwnership.get_owners(
                self.project.id, {"stacktrace": {"frames": [{"filename": "foo.py"}]}}
            ),
            ([ActorTuple(self.team.id, Team)], [rule_a]),
        )

        # Match only rule_b
        self.assert_ownership_equals(
            ProjectOwnership.get_owners(
                self.project.id, {"stacktrace": {"frames": [{"filename": "src/thing.txt"}]}}
            ),
            ([ActorTuple(self.user.id, User)], [rule_b]),
        )

        # Matches both rule_a and rule_b
        self.assert_ownership_equals(
            ProjectOwnership.get_owners(
                self.project.id, {"stacktrace": {"frames": [{"filename": "src/foo.py"}]}}
            ),
            ([ActorTuple(self.team.id, Team), ActorTuple(self.user.id, User)], [rule_a, rule_b]),
        )

        assert ProjectOwnership.get_owners(
            self.project.id, {"stacktrace": {"frames": [{"filename": "xxxx"}]}}
        ) == (ProjectOwnership.Everyone, None)

        # When fallthrough = False, we don't implicitly assign to Everyone
        owner = ProjectOwnership.objects.get(project_id=self.project.id)
        owner.fallthrough = False
        owner.save()

        assert ProjectOwnership.get_owners(
            self.project.id, {"stacktrace": {"frames": [{"filename": "xxxx"}]}}
        ) == ([], None)

        self.assert_ownership_equals(
            ProjectOwnership.get_owners(
                self.project.id, {"stacktrace": {"frames": [{"filename": "src/foo.py"}]}}
            ),
            ([ActorTuple(self.team.id, Team), ActorTuple(self.user.id, User)], [rule_a, rule_b]),
        )
Example #21
0
def build_events_by_actor(
        project_id: int, events: Iterable[Event],
        user_ids: Iterable[int]) -> Mapping[ActorTuple, Iterable[Event]]:
    """
    TODO(mgaeta): I know this is inefficient. ProjectOwnership.get_owners
     is O(n) queries and I'm doing that O(len(events)) times. I "will"
     create a follow-up PR to address this method's efficiency problem.
     Just wanted to make as few changes as possible for now.
    """
    events_by_actor: MutableMapping[ActorTuple, Set[Event]] = defaultdict(set)
    for event in events:
        actors, __ = ProjectOwnership.get_owners(project_id, event.data)
        if actors == ProjectOwnership.Everyone:
            actors = [ActorTuple(user_id, User) for user_id in user_ids]
        for actor in actors:
            events_by_actor[actor].add(event)
    return events_by_actor
Example #22
0
    def test_teams(self):
        # Normal team
        owner1 = Owner("team", self.team.slug)
        actor1 = ActorTuple(self.team.id, Team)

        # Team that doesn't exist
        owner2 = Owner("team", "nope")
        actor2 = None

        # A team that's not ours
        otherteam = Team.objects.exclude(projectteam__project_id=self.project.id)[0]
        owner3 = Owner("team", otherteam.slug)
        actor3 = None

        assert resolve_actors([owner1, owner2, owner3], self.project.id) == {
            owner1: actor1,
            owner2: actor2,
            owner3: actor3,
        }
Example #23
0
    def test_users(self):
        # Normal user
        owner1 = Owner("user", self.user.email)
        actor1 = ActorTuple(self.user.id, User)

        # An extra secondary email
        email1 = self.create_useremail(self.user, None, is_verified=True).email
        owner2 = Owner("user", email1)
        actor2 = actor1  # They map to the same user since it's just a secondary email

        # Another secondary email, that isn't verified
        email2 = self.create_useremail(self.user, None,
                                       is_verified=False).email
        owner3 = Owner("user", email2)
        # Intentionally allow unverified emails
        # actor3 = None
        actor3 = actor1

        # An entirely unknown user
        owner4 = Owner("user", "nope")
        actor4 = None

        # A user that doesn't belong with us
        otheruser = self.create_user()
        owner5 = Owner("user", otheruser.email)
        actor5 = None

        # Case-insensitive for user
        owner6 = Owner("user", self.user.email.upper())
        actor6 = actor1

        assert resolve_actors([owner1, owner2, owner3, owner4, owner5, owner6],
                              self.project.id) == {
                                  owner1: actor1,
                                  owner2: actor2,
                                  owner3: actor3,
                                  owner4: actor4,
                                  owner5: actor5,
                                  owner6: actor6,
                              }
Example #24
0
def get_owners(project: Project,
               event: Event | None = None) -> Sequence[Team | User]:
    """
    Given a project and an event, decide which users and teams are the owners.

    If when checking owners, there is a rule match we only notify the last owner
    (would-be auto-assignee) unless the organization passes the feature-flag
    """

    if event:
        owners, _ = ProjectOwnership.get_owners(project.id, event.data)
    else:
        owners = ProjectOwnership.Everyone

    if not owners:
        outcome = "empty"
        recipients = list()

    elif owners == ProjectOwnership.Everyone:
        outcome = "everyone"
        recipients = User.objects.filter(
            id__in=project.member_set.values_list("user", flat=True))

    else:
        outcome = "match"
        recipients = ActorTuple.resolve_many(owners)
        # Used to suppress extra notifications to all matched owners, only notify the would-be auto-assignee
        if not features.has("organizations:notification-all-recipients",
                            project.organization):
            recipients = recipients[-1:]

    metrics.incr(
        "features.owners.send_to",
        tags={
            "organization": project.organization_id,
            "outcome": outcome
        },
        skip_internal=True,
    )
    return recipients
Example #25
0
def build_assigned_text(identity: Identity, assignee: str):
    actor = ActorTuple.from_actor_identifier(assignee)

    try:
        assigned_actor = actor.resolve()
    except actor.type.DoesNotExist:
        return

    if actor.type == Team:
        assignee_text = f"#{assigned_actor.slug}"
    elif actor.type == User:
        try:
            assignee_ident = Identity.objects.get(
                user=assigned_actor, idp__type="slack", idp__external_id=identity.idp.external_id
            )
            assignee_text = f"<@{assignee_ident.external_id}>"
        except Identity.DoesNotExist:
            assignee_text = assigned_actor.get_display_name()
    else:
        raise NotImplementedError

    return f"*Issue assigned to {assignee_text} by <@{identity.external_id}>*"
Example #26
0
    def get(self, request: Request, project, event_id) -> Response:
        """
        Retrieve suggested owners information for an event
        ``````````````````````````````````````````````````

        :pparam string project_slug: the slug of the project the event
                                     belongs to.
        :pparam string event_id: the id of the event.
        :auth: required
        """
        event = eventstore.get_event_by_id(project.id, event_id)
        if event is None:
            return Response({"detail": "Event not found"}, status=404)

        owners, rules = ProjectOwnership.get_owners(project.id, event.data)

        # For sake of the API, we don't differentiate between
        # the implicit "everyone" and no owners
        if owners == ProjectOwnership.Everyone:
            owners = []

        serialized_owners = serialize(ActorTuple.resolve_many(owners),
                                      request.user, ActorSerializer())

        # Make sure the serialized owners are in the correct order
        ordered_owners = []
        owner_by_id = {(o["id"], o["type"]): o for o in serialized_owners}
        for o in owners:
            key = (str(o.id), "team" if o.type == Team else "user")
            if owner_by_id.get(key):
                ordered_owners.append(owner_by_id[key])

        return Response({
            "owners": ordered_owners,
            # TODO(mattrobenolt): We need to change the API here to return
            # all rules, just keeping this way currently for API compat
            "rule": rules[0].matcher if rules else None,
            "rules": rules or [],
        })
Example #27
0
def extract_user_ids_from_mentions(organization_id, mentions):
    """
    Extracts user ids from a set of mentions. Mentions should be a list of
    `ActorTuple` instances. Returns a dictionary with 'users' and 'team_users' keys.
    'users' is the user ids for all explicitly mentioned users, and 'team_users'
    is all user ids from explicitly mentioned teams, excluding any already
    mentioned users.
    """
    actors = ActorTuple.resolve_many(mentions)
    actor_mentions = separate_resolved_actors(actors)

    mentioned_team_users = list(
        User.objects.get_from_teams(
            organization_id, actor_mentions["teams"]).exclude(
                id__in={u.id
                        for u in actor_mentions["users"]}).values_list(
                            "id", flat=True))

    return {
        "users": {user.id
                  for user in actor_mentions["users"]},
        "team_users": set(mentioned_team_users),
    }
Example #28
0
    def assigned_actor(self):
        from sentry.models import ActorTuple

        return ActorTuple.from_actor_identifier(self.assigned_actor_id())
Example #29
0
    def owner(self):
        from sentry.models import ActorTuple

        return ActorTuple.from_actor_identifier(self.owner_id())
    def test_simple(self):
        project1 = self.create_project(
            teams=[self.team], slug="foo"
        )  # This project will return counts for this team
        user_owned_rule = self.create_alert_rule(
            organization=self.organization,
            projects=[project1],
            name="user owned rule",
            query="",
            aggregate="count()",
            time_window=1,
            threshold_type=AlertRuleThresholdType.ABOVE,
            resolve_threshold=10,
            threshold_period=1,
            owner=ActorTuple.from_actor_identifier(self.user.id),
        )
        user_owned_incident = self.create_incident(status=20, alert_rule=user_owned_rule)
        activities = []
        for i in range(1, 9):
            activities.append(
                IncidentActivity(
                    incident=user_owned_incident,
                    type=IncidentActivityType.CREATED.value,
                    value=IncidentStatus.OPEN,
                    date_added=before_now(days=i),
                )
            )
        IncidentActivity.objects.bulk_create(activities)

        self.login_as(user=self.user)
        response = self.get_success_response(self.team.organization.slug, self.team.slug)
        assert len(response.data) == 90
        for i in range(1, 9):
            assert (
                response.data[
                    str(
                        before_now(days=i)
                        .replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
                        .isoformat()
                    )
                ]
                == 1
            )

        for i in range(10, 90):
            assert (
                response.data[
                    str(
                        before_now(days=i)
                        .replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
                        .isoformat()
                    )
                ]
                == 0
            )

        response = self.get_success_response(
            self.team.organization.slug, self.team.slug, statsPeriod="7d"
        )
        assert len(response.data) == 7
        assert (
            response.data[
                str(
                    before_now(days=0)
                    .replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
                    .isoformat()
                )
            ]
            == 0
        )
        for i in range(1, 6):
            assert (
                response.data[
                    str(
                        before_now(days=i)
                        .replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
                        .isoformat()
                    )
                ]
                == 1
            )