* resolved merge
This commit is contained in:
commit
cc7bbf3f6a
|
|
@ -70,6 +70,7 @@ gem 'sendgrid', '1.2.0'
|
|||
gem 'geokit-rails'
|
||||
gem 'postgres_ext', '1.0.0'
|
||||
gem 'resque_mailer'
|
||||
gem 'rest-client'
|
||||
|
||||
group :libv8 do
|
||||
gem 'libv8', "~> 3.11.8"
|
||||
|
|
|
|||
|
|
@ -1,50 +1,65 @@
|
|||
ActiveAdmin.register JamRuby::EmailBatch, :as => 'Batch Emails' do
|
||||
|
||||
menu :label => 'Emails'
|
||||
menu :label => 'Batch Emails', :parent => 'Email'
|
||||
|
||||
config.sort_order = 'updated_at DESC'
|
||||
config.batch_actions = false
|
||||
# config.clear_action_items!
|
||||
config.clear_action_items!
|
||||
config.filters = false
|
||||
|
||||
form :partial => 'form'
|
||||
|
||||
action_item :only => [:show] do
|
||||
link_to('Edit Batch Email', edit_admin_batch_email_path(resource.id)) if resource.can_run_batch?
|
||||
end
|
||||
|
||||
action_item :only => [:show] do
|
||||
link_to("Test Batch (#{resource.test_count})",
|
||||
batch_test_admin_batch_email_path(resource.id),
|
||||
:confirm => "Run test batch with #{resource.test_count} emails?") if resource.can_run_test?
|
||||
end
|
||||
|
||||
action_item :only => [:show] do
|
||||
link_to("Deliver 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?") if resource.can_run_batch?
|
||||
end
|
||||
|
||||
action_item :only => [:show, :edit] do
|
||||
link_to('Clone Batch Email', batch_clone_admin_batch_email_path(resource.id))
|
||||
end
|
||||
|
||||
action_item do
|
||||
link_to('New Batch Email', new_admin_batch_email_path)
|
||||
end
|
||||
|
||||
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?")
|
||||
column 'Subject' do |bb| bb.subject end
|
||||
column 'Created' do |bb| bb.created_at end
|
||||
column 'From' do |bb| bb.from_email end
|
||||
column 'Status' do |bb| bb.aasm_state end
|
||||
column 'Test Emails' do |bb| bb.test_emails end
|
||||
column 'Email Count' do |bb| bb.opt_in_count end
|
||||
column 'Sent Count' do |bb| bb.sent_count end
|
||||
column 'Started' do |bb| bb.started_at end
|
||||
column 'Completed' do |bb| bb.completed_at end
|
||||
column 'Send Test' do |bb|
|
||||
bb.can_run_test? ? link_to("Test Batch (#{bb.test_count})",
|
||||
batch_test_admin_batch_email_path(bb.id),
|
||||
:confirm => "Run test batch with #{bb.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?")
|
||||
column 'Deliver Live' do |bb|
|
||||
bb.can_run_batch? ? link_to("Deliver Batch (#{User.email_opt_in.count})",
|
||||
batch_send_admin_batch_email_path(bb.id),
|
||||
:confirm => "Run LIVE batch with #{User.email_opt_in.count} emails?") : ''
|
||||
end
|
||||
column 'Clone' do |bb|
|
||||
link_to("Clone", batch_clone_admin_batch_email_path(bb.id))
|
||||
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
|
||||
|
|
@ -59,9 +74,7 @@ ActiveAdmin.register JamRuby::EmailBatch, :as => 'Batch Emails' 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 'Opt-in Count' do |obj| obj.opting_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
|
||||
|
|
@ -70,7 +83,11 @@ ActiveAdmin.register JamRuby::EmailBatch, :as => 'Batch Emails' do
|
|||
end
|
||||
end
|
||||
column do
|
||||
panel 'Send Results' do
|
||||
panel 'Send Chunks' do
|
||||
table_for(sets = obj.email_batch_sets) do
|
||||
column :started_at do |sets| sets.started_at.strftime('%b %d %Y, %H:%M') end
|
||||
column :batch_count do |sets| sets.batch_count end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -81,7 +98,6 @@ ActiveAdmin.register JamRuby::EmailBatch, :as => 'Batch Emails' 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
|
||||
|
|
@ -92,15 +108,18 @@ ActiveAdmin.register JamRuby::EmailBatch, :as => 'Batch Emails' do
|
|||
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)
|
||||
resource.send_test_batch
|
||||
redirect_to admin_batch_email_path(resource.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)
|
||||
resource.deliver_batch
|
||||
redirect_to admin_batch_email_path(resource.id)
|
||||
end
|
||||
|
||||
member_action :batch_clone, :method => :get do
|
||||
bb = resource.clone
|
||||
redirect_to edit_admin_batch_email_path(bb.id)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
ActiveAdmin.register JamRuby::EmailError, :as => 'Email Errors' do
|
||||
|
||||
menu :label => 'Email Errors', :parent => 'Email'
|
||||
|
||||
config.batch_actions = false
|
||||
config.filters = false
|
||||
config.clear_action_items!
|
||||
|
||||
index do
|
||||
column 'User' do |eerr|
|
||||
eerr.user ? link_to(eerr.user.name, admin_user_path(eerr.user_id)) : 'N/A'
|
||||
end
|
||||
column 'Error Type' do |eerr| eerr.error_type end
|
||||
column 'Email Address' do |eerr| eerr.email_address end
|
||||
column 'Status' do |eerr| eerr.status end
|
||||
column 'Reason' do |eerr| eerr.reason end
|
||||
column 'Email Date' do |eerr| eerr.email_date end
|
||||
end
|
||||
|
||||
controller do
|
||||
|
||||
def scoped_collection
|
||||
@eerrors ||= end_of_association_chain
|
||||
.includes([:user])
|
||||
.order('email_date DESC')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -25,7 +25,7 @@ ActiveAdmin.register JamRuby::MusicSessionHistory, :as => 'Music Session History
|
|||
index :as => :block do |msh|
|
||||
div :for => msh do
|
||||
h3 "Session ##{msh.music_session_id}: #{msh.created_at.strftime('%b %d %Y, %H:%M')}"
|
||||
h4 "(append URL with ?admin=0 to hide admin sessions)"
|
||||
h4 "(append URL with ?admin=1 to show admin sessions)"
|
||||
columns do
|
||||
column do
|
||||
panel 'Session Details' do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
class AdminAuthorization < ActiveAdmin::AuthorizationAdapter
|
||||
|
||||
def authorized?(action, subject = nil)
|
||||
subject.is_a?(EmailBatch) && :update == action ? subject.can_run_batch? : true
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -168,4 +168,8 @@ ActiveAdmin.setup do |config|
|
|||
|
||||
config.register_javascript 'autocomplete-rails.js'
|
||||
config.register_stylesheet 'jquery.ui.theme.css'
|
||||
|
||||
config.authorization_adapter = "AdminAuthorization"
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -140,3 +140,5 @@ notifications_with_text.sql
|
|||
notification_seen_at.sql
|
||||
order_event_session.sql
|
||||
emails.sql
|
||||
email_batch.sql
|
||||
user_progress_tracking2.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
CREATE TABLE email_batch_sets (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
email_batch_id VARCHAR(64) REFERENCES email_batches(id) ON DELETE CASCADE,
|
||||
|
||||
started_at TIMESTAMP,
|
||||
user_ids TEXT NOT NULL default '',
|
||||
batch_count INTEGER,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
ALTER TABLE email_batch_sets ADD CONSTRAINT email_batch_set_uniqkey UNIQUE (email_batch_id, started_at);
|
||||
CREATE INDEX email_batch_set_fkidx ON email_batch_sets (email_batch_id);
|
||||
|
||||
CREATE TABLE email_errors (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id VARCHAR(64) REFERENCES users(id) ON DELETE CASCADE,
|
||||
|
||||
error_type VARCHAR(32),
|
||||
email_address VARCHAR(256),
|
||||
status VARCHAR(32),
|
||||
email_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
reason TEXT,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX email_error_user_fkidx ON email_errors(user_id);
|
||||
CREATE INDEX email_error_address_idx ON email_errors(email_address);
|
||||
|
|
@ -6,9 +6,9 @@ CREATE TABLE email_batches (
|
|||
|
||||
aasm_state VARCHAR(32) NOT NULL default 'pending',
|
||||
|
||||
test_emails TEXT NOT NULL default '',
|
||||
test_emails TEXT NOT NULL default 'test@jamkazam.com',
|
||||
|
||||
qualified_count INTEGER NOT NULL default 0,
|
||||
opt_in_count INTEGER NOT NULL default 0,
|
||||
sent_count INTEGER NOT NULL default 0,
|
||||
|
||||
lock_version INTEGER,
|
||||
|
|
@ -20,19 +20,6 @@ CREATE TABLE email_batches (
|
|||
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;
|
||||
UPDATE users SET subscribe_email = true WHERE subscribe_email = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
-- tracks how users are progessing through the site: https://jamkazam.atlassian.net/wiki/pages/viewpage.action?pageId=3375145
|
||||
|
||||
ALTER TABLE users ADD COLUMN first_liked_us TIMESTAMP;
|
||||
|
|
@ -44,6 +44,7 @@ gem 'resque_mailer'
|
|||
gem 'oj'
|
||||
gem 'builder'
|
||||
gem 'fog'
|
||||
gem 'rest-client'
|
||||
|
||||
group :test do
|
||||
gem 'simplecov', '~> 0.7.1'
|
||||
|
|
@ -52,7 +53,6 @@ group :test do
|
|||
gem "rspec", "2.11"
|
||||
gem 'spork', '0.9.0'
|
||||
gem 'database_cleaner', '0.7.0'
|
||||
gem 'rest-client'
|
||||
gem 'faker'
|
||||
gem 'resque_spec'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ require "postgres_ext"
|
|||
require 'builder'
|
||||
require 'cgi'
|
||||
require 'resque_mailer'
|
||||
require 'rest-client'
|
||||
|
||||
require "jam_ruby/constants/limits"
|
||||
require "jam_ruby/constants/notification_types"
|
||||
|
|
@ -134,6 +135,8 @@ require "jam_ruby/models/country"
|
|||
require "jam_ruby/models/region"
|
||||
require "jam_ruby/models/city"
|
||||
require "jam_ruby/models/email_batch"
|
||||
require "jam_ruby/models/email_batch_set"
|
||||
require "jam_ruby/models/email_error"
|
||||
require "jam_ruby/app/mailers/async_mailer"
|
||||
require "jam_ruby/app/mailers/batch_mailer"
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ module JamRuby
|
|||
|
||||
sendgrid_recipients(emails)
|
||||
sendgrid_substitute(EmailBatch::VAR_FIRST_NAME, users.map(&:first_name))
|
||||
sendgrid_substitute('@USERID', users.map(&:id))
|
||||
|
||||
batch.did_send(emails)
|
||||
|
||||
|
|
@ -24,12 +25,12 @@ module JamRuby
|
|||
|
||||
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
|
||||
batch = EmailBatch.find(batch_id)
|
||||
self._send_batch(batch, users)
|
||||
end
|
||||
|
||||
def send_batch_email_test(batch_id)
|
||||
batch = EmailBatch.where(:id => batch_id).limit(1).first
|
||||
batch = EmailBatch.find(batch_id)
|
||||
users = batch.test_users
|
||||
self._send_batch(batch, users)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ module JamRuby
|
|||
sendgrid_category "Corporate"
|
||||
sendgrid_unique_args :type => "feedback"
|
||||
|
||||
sendgrid_recipients([@email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(@email)])
|
||||
|
||||
mail(:to => "info@jamkazam.com", :subject => "Feedback received from #{@email} ") do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ module JamRuby
|
|||
@signup_url = generate_signup_url(invited_user)
|
||||
@suppress_user_has_account_footer = true
|
||||
|
||||
sendgrid_recipients([invited_user.email])
|
||||
sendgrid_substitute('@USERID', [invited_user.id])
|
||||
|
||||
sendgrid_category "Welcome"
|
||||
sendgrid_unique_args :type => "welcome_betauser"
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@
|
|||
sendgrid_category "Confirm Email"
|
||||
sendgrid_unique_args :type => "confirm_email"
|
||||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
|
||||
mail(:to => user.email, :subject => "Please confirm your JamKazam email") do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -36,6 +39,9 @@
|
|||
sendgrid_category "Welcome"
|
||||
sendgrid_unique_args :type => "welcome_message"
|
||||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
|
||||
mail(:to => user.email, :subject => "Welcome to JamKazam") do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -44,6 +50,10 @@
|
|||
|
||||
def password_changed(user)
|
||||
@user = user
|
||||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
|
||||
sendgrid_unique_args :type => "password_changed"
|
||||
mail(:to => user.email, :subject => "JamKazam Password Changed") do |format|
|
||||
format.text
|
||||
|
|
@ -53,6 +63,10 @@
|
|||
|
||||
def password_reset(user, password_reset_url)
|
||||
@user = user
|
||||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
|
||||
@password_reset_url = password_reset_url
|
||||
sendgrid_unique_args :type => "password_reset"
|
||||
mail(:to => user.email, :subject => "JamKazam Password Reset") do |format|
|
||||
|
|
@ -63,6 +77,10 @@
|
|||
|
||||
def updating_email(user)
|
||||
@user = user
|
||||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
|
||||
sendgrid_unique_args :type => "updating_email"
|
||||
mail(:to => user.update_email, :subject => "JamKazam Email Change Confirmation") do |format|
|
||||
format.text
|
||||
|
|
@ -72,6 +90,10 @@
|
|||
|
||||
def updated_email(user)
|
||||
@user = user
|
||||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
|
||||
sendgrid_unique_args :type => "updated_email"
|
||||
mail(:to => user.email, :subject => "JamKazam Email Changed") do |format|
|
||||
format.text
|
||||
|
|
@ -81,6 +103,10 @@
|
|||
|
||||
def new_musicians(user, new_nearby, host='www.jamkazam.com')
|
||||
@user, @new_nearby, @host = user, new_nearby, host
|
||||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
|
||||
sendgrid_unique_args :type => "new_musicians"
|
||||
mail(:to => user.email, :subject => "JamKazam New Musicians in Your Area") do |format|
|
||||
format.text
|
||||
|
|
@ -97,6 +123,10 @@
|
|||
@body = msg
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -110,6 +140,10 @@
|
|||
@body = msg
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -123,6 +157,10 @@
|
|||
@body = msg
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -136,6 +174,10 @@
|
|||
@body = msg
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:bcc => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -149,6 +191,10 @@
|
|||
@body = msg
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -162,6 +208,10 @@
|
|||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session_id}"
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:bcc => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -176,6 +226,10 @@
|
|||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session_id}"
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:bcc => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -189,6 +243,10 @@
|
|||
@body = msg
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:bcc => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -202,6 +260,10 @@
|
|||
@body = msg
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:bcc => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -215,6 +277,10 @@
|
|||
@body = msg
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -228,6 +294,10 @@
|
|||
@body = msg
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
|
|
@ -246,6 +316,10 @@
|
|||
@sender_photo_url = sender_photo_url
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [User.id_for_email(email)])
|
||||
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html { render :layout => "from_user_mailer" }
|
||||
|
|
|
|||
|
|
@ -47,6 +47,13 @@
|
|||
<% end %>
|
||||
</table>
|
||||
<table align="center" width="650" cellpadding="10" bgcolor="#156572" cellspacing="0">
|
||||
<tr>
|
||||
<td align="center" valign="top">
|
||||
<% [:twitter, :facebook, :google].each do |src| %>
|
||||
<%= link_to(image_tag("http://www.jamkazam.com/assets/content/icon_#{src}.png", :style => "vertical-align:top"), "http://www.jamkazam.com/endorse/@USERID/#{src}") %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><font size="1" color="#ffffff" face="Arial, Helvetica, sans-serif">Copyright © <%= Time.now.year %> JamKazam, Inc. All rights reserved.</font>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
Resque::Mailer.error_handler = lambda { |mailer, message, error, action, args|
|
||||
# Necessary to re-enqueue jobs that receieve the SIGTERM signal
|
||||
if error.is_a?(Resque::TermException)
|
||||
Resque.enqueue(mailer, action, *args)
|
||||
else
|
||||
raise error
|
||||
end
|
||||
}
|
||||
|
|
@ -2,24 +2,27 @@ module JamRuby
|
|||
class EmailBatch < ActiveRecord::Base
|
||||
self.table_name = "email_batches"
|
||||
|
||||
has_many :email_batch_sets, :class_name => 'JamRuby::EmailBatchSet'
|
||||
|
||||
attr_accessible :from_email, :subject, :test_emails, :body
|
||||
attr_accessible :lock_version, :qualified_count, :sent_count, :started_at, :completed_at
|
||||
attr_accessible :lock_version, :opt_in_count, :sent_count, :started_at, :completed_at
|
||||
|
||||
default_scope :order => 'created_at DESC'
|
||||
|
||||
VAR_FIRST_NAME = '@FIRSTNAME'
|
||||
VAR_LAST_NAME = '@LASTNAME'
|
||||
|
||||
DEFAULT_SENDER = "support@jamkazam.com"
|
||||
BATCH_SIZE = 1000
|
||||
|
||||
BODY_TEMPLATE =<<FOO
|
||||
Hello #{VAR_FIRST_NAME},
|
||||
|
||||
<p>Pellentesque facilisis metus ac cursus varius. Nunc laoreet diam mauris, et rhoncus quam commodo vel. Vestibulum nec diam lobortis, posuere sapien id, faucibus nulla. Vivamus vitae pellentesque massa. Proin quis nibh eu nibh imperdiet porttitor. </p>
|
||||
<p>Paragraph 1 ... newline whitespace is significant for plain text conversions</p>
|
||||
|
||||
<p>Vestibulum mollis enim eu fringilla vulputate. Nam tincidunt, enim eget fringilla blandit, mi neque dictum dolor, non pellentesque libero erat sed massa. Morbi sodales lobortis eros, sed feugiat eros euismod eget. Nulla vulputate lobortis porttitor. </p>
|
||||
<p>Paragraph 2 ... "#{VAR_FIRST_NAME}" will be replaced by users first name</p>
|
||||
|
||||
<p>Thanks for using JamKazam!</p>
|
||||
|
||||
The JamKazam Team
|
||||
FOO
|
||||
|
||||
include AASM
|
||||
|
|
@ -27,51 +30,58 @@ FOO
|
|||
state :pending, :initial => true
|
||||
state :testing
|
||||
state :tested
|
||||
state :batching
|
||||
state :batched
|
||||
state :delivering
|
||||
state :delivered
|
||||
state :disabled
|
||||
|
||||
event :enable do
|
||||
transitions :from => :disabled, :to => :pending
|
||||
end
|
||||
event :reset do
|
||||
transitions :from => [:disabled, :testing, :tested, :batching, :batched, :pending], :to => :pending
|
||||
event :reset, :after => :did_reset do
|
||||
transitions :from => [:disabled, :testing, :tested, :delivering, :delivered, :pending], :to => :pending
|
||||
end
|
||||
event :do_test_run, :before => :running_tests do
|
||||
transitions :from => [:pending, :tested, :batched], :to => :testing
|
||||
event :do_test_run, :before => :will_run_tests do
|
||||
transitions :from => [:pending, :tested, :delivered], :to => :testing
|
||||
end
|
||||
event :did_test_run, :after => :ran_tests do
|
||||
transitions :from => :testing, :to => :tested
|
||||
end
|
||||
event :do_batch_run, :before => :running_batch do
|
||||
transitions :from => [:tested, :pending, :batched], :to => :batching
|
||||
event :do_batch_run, :before => :will_run_batch do
|
||||
transitions :from => [:tested, :pending, :delivered], :to => :delivering
|
||||
end
|
||||
event :did_batch_run, :after => :ran_batch do
|
||||
transitions :from => :batching, :to => :batched
|
||||
transitions :from => :delivering, :to => :delivered
|
||||
end
|
||||
event :disable do
|
||||
transitions :from => [:pending, :tested, :batched], :to => :disabled
|
||||
transitions :from => [:pending, :tested, :delivered], :to => :disabled
|
||||
end
|
||||
end
|
||||
|
||||
# has_many :email_batch_results, :class_name => 'JamRuby::EmailBatchResult'
|
||||
def self.new(*args)
|
||||
oo = super
|
||||
oo.body = BODY_TEMPLATE
|
||||
oo
|
||||
end
|
||||
|
||||
def self.create_with_params(params)
|
||||
obj = self.new
|
||||
params.each { |kk,vv| vv.strip! }
|
||||
params[:body] = BODY_TEMPLATE if params[:body].empty?
|
||||
obj.update_with_conflict_validation(params)
|
||||
obj
|
||||
end
|
||||
|
||||
def can_run_batch?
|
||||
self.tested? || self.pending?
|
||||
end
|
||||
|
||||
def can_run_test?
|
||||
self.test_emails.present? && (self.tested? || self.pending?)
|
||||
end
|
||||
|
||||
def deliver_batch
|
||||
self.perform_event('do_batch_run!')
|
||||
User.email_opt_in.find_in_batches(batch_size: 1000) do |users|
|
||||
if 'test' == Rails.env
|
||||
BatchMailer.send_batch_email(self.id, users.map(&:id)).deliver!
|
||||
else
|
||||
BatchMailer.send_batch_email(self.id, users.map(&:id)).deliver
|
||||
end
|
||||
User.email_opt_in.find_in_batches(batch_size: BATCH_SIZE) do |users|
|
||||
self.email_batch_sets << EmailBatchSet.deliver_set(self.id, users.map(&:id))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -92,7 +102,7 @@ FOO
|
|||
|
||||
def send_test_batch
|
||||
self.perform_event('do_test_run!')
|
||||
if 'test' == Rails.env
|
||||
if 'test'==Rails.env
|
||||
BatchMailer.send_batch_email_test(self.id).deliver!
|
||||
else
|
||||
BatchMailer.send_batch_email_test(self.id).deliver
|
||||
|
|
@ -106,8 +116,8 @@ FOO
|
|||
def did_send(emails)
|
||||
self.update_with_conflict_validation({ :sent_count => self.sent_count + emails.size })
|
||||
|
||||
if self.sent_count >= self.qualified_count
|
||||
if batching?
|
||||
if self.sent_count >= self.opt_in_count
|
||||
if delivering?
|
||||
self.perform_event('did_batch_run!')
|
||||
elsif testing?
|
||||
self.perform_event('did_test_run!')
|
||||
|
|
@ -128,26 +138,28 @@ FOO
|
|||
|
||||
def update_with_conflict_validation(*args)
|
||||
num_try = 0
|
||||
update_attributes(*args)
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
num_try += 1
|
||||
if 5 > num_try
|
||||
self.reload
|
||||
retry
|
||||
begin
|
||||
update_attributes(*args)
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
num_try += 1
|
||||
if 5 > num_try
|
||||
self.reload
|
||||
sleep(0.25)
|
||||
retry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def running_batch
|
||||
self.update_with_conflict_validation({:qualified_count => User.email_opt_in.count,
|
||||
def will_run_batch
|
||||
self.update_with_conflict_validation({:opt_in_count => User.email_opt_in.count,
|
||||
:sent_count => 0,
|
||||
:started_at => Time.now
|
||||
})
|
||||
end
|
||||
|
||||
def running_tests
|
||||
self.update_with_conflict_validation({:qualified_count => self.test_count,
|
||||
:sent_count => 0,
|
||||
:started_at => Time.now
|
||||
def will_run_tests
|
||||
self.update_with_conflict_validation({:opt_in_count => self.test_count,
|
||||
:sent_count => 0
|
||||
})
|
||||
end
|
||||
|
||||
|
|
@ -159,5 +171,29 @@ FOO
|
|||
self.update_with_conflict_validation({ :completed_at => Time.now })
|
||||
end
|
||||
|
||||
def clone
|
||||
bb = EmailBatch.new
|
||||
bb.subject = self.subject
|
||||
bb.body = self.body
|
||||
bb.from_email = self.from_email
|
||||
bb.test_emails = self.test_emails
|
||||
bb.save!
|
||||
bb
|
||||
end
|
||||
|
||||
def opting_in_count
|
||||
0 < opt_in_count ? opt_in_count : User.email_opt_in.count
|
||||
end
|
||||
|
||||
def did_reset
|
||||
self.email_batch_sets.map(&:destroy)
|
||||
self.update_with_conflict_validation({
|
||||
:opt_in_count => 0,
|
||||
:sent_count => 0,
|
||||
:started_at => nil,
|
||||
:completed_at => nil,
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
module JamRuby
|
||||
class EmailBatchSet < ActiveRecord::Base
|
||||
self.table_name = "email_batch_sets"
|
||||
|
||||
belongs_to :email_batch, :class_name => 'JamRuby::EmailBatch'
|
||||
|
||||
def self.deliver_set(batch_id, user_ids)
|
||||
bset = self.new
|
||||
bset.email_batch_id = batch_id
|
||||
bset.user_ids = user_ids.join(',')
|
||||
bset.started_at = Time.now
|
||||
bset.batch_count = user_ids.size
|
||||
bset.save!
|
||||
|
||||
if 'test' == Rails.env
|
||||
BatchMailer.send_batch_email(bset.email_batch_id, user_ids).deliver!
|
||||
else
|
||||
BatchMailer.send_batch_email(bset.email_batch_id, user_ids).deliver
|
||||
end
|
||||
bset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
module JamRuby
|
||||
class EmailError < ActiveRecord::Base
|
||||
self.table_name = "email_errors"
|
||||
|
||||
belongs_to :user, :class_name => 'JamRuby::User'
|
||||
|
||||
default_scope :order => 'email_date DESC'
|
||||
|
||||
ERR_BOUNCE = :bounce
|
||||
ERR_INVALID = :invalid
|
||||
|
||||
SENDGRID_UNAME = 'jamkazam'
|
||||
SENDGRID_PASSWD = 'jamjamblueberryjam'
|
||||
|
||||
def self.sendgrid_url(resource, action='get', params='')
|
||||
start_date, end_date = self.date_range
|
||||
"https://api.sendgrid.com/api/#{resource}.#{action}.json?api_user=#{EmailError::SENDGRID_UNAME}&api_key=#{EmailError::SENDGRID_PASSWD}&date=1&start_date=#{start_date.strftime('%Y-%m-%d')}&end_date=#{end_date.strftime('%Y-%m-%d')}&#{params}"
|
||||
end
|
||||
|
||||
def self.date_range
|
||||
tt = Time.now
|
||||
if eerr = self.first
|
||||
return [eerr.email_date, tt]
|
||||
end
|
||||
[tt - 1.year, tt]
|
||||
end
|
||||
|
||||
def self.did_capture?(email_addy)
|
||||
self.where(:email_address => email_addy).limit(1).first.present?
|
||||
end
|
||||
|
||||
def self.bounce_errors
|
||||
uu = self.sendgrid_url('bounces')
|
||||
response = RestClient.get(uu)
|
||||
if 200 == response.code
|
||||
return JSON.parse(response.body).collect do |jj|
|
||||
next if self.did_capture?(jj['email'])
|
||||
|
||||
ee = EmailError.new
|
||||
ee.error_type = 'bounces'
|
||||
ee.email_address = jj['email']
|
||||
ee.user_id = User.where(:email => ee.email_address).pluck(:id).first
|
||||
ee.status = jj['status']
|
||||
ee.email_date = jj['created']
|
||||
ee.reason = jj['reason']
|
||||
ee.save!
|
||||
# RestClient.delete(self.sendgrid_url('bounces', 'delete', "email=#{ee.email_address}"))
|
||||
ee
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.invalid_errors
|
||||
uu = self.sendgrid_url('invalidemails')
|
||||
response = RestClient.get(uu)
|
||||
if 200 == response.code
|
||||
return JSON.parse(response.body).collect do |jj|
|
||||
next if self.did_capture?(jj['email'])
|
||||
|
||||
ee = EmailError.new
|
||||
ee.error_type = 'invalidemails'
|
||||
ee.email_address = jj['email']
|
||||
ee.user_id = User.where(:email => ee.email_address).pluck(:id).first
|
||||
ee.email_date = jj['created']
|
||||
ee.reason = jj['reason']
|
||||
ee.save!
|
||||
uu =
|
||||
# RestClient.delete(self.sendgrid_url('invalidemails', 'delete', "email=#{ee.email_address}"))
|
||||
ee
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.capture_errors
|
||||
EmailError.bounce_errors
|
||||
EmailError.invalid_errors
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -1174,6 +1174,10 @@ module JamRuby
|
|||
# self.password_digest = encrypted_password
|
||||
#end
|
||||
|
||||
def self.id_for_email(email)
|
||||
User.where(:email => email).limit(1).pluck(:id).first
|
||||
end
|
||||
|
||||
# end devise compatibility
|
||||
private
|
||||
def create_remember_token
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
module JamRuby
|
||||
class EmailErrorCollector
|
||||
extend Resque::Plugins::LonelyJob
|
||||
|
||||
@queue = :email_error_collector
|
||||
@@log = Logging.logger[EmailErrorCollector]
|
||||
|
||||
def self.perform
|
||||
@@log.debug("waking up")
|
||||
EmailError.capture_errors
|
||||
@@log.debug("done")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -75,6 +75,7 @@ gem 'resque_mailer'
|
|||
gem 'quiet_assets', :group => :development
|
||||
gem 'bugsnag'
|
||||
gem 'multi_json', '1.9.0'
|
||||
gem 'rest_client'
|
||||
|
||||
group :development, :test do
|
||||
gem 'rspec-rails'
|
||||
|
|
@ -131,4 +132,3 @@ group :package do
|
|||
gem 'fpm'
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var instrumentLogoMap = context.JK.getInstrumentIconMap24();
|
||||
var hoverSelector = "#band-hover";
|
||||
|
||||
this.showBubble = function() {
|
||||
|
|
@ -28,7 +27,7 @@
|
|||
instrumentHtml = '<td><div class="nowrap">';
|
||||
if (val.instruments) { // @FIXME: edge case for Test user that has no instruments?
|
||||
$.each(val.instruments, function(index, instrument) {
|
||||
instrumentHtml += '<img src="' + instrumentLogoMap[instrument.instrument_id] + '" width="24" height="24" /> ';
|
||||
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(instrument.instrument_id) + '" width="24" height="24" /> ';
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var instrumentLogoMap = context.JK.getInstrumentIconMap24();
|
||||
var hoverSelector = "#musician-hover";
|
||||
|
||||
this.showBubble = function() {
|
||||
|
|
@ -20,7 +19,7 @@
|
|||
// instruments
|
||||
var instrumentHtml = '';
|
||||
$.each(response.instruments, function(index, val) {
|
||||
instrumentHtml += '<div class="left mr10 mb"><img src="' + instrumentLogoMap[val.instrument_id] + '" width="24" height="24" /></div>';
|
||||
instrumentHtml += '<div class="left mr10 mb"><img src="' + context.JK.getInstrumentIcon24(val.instrument_id) + '" width="24" height="24" /></div>';
|
||||
});
|
||||
|
||||
// followings
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
context.JK.RecordingHoverBubble = function(recordingId, position) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var instrumentLogoMap = context.JK.getInstrumentIconMap24();
|
||||
var hoverSelector = "#recording-hover";
|
||||
|
||||
function deDupTracks(recordedTracks) {
|
||||
|
|
@ -61,7 +60,7 @@
|
|||
|
||||
instrumentHtml = '<td><div class="nowrap">';
|
||||
$.each(val.instrument_ids, function(index, val) {
|
||||
instrumentHtml += '<img src="' + instrumentLogoMap[val] + '" width="24" height="24" /> ';
|
||||
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(val) + '" width="24" height="24" /> ';
|
||||
})
|
||||
instrumentHtml += '</div></td>';
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var instrumentLogoMap = context.JK.getInstrumentIconMap24();
|
||||
var hoverSelector = "#session-hover";
|
||||
|
||||
this.showBubble = function() {
|
||||
|
|
@ -28,7 +27,7 @@
|
|||
instrumentHtml = '<td><div class="nowrap">';
|
||||
var instruments = val.instruments.split("|");
|
||||
$.each(instruments, function(index, instrument) {
|
||||
instrumentHtml += '<img src="' + instrumentLogoMap[instrument] + '" width="24" height="24" /> ';
|
||||
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(instrument) + '" width="24" height="24" /> ';
|
||||
});
|
||||
|
||||
instrumentHtml += '</div></td>';
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
}
|
||||
|
||||
function togglePlay() {
|
||||
|
||||
if(playing) {
|
||||
stopPlay();
|
||||
}
|
||||
|
|
@ -51,10 +50,10 @@
|
|||
|
||||
function like() {
|
||||
rest.addRecordingLike(recordingId, claimedRecordingId, JK.currentUserId)
|
||||
.done(function(response) {
|
||||
$("#spnLikeCount").html(parseInt($("#spnLikeCount").text()) + 1);
|
||||
$("#btnLike", $scope).unbind("click");
|
||||
});
|
||||
.done(function(response) {
|
||||
$("#spnLikeCount").html(parseInt($("#spnLikeCount").text()) + 1);
|
||||
$("#btnLike", $scope).unbind("click");
|
||||
});
|
||||
}
|
||||
|
||||
function play() {
|
||||
|
|
@ -68,21 +67,35 @@
|
|||
var comment = $("#txtRecordingComment").val();
|
||||
if ($.trim(comment).length > 0) {
|
||||
rest.addRecordingComment(recordingId, JK.currentUserId, comment)
|
||||
.done(function(response) {
|
||||
$("#spnCommentCount", $scope).html(parseInt($("#spnCommentCount").text()) + 1);
|
||||
|
||||
var template = $('#template-landing-comment').html();
|
||||
var commentHtml = context.JK.fillTemplate(template, {
|
||||
avatar_url: context.JK.currentUserAvatarUrl,
|
||||
name: context.JK.currentUserName,
|
||||
comment: comment
|
||||
});
|
||||
|
||||
$(".landing-comment-scroller").prepend(commentHtml);
|
||||
});
|
||||
.done(function(response) {
|
||||
$("#spnCommentCount", $scope).html(parseInt($("#spnCommentCount").text()) + 1);
|
||||
renderComment(comment, context.JK.currentUserId, context.JK.currentUserName,
|
||||
context.JK.currentUserAvatarUrl, $.timeago(Date.now()), context.JK.currentUserMusician, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderComment(comment, userId, userName, userAvatarUrl, timeago, musician, append) {
|
||||
var template = $('#template-landing-comment').html();
|
||||
var commentHtml = context.JK.fillTemplate(template, {
|
||||
avatar_url: userAvatarUrl,
|
||||
user_id: userId,
|
||||
hoverAction: musician ? "musician" : "fan",
|
||||
name: userName,
|
||||
comment: comment,
|
||||
timeago: timeago
|
||||
});
|
||||
|
||||
if (append) {
|
||||
$(".landing-comment-scroller").append(commentHtml);
|
||||
}
|
||||
else {
|
||||
$(".landing-comment-scroller").prepend(commentHtml);
|
||||
}
|
||||
|
||||
context.JK.bindHoverEvents();
|
||||
}
|
||||
|
||||
function initialize(_claimedRecordingId, _recordingId) {
|
||||
recordingId = _recordingId;
|
||||
claimedRecordingId = _claimedRecordingId;
|
||||
|
|
@ -90,8 +103,7 @@
|
|||
$('.timeago').timeago();
|
||||
$playButton.click(togglePlay);
|
||||
$controls.bind('statechange.listenRecording', stateChange);
|
||||
|
||||
$controls.listenRecording({recordingId: recordingId, claimedRecordingId: claimedRecordingId, sliderSelector:'.recording-slider', sliderBarSelector: '.recording-playback', currentTimeSelector:'.recording-current'});
|
||||
$controls.listenRecording({recordingId: recordingId, claimedRecordingId: claimedRecordingId, sliderSelector:'.recording-slider', sliderBarSelector: '.recording-playback', currentTimeSelector:'.recording-current'});
|
||||
|
||||
if (JK.currentUserId) {
|
||||
var shareDialog = new JK.ShareDialog(JK.app, claimedRecordingId, "recording");
|
||||
|
|
@ -116,6 +128,32 @@
|
|||
|
||||
$("#btnLike").click(like);
|
||||
$("#btnPlay").click(play);
|
||||
|
||||
$playButton.trigger('click');
|
||||
|
||||
pollForUpdates(claimedRecordingId);
|
||||
}
|
||||
|
||||
function pollForUpdates(claimedRecordingId) {
|
||||
$(".landing-comment-scroller").empty();
|
||||
rest.getClaimedRecording(claimedRecordingId)
|
||||
.done(function(response) {
|
||||
if (response.recording && response.recording.comments) {
|
||||
$("#spnPlayCount", $scope).html(response.recording.play_count);
|
||||
$("#spnCommentCount", $scope).html(response.recording.comment_count);
|
||||
$("#spnLikeCount", $scope).html(response.recording.like_count);
|
||||
$.each(response.recording.comments, function(index, val) {
|
||||
renderComment(val.comment, val.creator.id, val.creator.name,
|
||||
context.JK.resolveAvatarUrl(val.creator.photo_url), $.timeago(val.created_at), val.creator.musician, true);
|
||||
});
|
||||
setTimeout(function() {
|
||||
pollForUpdates(claimedRecordingId);
|
||||
}, 60000);
|
||||
}
|
||||
})
|
||||
.fail(function(xhr) {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -4,37 +4,53 @@
|
|||
var logger = context.JK.logger;
|
||||
var rest = new JK.Rest();
|
||||
var sessionId = null;
|
||||
var $scope = $(".landing-details");
|
||||
var $controls = null;
|
||||
var $status = null;
|
||||
var $playButton = $('.play-button');
|
||||
var playing = false;
|
||||
|
||||
function like() {
|
||||
rest.addSessionLike(sessionId, JK.currentUserId)
|
||||
.done(function(response) {
|
||||
$("#spnLikeCount").html(parseInt($("#spnLikeCount").text()) + 1);
|
||||
$("#btnLike").unbind("click");
|
||||
});
|
||||
.done(function(response) {
|
||||
$("#spnLikeCount").html(parseInt($("#spnLikeCount").text()) + 1);
|
||||
$("#btnLike").unbind("click");
|
||||
});
|
||||
}
|
||||
|
||||
function addComment() {
|
||||
var comment = $("#txtSessionComment").val();
|
||||
if ($.trim(comment).length > 0) {
|
||||
rest.addSessionComment(sessionId, JK.currentUserId, comment)
|
||||
.done(function(response) {
|
||||
$("#spnCommentCount").html(parseInt($("#spnCommentCount").text()) + 1);
|
||||
|
||||
var template = $('#template-landing-comment').html();
|
||||
var commentHtml = context.JK.fillTemplate(template, {
|
||||
avatar_url: context.JK.currentUserAvatarUrl,
|
||||
name: context.JK.currentUserName,
|
||||
comment: comment
|
||||
});
|
||||
|
||||
$(".landing-comment-scroller").prepend(commentHtml);
|
||||
});
|
||||
rest.addSessionComment(sessionId, JK.currentUserId, comment)
|
||||
.done(function(response) {
|
||||
$("#spnCommentCount").html(parseInt($("#spnCommentCount").text()) + 1);
|
||||
renderComment(comment, context.JK.currentUserId, context.JK.currentUserName,
|
||||
context.JK.currentUserAvatarUrl, $.timeago(Date.now()), context.JK.currentUserMusician, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderComment(comment, userId, userName, userAvatarUrl, timeago, musician, append) {
|
||||
var template = $('#template-landing-comment').html();
|
||||
var commentHtml = context.JK.fillTemplate(template, {
|
||||
avatar_url: userAvatarUrl,
|
||||
user_id: userId,
|
||||
hoverAction: musician ? "musician" : "fan",
|
||||
name: userName,
|
||||
comment: comment,
|
||||
timeago: timeago
|
||||
});
|
||||
|
||||
if (append) {
|
||||
$(".landing-comment-scroller").append(commentHtml);
|
||||
}
|
||||
else {
|
||||
$(".landing-comment-scroller").prepend(commentHtml);
|
||||
}
|
||||
|
||||
context.JK.bindHoverEvents();
|
||||
}
|
||||
|
||||
function stateChange(e, data) {
|
||||
if(data.displayText)
|
||||
{
|
||||
|
|
@ -87,34 +103,57 @@
|
|||
$controls.bind('statechange.listenBroadcast', stateChange);
|
||||
context.JK.prettyPrintElements($('time.duration').show());
|
||||
context.JK.TickDuration(null);
|
||||
$('.play-button').click(togglePlay);
|
||||
|
||||
$playButton.click(togglePlay);
|
||||
|
||||
sessionId = musicSessionId;
|
||||
|
||||
if (JK.currentUserId) {
|
||||
var shareDialog = new JK.ShareDialog(context.JK.app, sessionId, "session");
|
||||
shareDialog.initialize(JK.FacebookHelperInstance);
|
||||
var shareDialog = new JK.ShareDialog(context.JK.app, sessionId, "session");
|
||||
shareDialog.initialize(JK.FacebookHelperInstance);
|
||||
|
||||
$("#btnShare").click(function(e) {
|
||||
shareDialog.showDialog();
|
||||
});
|
||||
$("#btnShare").click(function(e) {
|
||||
shareDialog.showDialog();
|
||||
});
|
||||
|
||||
$("#btnPostComment").click(function(e) {
|
||||
if ($.trim($("#txtSessionComment").val()).length > 0) {
|
||||
addComment();
|
||||
$("#txtSessionComment").val('');
|
||||
$("#txtSessionComment").blur();
|
||||
}
|
||||
});
|
||||
$("#btnPostComment").click(function(e) {
|
||||
if ($.trim($("#txtSessionComment").val()).length > 0) {
|
||||
addComment();
|
||||
$("#txtSessionComment").val('');
|
||||
$("#txtSessionComment").blur();
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
$("#txtSessionComment").attr("disabled", "disabled");
|
||||
$("#txtSessionComment").val("You must be logged in to add a comment.");
|
||||
$("#txtSessionComment").attr("disabled", "disabled");
|
||||
$("#txtSessionComment").val("You must be logged in to add a comment.");
|
||||
}
|
||||
|
||||
$("#btnLike").click(like);
|
||||
|
||||
$playButton.trigger('click');
|
||||
|
||||
pollForUpdates(musicSessionId);
|
||||
}
|
||||
|
||||
function pollForUpdates(musicSessionId) {
|
||||
$(".landing-comment-scroller").empty();
|
||||
rest.getSessionHistory(musicSessionId)
|
||||
.done(function(response) {
|
||||
if (response && response.comments) {
|
||||
$("#spnCommentCount", $scope).html(response.comment_count);
|
||||
$("#spnLikeCount", $scope).html(response.like_count);
|
||||
$.each(response.comments, function(index, val) {
|
||||
renderComment(val.comment, val.creator.id, val.creator.name,
|
||||
context.JK.resolveAvatarUrl(val.creator.photo_url), $.timeago(val.created_at), val.creator.musician, true);
|
||||
});
|
||||
setTimeout(function() {
|
||||
pollForUpdates(musicSessionId);
|
||||
}, 60000);
|
||||
}
|
||||
})
|
||||
.fail(function(xhr) {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -368,6 +368,23 @@ class UsersController < ApplicationController
|
|||
render :layout => "landing"
|
||||
end
|
||||
|
||||
def endorse
|
||||
if uu = User.where(['id = ? AND first_liked_us IS NULL',params[:id]]).limit(1).first
|
||||
uu.first_liked_us = Time.now
|
||||
uu.save!
|
||||
end if params[:id].present?
|
||||
|
||||
url, service = 'http://www.jamkazam.com', params[:service]
|
||||
if 'twitter'==service
|
||||
url = 'https://twitter.com/jamkazam'
|
||||
elsif 'facebook'==service
|
||||
url = 'https://www.facebook.com/JamKazam'
|
||||
elsif 'google'==service
|
||||
url = 'https://plus.google.com/u/0/106619885929396862606/about'
|
||||
end
|
||||
redirect_to url
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def is_native_client
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ child(:recording => :recording) {
|
|||
attributes :comment, :created_at
|
||||
|
||||
child(:user => :creator) {
|
||||
attributes :id, :first_name, :last_name, :photo_url
|
||||
attributes :id, :first_name, :last_name, :name, :photo_url, :musician
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,4 +22,12 @@ child(:music_session_user_histories => :users) {
|
|||
child(:user => :user) {
|
||||
attributes :name, :photo_url
|
||||
}
|
||||
}
|
||||
|
||||
child(:comments => :comments) {
|
||||
attributes :comment, :created_at
|
||||
|
||||
child(:user => :creator) {
|
||||
attributes :id, :first_name, :last_name, :name, :photo_url, :musician
|
||||
}
|
||||
}
|
||||
|
|
@ -92,10 +92,12 @@
|
|||
JK.currentUserId = '<%= current_user.id %>';
|
||||
JK.currentUserAvatarUrl = JK.resolveAvatarUrl('<%= current_user.photo_url %>');
|
||||
JK.currentUserName = '<%= current_user.name %>';
|
||||
JK.currentUserMusician = '<%= current_user.musician %>';
|
||||
<% else %>
|
||||
JK.currentUserId = null;
|
||||
JK.currentUserAvatarUrl = null;
|
||||
JK.currentUserName = null;
|
||||
JK.currentUserMusician = null;
|
||||
<% end %>
|
||||
|
||||
JK.app = JK.JamKazam();
|
||||
|
|
|
|||
|
|
@ -7,38 +7,23 @@
|
|||
<textarea id="<%= id %>" class="w100 p5 f15" rows="2" placeholder="Enter a comment..."></textarea>
|
||||
</div>
|
||||
<div class="right mr20">
|
||||
<a href="#" id="btnPostComment" class="button-orange">POST</a>
|
||||
<a id="btnPostComment" class="button-orange">POST</a>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
|
||||
<div class="landing-comment-scroller">
|
||||
<% comments.each do |c| %>
|
||||
<% hoverAction = c.user.musician ? "musician" : "fan" %>
|
||||
<div user-id="<%= c.user.id %>" hoveraction="<%= hoverAction %>" class="avatar-small mr10">
|
||||
<% unless c.user.photo_url.blank? %>
|
||||
<%= image_tag "#{c.user.photo_url}", {:alt => ""} %>
|
||||
<% else %>
|
||||
<%= image_tag "shared/avatar_generic.png", {:alt => ""} %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="w80 left p10 lightgrey mt10">
|
||||
<a user-id="<%= c.user.id %>" hoveraction="<%= hoverAction %>" href="#"><%= c.user.name %></a> <%= c.comment %>
|
||||
<br />
|
||||
<div class="f12 grey mt5"><%= c.created_at.strftime("%b %e %Y, %l:%M %p") %></div>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/template" id="template-landing-comment">
|
||||
<div class="avatar-small mr10">
|
||||
<img src="{avatar_url}" alt="" />
|
||||
<div user-id="{user_id}" hoveraction="{hoverAction}" class="avatar-small mr10">
|
||||
<img src="{avatar_url}" alt="" />
|
||||
</div>
|
||||
<div class="w80 left p10 lightgrey mt10">
|
||||
<a href="#">{name}</a> {comment}
|
||||
<br />
|
||||
<div class="f12 grey mt5">Just now</div>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
<a user-id="{user_id}" hoveraction="{hoverAction}">{name}</a> {comment}
|
||||
<br />
|
||||
<div class="f12 grey mt5">{timeago}</div>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
</script>
|
||||
|
|
@ -63,6 +63,8 @@ SampleApp::Application.routes.draw do
|
|||
|
||||
match '/events/:slug', to: 'events#show', :via => :get, :as => 'event'
|
||||
|
||||
match '/endorse/:id/:service', to: 'users#endorse', :as => 'endorse'
|
||||
|
||||
# temporarily allow for debugging--only allows admini n
|
||||
match '/listen_in', to: 'spikes#listen_in'
|
||||
|
||||
|
|
|
|||
|
|
@ -19,3 +19,8 @@ CleanupFacebookSignup:
|
|||
class: "JamRuby::CleanupFacebookSignup"
|
||||
description: "Deletes facebook_signups that are old"
|
||||
|
||||
EmailErrorCollector:
|
||||
cron: "0 14 * * *"
|
||||
class: "JamRuby::EmailErrorCollector"
|
||||
description: "Collects sendgrid email errors"
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Landing", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
let (:user) { FactoryGirl.create(:user) }
|
||||
|
||||
before(:all) do
|
||||
MusicSessionHistory.delete_all
|
||||
ClaimedRecording.delete_all
|
||||
Recording.delete_all
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
MusicSessionHistory.delete_all
|
||||
end
|
||||
|
||||
let (:claimed_recording) { FactoryGirl.create(:claimed_recording) }
|
||||
|
||||
it "should render comments" do
|
||||
pending "weird error"
|
||||
|
||||
recording = ClaimedRecording.first
|
||||
comment = "test comment"
|
||||
timestamp = "less than a minute ago"
|
||||
url = "/recordings/#{claimed_recording.id}"
|
||||
visit url
|
||||
|
||||
fill_in "txtRecordingComment", with: comment
|
||||
find('#btnPostComment').trigger(:click)
|
||||
|
||||
# (1) Test a user creating a comment and ensure it displays.
|
||||
|
||||
# comment body
|
||||
find('div', text: comment)
|
||||
|
||||
# timestamp
|
||||
find('div', text: timestamp)
|
||||
|
||||
# (2) Test a user visiting a landing page with an existing comment.
|
||||
|
||||
# re-visit page to reload from database
|
||||
visit url
|
||||
|
||||
# comment body
|
||||
find('div', text: comment)
|
||||
|
||||
# timestamp
|
||||
find('div', text: timestamp)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Landing", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
let (:user) { FactoryGirl.create(:user) }
|
||||
|
||||
before(:all) do
|
||||
MusicSessionHistory.delete_all
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
create_session(creator: user)
|
||||
formal_leave_by(user)
|
||||
end
|
||||
|
||||
it "should render comments" do
|
||||
pending "weird error"
|
||||
|
||||
msh = MusicSessionHistory.first
|
||||
comment = "test comment"
|
||||
timestamp = "less than a minute ago"
|
||||
url = "/sessions/#{msh.id}"
|
||||
visit url
|
||||
|
||||
# (1) Test a user creating a comment and ensure it displays.
|
||||
|
||||
fill_in "txtSessionComment", with: comment
|
||||
find('#btnPostComment').trigger(:click)
|
||||
|
||||
# comment body
|
||||
find('div', text: comment)
|
||||
|
||||
# timestamp
|
||||
find('div', text: timestamp)
|
||||
|
||||
# (2) Test a user visiting a landing page with an existing comment.
|
||||
|
||||
# re-visit page to reload from database
|
||||
visit url
|
||||
|
||||
# comment body
|
||||
find('div', text: comment)
|
||||
|
||||
# timestamp
|
||||
find('div', text: timestamp)
|
||||
end
|
||||
end
|
||||
|
|
@ -46,6 +46,7 @@ gem 'resque_mailer'
|
|||
gem 'geokit'
|
||||
gem 'geokit-rails', '2.0.1'
|
||||
gem 'mime-types', '1.25.1'
|
||||
gem 'rest-client'
|
||||
|
||||
group :development do
|
||||
gem 'pry'
|
||||
|
|
|
|||
Loading…
Reference in New Issue