Skip to content

Commit 4d9003d

Browse files
committed
Initial commit
0 parents  commit 4d9003d

28 files changed

+482
-0
lines changed

.gitignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
\#*
2+
*~
3+
.#*
4+
.DS_Store
5+
.idea
6+
.project
7+
.sass-cache
8+
coverage
9+
Gemfile.lock
10+
tmp
11+
nbproject
12+
pkg
13+
*.swp
14+
spec/dummy

.rspec

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--color

Gemfile

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
source 'https://rubygems.org'
2+
3+
gem 'spree', github: 'spree/spree', branch: '2-3-stable'
4+
# Provides basic authentication functionality for testing parts of your engine
5+
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '2-3-stable'
6+
7+
gemspec

LICENSE

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Copyright (c) 2014 Alessandro Lepore
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without modification,
5+
are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright notice,
8+
this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above copyright notice,
10+
this list of conditions and the following disclaimer in the documentation
11+
and/or other materials provided with the distribution.
12+
* Neither the name Spree nor the names of its contributors may be used to
13+
endorse or promote products derived from this software without specific
14+
prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
SpreeNewsletterSubscription
2+
===========================
3+
4+
Allow simple newsletter subscription on Spree stores.
5+
Uses mailchimp.
6+
7+
Installation
8+
------------
9+
10+
Add spree_newsletter_subscription to your Gemfile:
11+
12+
```ruby
13+
gem 'spree_newsletter_subscription'
14+
```
15+
16+
Bundle your dependencies and run the installation generator:
17+
18+
```shell
19+
bundle
20+
bundle exec rails g spree_newsletter_subscription:install
21+
```
22+
23+
Configuration
24+
-------------
25+
26+
Add your credentials to `config/initializers/spree.rb`:
27+
28+
```ruby
29+
SpreeNewsletterSubscription::Config.tap do |config|
30+
config.api_key = {
31+
default: 'xxxxxxxxxxxxx-us9',
32+
}
33+
34+
config.list_id = {
35+
default: 'xxxxxxxxx',
36+
en: 'yyyyyyyy' # use a different list for locale == :en
37+
}
38+
end
39+
```
40+
41+
You can have different list ids (and even api keys) for each locale.
42+
If missing, default is always used.
43+
44+
45+
Testing
46+
-------
47+
48+
First bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it does not exist, then it will run specs. The dummy app can be regenerated by using `rake test_app`.
49+
50+
```shell
51+
bundle
52+
bundle exec rake
53+
```
54+
55+
When testing your applications integration with this extension you may use it's factories.
56+
Simply add this require statement to your spec_helper:
57+
58+
```ruby
59+
require 'spree_newsletter_subscription/factories'
60+
```
61+
62+
Copyright (c) 2014 Alessandro Lepore, released under the New BSD License

Rakefile

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
require 'bundler'
2+
Bundler::GemHelper.install_tasks
3+
4+
require 'rspec/core/rake_task'
5+
require 'spree/testing_support/extension_rake'
6+
7+
RSpec::Core::RakeTask.new
8+
9+
task :default do
10+
if Dir["spec/dummy"].empty?
11+
Rake::Task[:test_app].invoke
12+
Dir.chdir("../../")
13+
end
14+
Rake::Task[:spec].invoke
15+
end
16+
17+
desc 'Generates a dummy app for testing'
18+
task :test_app do
19+
ENV['LIB_NAME'] = 'spree_newsletter_subscription'
20+
Rake::Task['extension:test_app'].invoke
21+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Placeholder manifest file.
2+
// the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/backend/all.js'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
$(function(){
2+
$('form#newsletter-subscription').submit(function() {
3+
$(this).addClass('submitted');
4+
});
5+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/*
2+
Placeholder manifest file.
3+
the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/backend/all.css'
4+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#newsletter-subscription-errors {
2+
color: red;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module Spree
2+
class NewsletterSubscriptionsController < StoreController
3+
def create
4+
@subscription = Spree::NewsletterSubscription.new(params[:newsletter_subscription])
5+
@success = @subscription.save!
6+
end
7+
end
8+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module Spree
2+
class NewsletterSubscription
3+
extend ActiveModel::Naming
4+
include ActiveModel::Conversion
5+
include ActiveModel::Validations
6+
7+
attr_accessor :email, :terms, :locale
8+
9+
validates :email, presence: true
10+
validates :terms, acceptance: true
11+
12+
def initialize(attributes = {})
13+
attributes.each do |name, value|
14+
send("#{name}=", value)
15+
end
16+
end
17+
18+
def save!
19+
return unless valid?
20+
21+
result = SpreeNewsletterSubscription::MailchimpSubscriber.new(email, locale).subscribe!
22+
if !result[:success] && result[:error].present?
23+
errors.add(:base, result[:error])
24+
end
25+
26+
result[:success]
27+
end
28+
29+
def persisted?
30+
false
31+
end
32+
end
33+
end

app/models/spree/user_decorator.rb

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Spree.user_class.class_eval do
2+
after_save :newsletter_subscription
3+
4+
private
5+
6+
def newsletter_subscription
7+
if id_changed? || subscribed_to_mailing_list_changed?
8+
if subscribed_to_mailing_list
9+
params = { email: email,
10+
terms: '1' }
11+
Spree::NewsletterSubscription.new(params).save!
12+
else
13+
# TODO unsubscribe?
14+
end
15+
end
16+
end
17+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
$('div#newsletter-subscription-errors').remove();
2+
3+
<% if @success %>
4+
content = '<%= Spree.t(:success_html, scope: :newsletter_subscription) %>'
5+
$('#newsletter-subscription.submitted').hide().html(content).fadeIn(400);
6+
<% else %>
7+
content = '<div id="newsletter-subscription-errors"><%= raw @subscription.errors.full_messages.join("<br>") %></div>'
8+
$('#newsletter-subscription.submitted').before(content);
9+
<% end %>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<%= form_for :newsletter_subscription, url: newsletter_subscriptions_path,
2+
remote: true , html: { id: 'newsletter-subscription' } do |f| %>
3+
4+
<%= f.hidden_field :locale, value: I18n.locale %>
5+
<%= f.email_field :email %>
6+
<%= f.check_box :terms %>
7+
<%= button_tag :submit %>
8+
9+
<% end %>

bin/rails

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
2+
3+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
4+
ENGINE_PATH = File.expand_path('../../lib/spree_newsletter_subscription/engine', __FILE__)
5+
6+
require 'rails/all'
7+
require 'rails/engine/commands'

config/locales/en.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
en:
2+
activemodel:
3+
attributes:
4+
spree/newsletter_subscription:
5+
terms: Terms and Conditions
6+
spree:
7+
newsletter_subscription:
8+
success_html: <h3>Successfully subscribed to our newsletter</h3>

config/locales/it.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
it:
2+
activemodel:
3+
attributes:
4+
spree/newsletter_subscription:
5+
terms: Termini e Condizioni
6+
spree:
7+
newsletter_subscription:
8+
success_html: <h3>Sei stato iscritto alla nostra newsletter!</h3>

config/routes.rb

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Spree::Core::Engine.routes.draw do
2+
resources :newsletter_subscriptions, only: [:create]
3+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddSubscribedToMailingListToSpreeUsers < ActiveRecord::Migration
2+
def change
3+
add_column Spree.user_class.table_name, :subscribed_to_mailing_list, :boolean, null: false, default: false
4+
end
5+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
module SpreeNewsletterSubscription
2+
module Generators
3+
class InstallGenerator < Rails::Generators::Base
4+
5+
class_option :auto_run_migrations, :type => :boolean, :default => false
6+
7+
def add_javascripts
8+
append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/spree_newsletter_subscription\n"
9+
append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/spree_newsletter_subscription\n"
10+
end
11+
12+
def add_stylesheets
13+
inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/spree_newsletter_subscription\n", :before => /\*\//, :verbose => true
14+
inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/spree_newsletter_subscription\n", :before => /\*\//, :verbose => true
15+
end
16+
17+
def add_migrations
18+
run 'bundle exec rake railties:install:migrations FROM=spree_newsletter_subscription'
19+
end
20+
21+
def run_migrations
22+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask 'Would you like to run the migrations now? [Y/n]')
23+
if run_migrations
24+
run 'bundle exec rake db:migrate'
25+
else
26+
puts 'Skipping rake db:migrate, don\'t forget to run it!'
27+
end
28+
end
29+
end
30+
end
31+
end

lib/spree_newsletter_subscription.rb

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require 'spree_core'
2+
require 'spree_newsletter_subscription/engine'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module SpreeNewsletterSubscription
2+
class Configuration < Spree::Preferences::Configuration
3+
preference :api_key, :hash
4+
preference :list_id, :hash
5+
# preference :double_opt_in, :boolean, default: true
6+
# preference :send_welcome, :boolean, default: true
7+
# preference :send_notify, :boolean, default: true
8+
# preference :merge_vars, :string, default: ''
9+
end
10+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module SpreeNewsletterSubscription
2+
class Engine < Rails::Engine
3+
require 'spree/core'
4+
isolate_namespace Spree
5+
engine_name 'spree_newsletter_subscription'
6+
7+
config.autoload_paths += %W(#{config.root}/lib)
8+
9+
# use rspec for tests
10+
config.generators do |g|
11+
g.test_framework :rspec
12+
end
13+
14+
initializer 'spree_newsletter_subscription.environment', before: :load_config_initializers do |app|
15+
SpreeNewsletterSubscription::Config = SpreeNewsletterSubscription::Configuration.new
16+
Spree::PermittedAttributes.user_attributes.push :subscribed_to_mailing_list
17+
end
18+
19+
def self.activate
20+
Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
21+
Rails.configuration.cache_classes ? require(c) : load(c)
22+
end
23+
end
24+
25+
config.to_prepare &method(:activate).to_proc
26+
end
27+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FactoryGirl.define do
2+
# Define your Spree extensions Factories within this file to enable applications, and other extensions to use and override them.
3+
#
4+
# Example adding this to your spec_helper will load these Factories for use:
5+
# require 'spree_newsletter_subscription/factories'
6+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
require 'mailchimp'
2+
3+
module SpreeNewsletterSubscription
4+
class MailchimpSubscriber
5+
def initialize(email, locale = nil)
6+
@email = email
7+
@locale = locale
8+
@list = get_config(:list_id)
9+
@mailchimp = Mailchimp::API.new(get_config(:api_key))
10+
@logger = Logger.new(Rails.root.join('log/newsletter_subscription.log'))
11+
end
12+
13+
def subscribe!
14+
@logger.debug("#subscribe!(#{@email})")
15+
begin
16+
result = @mailchimp.lists.subscribe(@list, { email: @email })
17+
{ success: true }
18+
rescue Exception => e
19+
@logger.debug(e.message)
20+
{ success: false, error: e.message }
21+
end
22+
end
23+
24+
private
25+
26+
def config
27+
@config ||= SpreeNewsletterSubscription::Config
28+
end
29+
30+
def get_config(key)
31+
conf = config[key][@locale.to_sym] if @locale
32+
conf ||= config[key][:default]
33+
end
34+
end
35+
end

0 commit comments

Comments
 (0)