refinerycms-mailchimp 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/admin/campaigns_controller.rb +80 -0
- data/app/models/campaign.rb +105 -0
- data/app/views/admin/campaigns/_campaign.html.erb +22 -0
- data/app/views/admin/campaigns/_form.html.erb +85 -0
- data/app/views/admin/campaigns/_modal_fields.html.erb +4 -0
- data/app/views/admin/campaigns/_sortable_list.html.erb +4 -0
- data/app/views/admin/campaigns/edit.html.erb +1 -0
- data/app/views/admin/campaigns/index.html.erb +49 -0
- data/app/views/admin/campaigns/new.html.erb +1 -0
- data/app/views/admin/campaigns/send_options.html.erb +40 -0
- data/config/locales/en.yml +60 -0
- data/config/locales/nb.yml +19 -0
- data/config/locales/nl.yml +19 -0
- data/config/routes.rb +13 -0
- data/db/migrate/1_create_campaigns.rb +25 -0
- data/db/seeds/campaigns.rb +10 -0
- data/features/campaigns.feature_brainstorm +15 -0
- data/features/support/factories/campaigns.rb +8 -0
- data/features/support/paths.rb +24 -0
- data/lib/generators/refinerycms_mailchimp_generator.rb +8 -0
- data/lib/refinerycms-mailchimp.rb +39 -0
- data/lib/tasks/mailchimp.rake +13 -0
- data/spec/controllers/admin/campaigns_controller_spec.rb +19 -0
- data/spec/models/api_spec.rb +35 -0
- data/spec/models/campaign_spec.rb +43 -0
- metadata +105 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
class Admin::CampaignsController < Admin::BaseController
|
2
|
+
|
3
|
+
crudify :campaign, :order => "updated_at desc", :sortable => false, :title_attribute => :subject
|
4
|
+
|
5
|
+
rescue_from Refinery::Mailchimp::API::BadAPIKeyError, :with => :need_api_key
|
6
|
+
rescue_from Hominid::APIError, :with => :need_api_key
|
7
|
+
|
8
|
+
before_filter :get_mailchimp_assets, :except => :index
|
9
|
+
before_filter :find_campaign, :except => [:index, :new, :create]
|
10
|
+
|
11
|
+
def new
|
12
|
+
@campaign = Campaign.new :to_name => RefinerySetting.get_or_set(Refinery::Mailchimp::API::DefaultToNameSetting[:name], Refinery::Mailchimp::API::DefaultToNameSetting[:default]),
|
13
|
+
:from_name => RefinerySetting.get_or_set(Refinery::Mailchimp::API::DefaultFromNameSetting[:name], Refinery::Mailchimp::API::DefaultFromNameSetting[:default]),
|
14
|
+
:from_email => RefinerySetting.get_or_set(Refinery::Mailchimp::API::DefaultFromEmailSetting[:name], Refinery::Mailchimp::API::DefaultFromEmailSetting[:default])
|
15
|
+
end
|
16
|
+
|
17
|
+
def send_options
|
18
|
+
end
|
19
|
+
|
20
|
+
def send_test
|
21
|
+
if @campaign.send_test_to params[:email]
|
22
|
+
flash[:notice] = t('admin.campaigns.campaign.send_test_success', :email => params[:email])
|
23
|
+
else
|
24
|
+
flash[:alert] = t('admin.campaigns.campaign.send_test_failure', :email => params[:email])
|
25
|
+
end
|
26
|
+
sending_redirect_to admin_campaigns_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def send_now
|
30
|
+
if @campaign.send_now
|
31
|
+
flash[:notice] = t('admin.campaigns.campaign.send_now_success')
|
32
|
+
else
|
33
|
+
flash[:alert] = t('admin.campaigns.campaign.send_now_failure')
|
34
|
+
end
|
35
|
+
sending_redirect_to admin_campaigns_path
|
36
|
+
end
|
37
|
+
|
38
|
+
def schedule
|
39
|
+
if @campaign.schedule_for DateTime.new(*params['date'].values_at('year','month','day','hour','minute').map{|x|x.to_i})
|
40
|
+
flash[:notice] = t('admin.campaigns.campaign.schedule_success')
|
41
|
+
else
|
42
|
+
flash[:alert] = t('admin.campaigns.campaign.schedule_failure')
|
43
|
+
end
|
44
|
+
sending_redirect_to admin_campaigns_path
|
45
|
+
end
|
46
|
+
|
47
|
+
def unschedule
|
48
|
+
if @campaign.unschedule
|
49
|
+
flash[:notice] = t('admin.campaigns.campaign.unschedule_success')
|
50
|
+
else
|
51
|
+
flash[:alert] = t('admin.campaigns.campaign.unschedule_failure')
|
52
|
+
end
|
53
|
+
sending_redirect_to admin_campaigns_path
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
def sending_redirect_to(path)
|
58
|
+
if from_dialog?
|
59
|
+
render :text => "<script>parent.window.location = '#{path}';</script>"
|
60
|
+
else
|
61
|
+
redirect_to path
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def need_api_key
|
66
|
+
msg = t('admin.campaigns.index.set_api_key')
|
67
|
+
msg += " <a href=\"#{edit_admin_refinery_setting_path(RefinerySetting.find_by_name(Refinery::Mailchimp::API::KeySetting[:name]))}\" style=\"display:inline\">#{t('admin.campaigns.index.set_api_link')}</a>"
|
68
|
+
flash[:alert] = msg.html_safe
|
69
|
+
redirect_to admin_campaigns_path
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_mailchimp_assets
|
73
|
+
@lists = client.lists['data']
|
74
|
+
@templates = client.templates['user']
|
75
|
+
end
|
76
|
+
|
77
|
+
def client
|
78
|
+
@client ||= Refinery::Mailchimp::API.new
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
class Campaign < ActiveRecord::Base
|
2
|
+
|
3
|
+
acts_as_indexed :fields => [:subject, :body]
|
4
|
+
|
5
|
+
validates_presence_of :subject, :body, :mailchimp_list_id, :from_email, :from_name, :to_name
|
6
|
+
|
7
|
+
before_save :update_mailchimp_campaign
|
8
|
+
before_create :create_mailchimp_campaign
|
9
|
+
before_destroy :delete_mailchimp_campaign
|
10
|
+
|
11
|
+
def sent?
|
12
|
+
!!sent_at || !!scheduled_at && scheduled_at <= Time.now
|
13
|
+
end
|
14
|
+
|
15
|
+
def scheduled?
|
16
|
+
!!scheduled_at && scheduled_at > Time.now
|
17
|
+
end
|
18
|
+
|
19
|
+
def sent
|
20
|
+
sent_at || scheduled_at
|
21
|
+
end
|
22
|
+
|
23
|
+
def send_test_to(*emails)
|
24
|
+
Refinery::Mailchimp::API.new.campaign_send_test mailchimp_campaign_id, emails
|
25
|
+
rescue Hominid::APIError
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def send_now
|
30
|
+
success = Refinery::Mailchimp::API.new.campaign_send_now mailchimp_campaign_id
|
31
|
+
self.update_attribute :sent_at, Time.now if success
|
32
|
+
success
|
33
|
+
rescue Hominid::APIError
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
37
|
+
def schedule_for(datetime)
|
38
|
+
success = Refinery::Mailchimp::API.new.campaign_schedule mailchimp_campaign_id, datetime.utc.strftime("%Y-%m-%d %H:%M:%S")
|
39
|
+
self.update_attribute :scheduled_at, datetime if success
|
40
|
+
success
|
41
|
+
rescue Hominid::APIError
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def unschedule
|
46
|
+
success = Refinery::Mailchimp::API.new.campaign_unschedule mailchimp_campaign_id
|
47
|
+
self.update_attribute :scheduled_at, nil if success
|
48
|
+
success
|
49
|
+
rescue Hominid::APIError
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
def google_analytics
|
54
|
+
RefinerySetting.find_or_set Refinery::Mailchimp::API::GoogleAnalyticsSetting[:name], Refinery::Mailchimp::API::GoogleAnalyticsSetting[:default]
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def create_mailchimp_campaign
|
60
|
+
options = { :subject => subject, :from_email => from_email, :from_name => from_name, :to_name => to_name, :list_id => mailchimp_list_id, :auto_tweet => auto_tweet }
|
61
|
+
options[:template_id] = mailchimp_template_id unless mailchimp_template_id.blank?
|
62
|
+
# options[:analytics] = { :google => google_analytics } unless google_analytics.blank?
|
63
|
+
|
64
|
+
self.mailchimp_campaign_id = begin
|
65
|
+
Refinery::Mailchimp::API.new.campaign_create 'regular', options, { content_key => body }
|
66
|
+
rescue Hominid::APIError
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
return halt_with_mailchimp_error if self.mailchimp_campaign_id.blank?
|
71
|
+
end
|
72
|
+
|
73
|
+
def update_mailchimp_campaign
|
74
|
+
return if new_record?
|
75
|
+
|
76
|
+
client = Refinery::Mailchimp::API.new
|
77
|
+
|
78
|
+
options = {:title => :subject, :from_email => :from_email, :from_name => :from_name, :to_name => :to_name, :list_id => :mailchimp_list_id, :template_id => :mailchimp_template_id, :content => :body, :auto_tweet => :auto_tweet }
|
79
|
+
options.each_pair do |option_name, attribute|
|
80
|
+
if changed.include?(attribute.to_s)
|
81
|
+
success = client.campaign_update mailchimp_campaign_id, option_name, (option_name == :content ? { content_key => body } : self.send(attribute))
|
82
|
+
return halt_with_mailchimp_error unless success
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def delete_mailchimp_campaign
|
88
|
+
success = begin
|
89
|
+
Refinery::Mailchimp::API.new.campaign_delete mailchimp_campaign_id
|
90
|
+
rescue Hominid::APIError
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
return halt_with_mailchimp_error unless success
|
95
|
+
end
|
96
|
+
|
97
|
+
def halt_with_mailchimp_error
|
98
|
+
self.errors.add :base, I18n.t('admin.campaigns.campaign.mailchimp_error')
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
|
102
|
+
def content_key
|
103
|
+
mailchimp_template_id.blank? ? :html : :html_MAIN
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<li class='clearfix record <%= cycle("on", "on-hover") %>' id="<%= dom_id(campaign) -%>">
|
2
|
+
<span class='subject'>
|
3
|
+
<%= campaign.subject %>
|
4
|
+
|
5
|
+
<% if campaign.sent? %>
|
6
|
+
<span class="preview" title="<%= campaign.sent %>">sent <%= distance_of_time_in_words_to_now(campaign.sent) %> ago</span>
|
7
|
+
<% elsif campaign.scheduled? %>
|
8
|
+
<span class="preview" title="<%= campaign.scheduled_at %>">sending in <%= distance_of_time_in_words_to_now(campaign.scheduled_at) %></span>
|
9
|
+
<% end %>
|
10
|
+
</span>
|
11
|
+
<span class='actions'>
|
12
|
+
<%= link_to refinery_icon_tag("application_edit.png"), edit_admin_campaign_path(campaign),
|
13
|
+
:subject => t('.edit') %>
|
14
|
+
<%= link_to refinery_icon_tag("email_go.png"), send_options_admin_campaign_path(campaign, :dialog => true, :width => 725, :height => 525),
|
15
|
+
:title => t('send_dialog', :scope => 'admin.campaigns.campaign') %>
|
16
|
+
<%= link_to refinery_icon_tag("delete.png"), admin_campaign_path(campaign),
|
17
|
+
:class => "cancel confirm-delete",
|
18
|
+
:subject => t('.delete'),
|
19
|
+
:'data-confirm' => t('admin.campaigns.campaign.delete_confirmation', :subject => campaign.subject),
|
20
|
+
:'data-method' => :delete %>
|
21
|
+
</span>
|
22
|
+
</li>
|
@@ -0,0 +1,85 @@
|
|
1
|
+
<% form_for [:admin, @campaign] do |f| -%>
|
2
|
+
<%= render :partial => "/shared/admin/error_messages", :locals => {
|
3
|
+
:object => @campaign,
|
4
|
+
:include_object_name => true
|
5
|
+
} %>
|
6
|
+
|
7
|
+
<div class='field'>
|
8
|
+
<span class='label_with_help'>
|
9
|
+
<%= f.label :subject -%>
|
10
|
+
<%= refinery_help_tag t('.subject_help') %>
|
11
|
+
</span>
|
12
|
+
<%= f.text_field :subject, :class => 'larger widest' -%>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class='field'>
|
16
|
+
<%= f.label :body -%>
|
17
|
+
<%= f.text_area :body, :rows => 20, :class => 'wymeditor widest' -%>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<div class="hemisquare">
|
21
|
+
<h2><%= t('.to_and_from') %></h2>
|
22
|
+
|
23
|
+
<div class='field'>
|
24
|
+
<span class='label_with_help'>
|
25
|
+
<%= f.label :to_name, t('.to_name') -%>
|
26
|
+
<%= refinery_help_tag t('.to_name_help') %>
|
27
|
+
</span>
|
28
|
+
<%= f.text_field :to_name %>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<div class='field'>
|
32
|
+
<span class='label_with_help'>
|
33
|
+
<%= f.label :from_name, t('.from_name') -%>
|
34
|
+
<%= refinery_help_tag t('.from_name_help') %>
|
35
|
+
</span>
|
36
|
+
<%= f.text_field :from_name %>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<div class='field'>
|
40
|
+
<span class='label_with_help'>
|
41
|
+
<%= f.label :from_email, t('.from_email') -%>
|
42
|
+
<%= refinery_help_tag t('.from_email_help') %>
|
43
|
+
</span>
|
44
|
+
<%= f.text_field :from_email %>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
|
48
|
+
<div class="hemisquare right_side">
|
49
|
+
<h2><%= t('.settings') %></h2>
|
50
|
+
|
51
|
+
<div class='field'>
|
52
|
+
<span class='label_with_help'>
|
53
|
+
<%= f.label :mailchimp_list_id, t('.mailchimp_list_id') -%>
|
54
|
+
<%= refinery_help_tag t('.mailchimp_list_id_help') %>
|
55
|
+
</span>
|
56
|
+
<%= f.select :mailchimp_list_id, @lists.collect{ |list| [list['name'], list['id']] } %>
|
57
|
+
</div>
|
58
|
+
|
59
|
+
<div class='field'>
|
60
|
+
<span class='label_with_help'>
|
61
|
+
<%= f.label :mailchimp_template_id, t('.mailchimp_template_id') -%>
|
62
|
+
<%= refinery_help_tag t('.mailchimp_template_id_help') %>
|
63
|
+
</span>
|
64
|
+
<%= f.select :mailchimp_template_id, @templates.collect{ |template| [template['name'], template['id']] }, :include_blank => true %>
|
65
|
+
</div>
|
66
|
+
|
67
|
+
<div class='field'>
|
68
|
+
<span class='label_with_help'>
|
69
|
+
<%= f.label :auto_tweet, t('.auto_tweet') -%>
|
70
|
+
<%= refinery_help_tag t('.auto_tweet_help') %>
|
71
|
+
</span>
|
72
|
+
<%= f.check_box :auto_tweet %>
|
73
|
+
</div>
|
74
|
+
</div>
|
75
|
+
|
76
|
+
<div class="clearfix"></div>
|
77
|
+
|
78
|
+
<%= render :partial => "/shared/admin/form_actions",
|
79
|
+
:locals => {
|
80
|
+
:f => f,
|
81
|
+
:continue_editing => false,
|
82
|
+
:delete_subject => t('admin.campaigns.campaign.delete'),
|
83
|
+
:delete_confirmation => t('admin.campaigns.campaign.delete_confirmation', :subject => @campaign.subject)
|
84
|
+
} %>
|
85
|
+
<% end -%>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render :partial => "form" %>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<div id='actions'>
|
2
|
+
<ul>
|
3
|
+
<% if Admin::CampaignsController.searchable? %>
|
4
|
+
<li>
|
5
|
+
<%= render :partial => "/shared/admin/search",
|
6
|
+
:locals => {
|
7
|
+
:url => admin_campaigns_url
|
8
|
+
} %>
|
9
|
+
</li>
|
10
|
+
<% end %>
|
11
|
+
<li>
|
12
|
+
<%= link_to t('.create_new'), new_admin_campaign_url,
|
13
|
+
:class => "add_icon" %>
|
14
|
+
</li>
|
15
|
+
</ul>
|
16
|
+
</div>
|
17
|
+
<div id='records'>
|
18
|
+
<% if searching? %>
|
19
|
+
<h2><%= t('shared.admin.search.results_for', :query => params[:search]) %></h2>
|
20
|
+
<% if @campaigns.any? %>
|
21
|
+
<%= will_paginate @campaigns, :previous_label => '«', :next_label => '»' %>
|
22
|
+
<ul>
|
23
|
+
<%= render :partial => "campaign",
|
24
|
+
:collection => @campaigns %>
|
25
|
+
</ul>
|
26
|
+
<%= will_paginate @campaigns, :previous_label => '«', :next_label => '»' %>
|
27
|
+
<% else %>
|
28
|
+
<p><%= t('shared.admin.search.no_results') %></p>
|
29
|
+
<% end %>
|
30
|
+
<% else %>
|
31
|
+
<% if @campaigns.any? %>
|
32
|
+
<%= will_paginate @campaigns,
|
33
|
+
:previous_label => '«',
|
34
|
+
:next_label => '»' %>
|
35
|
+
|
36
|
+
<%= render :partial => "sortable_list" %>
|
37
|
+
|
38
|
+
<%= will_paginate @campaigns,
|
39
|
+
:previous_label => '«',
|
40
|
+
:next_label => '»' %>
|
41
|
+
<% else %>
|
42
|
+
<p>
|
43
|
+
<strong>
|
44
|
+
<%= t('.no_items_yet') %>
|
45
|
+
</strong>
|
46
|
+
</p>
|
47
|
+
<% end %>
|
48
|
+
<% end %>
|
49
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render :partial => "form" %>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<% if @campaign.sent? %>
|
2
|
+
<h2>Sent</h2>
|
3
|
+
<p>
|
4
|
+
This campaign was sent <strong title="<%= @campaign.sent_at %>"><%= distance_of_time_in_words_to_now(@campaign.sent_at) %> ago</strong>.
|
5
|
+
</p>
|
6
|
+
<% elsif @campaign.scheduled? %>
|
7
|
+
<h2>Scheduled</h2>
|
8
|
+
<p>
|
9
|
+
This campaign is scheduled to be sent in <strong title="<%= @campaign.scheduled_at %>"><%= distance_of_time_in_words_to_now(@campaign.scheduled_at) %></strong>.
|
10
|
+
</p>
|
11
|
+
<%= form_tag unschedule_admin_campaign_path(@campaign) do -%>
|
12
|
+
<%= render :partial => "modal_fields" %>
|
13
|
+
<%= submit_tag "Unschedule Campaign"%>
|
14
|
+
<% end %>
|
15
|
+
<% else %>
|
16
|
+
<h2>Send Test Email</h2>
|
17
|
+
<p>This will send a test email to the email address you enter below.</p>
|
18
|
+
<%= form_tag send_test_admin_campaign_path(@campaign) do -%>
|
19
|
+
<%= render :partial => "modal_fields" %>
|
20
|
+
<%= label_tag :email %>
|
21
|
+
<%= text_field_tag :email, current_user.email %>
|
22
|
+
<%= submit_tag "Send Test" %>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<h2>Send Campaign Now</h2>
|
26
|
+
<p>This will send the campaign.</p>
|
27
|
+
<%= form_tag send_now_admin_campaign_path(@campaign) do -%>
|
28
|
+
<%= render :partial => "modal_fields" %>
|
29
|
+
<%= submit_tag "Send Now"%>
|
30
|
+
<% end %>
|
31
|
+
|
32
|
+
<h2>Schedule Campaign for Later</h2>
|
33
|
+
<p>This will schedule the campaign to be sent automatically at a future date.</p>
|
34
|
+
<%= form_tag schedule_admin_campaign_path(@campaign) do -%>
|
35
|
+
<%= render :partial => "modal_fields" %>
|
36
|
+
<%= label_tag :send_at %>
|
37
|
+
<%= select_datetime %>
|
38
|
+
<%= submit_tag "Schedule Campaign"%>
|
39
|
+
<% end %>
|
40
|
+
<% end %>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
en:
|
2
|
+
shared:
|
3
|
+
admin:
|
4
|
+
image_picker:
|
5
|
+
image: image
|
6
|
+
plugins:
|
7
|
+
campaigns:
|
8
|
+
title: Campaigns
|
9
|
+
admin:
|
10
|
+
refinery_settings:
|
11
|
+
form:
|
12
|
+
help:
|
13
|
+
mailchimp_api_key: "Get your API key from your Mailchimp dashboard by choosing 'Account' and then 'API Keys & Info.'"
|
14
|
+
mailchimp_default_to_name: "The default To: name recipients will see (not email address). This can be changed for each campaign."
|
15
|
+
mailchimp_default_from_name: "The default From: name for your campaign message (not an email address). This can be changed for each campaign."
|
16
|
+
mailchimp_default_from_email: "The default From: email address for your campaign message. This can be changed for each campaign."
|
17
|
+
mailchimp_admin_base_url: The base URL of your Mailchimp admin area. This is used to generate links to your campaigns for convenience. Only change it if you know what you're doing.
|
18
|
+
campaigns:
|
19
|
+
index:
|
20
|
+
create_new: Create a new Campaign
|
21
|
+
reorder: Reorder Campaigns
|
22
|
+
reorder_done: Done Reordering Campaigns
|
23
|
+
sorry_no_results: Sorry! There are no results found.
|
24
|
+
no_items_yet: There are no Campaigns yet. Click "Create a new Campaign" to add your first campaign.
|
25
|
+
set_api_key: You must set a valid Mailchimp API key.
|
26
|
+
set_api_link: Click here to update your key.
|
27
|
+
campaign:
|
28
|
+
view_live: View this campaign live <br/><em>(opens in a new window)</em>
|
29
|
+
edit: Edit this campaign
|
30
|
+
delete: Remove this campaign forever
|
31
|
+
delete_confirmation: "Are you sure you want to remove '%{subject}'?"
|
32
|
+
mailchimp_error: "Could not save to Mailchimp! Please make sure your API key is right and that you are using a good 'From' email address."
|
33
|
+
send_dialog: "Send, schedule, or test this campaign"
|
34
|
+
send_test_success: Test email successfully sent to %{email}.
|
35
|
+
send_test_failure: Test email could not be sent to %{email}. Please check the email address.
|
36
|
+
send_now_success: The campaign was successfully sent!
|
37
|
+
send_now_failure: The campaign could not be sent. Please check in Mailchimp to make sure everything is ok.
|
38
|
+
schedule_success: The campaign was successfully scheduled.
|
39
|
+
schedule_failure: The campaign could not be scheduled. Please check in Mailchimp to make sure everything is ok.
|
40
|
+
unschedule_success: The campaign was successfully unscheduled.
|
41
|
+
unschedule_failure: The campaign could not be unscheduled. Please check in Mailchimp to make sure everything is ok.
|
42
|
+
form:
|
43
|
+
to_and_from: To and From
|
44
|
+
settings: Settings
|
45
|
+
subject_help: The subject line that will be used for the campaign emails.
|
46
|
+
mailchimp_list_id: Mailing List
|
47
|
+
mailchimp_list_id_help: The mailing list to send this campaign to. These are managed in Mailchimp.
|
48
|
+
mailchimp_template_id: Template
|
49
|
+
mailchimp_template_id_help: The HTML template to use for this campaign. These are managed in Mailchimp.
|
50
|
+
to_name: To Name
|
51
|
+
to_name_help: "The To: name recipients will see (not email address). You can change the default in Settings."
|
52
|
+
from_name: From Name
|
53
|
+
from_name_help: "The From: name for your campaign message (not an email address). You can change the default in Settings."
|
54
|
+
from_email: From Email
|
55
|
+
from_email_help: "The From: email address for your campaign message. You can change the default in Settings."
|
56
|
+
auto_tweet: Auto Tweet
|
57
|
+
auto_tweet_help: Automatically tweet about this campaign when sent. Requires setting up Twitter from Mailchimp.
|
58
|
+
campaigns:
|
59
|
+
show:
|
60
|
+
other: Other Campaigns
|
@@ -0,0 +1,19 @@
|
|
1
|
+
nb:
|
2
|
+
plugins:
|
3
|
+
refinerycms_mailchimp:
|
4
|
+
title: Campaigns
|
5
|
+
admin:
|
6
|
+
campaigns:
|
7
|
+
index:
|
8
|
+
create_new: Lag en ny Campaign
|
9
|
+
reorder: Endre rekkefølgen på Campaigns
|
10
|
+
reorder_done: Ferdig å endre rekkefølgen Campaigns
|
11
|
+
sorry_no_results: Beklager! Vi fant ikke noen resultater.
|
12
|
+
no_items_yet: Det er ingen Campaigns enda. Klikk på "Lag en ny Campaign" for å legge til din første campaign.
|
13
|
+
campaign:
|
14
|
+
view_live: Vis hvordan denne campaign ser ut offentlig <br/><em>(åpner i et nytt vindu)</em>
|
15
|
+
edit: Rediger denne campaign
|
16
|
+
delete: Fjern denne campaign permanent
|
17
|
+
campaigns:
|
18
|
+
show:
|
19
|
+
other: Andre Campaigns
|
@@ -0,0 +1,19 @@
|
|
1
|
+
nl:
|
2
|
+
plugins:
|
3
|
+
refinerycms_mailchimp:
|
4
|
+
title: Campaigns
|
5
|
+
admin:
|
6
|
+
campaigns:
|
7
|
+
index:
|
8
|
+
create_new: Maak een nieuwe Campaign
|
9
|
+
reorder: Wijzig de volgorde van de Campaigns
|
10
|
+
reorder_done: Klaar met het wijzingen van de volgorde van de Campaigns
|
11
|
+
sorry_no_results: Helaas! Er zijn geen resultaten gevonden.
|
12
|
+
no_items_yet: Er zijn nog geen Campaigns. Druk op 'Maak een nieuwe Campaign' om de eerste aan te maken.
|
13
|
+
campaign:
|
14
|
+
view_live: Bekijk deze campaign op de website <br/><em>(opent een nieuw venster)</em>
|
15
|
+
edit: Bewerk deze campaign
|
16
|
+
delete: Verwijder deze campaign voor eeuwig
|
17
|
+
campaigns:
|
18
|
+
show:
|
19
|
+
other: Andere Campaigns
|
data/config/routes.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Refinery::Application.routes.draw do
|
2
|
+
scope(:path => 'refinery', :as => 'admin', :module => 'admin') do
|
3
|
+
resources :campaigns do
|
4
|
+
member do
|
5
|
+
get :send_options
|
6
|
+
post :send_test
|
7
|
+
post :send_now
|
8
|
+
post :schedule
|
9
|
+
post :unschedule
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class CreateCampaigns < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :campaigns do |t|
|
5
|
+
t.string :subject, :mailchimp_campaign_id, :mailchimp_list_id, :mailchimp_template_id, :from_email, :from_name, :to_name
|
6
|
+
t.text :body
|
7
|
+
t.datetime :sent_at, :scheduled_at
|
8
|
+
t.boolean :auto_tweet, :default => false
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
|
12
|
+
add_index :campaigns, :id
|
13
|
+
|
14
|
+
load(Rails.root.join('db', 'seeds', 'campaigns.rb'))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
UserPlugin.destroy_all({:name => "Campaigns"})
|
19
|
+
|
20
|
+
Page.delete_all({:link_url => "/campaigns"})
|
21
|
+
|
22
|
+
drop_table :campaigns
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
User.find(:all).each do |user|
|
2
|
+
user.plugins.create(:name => "campaigns",
|
3
|
+
:position => (user.plugins.maximum(:position) || -1) +1)
|
4
|
+
end
|
5
|
+
|
6
|
+
RefinerySetting.create :name => Refinery::Mailchimp::API::KeySetting[:name], :value => Refinery::Mailchimp::API::KeySetting[:default], :restricted => true
|
7
|
+
RefinerySetting.create :name => Refinery::Mailchimp::API::DefaultFromNameSetting[:name], :value => Refinery::Mailchimp::API::DefaultFromNameSetting[:default], :restricted => true
|
8
|
+
RefinerySetting.create :name => Refinery::Mailchimp::API::DefaultFromEmailSetting[:name], :value => Refinery::Mailchimp::API::DefaultFromEmailSetting[:default], :restricted => true
|
9
|
+
RefinerySetting.create :name => Refinery::Mailchimp::API::DefaultToNameSetting[:name], :value => Refinery::Mailchimp::API::DefaultToNameSetting[:default], :restricted => true
|
10
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
@campaign
|
2
|
+
Feature: Campaigns
|
3
|
+
Campaigns can be created through the given user model
|
4
|
+
current_user is assumed through admin screens
|
5
|
+
|
6
|
+
Scenario: Saving a campaign is successful
|
7
|
+
Given I am a logged in refinery user
|
8
|
+
|
9
|
+
When I am on the new campaign form
|
10
|
+
And I fill in "Subject" with "This is my campaign"
|
11
|
+
And I fill in "Body" with "And I love it"
|
12
|
+
And I press "Save"
|
13
|
+
|
14
|
+
Then there should be 1 campaign
|
15
|
+
And the campaign should belong to me
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module NavigationHelpers
|
2
|
+
module Refinery
|
3
|
+
module Mailchimp
|
4
|
+
def path_to(page_name)
|
5
|
+
case page_name
|
6
|
+
when /the list of campaigns/
|
7
|
+
admin_campaigns_path
|
8
|
+
when /the new campaigns? form/
|
9
|
+
new_admin_campaign_path
|
10
|
+
else
|
11
|
+
begin
|
12
|
+
if page_name =~ /the campaign subjectd "?([^\"]*)"?/ and (page = Campaign.find_by_subject($1)).present?
|
13
|
+
self.url_for(page.url)
|
14
|
+
else
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
rescue
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'refinery'
|
2
|
+
require 'hominid'
|
3
|
+
|
4
|
+
module Refinery
|
5
|
+
module Mailchimp
|
6
|
+
class Engine < Rails::Engine
|
7
|
+
initializer "static assets" do |app|
|
8
|
+
app.middleware.insert_after ::ActionDispatch::Static, ::ActionDispatch::Static, "#{root}/public"
|
9
|
+
end
|
10
|
+
|
11
|
+
config.after_initialize do
|
12
|
+
Refinery::Plugin.register do |plugin|
|
13
|
+
plugin.name = "campaigns"
|
14
|
+
plugin.activity = {:class => Campaign,}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class API < Hominid::API
|
20
|
+
KeySetting = { :name => "mailchimp_api_key", :default => "Set me!" }
|
21
|
+
DefaultFromNameSetting = { :name => "mailchimp_default_from_name", :default => "" }
|
22
|
+
DefaultFromEmailSetting = { :name => "mailchimp_default_from_email", :default => "" }
|
23
|
+
DefaultToNameSetting = { :name => "mailchimp_default_to_name", :default => "" }
|
24
|
+
|
25
|
+
class BadAPIKeyError < StandardError; end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
api_key = RefinerySetting.get_or_set KeySetting[:name], KeySetting[:default]
|
29
|
+
raise BadAPIKeyError if api_key.blank? || api_key == KeySetting[:default]
|
30
|
+
|
31
|
+
begin
|
32
|
+
super api_key
|
33
|
+
rescue ArgumentError
|
34
|
+
raise BadAPIKeyError
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
Dir[File.expand_path('../../../../features/support/factories/*.rb', __FILE__)].each{|factory| require factory}
|
3
|
+
|
4
|
+
describe Admin::CampaignsController do
|
5
|
+
describe "getting lists and templates" do
|
6
|
+
it "should get lists and templates on new"
|
7
|
+
it "should get lists and templates on create"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "creating a campaign" do
|
11
|
+
it "should redirect to index with flash message if API is not set up"
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "sending the campaign" do
|
15
|
+
it "should send a test email"
|
16
|
+
it "should send the campaign now"
|
17
|
+
it "should schedule the campaign to send in the future"
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hominid'
|
3
|
+
|
4
|
+
Dir[File.expand_path('../../../features/support/factories/*.rb', __FILE__)].each{|factory| require factory}
|
5
|
+
|
6
|
+
describe Refinery::Mailchimp::API do
|
7
|
+
describe "the client" do
|
8
|
+
before do
|
9
|
+
RefinerySetting.find_by_name(Refinery::Mailchimp::API::KeySetting[:name]).try :destroy
|
10
|
+
RefinerySetting.rewrite_cache
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should give a properly setup client if the API key is set" do
|
14
|
+
RefinerySetting.set Refinery::Mailchimp::API::KeySetting[:name], 'abcdefg-us1'
|
15
|
+
Refinery::Mailchimp::API.new
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should raise an error if the API key is not set" do
|
19
|
+
begin
|
20
|
+
client = Refinery::Mailchimp::API.new
|
21
|
+
fail
|
22
|
+
rescue Refinery::Mailchimp::API::BadAPIKeyError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should raise an error if the API key is malformed" do
|
27
|
+
begin
|
28
|
+
RefinerySetting.set Refinery::Mailchimp::API::KeySetting[:name], 'abcdefg'
|
29
|
+
client = Refinery::Mailchimp::API.new
|
30
|
+
fail
|
31
|
+
rescue Refinery::Mailchimp::API::BadAPIKeyError
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
Dir[File.expand_path('../../../features/support/factories/*.rb', __FILE__)].each{|factory| require factory}
|
3
|
+
|
4
|
+
describe Campaign do
|
5
|
+
describe "validations" do
|
6
|
+
it "should be valid with valid attributes" do
|
7
|
+
Factory.build(:campaign).should be_valid
|
8
|
+
end
|
9
|
+
|
10
|
+
it "requires subject" do
|
11
|
+
Factory.build(:campaign, :subject => "").should_not be_valid
|
12
|
+
end
|
13
|
+
|
14
|
+
it "requires a body" do
|
15
|
+
Factory.build(:campaign, :body => "").should_not be_valid
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "integrating with Mailchimp" do
|
20
|
+
it "should save to mailchimp before create" do
|
21
|
+
campaign = Factory.build(:campaign)
|
22
|
+
campaign.mailchimp_campaign_id.should be_nil
|
23
|
+
|
24
|
+
Refinery::Mailchimp::API.should_receive(:new).and_return(mock('api', :campaign_create => 'abcdef'))
|
25
|
+
campaign.save
|
26
|
+
campaign.reload.mailchimp_campaign_id.should == 'abcdef'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not create and add error if mailchimp create fails" do
|
30
|
+
campaign = Factory.build(:campaign)
|
31
|
+
mock_api = mock('api')
|
32
|
+
mock_api.stub(:campaign_create) { |*args| raise Hominid::APIError.new(mock('xmlerror', :faultCode => -32602, :message => "server error. invalid method parameters")) }
|
33
|
+
Refinery::Mailchimp::API.should_receive(:new).and_return(mock_api)
|
34
|
+
campaign.save.should be_false
|
35
|
+
campaign.errors[:base].should include(I18n.t('admin.campaigns.campaign.mailchimp_error'))
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should update mailchimp before save"
|
39
|
+
it "should not save if mailchimp update fails"
|
40
|
+
it "should know if it's been sent or scheduled"
|
41
|
+
it "should know where it was sent to"
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: refinerycms-mailchimp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ian Terrell
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-04-04 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: hominid
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
version: "3.0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
description: Ruby on Rails Mailchimp engine for Refinery CMS. Manage your campaigns right from the admin!
|
37
|
+
email: ian.terrell@gmail.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- lib/generators/refinerycms_mailchimp_generator.rb
|
46
|
+
- lib/refinerycms-mailchimp.rb
|
47
|
+
- lib/tasks/mailchimp.rake
|
48
|
+
- config/locales/en.yml
|
49
|
+
- config/locales/nb.yml
|
50
|
+
- config/locales/nl.yml
|
51
|
+
- config/routes.rb
|
52
|
+
- app/controllers/admin/campaigns_controller.rb
|
53
|
+
- app/models/campaign.rb
|
54
|
+
- app/views/admin/campaigns/_campaign.html.erb
|
55
|
+
- app/views/admin/campaigns/_form.html.erb
|
56
|
+
- app/views/admin/campaigns/_modal_fields.html.erb
|
57
|
+
- app/views/admin/campaigns/_sortable_list.html.erb
|
58
|
+
- app/views/admin/campaigns/edit.html.erb
|
59
|
+
- app/views/admin/campaigns/index.html.erb
|
60
|
+
- app/views/admin/campaigns/new.html.erb
|
61
|
+
- app/views/admin/campaigns/send_options.html.erb
|
62
|
+
- spec/controllers/admin/campaigns_controller_spec.rb
|
63
|
+
- spec/models/api_spec.rb
|
64
|
+
- spec/models/campaign_spec.rb
|
65
|
+
- features/campaigns.feature_brainstorm
|
66
|
+
- features/support/factories/campaigns.rb
|
67
|
+
- features/support/paths.rb
|
68
|
+
- db/migrate/1_create_campaigns.rb
|
69
|
+
- db/seeds/campaigns.rb
|
70
|
+
has_rdoc: true
|
71
|
+
homepage: https://github.com/ianterrell/refinerycms-mailchimp
|
72
|
+
licenses: []
|
73
|
+
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 3
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
97
|
+
requirements: []
|
98
|
+
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 1.5.2
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: Ruby on Rails Mailchimp engine for Refinery CMS
|
104
|
+
test_files: []
|
105
|
+
|