Browse Source

feat(team-workflow): Add team to GroupSubscription (#55879)

this pr adds back the addition of team as a field on GroupSubscription
(originally from https://github.com/getsentry/sentry/pull/55805 ,
removed in https://github.com/getsentry/sentry/pull/55870) .
Richard Roggenkemper 1 year ago
parent
commit
8a3850a571

+ 4 - 0
fixtures/backup/model_dependencies/detailed.json

@@ -1471,6 +1471,10 @@
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
       },
+      "team": {
+        "kind": "FlexibleForeignKey",
+        "model": "sentry.Team"
+      },
       "user_id": {
         "kind": "HybridCloudForeignKey",
         "model": "sentry.User"

+ 1 - 0
fixtures/backup/model_dependencies/flat.json

@@ -333,6 +333,7 @@
   "sentry.GroupSubscription": [
     "sentry.Group",
     "sentry.Project",
+    "sentry.Team",
     "sentry.User"
   ],
   "sentry.GroupTombstone": [

+ 1 - 1
migrations_lockfile.txt

@@ -8,5 +8,5 @@ will then be regenerated, and you should be able to merge without conflicts.
 feedback: 0001_feedback
 nodestore: 0002_nodestore_no_dictfield
 replays: 0003_add_size_to_recording_segment
-sentry: 0548_add_is_unclaimed_boolean_to_user
+sentry: 0549_re_add_groupsubscription_columns
 social_auth: 0002_default_auto_field

+ 72 - 0
src/sentry/migrations/0549_re_add_groupsubscription_columns.py

@@ -0,0 +1,72 @@
+# Generated by Django 3.2.20 on 2023-09-12 16:50
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+import sentry.db.models.fields.foreignkey
+from sentry.new_migrations.migrations import CheckedMigration
+
+
+class Migration(CheckedMigration):
+    # This flag is used to mark that a migration shouldn't be automatically run in production. For
+    # the most part, this should only be used for operations where it's safe to run the migration
+    # after your code has deployed. So this should not be used for most operations that alter the
+    # schema of a table.
+    # Here are some things that make sense to mark as dangerous:
+    # - Large data migrations. Typically we want these to be run manually by ops so that they can
+    #   be monitored and not block the deploy for a long period of time while they run.
+    # - Adding indexes to large tables. Since this can take a long time, we'd generally prefer to
+    #   have ops run this and not block the deploy. Note that while adding an index is a schema
+    #   change, it's completely safe to run the operation after the code has deployed.
+    is_dangerous = False
+
+    dependencies = [
+        ("sentry", "0548_add_is_unclaimed_boolean_to_user"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="groupsubscription",
+            name="team",
+            field=sentry.db.models.fields.foreignkey.FlexibleForeignKey(
+                null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.team"
+            ),
+        ),
+        migrations.SeparateDatabaseAndState(
+            state_operations=[
+                migrations.AlterField(
+                    model_name="groupsubscription",
+                    name="user_id",
+                    field=sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey(
+                        "sentry.User", db_index=True, null=True, on_delete="CASCADE"
+                    ),
+                ),
+            ],
+            database_operations=[
+                migrations.RunSQL(
+                    reverse_sql="""
+                    ALTER TABLE "sentry_groupsubscription" ALTER COLUMN "user_id" SET NOT NULL;
+                    """,
+                    sql="""
+                    ALTER TABLE "sentry_groupsubscription" ALTER COLUMN "user_id" DROP NOT NULL;
+                    """,
+                    hints={"tables": ["sentry_groupsubscription"]},
+                )
+            ],
+        ),
+        migrations.AlterUniqueTogether(
+            name="groupsubscription",
+            unique_together={("group", "team"), ("group", "user_id")},
+        ),
+        migrations.AddConstraint(
+            model_name="groupsubscription",
+            constraint=models.CheckConstraint(
+                check=models.Q(
+                    models.Q(("team_id__isnull", False), ("user_id__isnull", True)),
+                    models.Q(("team_id__isnull", True), ("user_id__isnull", False)),
+                    _connector="OR",
+                ),
+                name="subscription_team_or_user_check",
+            ),
+        ),
+    ]

+ 9 - 1
src/sentry/models/groupsubscription.py

@@ -179,6 +179,7 @@ class GroupSubscription(Model):
     project = FlexibleForeignKey("sentry.Project", related_name="subscription_set")
     group = FlexibleForeignKey("sentry.Group", related_name="subscription_set")
     user_id = HybridCloudForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete="CASCADE")
+    team = FlexibleForeignKey("sentry.Team", null=True, db_index=True, on_delete=models.CASCADE)
     is_active = models.BooleanField(default=True)
     reason = BoundedPositiveIntegerField(default=GroupSubscriptionReason.unknown)
     date_added = models.DateTimeField(default=timezone.now, null=True)
@@ -188,6 +189,13 @@ class GroupSubscription(Model):
     class Meta:
         app_label = "sentry"
         db_table = "sentry_groupsubscription"
-        unique_together = (("group", "user_id"),)
+        unique_together = (("group", "user_id"), ("group", "team"))
+        constraints = [
+            models.CheckConstraint(
+                check=models.Q(team_id__isnull=False, user_id__isnull=True)
+                | models.Q(team_id__isnull=True, user_id__isnull=False),
+                name="subscription_team_or_user_check",
+            )
+        ]
 
     __repr__ = sane_repr("project_id", "group_id", "user_id")