docbrown/app/services/mailchimp/bot.rb
Daniel Uber 324265e24e
Handle GibbonError when Mailchimp api key was not set (#14695)
* When an api key was not set - handle gibbon error as mailchimp error

see https://app.honeybadger.io/projects/72638/faults/73753178

It's possible the right answer is instead to either (1) not make the
call at all (2) not log as a mailchimp error but treat distinctly

* Only report error if GibbonError, don't attempt to resubscribe

Separate the rescue blocks since resubscribing doesn't make sense if
we're handling a gibbon error rather than a mailchimp error

* Add test for gibbon error being raised (and rescued)

Copied the existing test specifying that resubscribe is attempted on a
raised mailchimp error.

* Remove irrelevant resubscribe check - assert error is handled only
2021-09-13 10:30:35 -05:00

203 lines
6.1 KiB
Ruby

module Mailchimp
class Bot
attr_reader :user, :saved_changes, :gibbon
def initialize(user)
@user = user
@saved_changes = user.saved_changes
Gibbon::Request.api_key = Settings::General.mailchimp_api_key
Gibbon::Request.timeout = 15
@gibbon = Gibbon::Request.new
end
def upsert
return true unless Rails.env.production? || Rails.env.test?
manage_community_moderator_list
manage_tag_moderator_list
upsert_to_newsletter
end
def upsert_to_newsletter
# attempt to update email if user changed email addresses
success = false
begin
gibbon.lists(Settings::General.mailchimp_newsletter_id).members(target_md5_email).upsert(
body: {
email_address: user.email,
status: user.notification_setting.email_newsletter ? "subscribed" : "unsubscribed",
merge_fields: {
NAME: user.name.to_s,
USERNAME: user.username.to_s,
TWITTER: user.twitter_username.to_s,
GITHUB: user.github_username.to_s,
IMAGE_URL: user.profile_image_url.to_s,
ARTICLES: user.articles.size,
COMMENTS: user.comments.size,
ONBOARD_PK: user.onboarding_package_requested.to_s,
EXPERIENCE: user.setting.experience_level || 666
}
},
)
success = true
rescue Gibbon::GibbonError => e
report_error(e)
rescue Gibbon::MailChimpError => e
# If user was previously subscribed, set their status to "pending"
return resubscribe_to_newsletter if previously_subcribed?(e)
report_error(e)
end
success
end
def resubscribe_to_newsletter
success = false
begin
gibbon.lists(Settings::General.mailchimp_newsletter_id).members(target_md5_email).upsert(
body: { status: "pending" },
)
success = true
rescue Gibbon::MailChimpError => e
report_error(e)
end
success
end
def manage_community_moderator_list
return false unless Settings::General.mailchimp_community_moderators_id.present? && user.has_role?(:trusted)
success = false
status = user.notification_setting.email_community_mod_newsletter ? "subscribed" : "unsubscribed"
begin
gibbon.lists(Settings::General.mailchimp_community_moderators_id).members(target_md5_email).upsert(
body: {
email_address: user.email,
status: status,
merge_fields: {
NAME: user.name.to_s,
USERNAME: user.username.to_s,
TWITTER: user.twitter_username.to_s,
GITHUB: user.github_username.to_s,
IMAGE_URL: user.profile_image_url.to_s
}
},
)
success = true
rescue Gibbon::MailChimpError => e
report_error(e)
end
success
end
def manage_tag_moderator_list
return false unless Settings::General.mailchimp_tag_moderators_id.present? && user.tag_moderator?
success = false
tag_ids = user.roles.where(name: "tag_moderator").pluck(:resource_id)
tag_names = Tag.where(id: tag_ids).pluck(:name)
status = user.notification_setting.email_tag_mod_newsletter ? "subscribed" : "unsubscribed"
begin
gibbon.lists(Settings::General.mailchimp_tag_moderators_id).members(target_md5_email).upsert(
body: {
email_address: user.email,
status: status,
merge_fields: {
NAME: user.name.to_s,
USERNAME: user.username.to_s,
TWITTER: user.twitter_username.to_s,
GITHUB: user.github_username.to_s,
IMAGE_URL: user.profile_image_url.to_s,
TAGS: tag_names.join(", ")
}
},
)
success = true
rescue Gibbon::MailChimpError => e
report_error(e)
end
success
end
def unsub_sustaining_member
return unless Settings::General.mailchimp_sustaining_members_id.present? && a_sustaining_member?
gibbon.lists(Settings::General.mailchimp_sustaining_members_id).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
)
end
def unsub_community_mod
return unless Settings::General.mailchimp_community_moderators_id.present? && user.trusted
gibbon.lists(Settings::General.mailchimp_community_moderators_id).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
)
end
def unsub_tag_mod
return unless Settings::General.mailchimp_tag_moderators_id.present? && user.tag_moderator?
gibbon.lists(Settings::General.mailchimp_tag_moderators_id).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
)
end
def unsubscribe_all_newsletters
success = false
begin
gibbon.lists(Settings::General.mailchimp_newsletter_id).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
)
unsub_tag_mod
unsub_sustaining_member
unsub_community_mod
success = true
rescue Gibbon::MailChimpError => e
report_error(e)
end
success
end
private
def a_sustaining_member?
# Reasoning for including => saved_changes["monthly_dues"]
# Is that mailchimp should be updated if a user decides to
# unsubscribes
user.monthly_dues.positive? || saved_changes["monthly_dues"]
end
def md5_email(email)
Digest::MD5.hexdigest(email.downcase)
end
def report_error(exception)
Rails.logger.error(exception)
ForemStatsClient.increment("mailchimp.errors",
tags: ["action:failed", "user_id:#{user.id}", "source:gibbon-gem"])
end
def target_md5_email
email = saved_changes["unconfirmed_email"] ? saved_changes["email"][0] : user.email
md5_email(email)
end
def previously_subcribed?(error)
error.title.include?("Member In Compliance State")
end
end
end