Class: EmailPreference
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- EmailPreference
- Includes:
- Models::Auditable
- Defined in:
- app/models/email_preference.rb
Overview
== Schema Information
Table name: email_preferences
Database name: primary
id :integer not null, primary key
disable_announcements :boolean default(FALSE), not null
disable_events :boolean default(FALSE), not null
disable_newsletters :boolean default(FALSE), not null
disable_promotions :boolean default(FALSE), not null
disable_reviews :boolean default(FALSE), not null
disable_webinars :boolean default(FALSE), not null
email :string not null
last_delivery_status :enum
last_delivery_status_at :datetime
last_delivery_status_notes :string
created_at :datetime
updated_at :datetime
creator_id :integer
updater_id :integer
Indexes
index_email_preferences_on_email (email) UNIQUE
Constant Summary collapse
- ALL_STATES =
Recognised all states.
%w[suppressed dropped deferred bounced delivered spammed opened clicked unsubscribed].freeze
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #email ⇒ Object readonly
Has many collapse
- #accounts ⇒ ActiveRecord::Relation<Account>
- #communication_recipients ⇒ ActiveRecord::Relation<CommunicationRecipient>
- #contact_points ⇒ ActiveRecord::Relation<ContactPoint>
Class Method Summary collapse
- .can_receive_email_of_category(email, category) ⇒ Object
-
.completely_unsubscribed ⇒ ActiveRecord::Relation<EmailPreference>
A relation of EmailPreferences that are completely unsubscribed.
-
.decrypt_token(token) ⇒ Object
Returns the email encoded in the token, or nil if it can't be verified by any of the known formats.
-
.encrypt_email(email) ⇒ Object
Mints a signed token that encodes the customer's email address.
- .generate_email_preferences_form_url(email) ⇒ Object
- .import_suppressions(path) ⇒ Object
- .message_verifier ⇒ Object
- .unsubscribe(emails, disable: true) ⇒ Object
Instance Method Summary collapse
- #any? ⇒ Boolean
- #broadcast_updates ⇒ Object
-
#disable_all ⇒ Object
This is to allow the initial state on the form to be selected properly.
- #to_s ⇒ Object
- #unsubscribed_categories_changes ⇒ Object
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #creator, #should_not_save_version, #stamp_record, #updater
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#email ⇒ Object (readonly)
31 |
# File 'app/models/email_preference.rb', line 31 validates :email, email_format: true, presence: true, uniqueness: true |
Class Method Details
.can_receive_email_of_category(email, category) ⇒ Object
78 79 80 81 82 83 84 85 86 |
# File 'app/models/email_preference.rb', line 78 def self.can_receive_email_of_category(email, category) ep = EmailPreference.find_by(email: email) return true if ep.nil? # no preference exist so all is possible category_method = "disable_#{category}" return true unless ep.respond_to?(category_method) # unknown category is always good !ep.send(category_method) end |
.completely_unsubscribed ⇒ ActiveRecord::Relation<EmailPreference>
A relation of EmailPreferences that are completely unsubscribed. Active Record Scope
37 38 39 40 41 42 43 44 |
# File 'app/models/email_preference.rb', line 37 scope :completely_unsubscribed, -> { where(disable_promotions: true, disable_newsletters: true, disable_announcements: true, disable_events: true, disable_webinars: true, disable_reviews: true) } |
.decrypt_token(token) ⇒ Object
Returns the email encoded in the token, or nil if it can't be verified
by any of the known formats. Tries MessageVerifier (new format) first,
then the legacy decoders.
138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'app/models/email_preference.rb', line 138 def self.decrypt_token(token) verified = .verified(token, purpose: :email_preference) return verified if verified # Legacy fallback for in-flight customer-email URLs. res = Encryption.decrypt_string(token) return res if res.present? ActiveSupport::MessageEncryptor.new(Heatwave::Configuration.fetch(:secret_key_base)).decrypt_and_verify(token) rescue StandardError nil end |
.encrypt_email(email) ⇒ Object
Mints a signed token that encodes the customer's email address. Used by
unsubscribe / preference-center URLs in marketing email and in CRM
account UI.
New tokens are signed with ActiveSupport::MessageVerifier under the
purpose 'email_preference/v1' and a key derived from the application
key_generator — payload-bound and tampering-resistant. Legacy tokens
produced by Encryption.encrypt_string (Blowfish/AES, see lib/encryption.rb)
remain decodable via the fallback chain in decrypt_token so that
in-flight links sitting in customer mailboxes keep working through the
grace window. Drop the legacy decoders ~30 days after this lands when
outstanding emails have aged out.
131 132 133 |
# File 'app/models/email_preference.rb', line 131 def self.encrypt_email(email) .generate(email.to_s, purpose: :email_preference) end |
.generate_email_preferences_form_url(email) ⇒ Object
88 89 90 91 |
# File 'app/models/email_preference.rb', line 88 def self.generate_email_preferences_form_url(email) # locale: false ensures no locale prefix - Cloudflare worker will add appropriate locale based on user's country UrlHelper.instance.email_preferences_my_account_url(token: EmailPreference.encrypt_email(email), host: "https://#{WEB_HOSTNAME}", locale: false) end |
.import_suppressions(path) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 |
# File 'app/models/email_preference.rb', line 93 def self.import_suppressions(path) CSV.foreach(path) do |row| ep = find_or_create_by(email: row[0]) ep.update(disable_promotions: true, disable_newsletters: true, disable_announcements: true, disable_events: true, disable_webinars: true, disable_reviews: true) end end |
.message_verifier ⇒ Object
151 152 153 154 155 156 157 |
# File 'app/models/email_preference.rb', line 151 def self. @message_verifier ||= ActiveSupport::MessageVerifier.new( Rails.application.key_generator.generate_key('email_preference/v1'), digest: 'SHA256', serializer: JSON ) end |
.unsubscribe(emails, disable: true) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'app/models/email_preference.rb', line 105 def self.unsubscribe(emails, disable: true) email_preferences = EmailPreference.where(email: emails) email_preferences.each do |ep| ep.update( disable_promotions: disable, disable_newsletters: disable, disable_announcements: disable, disable_events: disable, disable_webinars: disable, disable_reviews: disable ) end end |
Instance Method Details
#accounts ⇒ ActiveRecord::Relation<Account>
34 |
# File 'app/models/email_preference.rb', line 34 has_many :accounts, foreign_key: :email, primary_key: :email |
#any? ⇒ Boolean
69 70 71 72 73 74 75 76 |
# File 'app/models/email_preference.rb', line 69 def any? disable_promotions || || disable_announcements || disable_events || disable_webinars || disable_reviews end |
#broadcast_updates ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'app/models/email_preference.rb', line 169 def broadcast_updates event_hash = { email: email } event_hash[:categories] = unsubscribed_categories_changes return if event_hash[:categories].blank? ActiveRecord.after_all_transactions_commit do Rails.configuration.event_store.publish( Events::EmailUnsubscribed.new(data: { email: event_hash[:email], categories: event_hash[:categories] }), stream_name: "EmailPreference-#{id}" ) end end |
#communication_recipients ⇒ ActiveRecord::Relation<CommunicationRecipient>
35 |
# File 'app/models/email_preference.rb', line 35 has_many :communication_recipients, foreign_key: :detail, primary_key: :email |
#contact_points ⇒ ActiveRecord::Relation<ContactPoint>
33 |
# File 'app/models/email_preference.rb', line 33 has_many :contact_points, foreign_key: :detail, primary_key: :email |
#disable_all ⇒ Object
This is to allow the initial state on the form to be selected properly
60 61 62 63 64 65 66 67 |
# File 'app/models/email_preference.rb', line 60 def disable_all disable_promotions && && disable_announcements && disable_events && disable_webinars && disable_reviews end |
#to_s ⇒ Object
159 160 161 |
# File 'app/models/email_preference.rb', line 159 def to_s email end |
#unsubscribed_categories_changes ⇒ Object
163 164 165 166 167 |
# File 'app/models/email_preference.rb', line 163 def unsubscribed_categories_changes saved_changes.select do |k, v| k.starts_with?('disable_') && v.last == true end.keys.map { |k| k.scan(/disable_(.*)/)[0][0].to_sym } end |