Skip to content

Commit eb8f3df

Browse files
committed
remove organization, move model to replays
1 parent 71f39ae commit eb8f3df

File tree

9 files changed

+55
-86
lines changed

9 files changed

+55
-86
lines changed

src/sentry/api/serializers/models/organization.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@
7676
from sentry.models.options.project_option import ProjectOption
7777
from sentry.models.organization import Organization, OrganizationStatus
7878
from sentry.models.organizationaccessrequest import OrganizationAccessRequest
79-
from sentry.models.organizationmemberreplayaccess import OrganizationMemberReplayAccess
8079
from sentry.models.organizationonboardingtask import OrganizationOnboardingTask
8180
from sentry.models.project import Project
8281
from sentry.models.team import Team, TeamStatus
8382
from sentry.organizations.absolute_url import generate_organization_url
8483
from sentry.organizations.services.organization import RpcOrganizationSummary
84+
from sentry.replays.models import OrganizationMemberReplayAccess
8585
from sentry.users.models.user import User
8686
from sentry.users.services.user.model import RpcUser
8787
from sentry.users.services.user.service import user_service
@@ -765,9 +765,9 @@ def serialize( # type: ignore[override]
765765
)
766766
context["hasGranularReplayPermissions"] = bool(permissions_enabled)
767767
context["replayAccessMembers"] = list(
768-
OrganizationMemberReplayAccess.objects.filter(organization=obj).values_list(
769-
"organizationmember_id", flat=True
770-
)
768+
OrganizationMemberReplayAccess.objects.filter(
769+
organizationmember__organization=obj
770+
).values_list("organizationmember_id", flat=True)
771771
)
772772

773773
if has_custom_dynamic_sampling(obj, actor=user):

src/sentry/core/endpoints/organization_details.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@
9797
from sentry.models.options.project_option import ProjectOption
9898
from sentry.models.organization import Organization, OrganizationStatus
9999
from sentry.models.organizationmember import OrganizationMember
100-
from sentry.models.organizationmemberreplayaccess import OrganizationMemberReplayAccess
101100
from sentry.models.project import Project
102101
from sentry.organizations.services.organization import organization_service
103102
from sentry.organizations.services.organization.model import (
@@ -106,6 +105,7 @@
106105
RpcOrganizationDeleteState,
107106
)
108107
from sentry.relay.datascrubbing import validate_pii_config_update, validate_pii_selectors
108+
from sentry.replays.models import OrganizationMemberReplayAccess
109109
from sentry.seer.autofix.constants import AutofixAutomationTuningSettings
110110
from sentry.services.organization.provisioning import (
111111
OrganizationSlugCollisionException,
@@ -633,9 +633,9 @@ def save(self, **kwargs):
633633
if member_ids is None:
634634
member_ids = []
635635
current_member_ids = set(
636-
OrganizationMemberReplayAccess.objects.filter(organization=org).values_list(
637-
"organizationmember_id", flat=True
638-
)
636+
OrganizationMemberReplayAccess.objects.filter(
637+
organizationmember__organization=org
638+
).values_list("organizationmember_id", flat=True)
639639
)
640640
new_member_ids = set(member_ids)
641641

@@ -657,17 +657,15 @@ def save(self, **kwargs):
657657

658658
OrganizationMemberReplayAccess.objects.bulk_create(
659659
[
660-
OrganizationMemberReplayAccess(
661-
organization=org, organizationmember_id=member_id
662-
)
660+
OrganizationMemberReplayAccess(organizationmember_id=member_id)
663661
for member_id in to_add
664662
],
665663
ignore_conflicts=True,
666664
)
667665

668666
if to_remove:
669667
OrganizationMemberReplayAccess.objects.filter(
670-
organization=org, organizationmember_id__in=to_remove
668+
organizationmember__organization=org, organizationmember_id__in=to_remove
671669
).delete()
672670

673671
if to_add or to_remove:

src/sentry/models/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@
7474
from .organizationmember import * # NOQA
7575
from .organizationmemberinvite import * # NOQA
7676
from .organizationmembermapping import * # NOQA
77-
from .organizationmemberreplayaccess import * # NOQA
7877
from .organizationmemberteam import * # NOQA
7978
from .organizationmemberteamreplica import * # NOQA
8079
from .organizationonboardingtask import * # NOQA

src/sentry/models/organizationmemberreplayaccess.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/sentry/migrations/1012_organizationmember_replay_access.py renamed to src/sentry/replays/migrations/0007_organizationmember_replay_access.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Generated by Django 5.2.8 on 2025-12-02 12:31
22

33
import django.db.models.deletion
4-
import django.utils.timezone
54
from django.db import migrations, models
65

76
import sentry.db.models.fields.bounded
@@ -25,7 +24,7 @@ class Migration(CheckedMigration):
2524
is_post_deployment = False
2625

2726
dependencies = [
28-
("sentry", "1011_update_oc_integration_cascade_to_null"),
27+
("replays", "0006_add_bulk_delete_job"),
2928
]
3029

3130
operations = [
@@ -38,27 +37,20 @@ class Migration(CheckedMigration):
3837
primary_key=True, serialize=False
3938
),
4039
),
41-
("date_added", models.DateTimeField(default=django.utils.timezone.now)),
42-
(
43-
"organization",
44-
sentry.db.models.fields.foreignkey.FlexibleForeignKey(
45-
on_delete=django.db.models.deletion.CASCADE,
46-
related_name="replay_access_set",
47-
to="sentry.organization",
48-
),
49-
),
40+
("date_updated", models.DateTimeField(auto_now=True)),
41+
("date_added", models.DateTimeField(auto_now_add=True)),
5042
(
5143
"organizationmember",
5244
sentry.db.models.fields.foreignkey.FlexibleForeignKey(
5345
on_delete=django.db.models.deletion.CASCADE,
5446
related_name="replay_access",
5547
to="sentry.organizationmember",
48+
unique=True,
5649
),
5750
),
5851
],
5952
options={
6053
"db_table": "sentry_organizationmemberreplayaccess",
61-
"unique_together": {("organization", "organizationmember")},
6254
},
6355
),
6456
]

src/sentry/replays/models.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from sentry.db.models import (
99
BoundedBigIntegerField,
1010
DefaultFieldsModel,
11+
FlexibleForeignKey,
1112
Model,
1213
region_silo_model,
1314
sane_repr,
@@ -78,3 +79,28 @@ def delete(self, *args, **kwargs):
7879

7980
rv = super().delete(*args, **kwargs)
8081
return rv
82+
83+
84+
@region_silo_model
85+
class OrganizationMemberReplayAccess(DefaultFieldsModel):
86+
"""
87+
Tracks which organization members have permission to access replay data.
88+
89+
When no records exist for an organization, all members have access (default).
90+
When records exist, only members with a record can access replays.
91+
"""
92+
93+
__relocation_scope__ = RelocationScope.Organization
94+
95+
organizationmember = FlexibleForeignKey(
96+
"sentry.OrganizationMember",
97+
on_delete=models.CASCADE,
98+
related_name="replay_access",
99+
unique=True,
100+
)
101+
102+
class Meta:
103+
app_label = "replays"
104+
db_table = "sentry_organizationmemberreplayaccess"
105+
106+
__repr__ = sane_repr("organizationmember_id")

src/sentry/testutils/helpers/backups.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -473,12 +473,10 @@ def create_exhaustive_organization(
473473
)
474474

475475
# OrganizationMemberReplayAccess - add for the owner member
476-
from sentry.models.organizationmemberreplayaccess import OrganizationMemberReplayAccess
476+
from sentry.replays.models import OrganizationMemberReplayAccess
477477

478478
owner_member = OrganizationMember.objects.get(organization=org, user_id=owner_id)
479-
OrganizationMemberReplayAccess.objects.create(
480-
organization=org, organizationmember=owner_member
481-
)
479+
OrganizationMemberReplayAccess.objects.create(organizationmember=owner_member)
482480

483481
# Team
484482
team = self.create_team(name=f"test_team_in_{slug}", organization=org)

tests/sentry/api/serializers/test_organization.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
from sentry.models.deploy import Deploy
1818
from sentry.models.environment import Environment
1919
from sentry.models.options.organization_option import OrganizationOption
20-
from sentry.models.organizationmemberreplayaccess import OrganizationMemberReplayAccess
2120
from sentry.models.organizationonboardingtask import (
2221
OnboardingTask,
2322
OnboardingTaskStatus,
2423
OrganizationOnboardingTask,
2524
)
2625
from sentry.models.releaseprojectenvironment import ReleaseProjectEnvironment
26+
from sentry.replays.models import OrganizationMemberReplayAccess
2727
from sentry.testutils.cases import TestCase
2828
from sentry.testutils.skips import requires_snuba
2929

@@ -204,12 +204,8 @@ def test_replay_access_members_serialized(self) -> None:
204204
member2 = self.create_member(
205205
organization=organization, user=self.create_user(), role="member"
206206
)
207-
OrganizationMemberReplayAccess.objects.create(
208-
organization=organization, organizationmember=member1
209-
)
210-
OrganizationMemberReplayAccess.objects.create(
211-
organization=organization, organizationmember=member2
212-
)
207+
OrganizationMemberReplayAccess.objects.create(organizationmember=member1)
208+
OrganizationMemberReplayAccess.objects.create(organizationmember=member2)
213209
acc = access.from_user(user, organization)
214210

215211
with self.feature("organizations:granular-replay-permissions"):

tests/sentry/core/endpoints/test_organization_details.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
from sentry.models.options.project_option import ProjectOption
3232
from sentry.models.organization import Organization, OrganizationStatus
3333
from sentry.models.organizationmapping import OrganizationMapping
34-
from sentry.models.organizationmemberreplayaccess import OrganizationMemberReplayAccess
3534
from sentry.models.organizationslugreservation import OrganizationSlugReservation
35+
from sentry.replays.models import OrganizationMemberReplayAccess
3636
from sentry.signals import project_created
3737
from sentry.silo.safety import unguarded_write
3838
from sentry.snuba.metrics import TransactionMRI
@@ -1548,7 +1548,7 @@ def test_replay_access_members_add(self) -> None:
15481548

15491549
access_members = list(
15501550
OrganizationMemberReplayAccess.objects.filter(
1551-
organization=self.organization
1551+
organizationmember__organization=self.organization
15521552
).values_list("organizationmember_id", flat=True)
15531553
)
15541554
assert set(access_members) == {member1.id, member2.id}
@@ -1566,12 +1566,8 @@ def test_replay_access_members_remove(self) -> None:
15661566
member2 = self.create_member(
15671567
organization=self.organization, user=self.create_user(), role="member"
15681568
)
1569-
OrganizationMemberReplayAccess.objects.create(
1570-
organization=self.organization, organizationmember=member1
1571-
)
1572-
OrganizationMemberReplayAccess.objects.create(
1573-
organization=self.organization, organizationmember=member2
1574-
)
1569+
OrganizationMemberReplayAccess.objects.create(organizationmember=member1)
1570+
OrganizationMemberReplayAccess.objects.create(organizationmember=member2)
15751571
with assume_test_silo_mode_of(AuditLogEntry):
15761572
AuditLogEntry.objects.filter(organization_id=self.organization.id).delete()
15771573

@@ -1581,7 +1577,7 @@ def test_replay_access_members_remove(self) -> None:
15811577

15821578
access_members = list(
15831579
OrganizationMemberReplayAccess.objects.filter(
1584-
organization=self.organization
1580+
organizationmember__organization=self.organization
15851581
).values_list("organizationmember_id", flat=True)
15861582
)
15871583
assert access_members == [member1.id]
@@ -1602,9 +1598,7 @@ def test_replay_access_members_add_and_remove(self) -> None:
16021598
member3 = self.create_member(
16031599
organization=self.organization, user=self.create_user(), role="member"
16041600
)
1605-
OrganizationMemberReplayAccess.objects.create(
1606-
organization=self.organization, organizationmember=member1
1607-
)
1601+
OrganizationMemberReplayAccess.objects.create(organizationmember=member1)
16081602
with assume_test_silo_mode_of(AuditLogEntry):
16091603
AuditLogEntry.objects.filter(organization_id=self.organization.id).delete()
16101604

@@ -1614,7 +1608,7 @@ def test_replay_access_members_add_and_remove(self) -> None:
16141608

16151609
access_members = set(
16161610
OrganizationMemberReplayAccess.objects.filter(
1617-
organization=self.organization
1611+
organizationmember__organization=self.organization
16181612
).values_list("organizationmember_id", flat=True)
16191613
)
16201614
assert access_members == {member2.id, member3.id}
@@ -1630,9 +1624,7 @@ def test_replay_access_members_clear_all(self) -> None:
16301624
member1 = self.create_member(
16311625
organization=self.organization, user=self.create_user(), role="member"
16321626
)
1633-
OrganizationMemberReplayAccess.objects.create(
1634-
organization=self.organization, organizationmember=member1
1635-
)
1627+
OrganizationMemberReplayAccess.objects.create(organizationmember=member1)
16361628
with assume_test_silo_mode_of(AuditLogEntry):
16371629
AuditLogEntry.objects.filter(organization_id=self.organization.id).delete()
16381630

@@ -1641,7 +1633,7 @@ def test_replay_access_members_clear_all(self) -> None:
16411633
self.get_success_response(self.organization.slug, **data)
16421634

16431635
access_count = OrganizationMemberReplayAccess.objects.filter(
1644-
organization=self.organization
1636+
organizationmember__organization=self.organization
16451637
).count()
16461638
assert access_count == 0
16471639

@@ -1703,7 +1695,7 @@ def test_replay_access_members_mixed_valid_and_invalid(self) -> None:
17031695
assert str(valid_member.id) not in response.data["replayAccessMembers"]
17041696

17051697
access_count = OrganizationMemberReplayAccess.objects.filter(
1706-
organization=self.organization
1698+
organizationmember__organization=self.organization
17071699
).count()
17081700
assert access_count == 0
17091701

0 commit comments

Comments
 (0)