Email newsletter subscription feature

jamesperet 9 years ago
parent
commit
d1f7d78c7d

+ 3 - 0
app/assets/javascripts/subscription.js.coffee

@@ -0,0 +1,3 @@
1
+# Place all the behaviors and hooks related to the matching controller here.
2
+# All this logic will automatically be available in application.js.
3
+# You can use CoffeeScript in this file: http://coffeescript.org/

+ 3 - 0
app/assets/stylesheets/subscription.css.scss

@@ -0,0 +1,3 @@
1
+// Place all the styles related to the subscription controller here.
2
+// They will automatically be included in application.css.
3
+// You can use Sass (SCSS) here: http://sass-lang.com/

+ 12 - 0
app/controllers/admin_panel_controller.rb

@@ -30,6 +30,18 @@ class AdminPanelController < ApplicationController
30 30
   def show_contact_message
31 31
     @msg = ContactMessage.find(params[:id])
32 32
   end
33
+  
34
+  def subscribers
35
+    @subscribers = Subscription.all
36
+  end
37
+  
38
+  def export_subscribers_list
39
+    @subscribers = Subscription.all
40
+    respond_to do |format|
41
+        format.html
42
+        format.csv { render text: @subscribers.to_csv }
43
+     end
44
+  end
33 45
 
34 46
   def users
35 47
     @users = User.order('created_at DESC').all

+ 1 - 0
app/controllers/application_controller.rb

@@ -1,4 +1,5 @@
1 1
 class ApplicationController < ActionController::Base
2
+  
2 3
   # Prevent CSRF attacks by raising an exception.
3 4
   # For APIs, you may want to use :null_session instead.
4 5
 

+ 1 - 0
app/controllers/start_controller.rb

@@ -2,6 +2,7 @@ class StartController < ApplicationController
2 2
   
3 3
   def index
4 4
     @blog_posts = BlogPost.order('created_at DESC').take(4)
5
+    @subscription = Subscription.new
5 6
   end
6 7
 
7 8
 end

+ 21 - 0
app/controllers/subscription_controller.rb

@@ -0,0 +1,21 @@
1
+class SubscriptionController < ApplicationController
2
+  def create
3
+    @subscription = Subscription.new(subscription_params)
4
+    respond_to do |format|
5
+      if @subscription.save
6
+        UserMailer.newsletter_subscription(@subscription).deliver 
7
+        format.html { redirect_to root_path, notice: 'Thanks for subscribing to our newsletter' }
8
+        format.json { render action: 'show', status: :created, location: @subscription }
9
+      else
10
+        format.html { redirect_to root_path, alert: 'An error ocured. Please try gain.' }
11
+        format.json { render json: @subscription.errors, status: :unprocessable_entity }
12
+      end
13
+    end
14
+  end
15
+  
16
+  # Never trust parameters from the scary internet, only allow the white list through.
17
+  def subscription_params
18
+    params.require(:subscription).permit(:first_name, :last_name, :email)
19
+  end
20
+  
21
+end

+ 2 - 0
app/helpers/subscription_helper.rb

@@ -0,0 +1,2 @@
1
+module SubscriptionHelper
2
+end

+ 9 - 0
app/mailers/user_mailer.rb

@@ -11,4 +11,13 @@ class UserMailer < ActionMailer::Base
11 11
          :body      => @msg.content
12 12
   end
13 13
   
14
+  def newsletter_subscription(subscription)
15
+    config = Info.first
16
+    mail :to        => subscription.email,
17
+         :subject   => (t 'newsletter_subscription.subject'),
18
+         :from      => config.contact_email,
19
+         :from_name => config.website_name,
20
+         :body      => (t 'newsletter_subscription.message')
21
+  end
22
+  
14 23
 end

+ 16 - 0
app/models/subscription.rb

@@ -0,0 +1,16 @@
1
+class Subscription < ActiveRecord::Base
2
+  
3
+  def full_name
4
+    return self.first_name + " " + self.last_name
5
+  end
6
+  
7
+  def self.to_csv
8
+      CSV.generate do |csv|
9
+        csv << column_names
10
+        all.each do |product|
11
+          csv << product.attributes.values_at(*column_names)
12
+        end
13
+      end
14
+  end
15
+  
16
+end

+ 3 - 0
app/views/admin_panel/_sidebar_nav.html.erb

@@ -16,6 +16,9 @@
16 16
 	   <% if current_page?(:action => 'users')%><li class="active"> <% else %><li><% end %>
17 17
 	   <%= link_to ('<i class="fa fa-users fa-fw"></i> '+(t "admin_panel.users")).html_safe, admin_users_path %></li>
18 18
 	   
19
+	   <% if current_page?(:action => 'subscribers')%><li class="active"> <% else %><li><% end %>
20
+	   <%= link_to ('<i class="fa fa-newspaper-o"></i> '+(t "admin_panel.subscribers")).html_safe, admin_subscribers_path %></li>
21
+	   
19 22
 	   <% if current_page?(:action => 'site_config')%><li class="active"> <% else %><li><% end %>
20 23
 	   <%= link_to ('<i class="fa fa-cog fa-fw"></i> '+(t "admin_panel.configurations")).html_safe, admin_config_path %></li>
21 24
 	   

+ 32 - 0
app/views/admin_panel/subscribers.html.erb

@@ -0,0 +1,32 @@
1
+<div class="row">
2
+	<%= render 'admin_panel/sidebar_nav' %>
3
+	<div class="span9">
4
+		<div class="page-header">
5
+		  <h1>
6
+  			<i class="fa fa-envelope"></i>
7
+			<%= t "admin_panel.subscribers" %> <%= link_to (t "subscription.export"), export_subscribers_list_path(format: :csv), class: 'btn btn-primary btn-mini pull-right', style: 'margin-top: 10px' %>
8
+		  </h1>
9
+		</div>
10
+		<%= bootstrap_flash %>
11
+		
12
+		<table class="table table-bordered">
13
+              <thead>
14
+                <tr>
15
+                  <th>Name</th>
16
+                  <th>Email</th>
17
+			   <th>Registered</th>
18
+                </tr>
19
+              </thead>
20
+		    <tbody>
21
+		       <% @subscribers.each do |subscription| %>
22
+			    <tr>
23
+				  <td><%= subscription.full_name %></td>
24
+				  <td><%= subscription.email %></td>
25
+				  <td><%= time_ago_in_words(subscription.created_at) %></td>
26
+			    </tr>
27
+			  <% end %>
28
+			</tbody>
29
+		</table>		
30
+	</div>
31
+</div>
32
+

+ 14 - 0
app/views/layouts/_subscribe_to_newsletter.html.erb

@@ -0,0 +1,14 @@
1
+<h3><%= (t 'subscription.header')%></h3>
2
+<%= bootstrap_form_for(@subscription) do |f| %>
3
+  <%= f.alert_message "Please fix the errors below."%>
4
+  <%= f.form_group :first_name do %>
5
+    	<%= f.text_field :first_name, label: (t 'registration.first_name'), class: 'input-block-level', required: true %>
6
+  <% end %>
7
+  <%= f.form_group :last_name do %>
8
+    	<%= f.text_field :last_name, label: (t 'registration.last_name'), class: 'input-block-level', required: true %>
9
+  <% end %>
10
+  <%= f.form_group :email do %>
11
+    	<%= f.text_field :email, label: (t 'registration.email'), class: 'input-block-level', required: true %>
12
+  <% end %>
13
+  <%= f.submit (t 'subscription.submit'), class: 'btn btn-success', id: 'submit_subscription' %>
14
+<% end %>

+ 1 - 0
app/views/start/index.html.erb

@@ -25,3 +25,4 @@
25 25
 
26 26
 
27 27
 <br>
28
+<%= render 'layouts/subscribe_to_newsletter' %>

+ 1 - 0
config/application.rb

@@ -1,5 +1,6 @@
1 1
 require File.expand_path('../boot', __FILE__)
2 2
 
3
+require 'csv'
3 4
 require 'rails/all'
4 5
 
5 6
 # Require the gems listed in Gemfile, including any gems

+ 4 - 1
config/locales/email.en.yml

@@ -4,4 +4,7 @@ en:
4 4
     reset_text: Someone has requested a link to change your password. You can do this through the link below.
5 5
     change_my_password: Change my password
6 6
     not_requested: "If you didn't request this, please ignore this email."
7
-    password_will_not_change: "Your password won't change until you access the link above and create a new one."
7
+    password_will_not_change: "Your password won't change until you access the link above and create a new one."
8
+  newsletter_subscription:
9
+    subject: Thanks for subscribing
10
+    message: Welcome to our website

+ 3 - 1
config/locales/email.pt-BR.yml

@@ -5,4 +5,6 @@ pt-BR:
5 5
     change_my_password: Trocar minha senha
6 6
     not_requested: "Se você não solicitou a mudança de senha, por favor ignore este email."
7 7
     password_will_not_change: Sua senha não vai mudar a não ser que você crie uma nova.
8
-    
8
+  newsletter_subscription:
9
+    subject: Bem vindo
10
+    message: Obrigado por se inscrever na nossa newsletter! 

+ 6 - 1
config/locales/en.yml

@@ -295,4 +295,9 @@ en:
295 295
     change_password: Save Password
296 296
     cancel_account: Delete Account
297 297
     cancel_confirmation: Are you sure you want to delete your account permenantly?
298
-    edit_password: Edit password
298
+    edit_password: Edit password
299
+  subscription:
300
+    subscribers: Subscribers
301
+    header: Subscribe to our newsletter
302
+    submit: Subscribe
303
+    export: Export CVS

+ 6 - 1
config/locales/pt-BR.yml

@@ -299,4 +299,9 @@ pt-BR:
299 299
     update: Atualizar
300 300
     cancel_account: Cancelar Conta
301 301
     cancel_confirmation: Você tem certeza que deseja cancelar sua conta?
302
-    edit_password: Editar senha
302
+    edit_password: Editar senha
303
+  subscription:
304
+    subscribers: Seguidores
305
+    header: Receba nossa newsletter
306
+    submit: Enviar
307
+    export: Exportart CVS

+ 8 - 3
config/routes.rb

@@ -1,11 +1,15 @@
1 1
 RailsWebsiteTemplate::Application.routes.draw do
2 2
   
3
+  root 'start#index'
3 4
   
5
+  get "subscription/create"
4 6
   resources :contact_messages, path: '/contact', :as => :contact_messages
5 7
 
6 8
   resources :uploads
7 9
   
8 10
   get "maintenance_mode" => "admin_panel#maintenance_mode", :as => :maintenance_mode
11
+  
12
+  post "subscribe" => "subscription#create", :as => :subscriptions
9 13
 
10 14
   get "admin/dashboard" => "admin_panel#dashboard", :as => :admin_dashboard
11 15
   get "admin" => "admin_panel#index"
@@ -13,7 +17,9 @@ RailsWebsiteTemplate::Application.routes.draw do
13 17
   get "admin/contact_messages" => "admin_panel#contact_messages", :as => :admin_contact_messages
14 18
   get "admin/contact_message/:id" => "admin_panel#show_contact_message", :as => :show_contact_message
15 19
   get "admin/contact_message/:id/mark_contact_message_as_readed" => "contact_messages#readed", :as => :mark_contact_message_as_readed
16
-  get "admin/contact_message/:id/mark_contact_message_as_unread" => "contact_messages#unread", :as => :mark_contact_message_as_unread  
20
+  get "admin/contact_message/:id/mark_contact_message_as_unread" => "contact_messages#unread", :as => :mark_contact_message_as_unread
21
+  get "admin/subscribers" => "admin_panel#subscribers", :as => :admin_subscribers
22
+  get "admin/subscribers/export/cvs" => "admin_panel#export_subscribers_list", :as => :export_subscribers_list 
17 23
   get "admin/users" => "admin_panel#users", :as => :admin_users
18 24
   get "admin/users/:id/make_admin" => "admin_panel#make_admin", :as => :make_admin
19 25
   get "admin/config" => "admin_panel#site_config", :as => :admin_config
@@ -27,7 +33,6 @@ RailsWebsiteTemplate::Application.routes.draw do
27 33
   get '/admin/files' => "admin_panel#files", :as => :admin_files
28 34
   resources :uploads, path: '/admin/files'
29 35
 
30
-  get "start/index"
31 36
   devise_for :users, :skip => [:sessions, :passwords, :confirmations, :registrations]
32 37
   as :user do
33 38
     get 'login' => 'devise/sessions#new', :as => :new_user_session
@@ -109,5 +114,5 @@ RailsWebsiteTemplate::Application.routes.draw do
109 114
   #     # (app/controllers/admin/products_controller.rb)
110 115
   #     resources :products
111 116
   #   end
112
-  root 'start#index'
117
+ 
113 118
 end

+ 11 - 0
db/migrate/20150105022653_create_subscriptions.rb

@@ -0,0 +1,11 @@
1
+class CreateSubscriptions < ActiveRecord::Migration
2
+  def change
3
+    create_table :subscriptions do |t|
4
+      t.string :first_name
5
+      t.string :last_name
6
+      t.string :email
7
+
8
+      t.timestamps
9
+    end
10
+  end
11
+end

+ 9 - 1
db/schema.rb

@@ -11,7 +11,7 @@
11 11
 #
12 12
 # It's strongly recommended that you check this file into your version control system.
13 13
 
14
-ActiveRecord::Schema.define(version: 20141101234157) do
14
+ActiveRecord::Schema.define(version: 20150105022653) do
15 15
 
16 16
   # These are extensions that must be enabled in order to support this database
17 17
   enable_extension "plpgsql"
@@ -71,6 +71,14 @@ ActiveRecord::Schema.define(version: 20141101234157) do
71 71
     t.string   "server_email"
72 72
   end
73 73
 
74
+  create_table "subscriptions", force: true do |t|
75
+    t.string   "first_name"
76
+    t.string   "last_name"
77
+    t.string   "email"
78
+    t.datetime "created_at"
79
+    t.datetime "updated_at"
80
+  end
81
+
74 82
   create_table "uploads", force: true do |t|
75 83
     t.string   "title"
76 84
     t.string   "file"

+ 1 - 1
features/admin_panel.feature

@@ -6,7 +6,7 @@ Feature: Admin Panel
6 6
 	
7 7
 	Background:
8 8
 	Given the website is configured
9
-	And the following blog_post list 
9
+	And the following list of blog posts
10 10
 	| title       | content                | published | description         | slug        | 
11 11
 	| Hello World | Welcome to the website | true      | First Post          | hello_world | 
12 12
 	| Test 001    | 1 2 3 testing          | true      | Testing the website | test_001    |

+ 1 - 1
features/blog.feature

@@ -6,7 +6,7 @@ Feature: Blog Posts
6 6
 	
7 7
 	Background:
8 8
 	Given the website is configured
9
-	And the following blog_post list 
9
+	And the following list of blog posts 
10 10
 	| title       | content                | published | description         | slug        | 
11 11
 	| Hello World | Welcome to the website | true      | First Post          | hello_world | 
12 12
 	| Test 001    | 1 2 3 testing          | true      | Testing the website | test_001    |

+ 2 - 2
features/contact_messages.feature

@@ -13,8 +13,8 @@ Feature: Contact Messages
13 13
 	Given the website is configured
14 14
 	
15 15
 	Scenario: Send Contact Message as a visitor
16
-		Given I go to the homepage
17
-		When I go to the contact page 
16
+		Given I visit the homepage
17
+		When I click in the link "Contact"
18 18
 		Then the page should have a "form" called "new_contact_message"
19 19
 		And I fill in "contact_message_email" with "yo@website.com"
20 20
 		And I fill in "contact_message_title" with "Hello Webmaster"

+ 50 - 0
features/email_subscription.feature

@@ -0,0 +1,50 @@
1
+@focus
2
+Feature: Email Subscription
3
+
4
+	In order to send newsletters to customers
5
+	As an marketing guy
6
+	I want to a email subscription button
7
+	
8
+	Background:
9
+	Given the website is configured
10
+	And the following subscription list 
11
+	| first_name | last_name | email 			   | 
12
+	| Jimy       | San  	| jimysan@website.com  |
13
+	| John       | Doe       | john_doe@website.com |
14
+
15
+	Scenario: Newsletter subscription form
16
+		Given I am not logged in
17
+		And I visit the homepage
18
+		And I should see "Subscribe to our newsletter"
19
+		And I fill in "subscription_first_name" with "Monty"
20
+		And I fill in "subscription_last_name" with "Cantsin"
21
+		And I fill in "subscription_email" with "monty_cantsin@canada.com"
22
+		And I click in the button "submit_subscription"
23
+		Then I should see "Thanks for subscribing to our newsletter"
24
+		And "monty_cantsin@canada.com" should receive an email with subject "Thanks for subscribing"
25
+		
26
+	Scenario: Admin panel email subscription list
27
+		Given I am logged in as admin
28
+		And I go to the admin dashboard
29
+		And I click in the link "Subscribers"
30
+		Then I should see "Jimy San"
31
+		And I should see "jimysan@website.com"		
32
+		And I should see "John Doe"
33
+		And I should see "john_doe@website.com"
34
+		
35
+	Scenario: Export subscription list as a CVS file
36
+		Given I am logged in as admin
37
+		And I go to the subscribers page
38
+		When I click in the link "Export CVS"
39
+		Then I should see "Jimy,San,jimysan@website.com,"
40
+		And I should see "John,Doe,john_doe@website.com"
41
+		
42
+		
43
+	# 1. Create subscription model
44
+	# 2. Create subscription controller
45
+	# 3. Create subscription form view helper
46
+	# 4. Define subscribers method in admin controller
47
+	# 5. Create subscribers view
48
+	# 6. Define Export to CVS method in admin controller
49
+	# 7. Hookup the mailchimp API and send subscriber after subscription
50
+	

+ 0 - 1
features/maintenance_mode.feature

@@ -1,4 +1,3 @@
1
-@focus
2 1
 Feature: Maintenance Mode
3 2
 
4 3
 	In order to change things in the website

+ 2 - 5
features/step_definitions/blog_steps.rb

@@ -1,9 +1,9 @@
1 1
 include Warden::Test::Helpers
2 2
 
3
-Given /^the following (.+) list ?$/ do |factory, table| 
3
+Given /^the following list of blog posts?$/ do |table| 
4 4
   user = FactoryGirl.create(:user) 
5 5
   table.hashes.each do |hash| 
6
-    post = FactoryGirl.create(factory, hash)
6
+    post = FactoryGirl.create("blog_post", hash)
7 7
     post.author = user
8 8
     post.save
9 9
   end
@@ -15,9 +15,6 @@ Given /^I have blog posts titled (.+)$/ do |titles|
15 15
   end
16 16
 end
17 17
 
18
-When /^I go to (.+)$/ do |page_name|
19
-  path_to(page_name)
20
-end
21 18
 
22 19
 Then(/^The current url should be "(.*?)"$/) do |arg1|
23 20
   uri = URI.parse(current_url)

+ 22 - 0
features/step_definitions/helper_steps.rb

@@ -14,3 +14,25 @@ end
14 14
 Given(/^Maintenance mode is activated$/) do
15 15
   Info.last.update(maintenance_mode: true, maintenance_title: 'Website under maintenance', maintenance_message: 'Please check back soon')
16 16
 end
17
+
18
+Given /^the following (.+) list ?$/ do |factory, table| 
19
+  table.hashes.each do |hash| 
20
+    FactoryGirl.create(factory, hash)
21
+  end
22
+end
23
+
24
+Then(/^spit out the page HTML$/) do
25
+  puts page.html
26
+end
27
+
28
+When /^I go to (.+)$/ do |page_name|
29
+  path_to(page_name)
30
+end
31
+
32
+Given /^I visit the "(.*)"/ do |place|
33
+ visit "/#{place}"
34
+end
35
+
36
+When /^I visit the homepage$/ do
37
+ visit ""
38
+end

+ 3 - 0
features/support/paths.rb

@@ -25,6 +25,9 @@ module NavigationHelpers
25 25
     when/the admin blog posts page/
26 26
       visit admin_posts_path
27 27
       
28
+    when/the subscribers page/
29
+      visit admin_subscribers_path
30
+      
28 31
     else
29 32
       raise "Can't find mapping from \"#{page_name}\" to a path."
30 33
     end

+ 6 - 0
spec/factories.rb

@@ -34,5 +34,11 @@ FactoryGirl.define do
34 34
     website_link 'http://localhost:3000'
35 35
   end
36 36
   
37
+  factory :subscription do |f|
38
+    f.first_name "foo"  
39
+    f.last_name "bar"
40
+    f.email "foobar@website.com"
41
+  end 
42
+  
37 43
 end  
38 44
 

+ 9 - 0
test/controllers/subscription_controller_test.rb

@@ -0,0 +1,9 @@
1
+require 'test_helper'
2
+
3
+class SubscriptionControllerTest < ActionController::TestCase
4
+  test "should get create" do
5
+    get :create
6
+    assert_response :success
7
+  end
8
+
9
+end

+ 11 - 0
test/fixtures/subscriptions.yml

@@ -0,0 +1,11 @@
1
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2
+
3
+one:
4
+  first_name: MyString
5
+  last_name: MyString
6
+  email: MyString
7
+
8
+two:
9
+  first_name: MyString
10
+  last_name: MyString
11
+  email: MyString

+ 4 - 0
test/helpers/subscription_helper_test.rb

@@ -0,0 +1,4 @@
1
+require 'test_helper'
2
+
3
+class SubscriptionHelperTest < ActionView::TestCase
4
+end

+ 7 - 0
test/models/subscription_test.rb

@@ -0,0 +1,7 @@
1
+require 'test_helper'
2
+
3
+class SubscriptionTest < ActiveSupport::TestCase
4
+  # test "the truth" do
5
+  #   assert true
6
+  # end
7
+end