def filter_to_accepting_recipients( self, project: "Project", recipients: Iterable[Union["Team", "User"]], ) -> Mapping[ExternalProviders, Iterable[Union["Team", "User"]]]: """ Filters a list of teams or users down to the recipients by provider who are subscribed to alerts. We check both the project level settings and global default settings. """ notification_settings = self.get_for_recipient_by_parent( NotificationSettingTypes.ISSUE_ALERTS, parent=project, recipients=recipients ) notification_settings_by_recipient = transform_to_notification_settings_by_recipient( notification_settings, recipients ) mapping = defaultdict(set) should_use_slack_automatic = features.has( "organizations:notification-slack-automatic", project.organization ) for recipient in recipients: providers = where_should_recipient_be_notified( notification_settings_by_recipient, recipient, should_use_slack_automatic ) for provider in providers: mapping[provider].add(recipient) return mapping
def disabled_users_from_project( project: Project) -> Mapping[ExternalProviders, set[User]]: """Get a set of users that have disabled Issue Alert notifications for a given project.""" user_ids = project.member_set.values_list("user", flat=True) users = User.objects.filter(id__in=user_ids) notification_settings = NotificationSetting.objects.get_for_recipient_by_parent( type=NotificationSettingTypes.ISSUE_ALERTS, parent=project, recipients=users, ) notification_settings_by_recipient = transform_to_notification_settings_by_recipient( notification_settings, users) # Although this can be done with dict comprehension, looping for clarity. output = defaultdict(set) for user in users: settings = notification_settings_by_recipient.get(user) if settings: settings_by_provider = get_settings_by_provider(settings) for provider, settings_value_by_scope in settings_by_provider.items( ): project_setting = settings_value_by_scope.get( NotificationScopeType.PROJECT) user_setting = settings_value_by_scope.get( NotificationScopeType.USER) or settings_value_by_scope.get( NotificationScopeType.TEAM) if project_setting == NotificationSettingOptionValues.NEVER or ( not project_setting and user_setting == NotificationSettingOptionValues.NEVER): output[provider].add(user) return output
def test_transform_to_notification_settings_by_recipient(self): assert transform_to_notification_settings_by_recipient( notification_settings=self.notification_settings, recipients=[self.user]) == { self.user: { NotificationScopeType.USER: { ExternalProviders.SLACK: NotificationSettingOptionValues.ALWAYS }, NotificationScopeType.PROJECT: { ExternalProviders.SLACK: NotificationSettingOptionValues.ALWAYS }, } }
def get_participants( self, group: "Group" ) -> Mapping[ExternalProviders, Mapping["User", int]]: """ Identify all users who are participating with a given issue. :param group: Group object """ from sentry.models import NotificationSetting, User all_possible_users = User.objects.get_from_group(group) active_and_disabled_subscriptions = self.filter( group=group, user__in=all_possible_users) notification_settings = NotificationSetting.objects.get_for_recipient_by_parent( NotificationSettingTypes.WORKFLOW, recipients=all_possible_users, parent=group.project, ) subscriptions_by_user_id = { subscription.user_id: subscription for subscription in active_and_disabled_subscriptions } notification_settings_by_recipient = transform_to_notification_settings_by_recipient( notification_settings, all_possible_users) should_use_slack_automatic = features.has( "organizations:notification-slack-automatic", group.organization) result: MutableMapping[ExternalProviders, MutableMapping["User", int]] = defaultdict(dict) for user in all_possible_users: subscription_option = subscriptions_by_user_id.get(user.id) providers = where_should_be_participating( user, subscription_option, notification_settings_by_recipient, should_use_slack_automatic=should_use_slack_automatic, ) for provider in providers: result[provider][user] = (subscription_option and subscription_option.reason or GroupSubscriptionReason.implicit) return result
def filter_to_accepting_recipients( self, parent: Project, recipients: Iterable[Team | User], type: NotificationSettingTypes = NotificationSettingTypes.ISSUE_ALERTS, ) -> Mapping[ExternalProviders, Iterable[Team | User]]: """ Filters a list of teams or users down to the recipients by provider who are subscribed to alerts. We check both the project level settings and global default settings. """ notification_settings = self.get_for_recipient_by_parent( type, parent, recipients) notification_settings_by_recipient = transform_to_notification_settings_by_recipient( notification_settings, recipients) mapping = defaultdict(set) for recipient in recipients: providers = where_should_recipient_be_notified( notification_settings_by_recipient, recipient, type) for provider in providers: mapping[provider].add(recipient) return mapping
def get_participants_for_release( projects: Iterable[Project], organization: Organization, user_ids: Set[int] ) -> Mapping[ExternalProviders, Mapping[User, int]]: # Collect all users with verified emails on a team in the related projects. users = set(User.objects.get_team_members_with_verified_email_for_projects(projects)) # Get all the involved users' settings for deploy-emails (including # users' organization-independent settings.) notification_settings = NotificationSetting.objects.get_for_recipient_by_parent( NotificationSettingTypes.DEPLOY, recipients=users, parent=organization, ) notification_settings_by_recipient = transform_to_notification_settings_by_recipient( notification_settings, users ) should_use_slack_automatic = features.has( "organizations:notification-slack-automatic", organization ) # Map users to their setting value. Prioritize user/org specific, then # user default, then product default. users_to_reasons_by_provider: MutableMapping[ ExternalProviders, MutableMapping[User, int] ] = defaultdict(dict) for user in users: notification_settings_by_scope = notification_settings_by_recipient.get(user, {}) values_by_provider = get_values_by_provider_by_type( notification_settings_by_scope, notification_providers(), NotificationSettingTypes.DEPLOY, should_use_slack_automatic=should_use_slack_automatic, ) for provider, value in values_by_provider.items(): reason_option = get_reason(user, value, user_ids) if reason_option: users_to_reasons_by_provider[provider][user] = reason_option return users_to_reasons_by_provider
def test_transform_to_notification_settings_by_recipient_empty(self): assert (transform_to_notification_settings_by_recipient( notification_settings=[], recipients=[]) == {}) assert (transform_to_notification_settings_by_recipient( notification_settings=[], recipients=[self.user]) == {})