Skip to content

Commit

Permalink
feat(notifications): adds backfill for weekly report settings (#58168)
Browse files Browse the repository at this point in the history
Need to backfill the weekly report settings because it comes from a
different source than the rest of the notifications
  • Loading branch information
Stephen Cefali authored Oct 16, 2023
1 parent 268280e commit f2145d9
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 1 deletion.
2 changes: 1 addition & 1 deletion migrations_lockfile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ feedback: 0003_feedback_add_env
hybridcloud: 0004_add_cache_version
nodestore: 0002_nodestore_no_dictfield
replays: 0003_add_size_to_recording_segment
sentry: 0573_add_first_seen_index_groupedmessage
sentry: 0574_backfill_weekly_report_settings
social_auth: 0002_default_auto_field
48 changes: 48 additions & 0 deletions src/sentry/migrations/0574_backfill_weekly_report_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Generated by Django 3.2.20 on 2023-10-16 15:23

from django.db import migrations

from sentry.new_migrations.migrations import CheckedMigration
from sentry.utils.query import RangeQuerySetWrapperWithProgressBar


def backfill_weekly_report_settings(apps, schema_editor):
UserOption = apps.get_model("sentry", "UserOption")
NotificationSettingOption = apps.get_model("sentry", "NotificationSettingOption")
for user_option in RangeQuerySetWrapperWithProgressBar(UserOption.objects.all()):
if user_option.key != "reports:disabled-organizations":
continue
for value in user_option.value:
NotificationSettingOption.objects.create(
user_id=user_option.user_id,
scope_type="organization",
scope_identifier=value,
value="never",
type="reports",
)


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", "0573_add_first_seen_index_groupedmessage"),
]

operations = [
migrations.RunPython(
backfill_weekly_report_settings,
migrations.RunPython.noop,
hints={"tables": ["sentry_useroption", "sentry_notificationsettingoption"]},
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from uuid import uuid4

from sentry.models.notificationsettingoption import NotificationSettingOption
from sentry.testutils.cases import TestMigrations


class BackfillWeeklyReportSettingsMigrationTest(TestMigrations):
migrate_from = "0573_add_first_seen_index_groupedmessage"
migrate_to = "0574_backfill_weekly_report_settings"
connection = "control"

def setup_before_migration(self, apps):
User = apps.get_model("sentry", "User")

def create_user():
email = uuid4().hex + "@example.com"
return User.objects.create(
email=email, username=email, is_staff=True, is_active=True, is_superuser=False
)

UserOption = apps.get_model("sentry", "UserOption")

# Given: We are simulating a few UserOption records
self.user1 = create_user()
self.user2 = create_user()
self.user3 = create_user() # This user has no orgs with disabled settings
self.org1_id = 201
self.org2_id = 202

UserOption.objects.create(
user_id=self.user1.id, key="reports:disabled-organizations", value=[self.org1_id]
)

UserOption.objects.create(
user_id=self.user2.id,
key="reports:disabled-organizations",
value=[self.org2_id, self.org1_id],
)

# Adding an unrelated UserOption record to ensure it's not affected
UserOption.objects.create(user_id=self.user3.id, key="other:key", value=[self.org2_id])

def test(self):
# After migration, verify the NotificationSettingOption records

notification_settings = NotificationSettingOption.objects.filter(
user_id__in=[self.user1.id, self.user2.id, self.user3.id],
scope_type="organization",
type="reports",
value="never",
)

self.assertEqual(notification_settings.count(), 3)

# Checking for each user
user1_settings = notification_settings.filter(user_id=self.user1.id)
user2_settings = notification_settings.filter(user_id=self.user2.id)
user3_settings = notification_settings.filter(user_id=self.user3.id)

self.assertEqual(user1_settings.count(), 1)
self.assertTrue(user1_settings.filter(scope_identifier=self.org1_id).exists())

self.assertEqual(user2_settings.count(), 2)
self.assertTrue(user2_settings.filter(scope_identifier=self.org1_id).exists())
self.assertTrue(user2_settings.filter(scope_identifier=self.org2_id).exists())

# User 3 should have no settings
self.assertEqual(user3_settings.count(), 0)

0 comments on commit f2145d9

Please sign in to comment.