Skip to content

Instantly share code, notes, and snippets.

@soulcutter
Last active August 29, 2015 14:20
Show Gist options
  • Save soulcutter/88b84dbda99a44ed02d3 to your computer and use it in GitHub Desktop.
Save soulcutter/88b84dbda99a44ed02d3 to your computer and use it in GitHub Desktop.
Toggling interest groups in list subscriptions in MailChimp's v2.0 API
require "active_support/core_ext"
require "delegate"
require "mailchimp"
require "singleton"
class MailingList::MailChimp
attr_reader :user, :member_info
def initialize(user, member_fetcher = member_info_api)
@user = user
@member_info = member_fetcher
@mailchimp = nil # lazily instantiated
end
def subscribed_to?(list)
member_info[list]["status"] == "subscribed"
end
def interested_in?(list:, grouping:, group:)
!!member_info[list]["merges"]["GROUPINGS"]
.find { |x| grouping.match x["name"] }["groups"]
.find { |x| group.match x["name"] }["interested"].presence
end
def subscribe_to(list, interest_groups: {})
# returns something like: {"email"=>"[email protected]", "euid"=>"5a9245aad2", "leid"=>"35566593"}
mailchimp.lists.subscribe(
list_id(list),
{ "email" => user.email },
merge_vars(list, interest_groups),
"html",
send_double_optin_message = false,
update_existing_subscriber = true,
replace_interest_groups = true,
send_welcome_email = true,
)
rescue Mailchimp::ListAlreadySubscribedError => e
# this should not happen because `update_existing_subscriber = true`
# but just in case... do nothing
rescue Mailchimp::ListInvalidInterestGroupError => e
NewRelic::Agent.notice_error e
Rails.logger.tagged("Mailchimp API") { |logger| logger.warn e }
ensure
invalidate_cache(list)
end
def unsubscribe_to(list)
# returns something like: {"complete"=>true}
mailchimp.lists.unsubscribe(
list_id(list),
{ "email" => user.email },
completely_delete_member = true,
send_goodbye_email = true,
send_unsubscribe_notice = true
)
rescue Mailchimp::EmailNotExistsError
# do nothing
ensure
invalidate_cache(list)
end
def merge_vars(list, interest_groups)
{
"FNAME" => user.first_name,
"LNAME" => user.last_name,
"groupings" => groupings_with(interest_groups, list: list)
}.tap do |hash|
Rails.logger.tagged("mailchimp", "MERGE VARS") { |log| log.debug hash.inspect }
end
end
def groupings_with(interest_groups, list: )
interest_groups = Hash(interest_groups)
groupings = member_info[list]["merges"]["GROUPINGS"].presence
groupings = flatten_interests(Array(groupings))
merge_groupings(groupings, interest_groups)
end
private
def mailchimp
@mailchimp ||= Mailchimp::API.new(Settings.mailchimp.api_key)
end
def member_info_api
Hash.new do |h, list|
response = mailchimp.lists.member_info(list_id(list), [{ email: user.email }])
response = SafeResponse.new(response)
h[list] = response["data"].first
end
end
def list_id(list)
Settings["mailchimp"].try(:[], "lists").try(:[], list.to_s)
end
def invalidate_cache(list)
member_info.delete(list)
end
def flatten_interests(groupings)
groupings.each_with_object([]) do |grouping, new_groupings|
active_interests = groups = []
Array(grouping["groups"]).each do |group|
active_interests << group["name"] if group["interested"]
end
new_groupings << { "name" => grouping["name"], "groups" => groups }
end
end
def merge_groupings(groupings, interest_groups)
interest_groups.each do |group, interests|
grouping = groupings.find { |x| x["name"] == group }
if grouping.nil?
grouping = { "name" => group, "groups" => [] }
groupings << grouping
end
interests.each do |interest_hash|
interest_name = interest_hash["name"]
is_interested = interest_hash["interested"]
if is_interested
grouping["groups"] << interest_name
else
grouping["groups"].delete(interest_name)
end
end
grouping["groups"].uniq!
end
groupings
end
class SafeResponse < SimpleDelegator
def self.safe_delegate(*methods)
methods.each do |method|
define_method(method, ->(*args, &block) {
value = __getobj__.send(method, *args, &block)
value.nil? ? BlackHole.instance : SafeResponse.new(value)
})
end
end
safe_delegate :[]
safe_delegate :detect, :find, :first, :select
end
class BlackHole
include Singleton
def itself; self end # TODO remove when upgrading to Ruby 2.2+
[:detect, :find, :first, :select].each do |method|
alias_method method, :itself
end
def [](*); self end
def blank?; true end
def empty?; true end
def presence; nil end
def present?; false end
def nil?; true end
end
end
# user must have #email #first_name and #last_name for everything to work
list = MailingList::MailChimp.new(user)
list.subscribe_to(:mailing_list, { "grouping name" => [{ "name" => "group name", "interested" => true}]
list.interested_in? :mailing_list, grouping: "grouping name", group: "group name" # => true
list.subscribe_to(:mailing_list, { "grouping name" => [{ "name" => "group name", "interested" => false}]
list.interested_in? :mailing_list, grouping: "grouping name", group: "group name" # => false
list.unsubscribe_to :mailing_list
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment