Move MailchimpBot to Mailchimp::Bot service (#12205)
* Move MailchimpBot to Mailchimp::Bot service * Update specs * Put back old Mailchimp Bot
This commit is contained in:
parent
19c9ce96aa
commit
dfeccf6c11
9 changed files with 351 additions and 9 deletions
|
|
@ -500,7 +500,7 @@ class User < ApplicationRecord
|
|||
def unsubscribe_from_newsletters
|
||||
return if email.blank?
|
||||
|
||||
MailchimpBot.new(self).unsubscribe_all_newsletters
|
||||
Mailchimp::Bot.new(self).unsubscribe_all_newsletters
|
||||
end
|
||||
|
||||
def auditable?
|
||||
|
|
|
|||
201
app/services/mailchimp/bot.rb
Normal file
201
app/services/mailchimp/bot.rb
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
module Mailchimp
|
||||
class Bot
|
||||
attr_reader :user, :saved_changes, :gibbon
|
||||
|
||||
def initialize(user)
|
||||
@user = user
|
||||
@saved_changes = user.saved_changes
|
||||
Gibbon::Request.api_key = SiteConfig.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(SiteConfig.mailchimp_newsletter_id).members(target_md5_email).upsert(
|
||||
body: {
|
||||
email_address: user.email,
|
||||
status: user.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.experience_level || 666
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
success = true
|
||||
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(SiteConfig.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 user.has_role?(:trusted)
|
||||
|
||||
success = false
|
||||
status = user.email_community_mod_newsletter ? "subscribed" : "unsubscribed"
|
||||
begin
|
||||
gibbon.lists(SiteConfig.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 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.email_tag_mod_newsletter ? "subscribed" : "unsubscribed"
|
||||
|
||||
begin
|
||||
gibbon.lists(SiteConfig.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 user.tag_moderator?
|
||||
|
||||
gibbon.lists(SiteConfig.mailchimp_tag_moderators_id).members(target_md5_email).update(
|
||||
body: {
|
||||
status: "unsubscribed"
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
def unsub_community_mod
|
||||
return unless user.has_role?(:trusted)
|
||||
|
||||
gibbon.lists(SiteConfig.mailchimp_community_moderators_id).members(target_md5_email).update(
|
||||
body: {
|
||||
status: "unsubscribed"
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
def unsub_tag_mod
|
||||
return unless a_sustaining_member?
|
||||
|
||||
gibbon.lists(SiteConfig.mailchimp_sustaining_members_id).members(target_md5_email).update(
|
||||
body: {
|
||||
status: "unsubscribed"
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
def unsubscribe_all_newsletters
|
||||
success = false
|
||||
begin
|
||||
gibbon.lists(SiteConfig.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)
|
||||
DatadogStatsClient.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
|
||||
|
|
@ -35,14 +35,14 @@ module Moderator
|
|||
@user.remove_role :trusted
|
||||
@user.remove_role :tag_moderator
|
||||
@user.update(email_tag_mod_newsletter: false)
|
||||
MailchimpBot.new(user).manage_tag_moderator_list
|
||||
Mailchimp::Bot.new(user).manage_tag_moderator_list
|
||||
@user.update(email_community_mod_newsletter: false)
|
||||
MailchimpBot.new(user).manage_community_moderator_list
|
||||
Mailchimp::Bot.new(user).manage_community_moderator_list
|
||||
end
|
||||
|
||||
def remove_tag_moderator_role
|
||||
@user.remove_role :tag_moderator
|
||||
MailchimpBot.new(user).manage_tag_moderator_list
|
||||
Mailchimp::Bot.new(user).manage_tag_moderator_list
|
||||
end
|
||||
|
||||
def create_note(reason, content)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ module TagModerators
|
|||
Rails.cache.delete("user-#{user.id}/tag_moderators_list")
|
||||
return unless tag_mod_newsletter_enabled?
|
||||
|
||||
MailchimpBot.new(user).manage_tag_moderator_list
|
||||
Mailchimp::Bot.new(user).manage_tag_moderator_list
|
||||
end
|
||||
|
||||
def tag_mod_newsletter_enabled?
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module TagModerators
|
|||
NotifyMailer.with(user: user).trusted_role_email.deliver_now
|
||||
return unless community_mod_newsletter_enabled?
|
||||
|
||||
MailchimpBot.new(user).manage_community_moderator_list
|
||||
Mailchimp::Bot.new(user).manage_community_moderator_list
|
||||
end
|
||||
|
||||
def self.community_mod_newsletter_enabled?
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module TagModerators
|
|||
Rails.cache.delete("user-#{user.id}/tag_moderators_list")
|
||||
return unless tag_mod_newsletter_enabled?
|
||||
|
||||
MailchimpBot.new(user).manage_tag_moderator_list
|
||||
Mailchimp::Bot.new(user).manage_tag_moderator_list
|
||||
end
|
||||
|
||||
def self.tag_mod_newsletter_enabled?
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module Users
|
|||
def perform(user_id)
|
||||
user = User.find_by(id: user_id)
|
||||
|
||||
MailchimpBot.new(user).upsert if user
|
||||
Mailchimp::Bot.new(user).upsert if user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
141
spec/services/mailchimp/bot_spec.rb
Normal file
141
spec/services/mailchimp/bot_spec.rb
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe Mailchimp::Bot, type: :service do
|
||||
let(:user) { create(:user, :with_newsletters, :ignore_mailchimp_subscribe_callback) }
|
||||
let(:article) { create(:article, user_id: user.id) }
|
||||
let(:my_gibbon_client) { class_double Gibbon::Request }
|
||||
let(:tag) do
|
||||
create(:tag,
|
||||
name: "tagname",
|
||||
bg_color_hex: Faker::Color.hex_color,
|
||||
text_color_hex: Faker::Color.hex_color,
|
||||
supported: true)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(Gibbon::Request).to receive(:new) { my_gibbon_client }
|
||||
allow(my_gibbon_client).to receive(:lists) { my_gibbon_client }
|
||||
allow(my_gibbon_client).to receive(:tag_mods) { my_gibbon_client }
|
||||
allow(my_gibbon_client).to receive(:community_mods) { my_gibbon_client }
|
||||
allow(my_gibbon_client).to receive(:members) { my_gibbon_client }
|
||||
allow(my_gibbon_client).to receive(:upsert).and_return(true)
|
||||
end
|
||||
|
||||
def matcher
|
||||
{
|
||||
body: {
|
||||
email_address: user.email,
|
||||
status: "subscribed",
|
||||
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.experience_level || 666
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
describe "#upsert" do
|
||||
it "works" do
|
||||
described_class.new(user).upsert
|
||||
expect(my_gibbon_client).to have_received(:upsert)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#upsert_to_newsletter" do
|
||||
it "sends proper information" do
|
||||
described_class.new(user).upsert_to_newsletter
|
||||
expect(my_gibbon_client).to have_received(:upsert).with(matcher)
|
||||
end
|
||||
|
||||
it "unsubscribes properly" do
|
||||
user.update(email_newsletter: false)
|
||||
described_class.new(user).upsert_to_newsletter
|
||||
expect(my_gibbon_client).to have_received(:upsert)
|
||||
.with(hash_including(body: hash_including(status: "unsubscribed")))
|
||||
end
|
||||
|
||||
it "subscribes properly" do
|
||||
user.update(email_newsletter: false)
|
||||
user.update(email_newsletter: true)
|
||||
described_class.new(user).upsert_to_newsletter
|
||||
expect(my_gibbon_client).to have_received(:upsert)
|
||||
.with(hash_including(body: hash_including(status: "subscribed")))
|
||||
end
|
||||
|
||||
it "updates email properly" do
|
||||
user.update(email: Faker::Internet.email)
|
||||
user.confirm
|
||||
described_class.new(user).upsert_to_newsletter
|
||||
expect(my_gibbon_client).to have_received(:upsert)
|
||||
.with(hash_including(body: hash_including(email_address: user.email)))
|
||||
end
|
||||
|
||||
it "tries to resubscribe the user if the user has previously been subscribed" do
|
||||
user.update(email_newsletter: false)
|
||||
mailchimp_bot = described_class.new(user)
|
||||
mc_error =
|
||||
Gibbon::MailChimpError.new("Error", status_code: 400, title: "Member In Compliance State")
|
||||
allow(mailchimp_bot.gibbon).to receive(:upsert).and_raise(mc_error)
|
||||
allow(mailchimp_bot).to receive(:resubscribe_to_newsletter)
|
||||
|
||||
mailchimp_bot.upsert_to_newsletter
|
||||
|
||||
expect(mailchimp_bot).to have_received(:resubscribe_to_newsletter)
|
||||
end
|
||||
end
|
||||
|
||||
describe "manage community moderator list" do
|
||||
it "returns false if user isn't a community moderator" do
|
||||
expect(described_class.new(user).manage_community_moderator_list).to be(false)
|
||||
end
|
||||
|
||||
it "sends proper information" do
|
||||
user.update(email_community_mod_newsletter: true)
|
||||
user.add_role :trusted
|
||||
described_class.new(user).manage_community_moderator_list
|
||||
expect(my_gibbon_client).to have_received(:upsert)
|
||||
.with(hash_including(
|
||||
body: hash_including(
|
||||
status: "subscribed",
|
||||
),
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
describe "manage tag moderator list" do
|
||||
it "returns false if user isn't a tag moderator" do
|
||||
expect(described_class.new(user).manage_community_moderator_list).to be(false)
|
||||
end
|
||||
|
||||
it "sends proper information" do
|
||||
user.update(email_tag_mod_newsletter: true)
|
||||
user.add_role(:tag_moderator, tag)
|
||||
described_class.new(user).manage_tag_moderator_list
|
||||
expect(my_gibbon_client).to have_received(:upsert)
|
||||
.with(hash_including(
|
||||
body: hash_including(
|
||||
status: "subscribed",
|
||||
),
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
describe "#unsubscribe_all_newsletters" do
|
||||
context "when called" do
|
||||
before { allow(my_gibbon_client).to receive(:update).and_return(true) }
|
||||
|
||||
it "unsubscribes the user from the weekly newsletter" do
|
||||
described_class.new(user).unsubscribe_all_newsletters
|
||||
expect(my_gibbon_client).to have_received(:update)
|
||||
.with(hash_including(body: hash_including(status: "unsubscribed")))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -9,7 +9,7 @@ RSpec.describe Users::SubscribeToMailchimpNewsletterWorker, type: :worker do
|
|||
|
||||
it "subscribes user to mailchimp newsletter" do
|
||||
mailchimp_bot = double
|
||||
allow(MailchimpBot).to receive(:new).and_return(mailchimp_bot)
|
||||
allow(Mailchimp::Bot).to receive(:new).and_return(mailchimp_bot)
|
||||
allow(mailchimp_bot).to receive(:upsert)
|
||||
|
||||
worker.perform(user.id)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue