Repository: getsentry/sentry

Issue:
Add `team_id` to GroupSubscription
Need to add `team_id` as a new field to the GroupSubscription table. Once added, we need to make sure that we add a constraint similar to this (https://github.com/getsentry/sentry/pull/48820/files#diff-1dae1776e3142b03d42523a1fc9791b25163b3ad842a00d72df620326deffbe3) that ensures that either the `user_id` or `team_id` fields are set



Discussion:

Resolving patch:
diff --git a/src/sentry/migrations/0543_add_team_id_to_groupsubscription.py b/src/sentry/migrations/0543_add_team_id_to_groupsubscription.py
new file mode 100644
--- /dev/null
+++ b/src/sentry/migrations/0543_add_team_id_to_groupsubscription.py
@@ -0,0 +1,58 @@
+# Generated by Django 3.2.20 on 2023-09-07 16:55
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+import sentry.db.models.fields.foreignkey
+import sentry.db.models.fields.hybrid_cloud_foreign_key
+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 = True
+
+    dependencies = [
+        ("sentry", "0542_rm_flatfile_file"),
+    ]
+
+    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.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"
+            ),
+        ),
+        migrations.AlterUniqueTogether(
+            name="groupsubscription",
+            unique_together={("group", "user_id"), ("group", "team")},
+        ),
+        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",
+            ),
+        ),
+    ]
diff --git a/src/sentry/models/groupsubscription.py b/src/sentry/models/groupsubscription.py
--- a/src/sentry/models/groupsubscription.py
+++ b/src/sentry/models/groupsubscription.py
@@ -178,7 +178,8 @@ 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, on_delete="CASCADE")
+    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")


Test patch: