Change e-mail notifications to only be sent when recipient is offline (#17984)
* Change e-mail notifications to only be sent when recipient is offline Change the default for follow and mention notifications back on * Add preference to always send e-mail notifications * Change wordinggh/stable
parent
fd9a9b07c2
commit
8e20e16cf0
|
@ -54,7 +54,8 @@ class Settings::PreferencesController < Settings::BaseController
|
|||
:setting_use_pending_items,
|
||||
:setting_trends,
|
||||
:setting_crop_images,
|
||||
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag),
|
||||
:setting_always_send_emails,
|
||||
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag appeal),
|
||||
interactions: %i(must_be_follower must_be_following must_be_following_dm)
|
||||
)
|
||||
end
|
||||
|
|
|
@ -38,6 +38,7 @@ class UserSettingsDecorator
|
|||
user.settings['use_pending_items'] = use_pending_items_preference if change?('setting_use_pending_items')
|
||||
user.settings['trends'] = trends_preference if change?('setting_trends')
|
||||
user.settings['crop_images'] = crop_images_preference if change?('setting_crop_images')
|
||||
user.settings['always_send_emails'] = always_send_emails_preference if change?('setting_always_send_emails')
|
||||
end
|
||||
|
||||
def merged_notification_emails
|
||||
|
@ -132,6 +133,10 @@ class UserSettingsDecorator
|
|||
boolean_cast_setting 'setting_crop_images'
|
||||
end
|
||||
|
||||
def always_send_emails_preference
|
||||
boolean_cast_setting 'setting_always_send_emails'
|
||||
end
|
||||
|
||||
def boolean_cast_setting(key)
|
||||
ActiveModel::Type::Boolean.new.cast(settings[key])
|
||||
end
|
||||
|
|
|
@ -130,7 +130,7 @@ class User < ApplicationRecord
|
|||
:reduce_motion, :system_font_ui, :noindex, :theme, :display_media,
|
||||
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
|
||||
:advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
|
||||
:disable_swiping,
|
||||
:disable_swiping, :always_send_emails,
|
||||
to: :settings, prefix: :setting, allow_nil: false
|
||||
|
||||
attr_reader :invite_code
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NotifyService < BaseService
|
||||
include Redisable
|
||||
|
||||
def call(recipient, type, activity)
|
||||
@recipient = recipient
|
||||
@activity = activity
|
||||
|
@ -8,10 +10,15 @@ class NotifyService < BaseService
|
|||
|
||||
return if recipient.user.nil? || blocked?
|
||||
|
||||
create_notification!
|
||||
@notification.save!
|
||||
|
||||
# It's possible the underlying activity has been deleted
|
||||
# between the save call and now
|
||||
return if @notification.activity.nil?
|
||||
|
||||
push_notification!
|
||||
push_to_conversation! if direct_message?
|
||||
send_email! if email_enabled?
|
||||
send_email! if email_needed?
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
nil
|
||||
end
|
||||
|
@ -92,8 +99,8 @@ class NotifyService < BaseService
|
|||
end
|
||||
|
||||
def blocked?
|
||||
blocked = @recipient.suspended? # Skip if the recipient account is suspended anyway
|
||||
blocked ||= from_self? && @notification.type != :poll # Skip for interactions with self
|
||||
blocked = @recipient.suspended?
|
||||
blocked ||= from_self? && @notification.type != :poll
|
||||
|
||||
return blocked if message? && from_staff?
|
||||
|
||||
|
@ -117,38 +124,52 @@ class NotifyService < BaseService
|
|||
end
|
||||
end
|
||||
|
||||
def create_notification!
|
||||
@notification.save!
|
||||
def push_notification!
|
||||
push_to_streaming_api! if subscribed_to_streaming_api?
|
||||
push_to_web_push_subscriptions!
|
||||
end
|
||||
|
||||
def push_notification!
|
||||
return if @notification.activity.nil?
|
||||
def push_to_streaming_api!
|
||||
redis.publish("timeline:#{@recipient.id}:notifications", Oj.dump(event: :notification, payload: InlineRenderer.render(@notification, @recipient, :notification)))
|
||||
end
|
||||
|
||||
Redis.current.publish("timeline:#{@recipient.id}:notifications", Oj.dump(event: :notification, payload: InlineRenderer.render(@notification, @recipient, :notification)))
|
||||
send_push_notifications!
|
||||
def subscribed_to_streaming_api?
|
||||
redis.exists?("subscribed:timeline:#{@recipient.id}") || redis.exists?("subscribed:timeline:#{@recipient.id}:notifications")
|
||||
end
|
||||
|
||||
def push_to_conversation!
|
||||
return if @notification.activity.nil?
|
||||
AccountConversation.add_status(@recipient, @notification.target_status)
|
||||
end
|
||||
|
||||
def send_push_notifications!
|
||||
subscriptions_ids = ::Web::PushSubscription.where(user_id: @recipient.user.id)
|
||||
.select { |subscription| subscription.pushable?(@notification) }
|
||||
.map(&:id)
|
||||
def push_to_web_push_subscriptions!
|
||||
::Web::PushNotificationWorker.push_bulk(web_push_subscriptions.select { |subscription| subscription.pushable?(@notification) }) { |subscription| [subscription.id, @notification.id] }
|
||||
end
|
||||
|
||||
::Web::PushNotificationWorker.push_bulk(subscriptions_ids) do |subscription_id|
|
||||
[subscription_id, @notification.id]
|
||||
end
|
||||
def web_push_subscriptions
|
||||
@web_push_subscriptions ||= ::Web::PushSubscription.where(user_id: @recipient.user.id).to_a
|
||||
end
|
||||
|
||||
def subscribed_to_web_push?
|
||||
web_push_subscriptions.any?
|
||||
end
|
||||
|
||||
def send_email!
|
||||
return if @notification.activity.nil?
|
||||
NotificationMailer.public_send(@notification.type, @recipient, @notification).deliver_later(wait: 2.minutes)
|
||||
NotificationMailer.public_send(@notification.type, @recipient, @notification).deliver_later(wait: 2.minutes) if NotificationMailer.respond_to?(@notification.type)
|
||||
end
|
||||
|
||||
def email_enabled?
|
||||
def email_needed?
|
||||
(!recipient_online? || always_send_emails?) && send_email_for_notification_type?
|
||||
end
|
||||
|
||||
def recipient_online?
|
||||
subscribed_to_streaming_api? || subscribed_to_web_push?
|
||||
end
|
||||
|
||||
def always_send_emails?
|
||||
@recipient.user.settings.always_send_emails
|
||||
end
|
||||
|
||||
def send_email_for_notification_type?
|
||||
@recipient.user.settings.notification_emails[@notification.type.to_s]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
= ff.input :pending_account, as: :boolean, wrapper: :with_label
|
||||
= ff.input :trending_tag, as: :boolean, wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_always_send_emails, as: :boolean, wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|
|
||||
= ff.input :digest, as: :boolean, wrapper: :with_label
|
||||
|
|
|
@ -49,6 +49,7 @@ en:
|
|||
phrase: Will be matched regardless of casing in text or content warning of a post
|
||||
scopes: Which APIs the application will be allowed to access. If you select a top-level scope, you don't need to select individual ones.
|
||||
setting_aggregate_reblogs: Do not show new boosts for posts that have been recently boosted (only affects newly-received boosts)
|
||||
setting_always_send_emails: Normally e-mail notifications won't be sent when you are actively using Mastodon
|
||||
setting_default_sensitive: Sensitive media is hidden by default and can be revealed with a click
|
||||
setting_display_media_default: Hide media marked as sensitive
|
||||
setting_display_media_hide_all: Always hide media
|
||||
|
@ -151,6 +152,7 @@ en:
|
|||
phrase: Keyword or phrase
|
||||
setting_advanced_layout: Enable advanced web interface
|
||||
setting_aggregate_reblogs: Group boosts in timelines
|
||||
setting_always_send_emails: Always send e-mail notifications
|
||||
setting_auto_play_gif: Auto-play animated GIFs
|
||||
setting_boost_modal: Show confirmation dialog before boosting
|
||||
setting_crop_images: Crop images in non-expanded posts to 16x9
|
||||
|
|
|
@ -38,16 +38,17 @@ defaults: &defaults
|
|||
trendable_by_default: false
|
||||
crop_images: true
|
||||
notification_emails:
|
||||
follow: false
|
||||
follow: true
|
||||
reblog: false
|
||||
favourite: false
|
||||
mention: false
|
||||
mention: true
|
||||
follow_request: true
|
||||
digest: true
|
||||
report: true
|
||||
pending_account: true
|
||||
trending_tag: true
|
||||
appeal: true
|
||||
always_send_emails: false
|
||||
interactions:
|
||||
must_be_follower: false
|
||||
must_be_following: false
|
||||
|
|
Reference in New Issue