Skip to content

Commit 586a2cc

Browse files
committed
update logic for invalid ids and add tests
1 parent 2376a85 commit 586a2cc

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

src/sentry/core/endpoints/organization_details.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
from sentry.models.options.organization_option import OrganizationOption
9292
from sentry.models.options.project_option import ProjectOption
9393
from sentry.models.organization import Organization, OrganizationStatus
94+
from sentry.models.organizationmember import OrganizationMember
9495
from sentry.models.organizationmemberreplayaccess import OrganizationMemberReplayAccess
9596
from sentry.models.project import Project
9697
from sentry.organizations.services.organization import organization_service
@@ -608,6 +609,19 @@ def save(self, **kwargs):
608609
to_remove = current_member_ids - new_member_ids
609610

610611
if to_add:
612+
valid_member_ids = set(
613+
OrganizationMember.objects.filter(
614+
organization=org, id__in=to_add
615+
).values_list("id", flat=True)
616+
)
617+
invalid_member_ids = to_add - valid_member_ids
618+
if invalid_member_ids:
619+
raise serializers.ValidationError(
620+
{
621+
"replayAccessMembers": f"Invalid organization member IDs: {sorted(invalid_member_ids)}"
622+
}
623+
)
624+
611625
OrganizationMemberReplayAccess.objects.bulk_create(
612626
[
613627
OrganizationMemberReplayAccess(

tests/sentry/core/endpoints/test_organization_details.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,6 +1673,42 @@ def test_replay_access_members_requires_admin_scope(self) -> None:
16731673
data = {"replayAccessMembers": [other_member.id]}
16741674
self.get_error_response(self.organization.slug, **data, status_code=403)
16751675

1676+
@with_feature("organizations:granular-replay-permissions")
1677+
def test_replay_access_members_invalid_member_ids(self) -> None:
1678+
nonexistent_id = 999999999
1679+
data = {"replayAccessMembers": [nonexistent_id]}
1680+
response = self.get_error_response(self.organization.slug, **data, status_code=400)
1681+
assert "replayAccessMembers" in response.data
1682+
assert str(nonexistent_id) in response.data["replayAccessMembers"]
1683+
1684+
@with_feature("organizations:granular-replay-permissions")
1685+
def test_replay_access_members_from_other_organization(self) -> None:
1686+
other_org = self.create_organization(owner=self.create_user())
1687+
other_org_member = self.create_member(
1688+
organization=other_org, user=self.create_user(), role="member"
1689+
)
1690+
data = {"replayAccessMembers": [other_org_member.id]}
1691+
response = self.get_error_response(self.organization.slug, **data, status_code=400)
1692+
assert "replayAccessMembers" in response.data
1693+
assert str(other_org_member.id) in response.data["replayAccessMembers"]
1694+
1695+
@with_feature("organizations:granular-replay-permissions")
1696+
def test_replay_access_members_mixed_valid_and_invalid(self) -> None:
1697+
valid_member = self.create_member(
1698+
organization=self.organization, user=self.create_user(), role="member"
1699+
)
1700+
nonexistent_id = 999999999
1701+
data = {"replayAccessMembers": [valid_member.id, nonexistent_id]}
1702+
response = self.get_error_response(self.organization.slug, **data, status_code=400)
1703+
assert "replayAccessMembers" in response.data
1704+
assert str(nonexistent_id) in response.data["replayAccessMembers"]
1705+
assert str(valid_member.id) not in response.data["replayAccessMembers"]
1706+
1707+
access_count = OrganizationMemberReplayAccess.objects.filter(
1708+
organization=self.organization
1709+
).count()
1710+
assert access_count == 0
1711+
16761712

16771713
class OrganizationDeleteTest(OrganizationDetailsTestBase):
16781714
method = "delete"

0 commit comments

Comments
 (0)