diff --git a/admin/Gemfile b/admin/Gemfile index 5ec8a3411..5fea93d71 100644 --- a/admin/Gemfile +++ b/admin/Gemfile @@ -65,10 +65,11 @@ gem 'logging-rails', :require => 'logging/rails' gem 'pg_migrate' gem 'ruby-protocol-buffers', '1.2.2' -gem 'sendgrid', '1.1.0' +gem 'sendgrid', '1.2.0' gem 'geokit-rails' gem 'postgres_ext', '1.0.0' +gem 'resque_mailer' group :libv8 do gem 'libv8', "~> 3.11.8" @@ -106,6 +107,7 @@ group :development, :test do gem 'factory_girl_rails', '4.1.0' gem 'database_cleaner', '0.7.0' gem 'launchy' + gem 'faker' end group :test do diff --git a/admin/app/admin/email_batch.rb b/admin/app/admin/email_batch.rb new file mode 100644 index 000000000..3f15aadd3 --- /dev/null +++ b/admin/app/admin/email_batch.rb @@ -0,0 +1,106 @@ +ActiveAdmin.register JamRuby::EmailBatch, :as => 'Batch Emails' do + + menu :label => 'Emails' + + config.sort_order = 'updated_at DESC' + config.batch_actions = false + # config.clear_action_items! + config.filters = false + + form :partial => 'form' + + index do + column 'Subject' do |pp| pp.subject end + column 'Updated' do |pp| pp.updated_at end + column 'From' do |pp| pp.from_email end + column 'Status' do |pp| pp.aasm_state end + column 'Test Emails' do |pp| pp.test_emails end + column 'Email Count' do |pp| pp.qualified_count end + column 'Send Count' do |pp| pp.sent_count end + column 'Started' do |pp| pp.started_at end + column 'Completed' do |pp| pp.completed_at end + column 'Send Test' do |pp| + link_to("Test Batch (#{pp.test_count})", + batch_test_admin_batch_email_path(pp.id), + :confirm => "Run test batch with #{pp.test_count} emails?") + end + column 'Send Live' do |pp| + link_to("Live Batch (#{User.email_opt_in.count})", + batch_send_admin_batch_email_path(pp.id), + :confirm => "Run LIVE batch with #{User.email_opt_in.count} emails?") + end + + default_actions + end + + action_item :only => :show do + link_to("Send Test Batch (#{resource.test_count})", + batch_test_admin_batch_email_path(resource.id), + :confirm => "Run test batch with #{resource.test_count} emails?") + end + + action_item :only => :show do + link_to("Send Live Batch (#{User.email_opt_in.count})", + batch_send_admin_batch_email_path(resource.id), + :confirm => "Run LIVE batch with #{User.email_opt_in.count} emails?") + end + + show :title => 'Batch Email' do |obj| + panel 'Email Contents' do + attributes_table_for obj do + row 'From' do |obj| obj.from_email end + row 'Test Emails' do |obj| obj.test_emails end + row 'Subject' do |obj| obj.subject end + row 'Body' do |obj| obj.body end + end + end + columns do + column do + panel 'Sending Parameters' do + attributes_table_for obj do + row 'State' do |obj| obj.aasm_state end + row 'User Count' do |obj| + obj.qualified_count ? obj.qualified_count : User.email_opt_in.count + end + row 'Sent Count' do |obj| obj.sent_count end + row 'Started' do |obj| obj.started_at end + row 'Completed' do |obj| obj.completed_at end + row 'Updated' do |obj| obj.updated_at end + end + end + end + column do + panel 'Send Results' do + end + end + end + end + + controller do + + def create + batch = EmailBatch.create_with_params(params[:jam_ruby_email_batch]) + redirect_to admin_batch_email_path(batch.id) + # redirect_to admin_batch_emails_path + end + + def update + resource.update_with_conflict_validation(params[:jam_ruby_email_batch]) + redirect_to admin_batch_email_path(resource.id) + end + + end + + member_action :batch_test, :method => :get do + batch = EmailBatch.find(params[:id]) + batch.send_test_batch + redirect_to admin_batch_email_path(batch.id) + end + + member_action :batch_send, :method => :get do + batch = EmailBatch.find(params[:id]) + batch.deliver_batch + redirect_to admin_batch_email_path(batch.id) + end + +end diff --git a/admin/app/views/admin/batch_emails/_form.html.erb b/admin/app/views/admin/batch_emails/_form.html.erb new file mode 100644 index 000000000..a9c83f836 --- /dev/null +++ b/admin/app/views/admin/batch_emails/_form.html.erb @@ -0,0 +1,9 @@ +<%= semantic_form_for([:admin, resource], :url => resource.new_record? ? admin_batch_emails_path : "/admin/batch_emails/#{resource.id}") do |f| %> + <%= f.inputs do %> + <%= f.input(:from_email, :label => "From Email", :input_html => {:maxlength => 64}) %> + <%= f.input(:subject, :label => "Subject", :input_html => {:maxlength => 128}) %> + <%= f.input(:test_emails, :label => "Test Emails", :input_html => {:maxlength => 1024, :size => '3x3'}) %> + <%= f.input(:body, :label => "Body", :input_html => {:maxlength => 3096, :size => '10x20'}) %> + <% end %> + <%= f.actions %> +<% end %> diff --git a/db/manifest b/db/manifest index baa454cbc..aba246d9b 100755 --- a/db/manifest +++ b/db/manifest @@ -138,4 +138,5 @@ events_social_description.sql fix_broken_cities.sql notifications_with_text.sql notification_seen_at.sql -order_event_session.sql \ No newline at end of file +order_event_session.sql +emails.sql diff --git a/db/up/emails.sql b/db/up/emails.sql new file mode 100644 index 000000000..86f8b4f6f --- /dev/null +++ b/db/up/emails.sql @@ -0,0 +1,38 @@ +CREATE TABLE email_batches ( + id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), + subject VARCHAR(256) NOT NULL, + body TEXT NOT NULL, + from_email VARCHAR(64) NOT NULL default 'support@jamkazam.com', + + aasm_state VARCHAR(32) NOT NULL default 'pending', + + test_emails TEXT NOT NULL default '', + + qualified_count INTEGER NOT NULL default 0, + sent_count INTEGER NOT NULL default 0, + + lock_version INTEGER, + + 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 ALTER COLUMN subscribe_email SET DEFAULT true; diff --git a/ruby/Gemfile b/ruby/Gemfile index 7ba18443c..cd4bca5ec 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -27,7 +27,7 @@ gem 'eventmachine', '1.0.3' gem 'amqp', '1.0.2' gem 'will_paginate' gem 'actionmailer', '3.2.13' -gem 'sendgrid' +gem 'sendgrid', '1.2.0' gem 'aws-sdk', '1.29.1' gem 'carrierwave' gem 'aasm', '3.0.16' @@ -40,6 +40,7 @@ gem 'resque' gem 'resque-retry' gem 'resque-failed-job-mailer' #, :path => "/Users/seth/workspace/resque_failed_job_mailer" gem 'resque-lonely_job', '~> 1.0.0' +gem 'resque_mailer' gem 'oj' gem 'builder' gem 'fog' diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index da72d911b..b6f17a3a4 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -16,6 +16,7 @@ require "geokit-rails" require "postgres_ext" require 'builder' require 'cgi' +require 'resque_mailer' require "jam_ruby/constants/limits" require "jam_ruby/constants/notification_types" @@ -132,6 +133,9 @@ 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" +require "jam_ruby/app/mailers/async_mailer" +require "jam_ruby/app/mailers/batch_mailer" include Jampb diff --git a/ruby/lib/jam_ruby/app/mailers/async_mailer.rb b/ruby/lib/jam_ruby/app/mailers/async_mailer.rb new file mode 100644 index 000000000..4cbad60e4 --- /dev/null +++ b/ruby/lib/jam_ruby/app/mailers/async_mailer.rb @@ -0,0 +1,8 @@ +require 'resque_mailer' + +module JamRuby + class AsyncMailer < ActionMailer::Base + include SendGrid + include Resque::Mailer + end +end 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..11e21efd2 --- /dev/null +++ b/ruby/lib/jam_ruby/app/mailers/batch_mailer.rb @@ -0,0 +1,38 @@ +module JamRuby + class BatchMailer < JamRuby::AsyncMailer + layout "user_mailer" + + sendgrid_category :use_subject_lines + sendgrid_unique_args :env => Environment.mode + + def _send_batch(batch, users) + @batch_body = batch.body + emails = users.map(&:email) + + sendgrid_recipients(emails) + sendgrid_substitute(EmailBatch::VAR_FIRST_NAME, users.map(&:first_name)) + + batch.did_send(emails) + + mail(:to => emails, + :from => batch.from_email, + :subject => batch.subject) do |format| + format.text + format.html + end + end + + def send_batch_email(batch_id, user_ids) + users = User.find_all_by_id(user_ids) + batch = EmailBatch.where(:id => batch_id).limit(1).first + self._send_batch(batch, users) + end + + def send_batch_email_test(batch_id) + batch = EmailBatch.where(:id => batch_id).limit(1).first + users = batch.test_users + self._send_batch(batch, users) + end + + end +end diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email.html.erb new file mode 100644 index 000000000..31bd20e21 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email.html.erb @@ -0,0 +1 @@ +<%= @body %> diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email.text.erb new file mode 100644 index 000000000..31bd20e21 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email.text.erb @@ -0,0 +1 @@ +<%= @body %> diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email_test.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email_test.html.erb new file mode 120000 index 000000000..f14e9223c --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email_test.html.erb @@ -0,0 +1 @@ +send_batch_email.html.erb \ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email_test.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email_test.text.erb new file mode 120000 index 000000000..2a1e564e8 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/batch_mailer/send_batch_email_test.text.erb @@ -0,0 +1 @@ +send_batch_email.text.erb \ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/layouts/user_mailer.html.erb b/ruby/lib/jam_ruby/app/views/layouts/user_mailer.html.erb index 6fcd69d53..1198a26f4 100644 --- a/ruby/lib/jam_ruby/app/views/layouts/user_mailer.html.erb +++ b/ruby/lib/jam_ruby/app/views/layouts/user_mailer.html.erb @@ -24,13 +24,11 @@
<%= yield %>
+<%= @batch_body ? @batch_body.html_safe : yield %>
This email was sent to you because you have an account at JamKazam. Click here to unsubscribe and update your profile settings.
-This email was sent to you because you have an account at JamKazam.