debian-mirror-gitlab/app/models/notification_recipient.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

200 lines
5.6 KiB
Ruby
Raw Normal View History

2018-11-18 11:00:15 +05:30
# frozen_string_literal: true
2017-09-10 17:25:29 +05:30
class NotificationRecipient
2018-11-08 19:23:39 +05:30
include Gitlab::Utils::StrongMemoize
2018-03-17 18:26:18 +05:30
attr_reader :user, :type, :reason
2019-10-12 21:52:04 +05:30
2021-01-03 14:25:43 +05:30
def initialize(user, type, opts = {})
2018-03-17 18:26:18 +05:30
unless NotificationSetting.levels.key?(type) || type == :subscription
raise ArgumentError, "invalid type: #{type.inspect}"
end
@custom_action = opts[:custom_action]
@acting_user = opts[:acting_user]
@target = opts[:target]
@project = opts[:project] || default_project
@group = opts[:group] || @project&.group
2017-09-10 17:25:29 +05:30
@user = user
@type = type
2018-03-17 18:26:18 +05:30
@reason = opts[:reason]
@skip_read_ability = opts[:skip_read_ability]
2017-09-10 17:25:29 +05:30
end
def notification_setting
@notification_setting ||= find_notification_setting
end
def notification_level
@notification_level ||= notification_setting&.level&.to_sym
end
def notifiable?
return false unless has_access?
2019-10-12 21:52:04 +05:30
return false if emails_disabled?
2017-09-10 17:25:29 +05:30
return false if own_activity?
# even users with :disabled notifications receive manual subscriptions
return !unsubscribed? if @type == :subscription
return false unless suitable_notification_level?
2022-10-11 01:57:18 +05:30
return false if email_blocked?
2017-09-10 17:25:29 +05:30
# check this last because it's expensive
# nobody should receive notifications if they've specifically unsubscribed
2018-05-09 12:01:36 +05:30
# except if they were mentioned.
return false if @type != :mention && unsubscribed?
2017-09-10 17:25:29 +05:30
true
end
def suitable_notification_level?
case notification_level
when :mention
@type == :mention
2019-07-31 22:56:46 +05:30
when :participating
2020-10-24 23:57:45 +05:30
participating_custom_action? || participating_or_mention?
2019-07-31 22:56:46 +05:30
when :custom
2020-10-24 23:57:45 +05:30
custom_enabled? || participating_or_mention?
2019-07-31 22:56:46 +05:30
when :watch
!excluded_watcher_action?
2017-09-10 17:25:29 +05:30
else
false
end
end
def custom_enabled?
2020-04-08 14:13:33 +05:30
return false unless @custom_action
return false unless notification_setting
notification_setting.event_enabled?(@custom_action) ||
# fixed_pipeline is a subset of success_pipeline event
(@custom_action == :fixed_pipeline &&
notification_setting.event_enabled?(:success_pipeline))
2017-09-10 17:25:29 +05:30
end
def unsubscribed?
2020-04-22 19:07:51 +05:30
subscribable_target = @target.is_a?(Note) ? @target.noteable : @target
2017-09-10 17:25:29 +05:30
2020-04-22 19:07:51 +05:30
return false unless subscribable_target
return false unless subscribable_target.respond_to?(:subscriptions)
subscription = subscribable_target.subscriptions.find { |subscription| subscription.user_id == @user.id }
2017-09-10 17:25:29 +05:30
subscription && !subscription.subscribed
end
def own_activity?
return false unless @acting_user
2018-03-17 18:26:18 +05:30
if user == @acting_user
# if activity was generated by the same user, change reason to :own_activity
@reason = NotificationReason::OWN_ACTIVITY
# If the user wants to be notified, we must return `false`
!@acting_user.notified_of_own_activity?
else
false
end
2017-09-10 17:25:29 +05:30
end
2022-10-11 01:57:18 +05:30
def email_blocked?
return false if Feature.disabled?(:block_emails_with_failures)
recipient_email = user.notification_email_for(@group)
Gitlab::ApplicationRateLimiter.peek(:permanent_email_failure, scope: recipient_email) ||
Gitlab::ApplicationRateLimiter.peek(:temporary_email_failure, scope: recipient_email)
end
2017-09-10 17:25:29 +05:30
def has_access?
DeclarativePolicy.subject_scope do
2018-10-15 14:42:47 +05:30
break false unless user.can?(:receive_notifications)
break true if @skip_read_ability
2018-03-17 18:26:18 +05:30
2018-10-15 14:42:47 +05:30
break false if @target && !user.can?(:read_cross_project)
break false if @project && !user.can?(:read_project, @project)
2017-09-10 17:25:29 +05:30
2018-10-15 14:42:47 +05:30
break true unless read_ability
break true unless DeclarativePolicy.has_policy?(@target)
2017-09-10 17:25:29 +05:30
user.can?(read_ability, @target)
end
end
def excluded_watcher_action?
2019-09-04 21:01:54 +05:30
return false unless @type == :watch
2019-07-31 22:56:46 +05:30
return false unless @custom_action
2017-09-10 17:25:29 +05:30
NotificationSetting::EXCLUDED_WATCHER_EVENTS.include?(@custom_action)
2018-05-09 12:01:36 +05:30
end
2017-09-10 17:25:29 +05:30
private
2019-10-12 21:52:04 +05:30
# They are disabled if the project or group has disallowed it.
# No need to check the group if there is already a project
def emails_disabled?
@project ? @project.emails_disabled? : @group&.emails_disabled?
end
2022-08-13 15:12:31 +05:30
def emails_enabled?
!emails_disabled?
end
2017-09-10 17:25:29 +05:30
def read_ability
2019-07-07 11:18:12 +05:30
return if @skip_read_ability
2017-09-10 17:25:29 +05:30
return @read_ability if instance_variable_defined?(:@read_ability)
@read_ability =
2019-05-03 19:53:19 +05:30
if @target.is_a?(Ci::Pipeline)
2017-09-10 17:25:29 +05:30
:read_build # We have build trace in pipeline emails
2019-05-03 19:53:19 +05:30
elsif default_ability_for_target
:"read_#{default_ability_for_target}"
end
end
def default_ability_for_target
@default_ability_for_target ||=
if @target.respond_to?(:to_ability_name)
@target.to_ability_name
elsif @target.class.respond_to?(:model_name)
@target.class.model_name.name.underscore
2017-09-10 17:25:29 +05:30
end
end
2018-03-17 18:26:18 +05:30
def default_project
2019-07-07 11:18:12 +05:30
return if @target.nil?
2018-03-17 18:26:18 +05:30
return @target if @target.is_a?(Project)
return @target.project if @target.respond_to?(:project)
end
2017-09-10 17:25:29 +05:30
def find_notification_setting
project_setting = @project && user.notification_settings_for(@project)
return project_setting unless project_setting.nil? || project_setting.global?
2019-09-04 21:01:54 +05:30
group_setting = closest_non_global_group_notification_setting
2017-09-10 17:25:29 +05:30
2018-11-08 19:23:39 +05:30
return group_setting unless group_setting.nil?
2017-09-10 17:25:29 +05:30
user.global_notification_setting
end
2018-11-08 19:23:39 +05:30
2019-07-07 11:18:12 +05:30
# Returns the notification_setting of the lowest group in hierarchy with non global level
2019-09-04 21:01:54 +05:30
def closest_non_global_group_notification_setting
2018-11-08 19:23:39 +05:30
return unless @group
2019-09-04 21:01:54 +05:30
@group
.notification_settings(hierarchy_order: :asc)
.where(user: user)
.where.not(level: NotificationSetting.levels[:global])
.first
2018-11-08 19:23:39 +05:30
end
2020-10-24 23:57:45 +05:30
def participating_custom_action?
%i[failed_pipeline fixed_pipeline moved_project].include?(@custom_action)
end
def participating_or_mention?
%i[participating mention].include?(@type)
end
2017-09-10 17:25:29 +05:30
end