spree_mail_chimp 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.textile +71 -0
- data/app/assets/javascripts/store/jquery.simplemodal.1.4.min.js +24 -0
- data/app/assets/javascripts/store/mailchimp_subscribe.js +46 -0
- data/app/assets/javascripts/store/spree_mail_chimp.js +1 -0
- data/app/assets/stylesheets/store/mail_chimp.css +21 -0
- data/app/assets/stylesheets/store/spree_mail_chimp.css +4 -0
- data/app/controllers/spree/admin/mail_chimp_settings_controller.rb +21 -0
- data/app/controllers/spree/subscriptions_controller.rb +39 -0
- data/app/models/app_configuration_decorator.rb +10 -0
- data/app/models/user_decorator.rb +121 -0
- data/app/overrides/add_mail_chimp_admin_menu_link.rb +4 -0
- data/app/overrides/add_newsletter_checkbox_to_create_account_page.rb +4 -0
- data/app/overrides/add_newsletter_subscribe_form_to_footer.rb +4 -0
- data/app/views/spree/admin/configurations/_spree_mail_chimp_configuration_link.html.erb +4 -0
- data/app/views/spree/admin/mail_chimp_settings/edit.html.erb +65 -0
- data/app/views/spree/admin/mail_chimp_settings/show.html.erb +26 -0
- data/app/views/spree/shared/_newsletter_subscribe_form.html.erb +14 -0
- data/app/views/spree/shared/_newsletter_subscribe_form_wo_butt.html.erb +5 -0
- data/app/views/spree/subscriptions/create.js.erb +20 -0
- data/app/views/spree/users/_subscribe_to_newsletter_field.html.erb +4 -0
- data/lib/generators/spree_mail_chimp/install/install_generator.rb +27 -0
- data/lib/spree/mail-chimp/config.rb +10 -0
- data/lib/spree_mail_chimp.rb +3 -0
- data/lib/spree_mail_chimp/engine.rb +15 -0
- data/lib/tasks/mail_chimp.rake +72 -0
- metadata +93 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Sam Beam
|
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,71 @@
|
|
1
|
+
h1. Spree + Mail Chimp
|
2
|
+
|
3
|
+
MailChimp API integration for your Spree store, using the hominid gem.
|
4
|
+
|
5
|
+
Adds a checkbox to the user signup form to allow customer to opt-in to your Mailchimp mailing list. Mailchimp API calls happen via the hominid gem.
|
6
|
+
|
7
|
+
Mailchimp subscription status is tracked with a boolean flag on the users table, we also fetch and store the unique MC record id when the subscription is created. This allows us to modify existing email addresses with minimal fuss.
|
8
|
+
|
9
|
+
This is a very simple extension as of now, *any ideas suggestions or improvements welcome!*
|
10
|
+
|
11
|
+
h2. Subscription form partial with JS
|
12
|
+
|
13
|
+
Also includes a partial at <code>shared/newsletter_subscribe_form</code> that can be included in your footer or sidebar anywhere on the site, has one field for the email address. jQuery code in <code>public/javascripts/mailchimp_subscribe.js</code> will POST to the SubscriptionsController which will relay to Mailchimp.
|
14
|
+
|
15
|
+
The SimpleModal plugin is used in the EJB to pop up a confirmation or error alert (because you won't be satisfied with a simple alert() box)
|
16
|
+
|
17
|
+
h3. Installation
|
18
|
+
|
19
|
+
Add to project's Gemfile:
|
20
|
+
<pre><code>
|
21
|
+
gem 'mail_chimp', '>=1.3', :git => 'git://github.com/sbeam/spree-mail-chimp.git'
|
22
|
+
</code> </pre>
|
23
|
+
|
24
|
+
Run from project's root:
|
25
|
+
<pre><code>
|
26
|
+
bundle install
|
27
|
+
|
28
|
+
rails g spree_mail_chimp:install
|
29
|
+
</code> </pre>
|
30
|
+
|
31
|
+
h3. Configuration
|
32
|
+
|
33
|
+
See the Mail Chimp Settings forms in the Admin under Configuration.
|
34
|
+
|
35
|
+
Note, using Mail Chimp "Merge Vars", you can have any callable methods on User sent
|
36
|
+
to the MC list, mapped to indentically named (but uppercased) fields in the MC list admin console.
|
37
|
+
Unfortunately these are only sent at the time the subscription is created, so there isn't much available.
|
38
|
+
|
39
|
+
h3. Changes
|
40
|
+
|
41
|
+
Version 3.0.0 - released 19 Apr 2012 - Spree 1.0 compat
|
42
|
+
Version 2.0.0 - released 6 Dec 2010 - Spree 0.30-stable
|
43
|
+
Version 1.0.1 - released 21 Nov 2010 - Spree 0.11-stable
|
44
|
+
|
45
|
+
h3. Requirements
|
46
|
+
|
47
|
+
Spree >= 1.0
|
48
|
+
hominid >= 2.2.0 http://rubygems.org/gems/hominid
|
49
|
+
|
50
|
+
Also uses the jQuery SimpleModal plugin, included.
|
51
|
+
|
52
|
+
h3. Credits
|
53
|
+
|
54
|
+
Authored by Sam Beam @sbeam
|
55
|
+
Migrated to Spree 0.30 by Bastian Schnurle @bzt
|
56
|
+
Migrated to Spree 1.0 (and extensively refactored) by James Kong @jkongie
|
57
|
+
|
58
|
+
Inspired originally by https://github.com/softa/mailee_spree
|
59
|
+
|
60
|
+
includes SimpleModal http://www.ericmmartin.com/projects/simplemodal/
|
61
|
+
|
62
|
+
h3. TODO
|
63
|
+
|
64
|
+
* make subscribe_to_newsletter_field work
|
65
|
+
* Send user address info to MC via merge vars, when address is given
|
66
|
+
* Export new orders to Mailchimp for full CRM gnarliness
|
67
|
+
* Utility to export existing users to Mailchimp
|
68
|
+
* Add admin controller to view lists and subscriptions
|
69
|
+
* Allow for multiple lists
|
70
|
+
* Tests :/
|
71
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
/*
|
2
|
+
* SimpleModal 1.4 - jQuery Plugin
|
3
|
+
* http://www.ericmmartin.com/projects/simplemodal/
|
4
|
+
* Copyright (c) 2010 Eric Martin (http://twitter.com/ericmmartin)
|
5
|
+
* Dual licensed under the MIT and GPL licenses
|
6
|
+
* Revision: $Id: jquery.simplemodal.js 256 2010-07-27 23:05:43Z emartin24 $
|
7
|
+
*/
|
8
|
+
(function(d){var k=d.browser.msie&&parseInt(d.browser.version)===6&&typeof window.XMLHttpRequest!=="object",l=null,f=[];d.modal=function(a,b){return d.modal.impl.init(a,b)};d.modal.close=function(){d.modal.impl.close()};d.modal.focus=function(a){d.modal.impl.focus(a)};d.modal.setContainerDimensions=function(){d.modal.impl.setContainerDimensions()};d.modal.setPosition=function(){d.modal.impl.setPosition()};d.modal.update=function(a,b){d.modal.impl.update(a,b)};d.fn.modal=function(a){return d.modal.impl.init(this,
|
9
|
+
a)};d.modal.defaults={appendTo:"body",focus:true,opacity:50,overlayId:"simplemodal-overlay",overlayCss:{},containerId:"simplemodal-container",containerCss:{},dataId:"simplemodal-data",dataCss:{},minHeight:null,minWidth:null,maxHeight:null,maxWidth:null,autoResize:false,autoPosition:true,zIndex:1E3,close:true,closeHTML:'<a class="modalCloseImg" title="Close"></a>',closeClass:"simplemodal-close",escClose:true,overlayClose:false,position:null,persist:false,modal:true,onOpen:null,onShow:null,onClose:null};
|
10
|
+
d.modal.impl={d:{},init:function(a,b){var c=this;if(c.d.data)return false;l=d.browser.msie&&!d.boxModel;c.o=d.extend({},d.modal.defaults,b);c.zIndex=c.o.zIndex;c.occb=false;if(typeof a==="object"){a=a instanceof jQuery?a:d(a);c.d.placeholder=false;if(a.parent().parent().size()>0){a.before(d("<span></span>").attr("id","simplemodal-placeholder").css({display:"none"}));c.d.placeholder=true;c.display=a.css("display");if(!c.o.persist)c.d.orig=a.clone(true)}}else if(typeof a==="string"||typeof a==="number")a=
|
11
|
+
d("<div></div>").html(a);else{alert("SimpleModal Error: Unsupported data type: "+typeof a);return c}c.create(a);c.open();d.isFunction(c.o.onShow)&&c.o.onShow.apply(c,[c.d]);return c},create:function(a){var b=this;f=b.getDimensions();if(b.o.modal&&k)b.d.iframe=d('<iframe src="javascript:false;"></iframe>').css(d.extend(b.o.iframeCss,{display:"none",opacity:0,position:"fixed",height:f[0],width:f[1],zIndex:b.o.zIndex,top:0,left:0})).appendTo(b.o.appendTo);b.d.overlay=d("<div></div>").attr("id",b.o.overlayId).addClass("simplemodal-overlay").css(d.extend(b.o.overlayCss,
|
12
|
+
{display:"none",opacity:b.o.opacity/100,height:b.o.modal?f[0]:0,width:b.o.modal?f[1]:0,position:"fixed",left:0,top:0,zIndex:b.o.zIndex+1})).appendTo(b.o.appendTo);b.d.container=d("<div></div>").attr("id",b.o.containerId).addClass("simplemodal-container").css(d.extend(b.o.containerCss,{display:"none",position:"fixed",zIndex:b.o.zIndex+2})).append(b.o.close&&b.o.closeHTML?d(b.o.closeHTML).addClass(b.o.closeClass):"").appendTo(b.o.appendTo);b.d.wrap=d("<div></div>").attr("tabIndex",-1).addClass("simplemodal-wrap").css({height:"100%",
|
13
|
+
outline:0,width:"100%"}).appendTo(b.d.container);b.d.data=a.attr("id",a.attr("id")||b.o.dataId).addClass("simplemodal-data").css(d.extend(b.o.dataCss,{display:"none"})).appendTo("body");b.setContainerDimensions();b.d.data.appendTo(b.d.wrap);if(k||l)b.fixIE()},bindEvents:function(){var a=this;d("."+a.o.closeClass).bind("click.simplemodal",function(b){b.preventDefault();a.close()});a.o.modal&&a.o.close&&a.o.overlayClose&&a.d.overlay.bind("click.simplemodal",function(b){b.preventDefault();a.close()});
|
14
|
+
d(document).bind("keydown.simplemodal",function(b){if(a.o.modal&&b.keyCode===9)a.watchTab(b);else if(a.o.close&&a.o.escClose&&b.keyCode===27){b.preventDefault();a.close()}});d(window).bind("resize.simplemodal",function(){f=a.getDimensions();a.o.autoResize?a.setContainerDimensions():a.o.autoPosition&&a.setPosition();if(k||l)a.fixIE();else if(a.o.modal){a.d.iframe&&a.d.iframe.css({height:f[0],width:f[1]});a.d.overlay.css({height:f[0],width:f[1]})}})},unbindEvents:function(){d("."+this.o.closeClass).unbind("click.simplemodal");
|
15
|
+
d(document).unbind("keydown.simplemodal");d(window).unbind("resize.simplemodal");this.d.overlay.unbind("click.simplemodal")},fixIE:function(){var a=this,b=a.o.position;d.each([a.d.iframe||null,!a.o.modal?null:a.d.overlay,a.d.container],function(c,h){if(h){var g=h[0].style;g.position="absolute";if(c<2){g.removeExpression("height");g.removeExpression("width");g.setExpression("height",'document.body.scrollHeight > document.body.clientHeight ? document.body.scrollHeight : document.body.clientHeight + "px"');
|
16
|
+
g.setExpression("width",'document.body.scrollWidth > document.body.clientWidth ? document.body.scrollWidth : document.body.clientWidth + "px"')}else{var e;if(b&&b.constructor===Array){c=b[0]?typeof b[0]==="number"?b[0].toString():b[0].replace(/px/,""):h.css("top").replace(/px/,"");c=c.indexOf("%")===-1?c+' + (t = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"':parseInt(c.replace(/%/,""))+' * ((document.documentElement.clientHeight || document.body.clientHeight) / 100) + (t = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"';
|
17
|
+
if(b[1]){e=typeof b[1]==="number"?b[1].toString():b[1].replace(/px/,"");e=e.indexOf("%")===-1?e+' + (t = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + "px"':parseInt(e.replace(/%/,""))+' * ((document.documentElement.clientWidth || document.body.clientWidth) / 100) + (t = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + "px"'}}else{c='(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (t = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"';
|
18
|
+
e='(document.documentElement.clientWidth || document.body.clientWidth) / 2 - (this.offsetWidth / 2) + (t = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + "px"'}g.removeExpression("top");g.removeExpression("left");g.setExpression("top",c);g.setExpression("left",e)}}})},focus:function(a){var b=this;a=a&&d.inArray(a,["first","last"])!==-1?a:"first";var c=d(":input:enabled:visible:"+a,b.d.wrap);setTimeout(function(){c.length>0?c.focus():b.d.wrap.focus()},
|
19
|
+
10)},getDimensions:function(){var a=d(window);return[d.browser.opera&&d.browser.version>"9.5"&&d.fn.jquery<"1.3"||d.browser.opera&&d.browser.version<"9.5"&&d.fn.jquery>"1.2.6"?a[0].innerHeight:a.height(),a.width()]},getVal:function(a,b){return a?typeof a==="number"?a:a==="auto"?0:a.indexOf("%")>0?parseInt(a.replace(/%/,""))/100*(b==="h"?f[0]:f[1]):parseInt(a.replace(/px/,"")):null},update:function(a,b){var c=this;if(!c.d.data)return false;c.d.origHeight=c.getVal(a,"h");c.d.origWidth=c.getVal(b,"w");
|
20
|
+
c.d.data.hide();a&&c.d.container.css("height",a);b&&c.d.container.css("width",b);c.setContainerDimensions();c.d.data.show();c.o.focus&&c.focus();c.unbindEvents();c.bindEvents()},setContainerDimensions:function(){var a=this,b=a.d.origHeight?a.d.origHeight:d.browser.opera?a.d.container.height():a.getVal(a.d.container.css("height"),"h"),c=a.d.origWidth?a.d.origWidth:d.browser.opera?a.d.container.width():a.getVal(a.d.container.css("width"),"w"),h=a.d.data.outerHeight(true),g=a.d.data.outerWidth(true);
|
21
|
+
a.d.origHeight=a.d.origHeight||b;a.d.origWidth=a.d.origWidth||c;var e=a.o.maxHeight?a.getVal(a.o.maxHeight,"h"):null,i=a.o.maxWidth?a.getVal(a.o.maxWidth,"w"):null;e=e&&e<f[0]?e:f[0];i=i&&i<f[1]?i:f[1];var j=a.o.minHeight?a.getVal(a.o.minHeight,"h"):"auto";b=b?a.o.autoResize&&b>e?e:b:h?h>e?e:a.o.minHeight&&j!=="auto"&&h<j?j:h:j;e=a.o.minWidth?a.getVal(a.o.minWidth,"w"):"auto";c=c?a.o.autoResize&&c>i?i:c:g?g>i?i:a.o.minWidth&&e!=="auto"&&g<e?e:g:e;a.d.container.css({height:b,width:c});a.d.wrap.css({overflow:h>
|
22
|
+
b||g>c?"auto":"visible"});a.o.autoPosition&&a.setPosition()},setPosition:function(){var a=this,b,c;b=f[0]/2-a.d.container.outerHeight(true)/2;c=f[1]/2-a.d.container.outerWidth(true)/2;if(a.o.position&&Object.prototype.toString.call(a.o.position)==="[object Array]"){b=a.o.position[0]||b;c=a.o.position[1]||c}else{b=b;c=c}a.d.container.css({left:c,top:b})},watchTab:function(a){var b=this;if(d(a.target).parents(".simplemodal-container").length>0){b.inputs=d(":input:enabled:visible:first, :input:enabled:visible:last",
|
23
|
+
b.d.data[0]);if(!a.shiftKey&&a.target===b.inputs[b.inputs.length-1]||a.shiftKey&&a.target===b.inputs[0]||b.inputs.length===0){a.preventDefault();b.focus(a.shiftKey?"last":"first")}}else{a.preventDefault();b.focus()}},open:function(){var a=this;a.d.iframe&&a.d.iframe.show();if(d.isFunction(a.o.onOpen))a.o.onOpen.apply(a,[a.d]);else{a.d.overlay.show();a.d.container.show();a.d.data.show()}a.o.focus&&a.focus();a.bindEvents()},close:function(){var a=this;if(!a.d.data)return false;a.unbindEvents();if(d.isFunction(a.o.onClose)&&
|
24
|
+
!a.occb){a.occb=true;a.o.onClose.apply(a,[a.d])}else{if(a.d.placeholder){var b=d("#simplemodal-placeholder");if(a.o.persist)b.replaceWith(a.d.data.removeClass("simplemodal-data").css("display",a.display));else{a.d.data.hide().remove();b.replaceWith(a.d.orig)}}else a.d.data.hide().remove();a.d.container.hide().remove();a.d.overlay.hide();a.d.iframe&&a.d.iframe.hide().remove();setTimeout(function(){a.d.overlay.remove();a.d={}},10)}}}})(jQuery);
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
var subscribe_email_default_txt = '';
|
3
|
+
|
4
|
+
jQuery.ajaxSetup({
|
5
|
+
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
|
6
|
+
});
|
7
|
+
|
8
|
+
var SpreeMailchimpApp = {
|
9
|
+
|
10
|
+
doSubmit: function(e) {
|
11
|
+
SpreeMailchimpApp.getBusy(null); // could really use $.proxy here but spree doesn't have 1.4
|
12
|
+
$.post(this.action+'.js', $(this).serialize(), SpreeMailchimpApp.getNotBusy, "script");
|
13
|
+
return false;
|
14
|
+
},
|
15
|
+
|
16
|
+
getBusy : function( fn ) {
|
17
|
+
$("body").css('cursor', 'progress');
|
18
|
+
$("#busy_indicator").fadeIn('fast', fn);
|
19
|
+
},
|
20
|
+
|
21
|
+
getNotBusy : function() {
|
22
|
+
$("body").css('cursor', 'default');
|
23
|
+
$("#busy_indicator").fadeOut('fast');
|
24
|
+
}
|
25
|
+
|
26
|
+
};
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
jQuery(document).ready( function() {
|
31
|
+
|
32
|
+
subscribe_email_default_txt = $('#subscribe_email').val();
|
33
|
+
|
34
|
+
$('#subscribe_email').bind('focus', function() {
|
35
|
+
if (this.value == subscribe_email_default_txt) this.value = '';
|
36
|
+
});
|
37
|
+
$('#subscribe_email').bind('blur', function() {
|
38
|
+
if (this.value == '') this.value = subscribe_email_default_txt;
|
39
|
+
});
|
40
|
+
|
41
|
+
$('#mailchimp_subscribe_wrap form').bind('submit', SpreeMailchimpApp.doSubmit);
|
42
|
+
|
43
|
+
});
|
44
|
+
|
45
|
+
|
46
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require store/spree_core
|
@@ -0,0 +1,21 @@
|
|
1
|
+
/* basic styles for simplemodal dialog to match Spree sample store */
|
2
|
+
.simplemodal-overlay {
|
3
|
+
background: #333;
|
4
|
+
}
|
5
|
+
.simplemodal-container {
|
6
|
+
border: 2px solid #162f54;
|
7
|
+
background: #fff;
|
8
|
+
width: 45%;
|
9
|
+
}
|
10
|
+
.simplemodal-close {
|
11
|
+
border-bottom: 1px solid #fff;
|
12
|
+
text-align: right;
|
13
|
+
background: #162f54;
|
14
|
+
color: #fff;
|
15
|
+
}
|
16
|
+
.simplemodal-container h1 {
|
17
|
+
font-size: 110%;
|
18
|
+
}
|
19
|
+
.simplemodal-data {
|
20
|
+
padding: 0.7em;
|
21
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Spree
|
2
|
+
|
3
|
+
class Admin::MailChimpSettingsController < Admin::BaseController
|
4
|
+
|
5
|
+
def show
|
6
|
+
end
|
7
|
+
|
8
|
+
def update
|
9
|
+
Spree::Config.set(params[:preferences])
|
10
|
+
|
11
|
+
respond_to do |format|
|
12
|
+
format.html {
|
13
|
+
redirect_to admin_mail_chimp_settings_path
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Spree::SubscriptionsController < Spree::BaseController
|
2
|
+
|
3
|
+
def hominid
|
4
|
+
@hominid ||= Hominid::Base.new({ :api_key => Spree::Config.get(:mailchimp_api_key) })
|
5
|
+
end
|
6
|
+
|
7
|
+
def create
|
8
|
+
@errors = []
|
9
|
+
|
10
|
+
if params[:email].blank?
|
11
|
+
@errors << t('missing_email')
|
12
|
+
elsif params[:email] !~ /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/i
|
13
|
+
@errors << t('invalid_email_address')
|
14
|
+
else
|
15
|
+
begin
|
16
|
+
self.class.benchmark "Checking if address exists and/or is valid" do
|
17
|
+
@mc_member = hominid.member_info(Spree::Config.get(:mailchimp_list_id), params[:email])
|
18
|
+
end
|
19
|
+
rescue Hominid::ListError => e
|
20
|
+
end
|
21
|
+
|
22
|
+
if @mc_member
|
23
|
+
@errors << t('that_address_is_already_subscribed')
|
24
|
+
else
|
25
|
+
begin
|
26
|
+
self.class.benchmark "Adding mailchimp subscriber" do
|
27
|
+
hominid.subscribe(Spree::Config.get(:mailchimp_list_id), params[:email], {}, MailChimpSync::Sync::mc_subscription_opts)
|
28
|
+
end
|
29
|
+
rescue Hominid::ValidationError => e
|
30
|
+
@errors << t('invalid_email_address')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
respond_to do |wants|
|
36
|
+
wants.js
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Spree::AppConfiguration.class_eval do
|
2
|
+
|
3
|
+
preference :mailchimp_double_opt_in, :boolean, :default => false
|
4
|
+
preference :mailchimp_send_welcome, :boolean, :default => false
|
5
|
+
preference :mailchimp_send_notify, :boolean, :default => false
|
6
|
+
preference :mailchimp_merge_vars, :string, :default => ''
|
7
|
+
preference :mailchimp_list_id, :string
|
8
|
+
preference :mailchimp_api_key, :string
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
Spree::User.class_eval do
|
2
|
+
|
3
|
+
before_create :mailchimp_add_to_mailing_list
|
4
|
+
before_update :mailchimp_update_in_mailing_list, :if => :is_mail_list_subscriber_changed?
|
5
|
+
|
6
|
+
attr_accessible :is_mail_list_subscriber
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
# Subscribes a user to the mailing list
|
11
|
+
#
|
12
|
+
# Returns ?
|
13
|
+
def mailchimp_add_to_mailing_list
|
14
|
+
if self.is_mail_list_subscriber?
|
15
|
+
begin
|
16
|
+
hominid.list_subscribe(mailchimp_list_id, self.email, mailchimp_merge_vars, 'html', *mailchimp_subscription_opts)
|
17
|
+
logger.debug "Fetching new mailchimp subscriber info"
|
18
|
+
|
19
|
+
assign_mailchimp_subscriber_id if self.mailchimp_subscriber_id.blank?
|
20
|
+
rescue Hominid::APIError => e
|
21
|
+
logger.warn "SpreeMailChimp: Failed to create contact in Mailchimp: #{e.message}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Removes the User from the Mailchimp mailing list
|
27
|
+
#
|
28
|
+
# Returns ?
|
29
|
+
def mailchimp_remove_from_mailing_list
|
30
|
+
if !self.is_mail_list_subscriber? && self.mailchimp_subscriber_id.present?
|
31
|
+
begin
|
32
|
+
# TODO: Get rid of those magic values. Maybe add them as Spree::Config options?
|
33
|
+
hominid.list_unsubscribe(mailchimp_list_id, self.email, false, false, true)
|
34
|
+
logger.debug "Removing mailchimp subscriber"
|
35
|
+
rescue Hominid::APIError => e
|
36
|
+
logger.warn "SpreeMailChimp: Failed to remove contact from Mailchimp: #{e.message}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Updates Mailchimp
|
42
|
+
#
|
43
|
+
# Returns nothing
|
44
|
+
# TODO: Update the user's email address in Mailchimp if it changes.
|
45
|
+
# Look at listMemberUpdate
|
46
|
+
def mailchimp_update_in_mailing_list
|
47
|
+
if self.is_mail_list_subscriber?
|
48
|
+
mailchimp_add_to_mailing_list
|
49
|
+
elsif !self.is_mail_list_subscriber?
|
50
|
+
mailchimp_remove_from_mailing_list
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Retrieves and stores the Mailchimp member id
|
55
|
+
#
|
56
|
+
# Returns the Mailchimp ID
|
57
|
+
def assign_mailchimp_subscriber_id
|
58
|
+
begin
|
59
|
+
response = hominid.list_member_info(mailchimp_list_id, [self.email]).with_indifferent_access
|
60
|
+
|
61
|
+
if response[:success] == 1
|
62
|
+
member = response[:data][0]
|
63
|
+
|
64
|
+
self.mailchimp_subscriber_id = member[:id]
|
65
|
+
end
|
66
|
+
rescue Hominid::APIError => e
|
67
|
+
logger.warn "SpreeMailChimp: Failed to retrieve and store Mailchimp ID: #{e.message}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Creates an instance of the Hominid::API
|
72
|
+
#
|
73
|
+
# Returns Hominid::API
|
74
|
+
def hominid
|
75
|
+
@hominid ||= Hominid::API.new(Spree::Config.get(:mailchimp_api_key))
|
76
|
+
end
|
77
|
+
|
78
|
+
# Gets the Mailchimp list ID that is stored in Spree::Config
|
79
|
+
#
|
80
|
+
# Returns a Mailchimp list ID String
|
81
|
+
def mailchimp_list_id
|
82
|
+
@mailchimp_list_id ||= Spree::Config.get(:mailchimp_list_id)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Generates the subsubcription options for the application
|
86
|
+
#
|
87
|
+
# The option values are returned as an Array in the following order:
|
88
|
+
#
|
89
|
+
# double_optin - Flag to control whether a double opt-in confirmation
|
90
|
+
# message is sent, defaults to true. Abusing this may
|
91
|
+
# cause your account to be suspended. (default: false)
|
92
|
+
# update_existing - Flag to control whether existing subscribers should be
|
93
|
+
# updated instead of throwing an error. (default: true)
|
94
|
+
# ( MailChimp's default is false )
|
95
|
+
# replace_interests - Flag to determine whether we replace the interest
|
96
|
+
# groups with the groups provided or we add the provided
|
97
|
+
# groups to the member's interest groups. (default: true)
|
98
|
+
# send_welcome - If the double_optin is false and this is true, a welcome
|
99
|
+
# email is sent out. If double_optin is true, this has no
|
100
|
+
# effect. (default: false)
|
101
|
+
#
|
102
|
+
# Returns an Array of subscription options
|
103
|
+
#
|
104
|
+
# TODO: Add configuration options for 'update_existing' and 'replace_interests'
|
105
|
+
# TODO: Remove configuration options for :mailchimp_send_notify
|
106
|
+
def mailchimp_subscription_opts
|
107
|
+
[Spree::Config.get(:mailchimp_double_opt_in), true, true, Spree::Config.get(:mailchimp_send_welcome)]
|
108
|
+
end
|
109
|
+
|
110
|
+
# Generates the merge variables for subscribing a user
|
111
|
+
def mailchimp_merge_vars
|
112
|
+
merge_vars = {}
|
113
|
+
if mailchimp_merge_user_attribs = Spree::Config.get(:mailchimp_merge_vars)
|
114
|
+
mailchimp_merge_user_attribs.split(',').each do |method|
|
115
|
+
merge_vars[method.upcase] = self.send(method.downcase) if @user.respond_to? method.downcase
|
116
|
+
end
|
117
|
+
end
|
118
|
+
merge_vars
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
<%= content_for :head do %>
|
2
|
+
<%= javascript_include_tag "jquery.validate.min" %>
|
3
|
+
<% end -%>
|
4
|
+
|
5
|
+
<%= render :partial => 'spree/admin/shared/configuration_menu' %>
|
6
|
+
|
7
|
+
<h1><%= t('mailchimp_settings') %></h1>
|
8
|
+
|
9
|
+
<%= form_tag(admin_mail_chimp_settings_path, :method => :put, :id => :mail_chimp_settings_form) do %>
|
10
|
+
|
11
|
+
<div class="yui-g">
|
12
|
+
<div class="yui-u first">
|
13
|
+
<fieldset>
|
14
|
+
<legend><%= t('mailchimp_keys') %></legend>
|
15
|
+
<p>
|
16
|
+
<label><%= t('mailchimp_api_key') %></label><br />
|
17
|
+
<%= text_field_tag('preferences[mailchimp_api_key]', Spree::Config[:mailchimp_api_key], :size => 46, :maxlength => 256, :class => 'email') %>
|
18
|
+
</p>
|
19
|
+
<p>
|
20
|
+
<label><%= t('mailchimp_list_id') %></label><br />
|
21
|
+
<%= text_field_tag('preferences[mailchimp_list_id]', Spree::Config[:mailchimp_list_id], :maxlength => 256, :class => 'email') %>
|
22
|
+
</p>
|
23
|
+
</fieldset>
|
24
|
+
|
25
|
+
<fieldset>
|
26
|
+
<legend><%= t('preferences') %></legend>
|
27
|
+
<p>
|
28
|
+
<label>
|
29
|
+
<input name="preferences[mailchimp_double_opt_in]" type="hidden" value="0" />
|
30
|
+
<%= check_box_tag('preferences[mailchimp_double_opt_in]', "1", Spree::Config[:mailchimp_double_opt_in]) %> <%= t('mailchimp_double_opt_in') %>
|
31
|
+
</label>
|
32
|
+
</p>
|
33
|
+
<p>
|
34
|
+
<label>
|
35
|
+
<input name="preferences[mailchimp_send_welcome]" type="hidden" value="0" />
|
36
|
+
<%= check_box_tag('preferences[mailchimp_send_welcome]', "1", Spree::Config[:mailchimp_send_welcome]) %> <%= t('mailchimp_send_welcome') %>
|
37
|
+
</label>
|
38
|
+
</p>
|
39
|
+
<p>
|
40
|
+
<label>
|
41
|
+
<input name="preferences[mailchimp_send_notify]" type="hidden" value="0" />
|
42
|
+
<%= check_box_tag('preferences[mailchimp_send_notify]', "1", Spree::Config[:mailchimp_send_notify]) %> <%= t('mailchimp_send_notify') %>
|
43
|
+
</label>
|
44
|
+
</p>
|
45
|
+
<p>
|
46
|
+
<label>
|
47
|
+
<%= t('mailchimp_merge_vars') %> <br /><%= text_field_tag('preferences[mailchimp_merge_vars]', Spree::Config[:mailchimp_merge_vars], :size => 44) %>
|
48
|
+
</label>
|
49
|
+
<br />
|
50
|
+
<span class="note"><%= t('mailchimp_merge_vars_help') %></span>
|
51
|
+
</p>
|
52
|
+
</fieldset>
|
53
|
+
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
|
57
|
+
<p class="form-buttons"><%= button t('save_preferences') %></p>
|
58
|
+
|
59
|
+
<script>
|
60
|
+
<%# TODO add validation for email list rather than simple email %>
|
61
|
+
$(document).ready(function(){
|
62
|
+
$("#inquiries_settings_form").validate();
|
63
|
+
});
|
64
|
+
</script>
|
65
|
+
<% end -%>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<%= render :partial => 'spree/admin/shared/configuration_menu' %>
|
2
|
+
|
3
|
+
<h1><%= t('mailchimp_settings') %></h1>
|
4
|
+
|
5
|
+
<table>
|
6
|
+
<tr>
|
7
|
+
<th scope="row"><%= t("mailchimp_api_key") %>:</th>
|
8
|
+
<td><%= Spree::Config[:mailchimp_api_key] %></td>
|
9
|
+
</tr>
|
10
|
+
<tr>
|
11
|
+
<th scope="row"><%= t("mailchimp_list_id") %>:</th>
|
12
|
+
<td><%= Spree::Config[:mailchimp_list_id] %></td>
|
13
|
+
</tr>
|
14
|
+
</table>
|
15
|
+
|
16
|
+
<h4><%= t("mailchimp_double_opt_in") %>: <%= Spree::Config[:mailchimp_double_opt_in]? t('yes') : t('no') %></h4>
|
17
|
+
<h4><%= t("mailchimp_send_welcome") %>: <%= Spree::Config[:mailchimp_send_welcome]? t('yes') : t('no') %></h4>
|
18
|
+
<h4><%= t("mailchimp_send_notify") %>: <%= Spree::Config[:mailchimp_send_notify]? t('yes') : t('no') %></h4>
|
19
|
+
<% unless Spree::Config[:mailchimp_merge_vars].blank? %>
|
20
|
+
<h4><%= t("mailchimp_merge_vars") %></h4>
|
21
|
+
<p>
|
22
|
+
<%= raw Spree::Config[:mailchimp_merge_vars].gsub(/,/, '<br >') %>
|
23
|
+
</p>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<p><%= link_to_with_icon 'edit', t("edit"), edit_admin_mail_chimp_settings_path %></p>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<div id="mailchimp_subscribe_wrap">
|
2
|
+
<%= form_for :user, :url => :subscriptions do |f| %>
|
3
|
+
<table>
|
4
|
+
<tr>
|
5
|
+
<td>
|
6
|
+
<%= text_field_tag :email, t('enter_your_email'), :class => 'email', :id => 'subscribe_email' %>
|
7
|
+
</td>
|
8
|
+
<td>
|
9
|
+
<%= submit_tag t('subscribe'), :id => 'op_subscribe' %>
|
10
|
+
</td>
|
11
|
+
</tr>
|
12
|
+
</table>
|
13
|
+
<% end -%>
|
14
|
+
</div>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<% flash[:notice] = nil %>
|
2
|
+
|
3
|
+
var modal_opts = { closeHTML : '<div>[x] CLOSE</div>',
|
4
|
+
|
5
|
+
containerCss : { height:80 },
|
6
|
+
|
7
|
+
onOpen: function (dialog) {
|
8
|
+
dialog.overlay.fadeIn('fast', function() {
|
9
|
+
dialog.data.show();
|
10
|
+
dialog.container.fadeIn('fast');
|
11
|
+
});
|
12
|
+
}
|
13
|
+
};
|
14
|
+
|
15
|
+
<% if @errors.empty? %>
|
16
|
+
$.modal('<div id="modal-notice"><h1><%= t("you_have_been_subscribed") %></h1></div>', modal_opts);
|
17
|
+
<% else %>
|
18
|
+
$.modal('<div id="modal-notice"><h1>ERROR:</h1> <%= @errors.join(' / ') %></div>', modal_opts);
|
19
|
+
<% end %>
|
20
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SpreeMailChimp
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
def add_javascripts
|
6
|
+
append_file "app/assets/javascripts/store/all.js", "//= require store/spree_mail_chimp\n"
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_stylesheets
|
10
|
+
inject_into_file "app/assets/stylesheets/store/all.css", " *= require store/spree_mail_chimp\n", :before => /\*\//, :verbose => true
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_migrations
|
14
|
+
run 'rake railties:install:migrations FROM=spree_mail_chimp'
|
15
|
+
end
|
16
|
+
|
17
|
+
def run_migrations
|
18
|
+
res = ask "Would you like to run the migrations now? [Y/n]"
|
19
|
+
if res == "" || res.downcase == "y"
|
20
|
+
run 'rake db:migrate'
|
21
|
+
else
|
22
|
+
puts "Skiping rake db:migrate, don't forget to run it!"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Spree::MailChimp
|
2
|
+
class Config < Spree::Config
|
3
|
+
class << self
|
4
|
+
def instance
|
5
|
+
return nil unless ActiveRecord::Base.connection.tables.include?('configurations')
|
6
|
+
MailChimpConfiguration.find_or_create_by_name("MailChimp configuration")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SpreeMailChimp
|
2
|
+
class Engine < Rails::Engine
|
3
|
+
engine_name 'spree_mail_chimp'
|
4
|
+
|
5
|
+
config.autoload_paths += %W(#{config.root}/lib)
|
6
|
+
|
7
|
+
def self.activate
|
8
|
+
Dir.glob(File.join(File.dirname(__FILE__), "../../app/**/*_decorator*.rb")) do |c|
|
9
|
+
Rails.application.config.cache_classes ? require(c) : load(c)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
config.to_prepare &method(:activate).to_proc
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils::Verbose
|
3
|
+
|
4
|
+
namespace :mail_chimp do
|
5
|
+
namespace :db do
|
6
|
+
desc "Custom migrations"
|
7
|
+
task :migrate do
|
8
|
+
require 'erb'
|
9
|
+
require 'logger'
|
10
|
+
require 'active_record'
|
11
|
+
reference = YAML::load(ERB.new(IO.read("#{Rails.root}/config/database.yml")).result)
|
12
|
+
env = RAILS_ENV = ENV['RAILS_ENV'] || 'development'
|
13
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
14
|
+
ActiveRecord::Base.logger.level = Logger::WARN
|
15
|
+
ActiveRecord::Base.configurations = reference.dup
|
16
|
+
reference.each_key do |name|
|
17
|
+
next unless name.include? env
|
18
|
+
puts "Migrating #{name}"
|
19
|
+
ActiveRecord::Base.clear_active_connections!
|
20
|
+
ActiveRecord::Base.configurations[env] = reference[name]
|
21
|
+
ActiveRecord::Base.establish_connection RAILS_ENV
|
22
|
+
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
23
|
+
ActiveRecord::Migrator.migrate("#{File.expand_path('../..', File.dirname(__FILE__))}/db/migrate", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
|
24
|
+
Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Loads a specified fixture using rake db:load_file[filename.rb]"
|
29
|
+
task :seed do
|
30
|
+
Rake::Task["mail_chimp:db:load_dir"].invoke("default")
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Loads a specified fixture using rake db:load_file[filename.rb]"
|
34
|
+
task :load_file, [:file] => :environment do |t, args|
|
35
|
+
file = args.file
|
36
|
+
ext = File.extname file
|
37
|
+
if ext == ".csv" or ext == ".yml"
|
38
|
+
puts "loading fixture " + file
|
39
|
+
Fixtures.create_fixtures(File.dirname(file), File.basename(file, '.*'))
|
40
|
+
else
|
41
|
+
if File.exists? file
|
42
|
+
puts "loading ruby " + file
|
43
|
+
require file
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Loads fixtures from the the dir you specify using rake db:load_dir[loadfrom]"
|
49
|
+
task :load_dir, [:dir] => :environment do |t, args|
|
50
|
+
dir = args.dir
|
51
|
+
fixtures = ActiveSupport::OrderedHash.new
|
52
|
+
ruby_files = ActiveSupport::OrderedHash.new
|
53
|
+
Dir.glob(File.join(File.expand_path('../..', File.dirname(__FILE__)), "db", dir, '*.{yml,csv,rb}')).each do |fixture_file|
|
54
|
+
ext = File.extname fixture_file
|
55
|
+
if ext == ".rb"
|
56
|
+
ruby_files[File.basename(fixture_file, '.*')] = fixture_file
|
57
|
+
else
|
58
|
+
fixtures[File.basename(fixture_file, '.*')] = fixture_file
|
59
|
+
end
|
60
|
+
end
|
61
|
+
fixtures.sort.each do |fixture, fixture_file|
|
62
|
+
# an invoke will only execute the task once
|
63
|
+
Rake::Task["db:load_file"].execute(Rake::TaskArguments.new([:file], [fixture_file]))
|
64
|
+
end
|
65
|
+
ruby_files.sort.each do |fixture, ruby_file|
|
66
|
+
# an invoke will only execute the task once
|
67
|
+
Rake::Task["db:load_file"].execute(Rake::TaskArguments.new([:file], [ruby_file]))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spree_mail_chimp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 3.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sam Beam
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: spree_core
|
16
|
+
requirement: &17066680 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *17066680
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hominid
|
27
|
+
requirement: &17064580 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *17064580
|
36
|
+
description:
|
37
|
+
email: sbeam@onsetcorps.net
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
extra_rdoc_files: []
|
41
|
+
files:
|
42
|
+
- README.textile
|
43
|
+
- LICENSE
|
44
|
+
- lib/spree_mail_chimp/engine.rb
|
45
|
+
- lib/spree_mail_chimp.rb
|
46
|
+
- lib/generators/spree_mail_chimp/install/install_generator.rb
|
47
|
+
- lib/tasks/mail_chimp.rake
|
48
|
+
- lib/spree/mail-chimp/config.rb
|
49
|
+
- app/controllers/spree/subscriptions_controller.rb
|
50
|
+
- app/controllers/spree/admin/mail_chimp_settings_controller.rb
|
51
|
+
- app/views/spree/users/_subscribe_to_newsletter_field.html.erb
|
52
|
+
- app/views/spree/shared/_newsletter_subscribe_form_wo_butt.html.erb
|
53
|
+
- app/views/spree/shared/_newsletter_subscribe_form.html.erb
|
54
|
+
- app/views/spree/subscriptions/create.js.erb
|
55
|
+
- app/views/spree/admin/configurations/_spree_mail_chimp_configuration_link.html.erb
|
56
|
+
- app/views/spree/admin/mail_chimp_settings/edit.html.erb
|
57
|
+
- app/views/spree/admin/mail_chimp_settings/show.html.erb
|
58
|
+
- app/overrides/add_newsletter_subscribe_form_to_footer.rb
|
59
|
+
- app/overrides/add_newsletter_checkbox_to_create_account_page.rb
|
60
|
+
- app/overrides/add_mail_chimp_admin_menu_link.rb
|
61
|
+
- app/assets/stylesheets/store/mail_chimp.css
|
62
|
+
- app/assets/stylesheets/store/spree_mail_chimp.css
|
63
|
+
- app/assets/javascripts/store/mailchimp_subscribe.js
|
64
|
+
- app/assets/javascripts/store/jquery.simplemodal.1.4.min.js
|
65
|
+
- app/assets/javascripts/store/spree_mail_chimp.js
|
66
|
+
- app/models/user_decorator.rb
|
67
|
+
- app/models/app_configuration_decorator.rb
|
68
|
+
homepage: https://github.com/sbeam/spree-mail-chimp
|
69
|
+
licenses: []
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 1.8.7
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements:
|
87
|
+
- none
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 1.8.11
|
90
|
+
signing_key:
|
91
|
+
specification_version: 3
|
92
|
+
summary: Mail Chimp subscriptions for your Spree store using hominid
|
93
|
+
test_files: []
|