Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/sentry/deletions/defaults/sentry_app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from collections.abc import Sequence

from sentry.constants import ObjectStatus
from sentry.deletions.base import BaseRelation, ModelDeletionTask, ModelRelation
from sentry.sentry_apps.models.sentry_app import SentryApp
from sentry.types.region import find_all_region_names
from sentry.workflow_engine.service.action import action_service


class SentryAppDeletionTask(ModelDeletionTask[SentryApp]):
Expand All @@ -25,6 +28,11 @@ def mark_deletion_in_progress(self, instance_list: Sequence[SentryApp]) -> None:
instance.update(status=SentryAppStatus.DELETION_IN_PROGRESS)

def delete_instance(self, instance: SentryApp) -> None:
# action service RPC goes here, iterating by region because children are deleted first
for region_name in find_all_region_names():
action_service.update_action_status_for_sentry_app_via_sentry_app_id(
region_name=region_name,
status=ObjectStatus.DISABLED,
sentry_app_id=instance.id,
)

return super().delete_instance(instance)
8 changes: 7 additions & 1 deletion src/sentry/deletions/defaults/sentry_app_installation.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from collections.abc import Sequence

from sentry.constants import ObjectStatus
from sentry.deletions.base import BaseRelation, ModelDeletionTask, ModelRelation
from sentry.deletions.defaults.apigrant import ModelApiGrantDeletionTask
from sentry.sentry_apps.models.sentry_app_installation import SentryAppInstallation
from sentry.workflow_engine.service.action import action_service


class SentryAppInstallationDeletionTask(ModelDeletionTask[SentryAppInstallation]):
Expand All @@ -27,6 +29,10 @@ def mark_deletion_in_progress(self, instance_list: Sequence[SentryAppInstallatio
pass

def delete_instance(self, instance: SentryAppInstallation) -> None:
# action_service RPC goes here
action_service.update_action_status_for_sentry_app_via_uuid(
organization_id=instance.organization_id,
status=ObjectStatus.DISABLED,
sentry_app_install_uuid=instance.uuid,
)

return super().delete_instance(instance)
33 changes: 31 additions & 2 deletions tests/sentry/deletions/test_sentry_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@
from django.db import connections, router

from sentry import deletions
from sentry.constants import ObjectStatus
from sentry.models.apiapplication import ApiApplication
from sentry.notifications.models.notificationaction import ActionTarget
from sentry.sentry_apps.models.sentry_app import SentryApp
from sentry.sentry_apps.models.sentry_app_installation import SentryAppInstallation
from sentry.testutils.cases import TestCase
from sentry.testutils.silo import control_silo_test
from sentry.testutils.silo import control_silo_test, create_test_regions
from sentry.users.models.user import User
from sentry.workflow_engine.models import Action
from sentry.workflow_engine.typings.notification_action import SentryAppIdentifier


@control_silo_test
@control_silo_test(regions=create_test_regions("us", "de"))
class TestSentryAppDeletionTask(TestCase):
def setUp(self) -> None:
self.user = self.create_user()
Expand Down Expand Up @@ -54,3 +58,28 @@ def test_soft_deletes_sentry_app(self) -> None:
)

assert c.fetchone()[0] == 1

def test_disables_actions(self) -> None:
action = self.create_action(
type=Action.Type.SENTRY_APP,
config={
"target_identifier": str(self.sentry_app.id),
"sentry_app_identifier": SentryAppIdentifier.SENTRY_APP_ID,
"target_type": ActionTarget.SENTRY_APP,
},
)
other_action = self.create_action(
type=Action.Type.SENTRY_APP,
config={
"target_identifier": "1212121212",
"sentry_app_identifier": SentryAppIdentifier.SENTRY_APP_ID,
"target_type": ActionTarget.SENTRY_APP,
},
)
deletions.exec_sync(self.sentry_app)

action.refresh_from_db()
assert action.status == ObjectStatus.DISABLED

other_action.refresh_from_db()
assert other_action.status == ObjectStatus.ACTIVE
29 changes: 29 additions & 0 deletions tests/sentry/deletions/test_sentry_app_installations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
from django.db.transaction import get_connection

from sentry import deletions
from sentry.constants import ObjectStatus
from sentry.deletions.tasks.hybrid_cloud import schedule_hybrid_cloud_foreign_key_jobs
from sentry.models.apigrant import ApiGrant
from sentry.models.apitoken import ApiToken
from sentry.notifications.models.notificationaction import ActionTarget
from sentry.sentry_apps.installations import SentryAppInstallationCreator
from sentry.sentry_apps.models.sentry_app_installation import SentryAppInstallation
from sentry.sentry_apps.models.sentry_app_installation_for_provider import (
Expand All @@ -17,6 +19,8 @@
from sentry.testutils.cases import TestCase
from sentry.testutils.outbox import outbox_runner
from sentry.testutils.silo import assume_test_silo_mode, control_silo_test
from sentry.workflow_engine.models import Action
from sentry.workflow_engine.typings.notification_action import SentryAppIdentifier


@control_silo_test
Expand Down Expand Up @@ -106,3 +110,28 @@ def test_soft_deletes_installation(self) -> None:
)

assert c.fetchone()[0] == 1

def test_disables_actions(self) -> None:
action = self.create_action(
type=Action.Type.SENTRY_APP,
config={
"target_identifier": self.install.uuid,
"sentry_app_identifier": SentryAppIdentifier.SENTRY_APP_INSTALLATION_UUID,
"target_type": ActionTarget.SENTRY_APP,
},
)
other_action = self.create_action(
type=Action.Type.SENTRY_APP,
config={
"target_identifier": "1234567890",
"sentry_app_identifier": SentryAppIdentifier.SENTRY_APP_INSTALLATION_UUID,
"target_type": ActionTarget.SENTRY_APP,
},
)
deletions.exec_sync(self.install)

action.refresh_from_db()
assert action.status == ObjectStatus.DISABLED

other_action.refresh_from_db()
assert other_action.status == ObjectStatus.ACTIVE
Loading