spree_mail 0.40.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/README.md +19 -0
  2. data/Rakefile +94 -0
  3. data/app/controllers/admin/emails_controller.rb +61 -0
  4. data/app/controllers/admin/subscribers_controller.rb +78 -0
  5. data/app/controllers/emails_controller.rb +19 -0
  6. data/app/controllers/subscribers_controller.rb +42 -0
  7. data/app/mailers/email_mailer.rb +24 -0
  8. data/app/model/email.rb +77 -0
  9. data/app/model/subscriber.rb +39 -0
  10. data/app/views/admin/emails/_form.html.erb +78 -0
  11. data/app/views/admin/emails/edit.html.erb +15 -0
  12. data/app/views/admin/emails/index.html.erb +64 -0
  13. data/app/views/admin/emails/new.html.erb +15 -0
  14. data/app/views/admin/emails/show.html.erb +20 -0
  15. data/app/views/admin/hooks/_subscribers_tab.html.erb +1 -0
  16. data/app/views/admin/shared/_spree_mail_sub_nav.html.erb +8 -0
  17. data/app/views/admin/subscribers/_form.html.erb +19 -0
  18. data/app/views/admin/subscribers/_options.html.erb +5 -0
  19. data/app/views/admin/subscribers/edit.html.erb +15 -0
  20. data/app/views/admin/subscribers/index.html.erb +76 -0
  21. data/app/views/admin/subscribers/new.html.erb +15 -0
  22. data/app/views/admin/subscribers/show.html.erb +19 -0
  23. data/app/views/hooks/_footer_left.html.erb +1 -0
  24. data/app/views/hooks/_subscriber_sign_up_form.html.erb +4 -0
  25. data/app/views/hooks/_subscriber_static_content.html.erb +3 -0
  26. data/app/views/layouts/email.html.erb +81 -0
  27. data/app/views/subscribers/_fields.html.erb +11 -0
  28. data/app/views/subscribers/new.html.erb +17 -0
  29. data/app/views/subscribers/show.html.erb +16 -0
  30. data/config/locales/en.yml +33 -0
  31. data/config/routes.rb +20 -0
  32. data/db/migrate/install_spree_mail.rb +25 -0
  33. data/lib/spree_mail.rb +24 -0
  34. data/lib/spree_mail/custom_hooks.rb +20 -0
  35. data/lib/spree_mail/version.rb +3 -0
  36. data/lib/tasks/install.rake +36 -0
  37. data/public/images/mailer/airmail.gif +0 -0
  38. data/public/images/mailer/background.jpg +0 -0
  39. data/public/images/mailer/postmark.png +0 -0
  40. data/public/stylesheets/admin/spree_mail.css +38 -0
  41. metadata +149 -0
@@ -0,0 +1,19 @@
1
+ Spree Mail
2
+ ----------
3
+
4
+ Spree Mail extends Spree by adding a mailing list subscriber model, sign up forms and an admin to send messages.
5
+
6
+
7
+
8
+ Demo
9
+ ----
10
+
11
+ rails new spree_mail_example; cd spree_mail_example; echo "gem 'spree', '0.40.2'" >> Gemfile; echo "gem 'spree_mail', '0.40.0.1'" >> Gemfile; rm public/index.html; bundle install; rake spree:install spree_mail:install db:migrate db:seed; rails s
12
+
13
+
14
+
15
+
16
+ License
17
+ -------
18
+
19
+ Copyright (c) 2011 Spencer Steffen, released under the New BSD License All rights reserved.
@@ -0,0 +1,94 @@
1
+ require 'bundler'
2
+ #require 'rake/testtask'
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ #Rake::TestTask.new do |t|
6
+ # t.libs << "lib"
7
+ # t.pattern = 'test/**/*_test.rb'
8
+ # t.verbose = true
9
+ #end
10
+
11
+
12
+ task :test do
13
+
14
+ root = ENV["RAILS_ROOT"] || File.expand_path('../spec/test_app', __FILE__)
15
+ env = File.join(root, 'config', 'environment.rb')
16
+ puts "(Rails Root: #{root})"
17
+
18
+ require env
19
+ require File.expand_path('../test/test_helper', __FILE__)
20
+ Dir["test/**/*.rb"].reject{|file| file.match(/test_helper/) != nil }.each do |file|
21
+ puts "Loading #{file}"
22
+ load file
23
+ end
24
+
25
+ end
26
+
27
+
28
+
29
+
30
+ desc "Default Task"
31
+ task :default => [ :test ]
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+ # TODO: pull in the spree/core/Rakefile bits that set up for testing
41
+ desc "Regenerates a Rails 3 app for testing"
42
+ task :test_app do
43
+ # TODO - this path requires a certain directory structure -- need
44
+ # to think about how to refactor
45
+
46
+
47
+ files = `gem contents spree`.split("\n").select{|file| file.match("test_app_generator")}
48
+ if files.length == 1
49
+ require files.first
50
+ class SpreeMailTestAppGenerator < Spree::Generators::TestAppGenerator
51
+ def tweak_gemfile
52
+ append_file "Gemfile" ,
53
+ <<-gems
54
+ gem 'activemerchant'
55
+ gem 'spree_core', '>=0.40.2'
56
+ gem 'spree_auth', '>=0.40.2'
57
+ gem 'spree_mail', :path => "#{File.dirname(__FILE__)}"
58
+ gems
59
+ end
60
+
61
+ def install_spree_gems
62
+
63
+ puts "-----------------------------------------"
64
+ puts "Installing gems..."
65
+ `bundle install --gemfile=spec/test_app/Gemfile`
66
+ puts "-----------------------------------------"
67
+
68
+ inside "test_app" do
69
+ run 'rake spree_core:install'
70
+ run 'rake spree_auth:install'
71
+ run 'rake spree_mail:install'
72
+ end
73
+ end
74
+
75
+ def migrate_db
76
+ run_migrations
77
+ end
78
+ end
79
+
80
+ SpreeMailTestAppGenerator.start
81
+
82
+ puts "spec/test_app created. "
83
+
84
+ else
85
+ puts "Failed: Could not find lib/generators/spree/test_app_generator.rb"
86
+ end
87
+ end
88
+
89
+ namespace :test_app do
90
+ desc 'Rebuild test database'
91
+ task :rebuild_db do
92
+ system("cd spec/test_app && rake db:drop db:migrate RAILS_ENV=test")
93
+ end
94
+ end
@@ -0,0 +1,61 @@
1
+ class Admin::EmailsController < Admin::BaseController
2
+
3
+ resource_controller
4
+
5
+ before_filter :check_json_authenticity, :only => :index
6
+ before_filter :get_subscribers, :only => [:new, :create, :edit, :update]
7
+
8
+ index.response do |wants|
9
+ wants.html { render :action => :index }
10
+ wants.json { render :json => json_data }
11
+ end
12
+ destroy.success.wants.js { render_js_for_destroy }
13
+
14
+
15
+ def deliver
16
+ @email = Email.find(params[:id])
17
+ sent, count = @email.deliver!
18
+ if sent
19
+ flash[:notice] = t('delivery_success', count)
20
+ else
21
+ flash[:error] = t('delivery_failed', count)
22
+ end
23
+ redirect_to admin_email_path(@email)
24
+ end
25
+
26
+
27
+
28
+ private
29
+
30
+ ## Allow different formats of json data to suit different ajax calls
31
+ #def json_data
32
+ # json_format = params[:json_format] or 'default'
33
+ # case json_format
34
+ # when 'basic'
35
+ # collection.map {|u| {'id' => u.id, 'name' => u.email}}.to_json
36
+ # else
37
+ # collection.to_json(:include =>
38
+ # {:bill_address => {:include => [:state, :country]},
39
+ # :ship_address => {:include => [:state, :country]}})
40
+ # end
41
+ #end
42
+
43
+ def get_subscribers
44
+ @subscribers = Subscriber.active
45
+ end
46
+
47
+ def collection
48
+ return @collection if @collection.present?
49
+ unless request.xhr?
50
+ @search = Email.searchlogic(params[:search])
51
+
52
+ #set order by to default or form result
53
+ @search.order ||= "ascend_by_name"
54
+
55
+ @collection = @search.do_search.paginate(:per_page => Spree::Config[:admin_products_per_page], :page => params[:page])
56
+
57
+ else
58
+ @collection = Email.where("wholesalers.name like :search", {:search => "#{params[:q].strip}%"}).limit(params[:limit] || 100)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,78 @@
1
+ class Admin::SubscribersController < Admin::BaseController
2
+
3
+ resource_controller
4
+
5
+ before_filter :check_json_authenticity, :only => :index
6
+
7
+ #index.response do |wants|
8
+ # wants.html { render :action => :index }
9
+ # wants.json { render :json => json_data }
10
+ #end
11
+
12
+ destroy.success.wants.js { render_js_for_destroy }
13
+
14
+ create.response do |wants|
15
+ wants.html { redirect_to admin_subscribers_path }
16
+ end
17
+
18
+ update.response do |wants|
19
+ wants.html { redirect_to admin_subscribers_path }
20
+ end
21
+
22
+ def resubscribe
23
+ @subscriber = object
24
+ if @subscriber.resubscribe!
25
+ flash[:notice] = t("resubscribe_success")
26
+ else
27
+ flash[:error] = t("resubscribe_failed")
28
+ end
29
+ redirect_to request.referer
30
+ end
31
+
32
+ def unsubscribe
33
+ @subscriber = object
34
+ if @subscriber.unsubscribe!
35
+ flash[:notice] = t("unsubscribe_success")
36
+ else
37
+ flash[:error] = t("unsubscribe_failed")
38
+ end
39
+ redirect_to request.referer
40
+ end
41
+
42
+ def unsubscribed
43
+ @search = Subscriber.searchlogic(params[:search])
44
+
45
+ #set order by to default or form result
46
+ @search.order ||= "ascend_by_name"
47
+
48
+ @subscribers = @collection = @search.do_search.unsubscribed.paginate(:per_page => Spree::Config[:admin_products_per_page], :page => params[:page])
49
+ render :template => 'admin/subscribers/index'
50
+ end
51
+
52
+
53
+ private
54
+
55
+ # Allow different formats of json data to suit different ajax calls
56
+ #def json_data
57
+ # json_format = params[:json_format] or 'default'
58
+ # case json_format
59
+ # when 'basic'
60
+ # collection.map {|u| {'id' => u.id, 'name' => u.email}}.to_json
61
+ # else
62
+ # collection.to_json(:include =>
63
+ # {:bill_address => {:include => [:state, :country]},
64
+ # :ship_address => {:include => [:state, :country]}})
65
+ # end
66
+ #end
67
+
68
+ def collection
69
+ return @collection if @collection.present?
70
+ @search = Subscriber.searchlogic(params[:search])
71
+
72
+ #set order by to default or form result
73
+ @search.order ||= "ascend_by_name"
74
+
75
+ @collection = @search.do_search.active.paginate(:per_page => Spree::Config[:admin_products_per_page], :page => params[:page])
76
+
77
+ end
78
+ end
@@ -0,0 +1,19 @@
1
+ class EmailsController < Spree::BaseController
2
+
3
+ include ActionView::Helpers::TagHelper
4
+ include ActionView::Helpers::TextHelper
5
+
6
+ def show
7
+ @subscriber = Subscriber.find_by_token(params[:token])
8
+ @email = Email.find_by_token(params[:id])
9
+
10
+ return redirect_to new_subscriber_path unless @email.recipients.include?(@subscriber.email)
11
+
12
+ @email_subject = @email.render(:subject, @subscriber)
13
+ @text = @email.render(:body, @subscriber)
14
+ @base_url = "http://#{Spree::Config[:site_url]}"
15
+
16
+ render :layout => 'email', :text => simple_format(@text)
17
+ end
18
+
19
+ end
@@ -0,0 +1,42 @@
1
+ class SubscribersController < Spree::BaseController
2
+
3
+ before_filter :get_subscriber, :only => [:show, :unsubscribe]
4
+
5
+ def index
6
+ redirect_to new_subscriber_path
7
+ end
8
+
9
+ def new
10
+ @subscriber = Subscriber.new
11
+ end
12
+
13
+ def show
14
+ end
15
+
16
+ def create
17
+ @subscriber = Subscriber.new(params[:subscriber])
18
+ if @subscriber.valid? && @subscriber.save
19
+ flash[:notice] = "Thanks for signing up for our newsletter!"
20
+ redirect_to new_subscriber_path
21
+ else
22
+ flash[:error] = "Sorry, we could not sign you up."
23
+ render :action => 'new'
24
+ end
25
+ end
26
+
27
+ def unsubscribe
28
+ if @subscriber.email == params[:subscriber][:email] && @subscriber.unsubscribe!
29
+ flash[:notice] = "You were successfully unsubscribed from the mailing list."
30
+ else
31
+ flash[:error] = "We're sorry, you could not be unsubscribed at this time."
32
+ end
33
+ redirect_to new_subscriber_path
34
+ end
35
+
36
+ private
37
+
38
+ def get_subscriber
39
+ @subscriber = Subscriber.find_by_token(params[:id])
40
+ end
41
+
42
+ end
@@ -0,0 +1,24 @@
1
+ class EmailMailer < ActionMailer::Base
2
+
3
+ include ActionView::Helpers::TagHelper
4
+ include ActionView::Helpers::TextHelper
5
+
6
+ default_url_options[:host] = "10.0.1.10:3000"
7
+
8
+ def with_layout(email, subscriber)
9
+ @email = email
10
+ @subscriber = subscriber
11
+ @email_subject = @email.render(:subject, @subscriber)
12
+ @text = @email.render(:body, @subscriber)
13
+ @base_url = "http://10.0.1.10:3000" ##{Spree::Config[:site_url]}
14
+ @link_to_browser = read_email_url(@subscriber.token, @email.token)
15
+
16
+ unless @email.nil? || @email_subject.empty? || @text.empty?
17
+ mail(:to => @subscriber.email, :from => @email.from, :subject => @email_subject) do |format|
18
+ format.text { render :text => @text }
19
+ format.html { render :layout => 'email', :text => simple_format(@text) }
20
+ end
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,77 @@
1
+ class Email < ActiveRecord::Base
2
+
3
+ validates :to, :presence => true
4
+ validates :subject, :presence => true
5
+ validates :body, :presence => true
6
+
7
+ before_create :set_token
8
+
9
+ def to=(value)
10
+ value = {} unless value.is_a? Hash
11
+ value.delete("0")
12
+ return false if value.empty?
13
+ write_attribute :to, value.inspect
14
+ end
15
+
16
+ def from
17
+ MailMethod.current.preferred_mails_from rescue "no-reply@spree-mail-example.com"
18
+ end
19
+
20
+ def recipients
21
+ hash = eval(read_attribute(:to)) rescue {}
22
+ hash.values
23
+ end
24
+
25
+ def recipient_list
26
+ recipients.join(", ")
27
+ end
28
+
29
+ def deliver!
30
+ count = 0
31
+ recipients.each do |email|
32
+ subscriber = Subscriber.find_by_email(email) rescue nil
33
+ if subscriber
34
+ mail = EmailMailer.with_layout(self, subscriber)
35
+ count += 1 if mail && mail.deliver!
36
+ end
37
+ end
38
+ return 0 < count, count
39
+ end
40
+
41
+
42
+
43
+ def render(attribute, subscriber)
44
+ Mustache.render(self.send(attribute), subscriber.attributes)
45
+ end
46
+
47
+ private
48
+
49
+ def set_token
50
+ write_attribute :token, Digest::SHA1.hexdigest(Time.now.to_s)
51
+ end
52
+
53
+
54
+ class << self
55
+
56
+ def new(parameters={})
57
+ parameters ||= {}
58
+ super(parameters.reverse_merge!(:body => template))
59
+ end
60
+
61
+ def template
62
+ txt=<<TXT
63
+ Hello {{name}},
64
+
65
+
66
+
67
+ Regards,
68
+
69
+ #{Spree::Config[:site_name]}
70
+
71
+ TXT
72
+ end
73
+
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,39 @@
1
+ class Subscriber < ActiveRecord::Base
2
+
3
+ attr_protected :token
4
+
5
+ scope :active, where("unsubscribed_at IS NULL").order(:name)
6
+ scope :unsubscribed, where("unsubscribed_at IS NOT NULL").order(:name)
7
+
8
+ validates :name, :presence => true
9
+ validates :email, :format => Devise.email_regexp, :uniqueness => true
10
+
11
+ before_create :set_token
12
+
13
+ def active?
14
+ unsubscribed_at.to_s.empty?
15
+ end
16
+
17
+ def resubscribe!
18
+ return true if active?
19
+ self.unsubscribed_at = nil
20
+ save
21
+ end
22
+
23
+ def unsubscribe!
24
+ return true unless active?
25
+ self.unsubscribed_at = Time.now
26
+ save
27
+ end
28
+
29
+ def email=(value)
30
+ write_attribute :email, value.strip.downcase
31
+ end
32
+
33
+ private
34
+
35
+ def set_token
36
+ write_attribute :token, Digest::SHA1.hexdigest(Time.now.to_s)
37
+ end
38
+
39
+ end