From 9d4925dc784229fe5af10feed95e8803f2b9e571 Mon Sep 17 00:00:00 2001 From: Eric Schultz Date: Wed, 24 Oct 2018 11:36:02 -0500 Subject: [PATCH] Can hard sync a mailchimp list --- app/models/email_list.rb | 5 ++++ app/models/tag_join.rb | 1 + app/models/tag_master.rb | 1 + lib/mailchimp.rb | 56 +++++++++++++++++++++++++++++++++++ spec/factories/email_lists.rb | 5 ++++ spec/lib/mailchimp_spec.rb | 47 +++++++++++++++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 app/models/email_list.rb create mode 100644 spec/factories/email_lists.rb create mode 100644 spec/lib/mailchimp_spec.rb diff --git a/app/models/email_list.rb b/app/models/email_list.rb new file mode 100644 index 00000000..1d148f22 --- /dev/null +++ b/app/models/email_list.rb @@ -0,0 +1,5 @@ +class EmailList < ActiveRecord::Base + attr_accessible :list_name, :mailchimp_list_id + belongs_to :nonprofit + belongs_to :tag_master +end diff --git a/app/models/tag_join.rb b/app/models/tag_join.rb index bcaad420..5f0e402a 100644 --- a/app/models/tag_join.rb +++ b/app/models/tag_join.rb @@ -8,6 +8,7 @@ class TagJoin < ActiveRecord::Base validates :tag_master, presence: true belongs_to :tag_master + belongs_to :supporter def name; self.tag_master.name; end diff --git a/app/models/tag_master.rb b/app/models/tag_master.rb index 70272a56..6e9f0ffd 100644 --- a/app/models/tag_master.rb +++ b/app/models/tag_master.rb @@ -12,6 +12,7 @@ class TagMaster < ActiveRecord::Base belongs_to :nonprofit has_many :tag_joins, dependent: :destroy + has_one :email_list scope :not_deleted, ->{where(deleted: [nil,false])} diff --git a/lib/mailchimp.rb b/lib/mailchimp.rb index f8f2c129..03460de7 100644 --- a/lib/mailchimp.rb +++ b/lib/mailchimp.rb @@ -154,4 +154,60 @@ module Mailchimp .execute.map{|h| h['mailchimp_list_id']} end + + # @param [Nonprofit] nonprofit + def self.hard_sync_lists(nonprofit) + return if !nonprofit + + nonprofit.tag_masters.not_deleted.each do |i| + if (i.email_list) + hard_sync_list(i.email_list) + end + end + end + + # @param [EmailList] email_list + def self.hard_sync_list(email_list) + ops = generate_batch_ops_for_hard_sync(email_list) + perform_batch_operations(email_list.nonprofit.id, ops) + + end + + def self.generate_batch_ops_for_hard_sync(email_list) + #get the subscribers from mailchimp + mailchimp_subscribers = get_list_mailchimp_subscribers(email_list) + #get our subscribers + our_supporters = email_list.tag_master.tag_joins.map{|i| i.supporter} + + #split them as follows: + # on both lists, on our list, on the mailchimp list + in_both, in_mailchimp_only = mailchimp_subscribers.partition do |mc_sub| + our_supporters.any?{|s| s.email.downcase == mc_sub[:email_address].downcase} + end + + _, in_our_side_only = our_supporters.partition do |s| + mailchimp_subscribers.any?{|mc_sub| s.email.downcase == mc_sub[:email_address].downcase} + end + + # if on our list, add to mailchimp + output = in_our_side_only.map{|i| + {method: 'POST', path: "lists/#{email_list.mailchimp_list_id}/members", body: {email_address: i.email, status: 'subscribed'}.to_json} + } + + # if on mailchimp list, delete from mailchimp + output = output.concat(in_mailchimp_only.map{|i| {method: 'DELETE', path: "lists/#{email_list.mailchimp_list_id}/members/#{i[:id]}"}}) + + return output + end + + def self.get_list_mailchimp_subscribers(email_list) + mailchimp_token = get_mailchimp_token(email_list.tag_master.nonprofit.id) + uri = base_uri(mailchimp_token) + result = get(uri + "/lists/#{email_list.mailchimp_list_id}/members", { + basic_auth: {username: "CommitChange", password: mailchimp_token}, + headers: {'Content-Type' => 'application/json'}}) + members = result['members'].map do |i| + {id: i['id'], email_address: i['email_address']} + end.to_a + end end diff --git a/spec/factories/email_lists.rb b/spec/factories/email_lists.rb new file mode 100644 index 00000000..677617be --- /dev/null +++ b/spec/factories/email_lists.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :email_list do + + end +end diff --git a/spec/lib/mailchimp_spec.rb b/spec/lib/mailchimp_spec.rb new file mode 100644 index 00000000..f710e70b --- /dev/null +++ b/spec/lib/mailchimp_spec.rb @@ -0,0 +1,47 @@ +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +require 'rails_helper' + +describe Mailchimp do + describe '.hard_sync_list' do + let(:ret_val) { [{id: 'on_both', email_address: 'on_both@email.com'}, + {id: 'on_mailchimp', email_address: 'on_mailchimp@email.com'}]} + + let(:np) { force_create(:nonprofit)} + let(:tag_master) {force_create(:tag_master, nonprofit: np)} + let(:email_list) {force_create(:email_list, mailchimp_list_id: 'list_id', tag_master: tag_master, nonprofit:np, list_name: "temp")} + let(:supporter_on_both) { force_create(:supporter, nonprofit:np, email: 'on_BOTH@email.com')} + let(:supporter_on_local) { force_create(:supporter, nonprofit:np, email: 'on_local@email.com')} + let(:tag_join) {force_create(:tag_join, tag_master: tag_master, supporter: supporter_on_both)} + + let(:tag_join2) {force_create(:tag_join, tag_master: tag_master, supporter: supporter_on_local)} + + + it 'excepts when excepting' do + expect(Mailchimp).to receive(:get_list_mailchimp_subscribers).with(email_list).and_raise + + expect{ Mailchimp.generate_batch_ops_for_hard_sync(email_list)}.to raise_error + end + + it 'passes' do + tag_join + tag_join2 + email_list + + expect(Mailchimp).to receive(:get_list_mailchimp_subscribers).with(email_list).and_return(ret_val) + + result = Mailchimp.generate_batch_ops_for_hard_sync(email_list) + + expect(result).to contain_exactly( + { + method: 'POST', + path: 'lists/list_id/members', + body: {email_address: supporter_on_local.email, status: 'subscribed'}.to_json + }, + { + method: 'DELETE', + path: 'lists/list_id/members/on_mailchimp' + }) + end + end + +end