houdini/lib/mailchimp.rb
Bradley M. Kuhn 6772312ea7 Relicense all .rb files under new project license.
The primary license of the project is changing to:
  AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later

with some specific files to be licensed under the one of two licenses:
   CC0-1.0
   LGPL-3.0-or-later

This commit is one of the many steps to relicense the entire codebase.

Documentation granting permission for this relicensing (from all past
contributors who hold copyrights) is on file with Software Freedom
Conservancy, Inc.
2018-03-25 15:10:40 -04:00

157 lines
5.9 KiB
Ruby

# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
require 'httparty'
require 'digest/md5'
module Mailchimp
include HTTParty
format :json
def self.base_uri(key)
dc = get_datacenter(key)
return "https://#{dc}.api.mailchimp.com/3.0"
end
# Run the configuration from an initializer
# data: {:api_key => String}
def self.config(hash)
@options = {
:headers => {
'Content-Type' => 'application/json',
'Accept' => 'application/json'
}
}
@body = {
:apikey => hash[:api_key]
}
end
# Given a nonprofit mailchimp oauth2 key, return its current datacenter
def self.get_datacenter(key)
metadata = HTTParty.get('https://login.mailchimp.com/oauth2/metadata', {
headers: {
'User-Agent' => 'oauth2-draft-v10',
'Host' => 'login.mailchimp.com',
'Accept' => 'application/json',
'Authorization' => "OAuth #{key}"
}
})
return metadata['dc']
end
def self.signup email, mailchimp_list_id
body_hash = @body.merge({
:id => mailchimp_list_id,
:email => {:email => email}
})
post("/lists/subscribe", @options.merge(:body => body_hash.to_json)).parsed_response
end
def self.get_mailchimp_token(npo_id)
mailchimp_token = QueryNonprofitKeys.get_key(npo_id, 'mailchimp_token')
throw RuntimeError.new("No Mailchimp connection for this nonprofit: #{npo_id}") if mailchimp_token.nil?
return mailchimp_token
end
# Given a nonprofit id and a list of tag master ids that they make into email lists,
# create those email lists on mailchimp and return an array of hashes of mailchimp list ids, names, and tag_master_id
def self.create_mailchimp_lists(npo_id, tag_master_ids)
mailchimp_token = get_mailchimp_token(npo_id)
uri = base_uri(mailchimp_token)
puts "URI #{uri}"
puts "KEY #{mailchimp_token}"
npo = Qx.fetch(:nonprofits, npo_id).first
tags = Qx.select("DISTINCT(tag_masters.name) AS tag_name, tag_masters.id")
.from(:tag_masters)
.where({"tag_masters.nonprofit_id" => npo_id})
.and_where("tag_masters.id IN ($ids)", ids: tag_master_ids)
.join(:nonprofits, "tag_masters.nonprofit_id = nonprofits.id")
.execute
tags.map do |h|
list = post(uri+'/lists', {
basic_auth: {username: '', password: mailchimp_token},
headers: {'Content-Type' => 'application/json'},
body: {
name: 'CommitChange-'+h['tag_name'],
contact: {
company: npo['name'],
address1: npo['address'] || '',
city: npo['city'] || '',
state: npo['state_code'] || '',
zip: npo['zip_code'] || '',
country: npo['state_code'] || '',
phone: npo['phone'] || ''
},
permission_reminder: 'You are a registered supporter of our nonprofit.',
campaign_defaults: {
from_name: npo['name'] || '',
from_email: npo['email'].blank? ? "support@commichange.com" : npo['email'],
subject: "Enter your subject here...",
language: 'en'
},
email_type_option: false,
visibility: 'prv'
}.to_json
})
if list.code != 200
raise Exception.new("Failed to create list: #{list}")
end
{id: list['id'], name: list['name'], tag_master_id: h['id']}
end
end
# Given a nonprofit id and post_data, which is an array of batch operation hashes
# See here: http://developer.mailchimp.com/documentation/mailchimp/guides/how-to-use-batch-operations/
# Perform all the batch operations and return a status report
def self.perform_batch_operations(npo_id, post_data)
return if post_data.empty?
mailchimp_token = get_mailchimp_token(npo_id)
uri = base_uri(mailchimp_token)
batch_job_id = post(uri + '/batches', {
basic_auth: {username: "CommitChange", password: mailchimp_token},
headers: {'Content-Type' => 'application/json'},
body: {operations: post_data}.to_json
})['id']
check_batch_status(npo_id, batch_job_id)
end
def self.check_batch_status(npo_id, batch_job_id)
mailchimp_token = get_mailchimp_token(npo_id)
uri = base_uri(mailchimp_token)
batch_status = get(uri+'/batches/'+batch_job_id, {
basic_auth: {username: "CommitChange", password: mailchimp_token},
headers: {'Content-Type' => 'application/json'}
})
end
def self.delete_mailchimp_lists(npo_id, mailchimp_list_ids)
mailchimp_token = get_mailchimp_token(npo_id)
uri = base_uri(mailchimp_token)
mailchimp_list_ids.map do |id|
delete(uri + "/lists/#{id}", {basic_auth: {username: "CommitChange", password: mailchimp_token}})
end
end
# `removed` and `added` are arrays of tag join ids that have been added or removed to a supporter
def self.sync_supporters_to_list_from_tag_joins(npo_id, supporter_ids, tag_data)
emails = Qx.select(:email).from(:supporters).where("id IN ($ids)", ids: supporter_ids).execute.map{|h| h['email']}
to_add = get_mailchimp_list_ids(tag_data.select{|h| h['selected']}.map{|h| h['tag_master_id']})
to_remove = get_mailchimp_list_ids(tag_data.reject{|h| h['selected']}.map{|h| h['tag_master_id']})
return if to_add.empty? && to_remove.empty?
bulk_post = emails.map{|em| to_add.map{|ml_id| {method: 'POST', path: "lists/#{ml_id}/members", body: {email_address: em, status: 'subscribed'}.to_json}}}.flatten
bulk_delete = emails.map{|em| to_remove.map{|ml_id| {method: 'DELETE', path: "lists/#{ml_id}/members/#{Digest::MD5.hexdigest(em.downcase).to_s}"}}}.flatten
perform_batch_operations(npo_id, bulk_post.concat(bulk_delete))
end
def self.get_mailchimp_list_ids(tag_master_ids)
return [] if tag_master_ids.empty?
to_insert_data = Qx.select("email_lists.mailchimp_list_id")
.from(:tag_masters)
.where("tag_masters.id IN ($ids)", ids: tag_master_ids)
.join("email_lists", "email_lists.tag_master_id=tag_masters.id")
.execute.map{|h| h['mailchimp_list_id']}
end
end