effective_mailchimp 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3b3306349bc71e4dcd895a1be96411b94e82c76155972d5ee73ad302487fa5d
4
- data.tar.gz: 590439bc94cc48d34586b14eeba77476e5fc715ee32118a973c640fdc25e6def
3
+ metadata.gz: 56caa6a3804ed54f997cb2a732022cb077c37ec186f2a42476b2433b59f80bab
4
+ data.tar.gz: 51a5b095d91881d957c227c6f13155d78d3a9178aa3703982cf2fd4b8d92cd37
5
5
  SHA512:
6
- metadata.gz: 59eab329289651cd579828198bafbad8093aa94e452866f6dc2a51b5a787a7b077e57d644e5caa7cf91b868d12db82bdb28284680e7a3608f216c7bbbd4e73ad
7
- data.tar.gz: fc0bbcadfffd0caae215be540ad150bf588264ae7ee013b4a4cbe8d0ea7064fe603d4f9bd4abfe70c6ef341d931d5e1ec1bed60f15735f5603f777e54c827d1a
6
+ metadata.gz: 246b57c7659cbb154db572309d4a886132cef6cdf9d1bd09e4cafd37fd15dfc2d109375a2c179173bf710c478fb71306b1dc69a0c57587a6d66c4286edf6b446
7
+ data.tar.gz: 578e421f5e538bc705fcc0a4ab8290cd0adc4fae51388ddf941f934bbd4ea2c069eb13530d96c789ed4c8110d2e4ca5960a8274a1ae154e58cc30971a8722f3f
@@ -16,9 +16,7 @@ module Admin
16
16
  EffectiveResources.authorize!(self, :admin, :mailchimp_sync)
17
17
 
18
18
  api = EffectiveMailchimp.api
19
- merge_fields = current_user.class.new().mailchimp_merge_fields
20
-
21
- Effective::MailchimpList.sync!(api: api, merge_fields: merge_fields)
19
+ Effective::MailchimpList.sync!(api: api)
22
20
  Effective::MailchimpCategory.sync!(api: api)
23
21
  Effective::MailchimpInterest.sync!(api: api)
24
22
 
@@ -31,6 +31,10 @@ module Admin
31
31
  ml.merge_fields.join(', ')
32
32
  end
33
33
 
34
+ col :member_count do |list|
35
+ list.member_count.to_i
36
+ end
37
+
34
38
  actions_col
35
39
  end
36
40
 
@@ -0,0 +1,8 @@
1
+ class EffectiveMailchimpSubscribeAllMembersJob < ApplicationJob
2
+
3
+ def perform(mailchimp_list)
4
+ raise('expected an Effective::MailchimpList') unless mailchimp_list.kind_of?(Effective::MailchimpList)
5
+ mailchimp_list.subscribe_all_members!(now: true)
6
+ end
7
+
8
+ end
@@ -0,0 +1,8 @@
1
+ class EffectiveMailchimpSubscribeAllUsersJob < ApplicationJob
2
+
3
+ def perform(mailchimp_list)
4
+ raise('expected an Effective::MailchimpList') unless mailchimp_list.kind_of?(Effective::MailchimpList)
5
+ mailchimp_list.subscribe_all_users!(now: true)
6
+ end
7
+
8
+ end
@@ -59,12 +59,13 @@ module EffectiveMailchimpUser
59
59
  member.assign_attributes(subscribed: subscribed)
60
60
  end
61
61
 
62
- # This sets up the after_commit to run the mailchimp_update! job
63
- assign_attributes(mailchimp_user_form_action: true)
64
-
65
62
  # For use in a rake task. Run the update right now
66
- mailchimp_update! if now
63
+ if now
64
+ return mailchimp_update!(only: mailchimp_lists)
65
+ end
67
66
 
67
+ # This sets up the after_commit to run the mailchimp_update! job
68
+ assign_attributes(mailchimp_user_form_action: true)
68
69
  save!
69
70
  end
70
71
 
@@ -173,8 +174,7 @@ module EffectiveMailchimpUser
173
174
  # Pulls the current status from Mailchimp API into the Mailchimp List Member objects
174
175
  # Run before the mailchimp fields are displayed
175
176
  # Only run in the background when a user or admin clicks sync now
176
- def mailchimp_sync!
177
- api = EffectiveMailchimp.api
177
+ def mailchimp_sync!(api: EffectiveMailchimp.api)
178
178
  lists = Effective::MailchimpList.subscribable.sorted.to_a
179
179
 
180
180
  assign_attributes(mailchimp_user_form_action: nil)
@@ -198,12 +198,13 @@ module EffectiveMailchimpUser
198
198
 
199
199
  # Pushes the current Mailchimp List Member objects to Mailchimp when needed
200
200
  # Called in the background after a form submission that changes the user email/last_name/first_name or mailchimp subscriptions
201
- def mailchimp_update!
202
- api = EffectiveMailchimp.api
203
-
201
+ def mailchimp_update!(api: EffectiveMailchimp.api, only: [], except: [])
204
202
  assign_attributes(mailchimp_user_form_action: nil)
205
203
 
206
204
  mailchimp_list_members.each do |member|
205
+ next if only.present? && Array(only).exclude?(member.mailchimp_list)
206
+ next if except.present? && Array(except).include?(member.mailchimp_list)
207
+
207
208
  begin
208
209
  list_member = if member.mailchimp_id.blank? && member.subscribed?
209
210
  api.list_member_add(member)
@@ -25,6 +25,10 @@ module Effective
25
25
  Rails.env.development?
26
26
  end
27
27
 
28
+ def sandbox_mode?
29
+ EffectiveMailchimp.sandbox_mode?
30
+ end
31
+
28
32
  def admin_url
29
33
  "https://#{server}.admin.mailchimp.com"
30
34
  end
@@ -56,27 +60,27 @@ module Effective
56
60
  # Returns an Array of Lists, which are each Hash
57
61
  # Like this [{ ...}, { ... }]
58
62
  def lists
59
- Rails.logger.info "[effective_mailchimp] Index Lists..." if debug?
63
+ Rails.logger.info "[effective_mailchimp] Index Lists" if debug?
60
64
 
61
65
  response = client.lists.get_all_lists(count: 250)
62
66
  Array(response['lists']) - [nil, '', {}]
63
67
  end
64
68
 
65
69
  def list(id)
66
- Rails.logger.info "[effective_mailchimp] Show List..." if debug?
70
+ Rails.logger.info "[effective_mailchimp] Get List" if debug?
67
71
 
68
72
  client.lists.get_list(id.try(:mailchimp_id) || id)
69
73
  end
70
74
 
71
75
  def categories(list_id)
72
- Rails.logger.info "[effective_mailchimp] Index Interest Categories..." if debug?
76
+ Rails.logger.info "[effective_mailchimp] Index Interest Categories" if debug?
73
77
 
74
78
  response = client.lists.get_list_interest_categories(list_id.try(:mailchimp_id) || list_id)
75
79
  Array(response['categories']) - [nil, '', {}]
76
80
  end
77
81
 
78
82
  def interests(list_id, category_id)
79
- Rails.logger.info "[effective_mailchimp] Index Interest Category Interests..." if debug?
83
+ Rails.logger.info "[effective_mailchimp] Index Interest Category Interests" if debug?
80
84
 
81
85
  response = client.lists.list_interest_category_interests(list_id, category_id)
82
86
  Array(response['interests']) - [nil, '', {}]
@@ -85,6 +89,8 @@ module Effective
85
89
  def list_member(id, email)
86
90
  raise('expected an email') unless email.to_s.include?('@')
87
91
 
92
+ Rails.logger.info "[effective_mailchimp] Get List Member" if debug?
93
+
88
94
  begin
89
95
  client.lists.get_list_member(id.try(:mailchimp_id) || id, email)
90
96
  rescue MailchimpMarketing::ApiError => e
@@ -93,18 +99,24 @@ module Effective
93
99
  end
94
100
 
95
101
  def list_merge_fields(id)
102
+ Rails.logger.info "[effective_mailchimp] Get List Merge Fields" if debug?
103
+
96
104
  response = client.lists.get_list_merge_fields(id.try(:mailchimp_id) || id, count: 100)
97
- Array(response['merge_fields']) - [nil, '', {}]
105
+ Array(response['merge_fields']) - [nil, '', ' ', {}]
98
106
  end
99
107
 
100
108
  def add_merge_field(id, name:, type: :text)
101
109
  raise("invalid mailchimp merge key: #{name}. Must be 10 or fewer characters") if name.to_s.length > 10
102
110
 
111
+ return if sandbox_mode?
112
+ Rails.logger.info "[effective_mailchimp] Add List Merge Field #{name}" if debug?
113
+
103
114
  payload = { name: name.to_s.titleize, tag: name.to_s, type: type }
104
115
 
105
116
  begin
106
117
  client.lists.add_list_merge_field(id.try(:mailchimp_id) || id, payload)
107
118
  rescue MailchimpMarketing::ApiError => e
119
+ EffectiveLogger.error(e.message, details: name.to_s) if defined?(EffectiveLogger)
108
120
  false
109
121
  end
110
122
  end
@@ -112,9 +124,18 @@ module Effective
112
124
  def list_member_add(member)
113
125
  raise('expected an Effective::MailchimpListMember') unless member.kind_of?(Effective::MailchimpListMember)
114
126
 
127
+ return if sandbox_mode?
128
+ Rails.logger.info "[effective_mailchimp] Add List Member" if debug?
129
+
130
+ # See if they exist somehow
115
131
  existing = list_member(member.mailchimp_list, member.user.email)
116
- return existing if existing.present?
117
132
 
133
+ if existing.present?
134
+ member.assign_attributes(mailchimp_id: existing['id'])
135
+ return list_member_update(member)
136
+ end
137
+
138
+ # Actually add
118
139
  payload = list_member_payload(member)
119
140
  client.lists.add_list_member(member.mailchimp_list.mailchimp_id, payload)
120
141
  end
@@ -122,6 +143,9 @@ module Effective
122
143
  def list_member_update(member)
123
144
  raise('expected an Effective::MailchimpListMember') unless member.kind_of?(Effective::MailchimpListMember)
124
145
 
146
+ return if sandbox_mode?
147
+ Rails.logger.info "[effective_mailchimp] Update List Member" if debug?
148
+
125
149
  payload = list_member_payload(member)
126
150
  client.lists.update_list_member(member.mailchimp_list.mailchimp_id, member.email, payload)
127
151
  end
@@ -25,7 +25,8 @@ module Effective
25
25
  scope :sorted, -> { order(:name) }
26
26
  scope :subscribable, -> { all }
27
27
 
28
- # Creates or builds all the Lists
28
+ # Reads all the InterestCategories from Mailchimp and creates local MailchimpCategory records
29
+ # This is part of the Sync changes from Mailchimp button
29
30
  def self.sync!(api: EffectiveMailchimp.api)
30
31
  # For every mailchimp_list, get all the categories
31
32
  mailchimp_lists = Effective::MailchimpList.all
@@ -33,7 +33,8 @@ module Effective
33
33
  scope :sorted, -> { order(:display_order) }
34
34
  scope :subscribable, -> { where(can_subscribe: true) }
35
35
 
36
- # Creates or builds all the Lists
36
+ # Reads all the InterestCategoriesInterests from Mailchimp and creates local MailchimpInterest records
37
+ # This is part of the Sync changes from Mailchimp button
37
38
  def self.sync!(api: EffectiveMailchimp.api)
38
39
  # For every mailchimp_list, get all the interests
39
40
  mailchimp_lists = Effective::MailchimpList.deep.all
@@ -22,8 +22,10 @@ module Effective
22
22
  scope :sorted, -> { order(:name) }
23
23
  scope :subscribable, -> { where(can_subscribe: true) }
24
24
 
25
- # Creates or builds all the Lists
26
- def self.sync!(api: EffectiveMailchimp.api, merge_fields: nil)
25
+ # Reads all the Lists from Mailchimp and creates local MailchimpList records
26
+ # Also writes our merge fields to Mailchimp if they don't exist
27
+ # This is part of the Sync changes from Mailchimp button
28
+ def self.sync!(api: EffectiveMailchimp.api)
27
29
  # All the Lists from Mailchimp
28
30
  lists = api.lists()
29
31
 
@@ -40,6 +42,7 @@ module Effective
40
42
 
41
43
  web_id: list['web_id'],
42
44
  name: list['name'],
45
+ member_count: (list.dig('stats', 'member_count') || 0),
43
46
  updated_at: Time.zone.now
44
47
  )
45
48
 
@@ -54,21 +57,34 @@ module Effective
54
57
  end
55
58
 
56
59
  # Sync merge fields
57
- if merge_fields.present?
60
+ if (merge_fields = EffectiveMailchimp.merge_fields).present?
58
61
  merge_field_keys = merge_fields.keys.map(&:to_s)
59
62
 
60
63
  mailchimp_lists.reject(&:destroyed?).each do |mailchimp_list|
61
64
  existing = api.list_merge_fields(mailchimp_list).map { |hash| hash['tag'] }
62
- (merge_field_keys - existing).each do |name|
63
- puts "Adding merge field #{name} to #{mailchimp_list}"
64
- api.add_merge_field(mailchimp_list, name: name)
65
- end
65
+ (merge_field_keys - existing).each { |name| api.add_merge_field(mailchimp_list, name: name) }
66
66
  end
67
67
  end
68
68
 
69
69
  true
70
70
  end
71
71
 
72
+ def subscribe_all_users!(now: false)
73
+ if now
74
+ subscribe_all!(EffectiveMailchimp.User.all)
75
+ else
76
+ EffectiveMailchimpSubscribeAllUsersJob.perform_later(self)
77
+ end
78
+ end
79
+
80
+ def subscribe_all_members!(now: false)
81
+ if now
82
+ subscribe_all!(EffectiveMailchimp.User.all.members)
83
+ else
84
+ EffectiveMailchimpSubscribeAllMembersJob.perform_later(self)
85
+ end
86
+ end
87
+
72
88
  def to_s
73
89
  name.presence || model_name.human
74
90
  end
@@ -94,5 +110,21 @@ module Effective
94
110
  EffectiveMailchimp.api.admin_url + "/lists/settings/merge-tags?id=#{web_id}"
95
111
  end
96
112
 
113
+ private
114
+
115
+ def subscribe_all!(users)
116
+ users.find_each do |user|
117
+ begin
118
+ user.mailchimp_subscribe!(self, subscribed: true, now: true)
119
+ rescue => e
120
+ EffectiveLogger.error(e.message, associated: user) if defined?(EffectiveLogger)
121
+ ExceptionNotifier.notify_exception(e, data: { user_id: user.id, mailchimp_list_id: id }) if defined?(ExceptionNotifier)
122
+ raise(e) if Rails.env.test? || Rails.env.development?
123
+ end
124
+ end
125
+
126
+ true
127
+ end
128
+
97
129
  end
98
130
  end
@@ -20,14 +20,13 @@
20
20
  = link_to('campaigns', EffectiveMailchimp.api.campaigns_url, target: '_blank')
21
21
  at anytime.
22
22
 
23
- %p.text-muted
24
- %small
25
- To change the names or display order of items below, please visit the Mailchimp website then sync changes.
26
- %br
27
- This operation also creates the audience merge fields and updates the subscriber counts for each group below.
23
+ %p To change the names or display order of items below, please visit the Mailchimp website then sync changes.
28
24
 
29
25
  = render('admin/mailchimp/sync')
30
26
 
27
+ %p.text-muted
28
+ %small This operation also creates the audience merge fields and updates the member and subscriber counts below.
29
+
31
30
  = collapse('More settings') do
32
31
  %p
33
32
  For more information see
@@ -44,7 +43,7 @@
44
43
  %p The following merge fields are sent to Mailchimp when a user subscribes:
45
44
 
46
45
  %ul
47
- - current_user.mailchimp_merge_fields.keys.sort.each do |key|
46
+ - EffectiveMailchimp.merge_fields.keys.sort.each do |key|
48
47
  %li= key
49
48
 
50
49
  .mb-4
@@ -60,7 +59,7 @@
60
59
  Press the Edit button to change the Can Subscribe and Force Subscribe settings.
61
60
 
62
61
  - datatable = Admin::EffectiveMailchimpListsDatatable.new
63
- = render_datatable(datatable, simple: true, inline: true)
62
+ = render_datatable(datatable, inline: true, short: true, search: false, sort: false)
64
63
 
65
64
  = card(Effective::MailchimpCategory) do
66
65
  %p
@@ -76,5 +75,5 @@
76
75
  - Effective::MailchimpCategory.all.each do |mailchimp_category|
77
76
  = card(mailchimp_category.to_s) do
78
77
  - datatable = Admin::EffectiveMailchimpInterestsDatatable.new(mailchimp_category: mailchimp_category)
79
- = render_datatable(datatable, simple: true, inline: true)
78
+ = render_datatable(datatable, inline: true, short: true, search: false, sort: false)
80
79
 
@@ -5,4 +5,10 @@ EffectiveMailchimp.setup do |config|
5
5
 
6
6
  # Mailchimp Settings
7
7
  config.api_key = '' # From mailchimp's /account/api/ screen
8
+
9
+ # In Sandbox Mode you can only READ from Mailchimp not actually write to it
10
+ config.sandbox_mode = false
11
+
12
+ # Assign the User class name. For use in determining all merge_fields
13
+ # config.user_class_name = 'User'
8
14
  end
data/config/routes.rb CHANGED
@@ -13,7 +13,11 @@ EffectiveMailchimp::Engine.routes.draw do
13
13
  end
14
14
 
15
15
  namespace :admin do
16
- resources :mailchimp_lists, only: [:index, :edit, :update]
16
+ resources :mailchimp_lists, only: [:index, :edit, :update] do
17
+ post :subscribe_all_users, on: :member
18
+ post :subscribe_all_members, on: :member
19
+ end
20
+
17
21
  resources :mailchimp_interests, only: [:index, :edit, :update]
18
22
  resources :mailchimp_categories, only: :index
19
23
  resources :mailchimp_list_members, only: :index
@@ -5,6 +5,8 @@ class CreateEffectiveMailchimp < ActiveRecord::Migration[6.0]
5
5
  t.string :web_id
6
6
  t.string :name
7
7
 
8
+ t.integer :member_count
9
+
8
10
  t.boolean :can_subscribe
9
11
  t.boolean :force_subscribe
10
12
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveMailchimp
2
- VERSION = '0.7.0'.freeze
2
+ VERSION = '0.8.0'.freeze
3
3
  end
@@ -9,7 +9,7 @@ module EffectiveMailchimp
9
9
  [
10
10
  :mailchimp_lists_table_name, :mailchimp_list_members_table_name, :mailchimp_categories_table_name, :mailchimp_interests_table_name,
11
11
  :layout,
12
- :api_key
12
+ :api_key, :sandbox_mode, :user_class_name
13
13
  ]
14
14
  end
15
15
 
@@ -19,6 +19,10 @@ module EffectiveMailchimp
19
19
  Effective::MailchimpApi.new(api_key: api_key)
20
20
  end
21
21
 
22
+ def self.sandbox_mode?
23
+ !!sandbox_mode
24
+ end
25
+
22
26
  def self.api_present?
23
27
  api_key.present?
24
28
  end
@@ -27,6 +31,23 @@ module EffectiveMailchimp
27
31
  api_key.blank?
28
32
  end
29
33
 
34
+ def self.User
35
+ klass = user_class_name.constantize if user_class_name.present?
36
+ klass ||= Tenant.User if defined?(Tenant)
37
+ klass ||= '::User'.safe_constantize
38
+
39
+ raise('unable to determine User klass. Please set config.user_class_name') unless klass.kind_of?(Class)
40
+ raise('expecting an effective_mailchimp_user User class') unless klass.respond_to?(:effective_mailchimp_user)
41
+
42
+ klass
43
+ end
44
+
45
+ def self.merge_fields
46
+ merge_fields = self.User().new.mailchimp_merge_fields
47
+ raise('expected a Hash of merge fields') unless merge_fields.kind_of?(Hash)
48
+ merge_fields
49
+ end
50
+
30
51
  def self.permitted_params
31
52
  [ :mailchimp_user_form_action, mailchimp_list_members_attributes: [:id, :mailchimp_list_id, :subscribed, interests: []] ]
32
53
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_mailchimp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-05 00:00:00.000000000 Z
11
+ date: 2024-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -204,6 +204,8 @@ files:
204
204
  - app/datatables/admin/effective_mailchimp_list_members_datatable.rb
205
205
  - app/datatables/admin/effective_mailchimp_lists_datatable.rb
206
206
  - app/helpers/effective_mailchimp_helper.rb
207
+ - app/jobs/effective_mailchimp_subscribe_all_members_job.rb
208
+ - app/jobs/effective_mailchimp_subscribe_all_users_job.rb
207
209
  - app/jobs/effective_mailchimp_update_job.rb
208
210
  - app/models/concerns/effective_mailchimp_user.rb
209
211
  - app/models/effective/mailchimp_api.rb