From e6d0851391f722eb068b4b034fd6eacd72ea3d2c Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 18 Mar 2014 15:07:45 +0000 Subject: [PATCH] VRFS-1483 adding first set of updates for batch emails --- db/manifest | 1 + db/up/emails.sql | 32 +++ ruby/lib/jam_ruby.rb | 1 + ruby/lib/jam_ruby/app/mailers/batch_mailer.rb | 241 ++++++++++++++++++ ruby/lib/jam_ruby/models/email_batch.rb | 21 ++ ruby/spec/factories.rb | 7 + ruby/spec/jam_ruby/models/email_batch_spec.rb | 11 + ruby/spec/mailers/batch_mailer_spec.rb | 149 +++++++++++ 8 files changed, 463 insertions(+) create mode 100644 db/up/emails.sql create mode 100644 ruby/lib/jam_ruby/app/mailers/batch_mailer.rb create mode 100644 ruby/lib/jam_ruby/models/email_batch.rb create mode 100644 ruby/spec/jam_ruby/models/email_batch_spec.rb create mode 100644 ruby/spec/mailers/batch_mailer_spec.rb diff --git a/db/manifest b/db/manifest index bad9decf1..2423e0138 100755 --- a/db/manifest +++ b/db/manifest @@ -136,4 +136,5 @@ events.sql cascading_delete_constraints_for_release.sql events_social_description.sql fix_broken_cities.sql +emails.sql diff --git a/db/up/emails.sql b/db/up/emails.sql new file mode 100644 index 000000000..c4290bda1 --- /dev/null +++ b/db/up/emails.sql @@ -0,0 +1,32 @@ +CREATE TABLE email_batches ( + id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), + subject VARCHAR(256) NOT NULL, + body TEXT NOT NULL, + aasm_state VARCHAR(32) NOT NULL default 'pending', + + test_emails TEXT NOT NULL, + batch_size INTEGER NOT NULL default 1000, + + started_at TIMESTAMP, + completed_at TIMESTAMP, + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE email_batch_results ( + id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), + email_batch_id VARCHAR(64) REFERENCES email_batches(id) ON DELETE CASCADE, + user_id VARCHAR(64) REFERENCES users(id) ON DELETE CASCADE, + + error_type VARCHAR(32), + email_address VARCHAR(256), + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +ALTER TABLE email_batch_results ADD CONSTRAINT email_batch_uniqkey UNIQUE (email_batch_id); +ALTER TABLE email_batch_results ADD CONSTRAINT email_user_uniqkey UNIQUE (user_id); + +ALTER TABLE users ADD COLUMN opt_out_email_batch boolean DEFAULT false; diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index b6103cd16..572b18c16 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -131,6 +131,7 @@ require "jam_ruby/models/playable_play" require "jam_ruby/models/country" require "jam_ruby/models/region" require "jam_ruby/models/city" +require "jam_ruby/models/email_batch" include Jampb diff --git a/ruby/lib/jam_ruby/app/mailers/batch_mailer.rb b/ruby/lib/jam_ruby/app/mailers/batch_mailer.rb new file mode 100644 index 000000000..2aada35c8 --- /dev/null +++ b/ruby/lib/jam_ruby/app/mailers/batch_mailer.rb @@ -0,0 +1,241 @@ +module JamRuby + class BatchMailer < ActionMailer::Base + include SendGrid + + layout "batch_mailer" + + DEFAULT_SENDER = "support@jamkazam.com" + + default :from => DEFAULT_SENDER + + sendgrid_category :batch_email + sendgrid_category :use_subject_lines + sendgrid_unique_args :env => Environment.mode + + def send_batch_email(user, signup_confirm_url) + @user = user + @signup_confirm_url = signup_confirm_url + sendgrid_category "Confirm Email" + sendgrid_unique_args :type => "confirm_email" + + mail(:to => user.email, :subject => "Please confirm your JamKazam email") do |format| + format.text + format.html + end + end + + def welcome_message(user) + @user = user + sendgrid_category "Welcome" + sendgrid_unique_args :type => "welcome_message" + + mail(:to => user.email, :subject => "Welcome to JamKazam") do |format| + format.text + format.html + end + end + + def password_changed(user) + @user = user + sendgrid_unique_args :type => "password_changed" + mail(:to => user.email, :subject => "JamKazam Password Changed") do |format| + format.text + format.html + end + end + + def password_reset(user, password_reset_url) + @user = user + @password_reset_url = password_reset_url + sendgrid_unique_args :type => "password_reset" + mail(:to => user.email, :subject => "JamKazam Password Reset") do |format| + format.text + format.html + end + end + + def updating_email(user) + @user = user + sendgrid_unique_args :type => "updating_email" + mail(:to => user.update_email, :subject => "JamKazam Email Change Confirmation") do |format| + format.text + format.html + end + end + + def updated_email(user) + @user = user + sendgrid_unique_args :type => "updated_email" + mail(:to => user.email, :subject => "JamKazam Email Changed") do |format| + format.text + format.html + end + end + + def new_musicians(user, new_nearby, host='www.jamkazam.com') + @user, @new_nearby, @host = user, new_nearby, host + sendgrid_unique_args :type => "new_musicians" + mail(:to => user.email, :subject => "JamKazam New Musicians in Your Area") do |format| + format.text + format.html + end + end + + #################################### NOTIFICATION EMAILS #################################### + def friend_request(email, msg) + subject = "You have a new friend request on JamKazam" + unique_args = {:type => "friend_request"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def friend_request_accepted(email, msg) + subject = "You have a new friend on JamKazam" + unique_args = {:type => "friend_request_accepted"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def new_user_follower(email, msg) + subject = "You have a new follower on JamKazam" + unique_args = {:type => "new_user_follower"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def new_band_follower(email, msg) + subject = "Your band has a new follower on JamKazam" + unique_args = {:type => "new_band_follower"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:bcc => email, :subject => subject) do |format| + format.text + format.html + end + end + + def session_invitation(email, msg) + subject = "You have been invited to a session on JamKazam" + unique_args = {:type => "session_invitation"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def musician_session_join(email, msg, session_id) + subject = "Someone you know is in a session on JamKazam" + unique_args = {:type => "musician_session_join"} + @body = msg + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session_id}" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:bcc => email, :subject => subject) do |format| + format.text + format.html + end + end + + def band_session_join(email, msg, session_id) + subject = "A band that you follow has joined a session" + unique_args = {:type => "band_session_join"} + + @body = msg + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session_id}" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:bcc => email, :subject => subject) do |format| + format.text + format.html + end + end + + def musician_recording_saved(email, msg) + subject = "A musician has saved a new recording on JamKazam" + unique_args = {:type => "musician_recording_saved"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:bcc => email, :subject => subject) do |format| + format.text + format.html + end + end + + def band_recording_saved(email, msg) + subject = "A band has saved a new recording on JamKazam" + unique_args = {:type => "band_recording_saved"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:bcc => email, :subject => subject) do |format| + format.text + format.html + end + end + + def band_invitation(email, msg) + subject = "You have been invited to join a band on JamKazam" + unique_args = {:type => "band_invitation"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def band_invitation_accepted(email, msg) + subject = "Your band invitation was accepted" + unique_args = {:type => "band_invitation_accepted"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + # def send_notification(email, subject, msg, unique_args) + # @body = msg + # sendgrid_category "Notification" + # sendgrid_unique_args :type => unique_args[:type] + # mail(:bcc => email, :subject => subject) do |format| + # format.text + # format.html + # end + # end + ############################################################################################# + + end +end diff --git a/ruby/lib/jam_ruby/models/email_batch.rb b/ruby/lib/jam_ruby/models/email_batch.rb new file mode 100644 index 000000000..9e1a11566 --- /dev/null +++ b/ruby/lib/jam_ruby/models/email_batch.rb @@ -0,0 +1,21 @@ +module JamRuby + class EmailBatch < ActiveRecord::Base + self.table_name = "email_batches" + + # has_many :email_batch_results, :class_name => 'JamRuby::EmailBatchResult' + + def self.qualified_users + User.select(:email) + .where(:opt_out_email_batch => false) + .order('created_at DESC') + end + + def deliver + self.class.qualified_users.each + end + + def test_batch + end + + end +end diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb index 0db11878c..08d44fd6f 100644 --- a/ruby/spec/factories.rb +++ b/ruby/spec/factories.rb @@ -424,4 +424,11 @@ FactoryGirl.define do factory :event_session, :class => JamRuby::EventSession do end + + factory :email_batch, :class => JamRuby::EmailBatch do + subject Faker::Lorem.sentence + body Faker::Lorem.paragraph(3) + test_emails 4.times.collect { Faker::Internet.safe_email }.join(',') + end + end diff --git a/ruby/spec/jam_ruby/models/email_batch_spec.rb b/ruby/spec/jam_ruby/models/email_batch_spec.rb new file mode 100644 index 000000000..a59e5a377 --- /dev/null +++ b/ruby/spec/jam_ruby/models/email_batch_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe EmailBatch do + let (:email_batch) { FactoryGirl.create(:email_batch) } + + it 'runs test' do + expect(email_batch.test_emails.present?).to be true + # email_batch.test_batch + end + +end diff --git a/ruby/spec/mailers/batch_mailer_spec.rb b/ruby/spec/mailers/batch_mailer_spec.rb new file mode 100644 index 000000000..06c9393d0 --- /dev/null +++ b/ruby/spec/mailers/batch_mailer_spec.rb @@ -0,0 +1,149 @@ +require "spec_helper" + +describe BatchMailer do + + let(:user) { FactoryGirl.create(:user) } + let(:batch) { FactoryGirl.create(:email_batch) } + + before(:each) do + BatchMailer.deliveries.clear + end + + describe "should create a batch email" do + let (:mail) { BatchMailer.deliveries[0] } + let (:signup_confirmation_url) { "http://example.com/confirm" } + let (:signup_confirmation_url_with_token ) { "#{signup_confirmation_url}/#{user.signup_token}" } + + before(:each) do + BatchMailer.confirm_email(user, signup_confirmation_url_with_token).deliver + end + + it { UserMailer.deliveries.length.should == 1 } + it { mail['from'].to_s.should == UserMailer::DEFAULT_SENDER } + it { mail['to'].to_s.should == user.email } + it { mail.multipart?.should == true } # because we send plain + html + + # verify that the messages are correctly configured + it { mail.html_part.body.include?("Welcome").should be_true } + it { mail.html_part.body.include?(signup_confirmation_url_with_token).should be_true } + it { mail.text_part.body.include?("Welcome").should be_true } + it { mail.text_part.body.include?(signup_confirmation_url_with_token).should be_true } + end + + describe "should send welcome email" do + + let (:mail) { UserMailer.deliveries[0] } + + before(:each) do + UserMailer.welcome_message(user).deliver + end + + + it { UserMailer.deliveries.length.should == 1 } + it { mail['from'].to_s.should == UserMailer::DEFAULT_SENDER } + it { mail['to'].to_s.should == user.email } + it { mail.multipart?.should == true } # because we send plain + html + + # verify that the messages are correctly configured + it { mail.html_part.body.include?("delighted").should be_true } + it { mail.text_part.body.include?("delighted").should be_true } + end + + describe "should send reset password" do + + let(:mail) { UserMailer.deliveries[0] } + before(:each) do + UserMailer.password_reset(user, '/reset_password').deliver + end + + + it { UserMailer.deliveries.length.should == 1 } + + it { mail['from'].to_s.should == UserMailer::DEFAULT_SENDER } + it { mail['to'].to_s.should == user.email } + it { mail.multipart?.should == true } # because we send plain + html + + # verify that the messages are correctly configured + it { mail.html_part.body.include?("Reset").should be_true } + it { mail.text_part.body.include?("Reset").should be_true } + end + + describe "should send change password confirmation" do + + let(:mail) { UserMailer.deliveries[0] } + + before(:each) do + UserMailer.password_changed(user).deliver + end + + it { UserMailer.deliveries.length.should == 1 } + + it { mail['from'].to_s.should == UserMailer::DEFAULT_SENDER } + it { mail['to'].to_s.should == user.email } + it { mail.multipart?.should == true } # because we send plain + html + + # verify that the messages are correctly configured + it { mail.html_part.body.include?("changed your password").should be_true } + it { mail.text_part.body.include?("changed your password").should be_true } + end + + describe "should send update email confirmation" do + + let(:mail) { UserMailer.deliveries[0] } + + before(:each) do + UserMailer.updated_email(user).deliver + end + + it { UserMailer.deliveries.length.should == 1 } + + it { mail['from'].to_s.should == UserMailer::DEFAULT_SENDER } + it { mail['to'].to_s.should == user.email } + it { mail.multipart?.should == true } # because we send plain + html + + # verify that the messages are correctly configured + it { mail.html_part.body.include?("#{user.email} has been confirmed as your new email address.").should be_true } + it { mail.text_part.body.include?("#{user.email} has been confirmed as your new email address.").should be_true } + end + + describe "should send updating email" do + + let(:mail) { UserMailer.deliveries[0] } + + before(:each) do + user.update_email = "my_new_email@jamkazam.com" + UserMailer.updating_email(user).deliver + end + + it { UserMailer.deliveries.length.should == 1 } + + it { mail['from'].to_s.should == UserMailer::DEFAULT_SENDER } + it { mail['to'].to_s.should == user.update_email } + it { mail.multipart?.should == true } # because we send plain + html + + # verify that the messages are correctly configured + it { mail.html_part.body.include?("to confirm your change in email").should be_true } + it { mail.text_part.body.include?("to confirm your change in email").should be_true } + end + + + describe "sends new musicians email" do + + let(:mail) { UserMailer.deliveries[0] } + + before(:each) do + UserMailer.new_musicians(user, User.musicians).deliver + end + + it { UserMailer.deliveries.length.should == 1 } + + it { mail['from'].to_s.should == UserMailer::DEFAULT_SENDER } + it { mail['to'].to_s.should == user.email } + it { mail.multipart?.should == true } # because we send plain + html + + # verify that the messages are correctly configured + it { mail.html_part.body.include?("New JamKazam Musicians in your Area").should be_true } + it { mail.text_part.body.include?("New JamKazam Musicians in your Area").should be_true } + end + +end