chimpactions 0.0.0 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +14 -2
- data/MIT-LICENSE +20 -0
- data/README.textile +134 -0
- data/Rakefile +44 -0
- data/app/controllers/chimpactions_controller.rb +123 -0
- data/app/models/chimpaction.rb +20 -0
- data/app/views/chimpactions/_errors.html.erb +10 -0
- data/app/views/chimpactions/_form.html.erb +26 -0
- data/app/views/chimpactions/_list.html.erb +6 -0
- data/app/views/chimpactions/edit.html.erb +4 -0
- data/app/views/chimpactions/index.html.erb +22 -0
- data/app/views/chimpactions/new.html.erb +4 -0
- data/app/views/chimpactions/webhooks.html.erb +26 -0
- data/chimpactions.gemspec +9 -4
- data/config/deploy/templates/nginx.conf.tpl_ +0 -0
- data/config/deploy/templates/unicorn.conf.tpl_ +0 -0
- data/config/routes.rb +8 -0
- data/lib/chimpactions.rb +210 -2
- data/lib/chimpactions/action.rb +73 -0
- data/lib/chimpactions/engine.rb +21 -0
- data/lib/chimpactions/exception.rb +14 -0
- data/lib/chimpactions/list.rb +113 -0
- data/lib/chimpactions/notifier.rb +9 -0
- data/lib/chimpactions/setup.rb +42 -0
- data/lib/chimpactions/subscriber.rb +125 -0
- data/lib/chimpactions/utility.rb +13 -0
- data/lib/chimpactions/version.rb +1 -1
- data/lib/generators/chimpactions/customize/customize_generator.rb +19 -0
- data/lib/generators/chimpactions/customize/templates/views/_errors.html.erb +10 -0
- data/lib/generators/chimpactions/customize/templates/views/_form.html.erb +26 -0
- data/lib/generators/chimpactions/customize/templates/views/_list.html.erb +6 -0
- data/lib/generators/chimpactions/customize/templates/views/edit.html.erb +4 -0
- data/lib/generators/chimpactions/customize/templates/views/index.html.erb +22 -0
- data/lib/generators/chimpactions/customize/templates/views/new.html.erb +4 -0
- data/lib/generators/chimpactions/customize/templates/views/webhooks.html.erb +26 -0
- data/lib/generators/chimpactions/install/install_generator.rb +19 -0
- data/lib/generators/chimpactions/install/templates/README +10 -0
- data/lib/generators/chimpactions/install/templates/chimpactions.yml +39 -0
- data/lib/generators/chimpactions/install/templates/chimpactions_initializer.rb +1 -0
- data/lib/generators/chimpactions/migration/migration_generator.rb +26 -0
- data/lib/generators/chimpactions/migration/templates/create_chimpactions.rb +16 -0
- data/lib/railtie.rb +16 -0
- metadata +82 -38
- data/.gitignore +0 -4
data/Gemfile
CHANGED
@@ -1,4 +1,16 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
gem "rails", "3.0.7"
|
4
|
+
gem "capybara", ">= 0.4.0"
|
5
|
+
gem "sqlite3"
|
6
|
+
gem "gibbon", ">= 0.1.5"
|
7
|
+
# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
|
8
|
+
# gem 'ruby-debug'
|
9
|
+
# gem 'ruby-debug19'
|
10
|
+
|
11
|
+
group :test do
|
12
|
+
gem "factory_girl"
|
13
|
+
gem "shoulda"
|
14
|
+
gem 'simplecov'
|
15
|
+
gem 'mocha'
|
16
|
+
end
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 Peter Bonnell / CIRCUIT LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
h1. Chimpactions
|
2
|
+
|
3
|
+
Easily move contacts between MailChimp lists in your Rails 3 application.
|
4
|
+
|
5
|
+
h2. Requirements
|
6
|
+
|
7
|
+
A MailChimp account and "API key":http://admin.mailchimp.com/account/api.
|
8
|
+
|
9
|
+
h2. Installation
|
10
|
+
|
11
|
+
h3. Base
|
12
|
+
|
13
|
+
# *_Gemfile_* -> <code>gem "chimpactions", "~> 0.0.1"</code>
|
14
|
+
# <code>rails generate chimpactions:install</code>
|
15
|
+
# _Edit config/chimpactions.yml_ with your information.
|
16
|
+
# add <code>include Chimpactions::Subscriber</code> to your model.
|
17
|
+
# add <code>after_save :chimpactions </code> (if that's what you want) to your model.
|
18
|
+
|
19
|
+
The YourModel.chimpactions method fires the actions to move subscribers as specified.
|
20
|
+
|
21
|
+
Generates:
|
22
|
+
* config/chimpactions.yml config file
|
23
|
+
|
24
|
+
h3. ActiveRecord store
|
25
|
+
|
26
|
+
<code>rails generate chimpactions:migration </code>
|
27
|
+
|
28
|
+
<code> rake db:migrate </code>
|
29
|
+
|
30
|
+
Generates:
|
31
|
+
* chimpactions ActiveRecord migration
|
32
|
+
|
33
|
+
h3. Customizing Admin
|
34
|
+
|
35
|
+
Chimpactions provides a basic scaffold for managing ActiveRecord Actions @ http:yourapp/chimpactions.
|
36
|
+
To override the gem views :
|
37
|
+
|
38
|
+
<code>rails generate chimpactions:customize </code>
|
39
|
+
|
40
|
+
Generates:
|
41
|
+
|
42
|
+
* chimpactions view files for administrative interface
|
43
|
+
* yourapp/app/views/chimpactions
|
44
|
+
|
45
|
+
h2. Configuration
|
46
|
+
|
47
|
+
_See installed config/chimpactions.yml for configuration options_
|
48
|
+
|
49
|
+
h2. Usage
|
50
|
+
|
51
|
+
h3. What's available
|
52
|
+
|
53
|
+
Once defined (in chimpactions.yml) the local Rails model inherits the following methods from the Chimpactions gem :
|
54
|
+
* add_to(List)
|
55
|
+
* move_to(List)
|
56
|
+
* remove_from(List)
|
57
|
+
|
58
|
+
h3. A Chimpaction :
|
59
|
+
|
60
|
+
*WHENN (A model method/attribute) IS (<,>,=) VALUE, ACTION (Chimpactions method) LIST (One of your MailChimp Lists)*
|
61
|
+
|
62
|
+
ex.
|
63
|
+
|
64
|
+
'When a user has more than 50 posts, move them to the Power Poster list'
|
65
|
+
|
66
|
+
*_in chimpactions.yml_*
|
67
|
+
<pre><code> action:
|
68
|
+
-
|
69
|
+
action: :move_to,
|
70
|
+
list: Power Posters,
|
71
|
+
whenn: posts.count,
|
72
|
+
is: >,
|
73
|
+
value: 50
|
74
|
+
-
|
75
|
+
</code></pre>
|
76
|
+
|
77
|
+
*_for ActiveRecord store_*
|
78
|
+
The admin interface should be a straightforward representation.
|
79
|
+
|
80
|
+
h3. Administrative Interface
|
81
|
+
|
82
|
+
Direct your browser to http://yourapp.chimpactions for a simple CRUD to build and manage Actions.
|
83
|
+
Available values are set in the forms where applicable, validations will tell you if a value won't work.
|
84
|
+
|
85
|
+
h3. Manual access
|
86
|
+
|
87
|
+
You can move subscribers around arbitrarily as well:
|
88
|
+
|
89
|
+
<pre><code>user = User.find(123)
|
90
|
+
user.remove_from("Power Posters")
|
91
|
+
</code></pre>
|
92
|
+
|
93
|
+
h3. Chimpactions Module
|
94
|
+
|
95
|
+
All your lists with a ton of info:
|
96
|
+
<pre><code>@lists = Chimpactions.available_lists
|
97
|
+
...view
|
98
|
+
<%= var_dump(@lists) ->
|
99
|
+
</code></pre>
|
100
|
+
|
101
|
+
Calling the MailChimp API directly:
|
102
|
+
|
103
|
+
Direct access to the "gibbon":http://rubygems.org/gems/gibbon/ socket :
|
104
|
+
<pre><code>api_result = Chimpactions.socket.campaigns({:start => 0, :limit => 100})
|
105
|
+
</code></pre>
|
106
|
+
|
107
|
+
|
108
|
+
h3. Webhooks
|
109
|
+
|
110
|
+
To register your application with your MailChimp List direct your browser to : http://yourapp/chimpactions/webhooks
|
111
|
+
|
112
|
+
The links next to each list will add/delete the webhook http://yourapp/chimpactions/receive to that list.
|
113
|
+
|
114
|
+
You must handle the post itself in <pre><code> receive_webhook(mc_post_data) </code> </pre> in your mix-in model for it have an effect.
|
115
|
+
|
116
|
+
|
117
|
+
h2. TODO
|
118
|
+
|
119
|
+
* implement VCR for tests so we don't have to use a real API key
|
120
|
+
* get loading don't so we don't have to add <code>include Chimpactions::Subscriber</code> in the model
|
121
|
+
|
122
|
+
h2. License
|
123
|
+
|
124
|
+
This project released under the MIT-LICENSE.
|
125
|
+
|
126
|
+
h2. Thanks
|
127
|
+
|
128
|
+
p. Made possible by the generous support of the "MailChimp Integration Fund":http://www.mailchimp.com/about/integration-fund/ .
|
129
|
+
|
130
|
+
h2. Copyrights
|
131
|
+
|
132
|
+
(c) circuitllc & "imgenius":http://imgeni.us 2011 - Released under the MIT license.
|
133
|
+
|
134
|
+
|
data/Rakefile
CHANGED
@@ -1,2 +1,46 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'rubygems'
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
1
9
|
require 'bundler'
|
2
10
|
Bundler::GemHelper.install_tasks
|
11
|
+
|
12
|
+
require 'rake'
|
13
|
+
require 'rake/rdoctask'
|
14
|
+
|
15
|
+
require 'rake/testtask'
|
16
|
+
|
17
|
+
Rake::TestTask.new(:test) do |t|
|
18
|
+
t.libs << 'lib'
|
19
|
+
t.libs << 'test'
|
20
|
+
t.pattern = 'test/**/*_test.rb'
|
21
|
+
t.verbose = false
|
22
|
+
end
|
23
|
+
|
24
|
+
Rake::TestTask.new(:units) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/unit/*_test.rb'
|
28
|
+
t.verbose = false
|
29
|
+
end
|
30
|
+
|
31
|
+
Rake::TestTask.new(:functionals) do |t|
|
32
|
+
t.libs << 'lib'
|
33
|
+
t.libs << 'test'
|
34
|
+
t.pattern = 'test/integration/*_test.rb'
|
35
|
+
t.verbose = false
|
36
|
+
end
|
37
|
+
|
38
|
+
task :default => :test
|
39
|
+
|
40
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
41
|
+
rdoc.rdoc_dir = 'rdoc'
|
42
|
+
rdoc.title = 'Chimpactions'
|
43
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
44
|
+
rdoc.rdoc_files.include('README.rdoc')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
class ChimpactionsController < ApplicationController
|
2
|
+
def index
|
3
|
+
@all_actions = Chimpactions.actions
|
4
|
+
@registered = Chimpactions.registered_class_name
|
5
|
+
@actions = Chimpaction.all
|
6
|
+
@lists = Chimpactions.available_lists
|
7
|
+
end
|
8
|
+
|
9
|
+
# GET /chimpactions/new
|
10
|
+
# GET /chimpactions/new.xml
|
11
|
+
def new
|
12
|
+
@chimpaction = Chimpaction.new
|
13
|
+
|
14
|
+
respond_to do |format|
|
15
|
+
format.html # new.html.erb
|
16
|
+
format.xml { render :xml => @chimpaction }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# GET /chimpactions/1/edit
|
21
|
+
def edit
|
22
|
+
@chimpaction = Chimpaction.find(params[:id])
|
23
|
+
end
|
24
|
+
|
25
|
+
# POST /chimpactions
|
26
|
+
# POST /chimpactions.xml
|
27
|
+
def create
|
28
|
+
@chimpaction = Chimpaction.new(params[:chimpaction])
|
29
|
+
|
30
|
+
respond_to do |format|
|
31
|
+
if @chimpaction.save
|
32
|
+
format.html { redirect_to(chimpactions_url, :notice => 'Chimpaction was successfully created.') }
|
33
|
+
format.xml { render :xml => @chimpaction, :status => :created, :location => @chimpaction }
|
34
|
+
else
|
35
|
+
format.html { render :action => "new" }
|
36
|
+
format.xml { render :xml => @chimpaction.errors, :status => :unprocessable_entity }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# PUT /chimpactions/1
|
42
|
+
# PUT /chimpactions/1.xml
|
43
|
+
def update
|
44
|
+
@chimpaction = Chimpaction.find(params[:id])
|
45
|
+
|
46
|
+
respond_to do |format|
|
47
|
+
if @chimpaction.update_attributes(params[:chimpaction])
|
48
|
+
format.html { redirect_to(chimpactions_url, :notice => 'Chimpaction was successfully updated.') }
|
49
|
+
format.xml { head :ok }
|
50
|
+
else
|
51
|
+
format.html { render :action => "edit" }
|
52
|
+
format.xml { render :xml => @chimpaction.errors, :status => :unprocessable_entity }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# DELETE /chimpactions/1
|
58
|
+
# DELETE /chimpactions/1.xml
|
59
|
+
def destroy
|
60
|
+
@chimpaction = Chimpaction.find(params[:id])
|
61
|
+
@chimpaction.destroy
|
62
|
+
|
63
|
+
respond_to do |format|
|
64
|
+
format.html { redirect_to(chimpactions_url) }
|
65
|
+
format.xml { head :ok }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def webhooks
|
70
|
+
@lists = Chimpactions.available_lists
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_webhook
|
74
|
+
list = Chimpactions.list(params[:id])
|
75
|
+
if list.set_webhook :url => 'http://www.postbin.org/1iwea1s'#webhook_url
|
76
|
+
flash[:notice] = "Added Webhook!"
|
77
|
+
end
|
78
|
+
redirect_to '/chimpactions/webhooks'
|
79
|
+
end
|
80
|
+
|
81
|
+
def delete_webhook
|
82
|
+
list = Chimpactions.list(params[:id])
|
83
|
+
if list.remove_webhook :url => 'http://www.postbin.org/1iwea1s' #webhook_url
|
84
|
+
flash[:notice] = "Removed Webhook!"
|
85
|
+
end
|
86
|
+
redirect_to '/chimpactions/webhooks'
|
87
|
+
end
|
88
|
+
|
89
|
+
def receive
|
90
|
+
if params['data']
|
91
|
+
subscriber = Chimpactions.registered_class.find_by_email(params['data']['email'])
|
92
|
+
subscriber.receive_webhook(params) if subscriber.respond_to?(:receive_webhook)
|
93
|
+
end
|
94
|
+
render :nothing => true
|
95
|
+
end
|
96
|
+
# data[email] = 'federico@mailchimp.com'
|
97
|
+
#
|
98
|
+
# data[email_type] = 'html'
|
99
|
+
#
|
100
|
+
# data[id] = 'da1b07ac4c'
|
101
|
+
#
|
102
|
+
# data[ip_opt]='69.12.4.2'
|
103
|
+
#
|
104
|
+
# data[list_id]='45a650bc63'
|
105
|
+
#
|
106
|
+
# data[merges][EMAIL]='federico@mailchimp.com'
|
107
|
+
#
|
108
|
+
# data[merges][FNAME] ='Federico'
|
109
|
+
#
|
110
|
+
# data[merges][IP] ='127.0.0.1'
|
111
|
+
#
|
112
|
+
# data[merges][LNAME]='Holgado'
|
113
|
+
#
|
114
|
+
# data[merges][SIGNUP]=''
|
115
|
+
#
|
116
|
+
# data[web_id]='234305517'
|
117
|
+
#
|
118
|
+
# fired_at = '2011-06-30 02:34:35'
|
119
|
+
#
|
120
|
+
# type ='profile'
|
121
|
+
# end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "chimpactions"
|
2
|
+
|
3
|
+
class ResponseValidator < ActiveModel::Validator
|
4
|
+
def validate(record)
|
5
|
+
# k = Kernel.const_get(Chimpactions::registered_class.name.to_s.capitalize).new
|
6
|
+
k = Chimpactions.registered_class
|
7
|
+
if k.respond_to?(record.action) != true
|
8
|
+
record.errors[:action] << "- '#{record.action}' is not a method of #{k.class.name} !"
|
9
|
+
end
|
10
|
+
if k.respond_to?(record.whenn) != true
|
11
|
+
record.errors[:whenn] << "- '#{record.whenn}' is not a method of #{k.class.name} !"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# ActiveRecord 'wrapper' for Chimpactions::Action to provide non-yml peristence & customization
|
17
|
+
class Chimpaction < ActiveRecord::Base
|
18
|
+
validates_presence_of :list, :action, :whenn, :is, :value
|
19
|
+
validates_with ResponseValidator
|
20
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% if target.errors.any? %>
|
2
|
+
<div id="errorExplanation">
|
3
|
+
<h2><%= pluralize(target.errors.count, "error") %> prohibited this record from being saved:</h2>
|
4
|
+
<ul>
|
5
|
+
<% target.errors.full_messages.each do |msg| %>
|
6
|
+
<li><%= msg %></li>
|
7
|
+
<% end %>
|
8
|
+
</ul>
|
9
|
+
</div>
|
10
|
+
<% end %>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<style>
|
2
|
+
.ca_action_form {padding-bottom:25px;width:350px;}
|
3
|
+
.ca_action_form fieldset {background-color:inherit;padding:0px;margin:0px;}
|
4
|
+
.ca_action_form fieldset legend {background-color:inherit;}
|
5
|
+
.ca_action_form * {float:none;font-family: verdana, arial, helvetica, sans-serif;
|
6
|
+
font-size: 12px!important;
|
7
|
+
line-height: 14px!important;}
|
8
|
+
.ca_action_form label {padding:0 4px;}
|
9
|
+
.ca_action_form div {display:inline;}
|
10
|
+
.ca_action_form .field_with_errors input {border:1px solid red;}
|
11
|
+
.ca_action_form ol {list-style:none;padding:14px;margin: 0px auto;max-width:315px;}
|
12
|
+
.ca_action_form ol li{padding:4px;}
|
13
|
+
.ca_action_form .bold {font-weight:bold;}
|
14
|
+
</style>
|
15
|
+
<%= form_for @chimpaction, :html => {:class => 'ca_action_form'} do |c| %>
|
16
|
+
<%= render "chimpactions/errors", :target => @chimpaction %>
|
17
|
+
<fieldset>
|
18
|
+
<ol>
|
19
|
+
<li><%= c.label :when, {:class => 'bold'} %> <%= Chimpactions.registered_class_name%>.<%= c.text_field :whenn, {:size => '15'} %> </li>
|
20
|
+
<li><%= select(:chimpaction, :is, %w(= < >)) %> <%= c.text_field :value %><%= c.label '(Value)' %></li>
|
21
|
+
<li><%= c.label "THEN", {:class => 'bold'}%></li>
|
22
|
+
<li><%= select(:chimpaction, :action, %w(add_to move_to remove_from).map {|l| [l.gsub('_',' ').titleize , l]}) -%></li>
|
23
|
+
<li><%= collection_select(:chimpaction, :list, Chimpactions.available_lists, :name, :name)%></li>
|
24
|
+
<li><%= submit_tag "submit"%></li>
|
25
|
+
</fieldset>
|
26
|
+
<% end %>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<section>
|
2
|
+
<% %w(notice warning error).each do |msg| %>
|
3
|
+
<% unless flash[msg.to_sym].blank? %>
|
4
|
+
<div class='message <%=msg-%>'><p><%=flash[msg.to_sym]-%></p></div>
|
5
|
+
<% end %>
|
6
|
+
<% end %>
|
7
|
+
<h1>Current Chimpactions : </h1>
|
8
|
+
<ul>
|
9
|
+
<% @actions.each do |action|%>
|
10
|
+
<li> When a <%= @registered %> <%= action.whenn %> <%= action.is %> <%= action.value %> => <%= @registered%>.<%= action.action %> (<%= action.list %>)
|
11
|
+
<%= link_to 'Edit', edit_chimpaction_path(action) %> ||
|
12
|
+
<%= link_to 'Destroy', chimpaction_path(action.id), :confirm => 'Are you sure?', :method => :delete %></li>
|
13
|
+
<%end%>
|
14
|
+
</ul>
|
15
|
+
</section>
|
16
|
+
<section>
|
17
|
+
<h1> <%= link_to "Add New Chimpaction", new_chimpaction_path %> </h1>
|
18
|
+
</section>
|
19
|
+
<section>
|
20
|
+
<h1>Your MailChimp lists: </h1>
|
21
|
+
<%= render :partial => 'list', :collection => @lists if @lists.count > 0%>
|
22
|
+
</section>
|