Merge branch 'feature/scheduled_sessions' into feature/create_session_flow
This commit is contained in:
commit
e49c98c659
|
|
@ -1,7 +1,7 @@
|
|||
source 'http://rubygems.org'
|
||||
|
||||
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/'
|
||||
devenv = ENV["BUILD_NUMBER"].nil? || ENV["TEST_WWW"] == "1"
|
||||
devenv = ENV["BUILD_NUMBER"].nil?
|
||||
|
||||
if devenv
|
||||
gem 'jam_db', :path=> "../db/target/ruby_package"
|
||||
|
|
@ -72,9 +72,6 @@ gem 'postgres_ext', '1.0.0'
|
|||
gem 'resque_mailer'
|
||||
gem 'rest-client'
|
||||
|
||||
gem 'geokit-rails'
|
||||
gem 'postgres_ext', '1.0.0'
|
||||
|
||||
group :libv8 do
|
||||
gem 'libv8', "~> 3.11.8"
|
||||
end
|
||||
|
|
@ -104,11 +101,7 @@ group :development, :test do
|
|||
gem 'capybara'
|
||||
gem 'rspec-rails'
|
||||
gem 'guard-rspec', '0.5.5'
|
||||
gem 'jasmine', '1.3.1'
|
||||
gem 'pry'
|
||||
gem 'pry-remote'
|
||||
gem 'pry-stack_explorer'
|
||||
gem 'pry-debugger'
|
||||
gem 'jasmine', '1.3.1'
|
||||
gem 'execjs', '1.4.0'
|
||||
gem 'therubyracer' #, '0.11.0beta8'
|
||||
gem 'factory_girl_rails', '4.1.0'
|
||||
|
|
@ -120,4 +113,12 @@ end
|
|||
group :test do
|
||||
gem 'simplecov', '~> 0.7.1'
|
||||
gem 'simplecov-rcov'
|
||||
end
|
||||
gem 'capybara-webkit'
|
||||
gem 'capybara-screenshot'
|
||||
gem 'poltergeist'
|
||||
end
|
||||
|
||||
gem 'pry'
|
||||
gem 'pry-remote'
|
||||
gem 'pry-stack_explorer'
|
||||
gem 'pry-debugger'
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ ActiveAdmin.register_page "Dashboard" do
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# column do
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ ActiveAdmin.register JamRuby::EmailBatch, :as => 'Batch Emails' do
|
|||
end
|
||||
|
||||
member_action :batch_send, :method => :get do
|
||||
resource.deliver_batch
|
||||
resource.deliver_batch_async
|
||||
redirect_to admin_batch_email_path(resource.id)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
ActiveAdmin.register_page 'Feed' do
|
||||
content do
|
||||
|
||||
# get user information via params
|
||||
user_id = nil
|
||||
user_id = params[:feed][:user_id] if params[:feed] && params[:feed][:user_id] != ''
|
||||
user_name = 'All'
|
||||
user_name = User.find(user_id).to_label if user_id
|
||||
|
||||
render :partial => 'form', locals: {user_name: user_name, user_id: user_id }
|
||||
|
||||
page = (params[:page] ||= 1).to_i
|
||||
per_page = 10
|
||||
offset = (page - 1) * per_page
|
||||
|
||||
# get feed ids
|
||||
where_sql = ''
|
||||
where_sql = "where user_id = '#{user_id}'" if user_id
|
||||
sql_feed_ids = "SELECT id, 'music_sessions' as type, created_at FROM music_sessions #{where_sql}
|
||||
UNION ALL
|
||||
SELECT DISTINCT recording_id as id, 'recordings' as type, created_at FROM recorded_tracks #{where_sql}
|
||||
UNION ALL
|
||||
SELECT id, 'diagnostics' as type, created_at FROM diagnostics #{where_sql}
|
||||
ORDER BY created_at DESC
|
||||
OFFSET #{offset}
|
||||
LIMIT #{per_page};"
|
||||
|
||||
sql_feed_count = "SELECT COUNT(*) FROM (
|
||||
SELECT id, 'music_sessions' as type, created_at FROM music_sessions #{where_sql}
|
||||
UNION ALL
|
||||
SELECT DISTINCT recording_id as id, 'recordings' as type, created_at FROM recorded_tracks #{where_sql}
|
||||
UNION ALL
|
||||
SELECT id, 'diagnostics' as type, created_at FROM diagnostics #{where_sql}
|
||||
ORDER BY created_at DESC
|
||||
) AS IDS;"
|
||||
feed_count = ActiveRecord::Base.connection.execute(sql_feed_count).values[0][0].to_i
|
||||
id_types = ActiveRecord::Base.connection.execute(sql_feed_ids).values
|
||||
|
||||
@feed_pages = WillPaginate::Collection.create(page, per_page) do |pager|
|
||||
pager.total_entries = feed_count
|
||||
pager.replace(id_types)
|
||||
end
|
||||
|
||||
div class: 'feed-pagination' do
|
||||
will_paginate @feed_pages
|
||||
end
|
||||
|
||||
recordings = []
|
||||
sessions = []
|
||||
diagnostics = []
|
||||
id_types.each do |id_and_type|
|
||||
if id_and_type[1] == "music_sessions"
|
||||
sessions << JamRuby::MusicSession.find(id_and_type[0])
|
||||
elsif id_and_type[1] == "recordings"
|
||||
recordings << JamRuby::Recording.find(id_and_type[0])
|
||||
elsif id_and_type[1] == "diagnostics"
|
||||
diagnostics << JamRuby::Diagnostic.find(id_and_type[0])
|
||||
else
|
||||
raise "Unknown type returned from feed ids"
|
||||
end
|
||||
end
|
||||
|
||||
columns do
|
||||
column do
|
||||
panel "Music Sessions - #{user_name}" do
|
||||
if sessions.count > 0
|
||||
table_for(sessions) do
|
||||
column :creator do |msh|
|
||||
link_to msh.creator.to_label, admin_feed_path({feed: {user_id: msh.creator.id}})
|
||||
end
|
||||
column :created_at do |msh| msh.created_at.strftime('%b %d %Y, %H:%M') end
|
||||
column :duration do |msh| "#{msh.duration_minutes.round(2)} minutes" end
|
||||
column :members do |msh|
|
||||
uu = msh.unique_users
|
||||
if uu.length > 0
|
||||
uu.each do |u|
|
||||
span link_to u.to_label + ', ', admin_feed_path({feed: {user_id: u.id}})
|
||||
end
|
||||
else
|
||||
span para 'No members'
|
||||
end
|
||||
end
|
||||
|
||||
column :band do |msh| auto_link(msh.band, msh.band.try(:name)) end
|
||||
column :fan_access do |msh| msh.fan_access end
|
||||
column :plays do |msh| msh.plays.count end
|
||||
column :likes do |msh| msh.likes.count end
|
||||
column :comments do |msh|
|
||||
if msh.comment_count > 0
|
||||
text_node "(#{msh.comment_count}) "
|
||||
msh.comments.each do |comment|
|
||||
text_node comment.user.to_label + ', '
|
||||
end
|
||||
else
|
||||
span para 'No comments'
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
span class: 'text-center' do
|
||||
para 'No session activities.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
panel "Recordings - #{user_name}" do
|
||||
if recordings.count > 0
|
||||
table_for(recordings) do
|
||||
column :starter do |rec|
|
||||
link_to rec.owner.to_label, admin_feed_path({feed: {user_id: rec.owner.id}})
|
||||
end
|
||||
column :mixes do |rec|
|
||||
ul do
|
||||
mixes = rec.mixes
|
||||
if mixes.count > 0
|
||||
mixes.each do |mix|
|
||||
li do
|
||||
text_node "Created At: #{mix.created_at.strftime('%b %d %Y, %H:%M')}, "
|
||||
text_node "Started At: #{mix.started_at.strftime('%b %d %Y, %H:%M')}, "
|
||||
text_node "Completed At: #{mix.completed_at.strftime('%b %d %Y, %H:%M')}, "
|
||||
text_node "Error Count: #{mix.error_count}, "
|
||||
text_node "Error Reason: #{mix.error_reason}, "
|
||||
text_node "Error Detail: #{mix.error_detail}, "
|
||||
text_node "Download Count: #{mix.download_count}, "
|
||||
if !mix.nil? && !mix[:ogg_url].nil?
|
||||
span link_to 'Download OGG', mix.sign_url(3600, 'ogg')
|
||||
else
|
||||
text_node 'OGG download not available'
|
||||
end
|
||||
if !mix.nil? && !mix[:mp3_url].nil?
|
||||
span link_to 'Download MP3', mix.sign_url(3600, 'mp3')
|
||||
else
|
||||
text_node 'MP3 download not available'
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
span para 'No mixes'
|
||||
end
|
||||
end
|
||||
end
|
||||
column :recorded_tracks do |rec|
|
||||
ul do
|
||||
rts = rec.recorded_tracks
|
||||
if rts.count > 0
|
||||
rts.each do |gt|
|
||||
li do
|
||||
span link_to gt.musician.to_label, admin_feed_path({feed: {user_id: gt.musician.id}})
|
||||
span ", #{gt.instrument_id}, "
|
||||
span "Download Count: #{gt.download_count}, "
|
||||
span "Fully uploaded: #{gt.fully_uploaded}, "
|
||||
span "Upload failures: #{gt.upload_failures}, "
|
||||
span "Part failures: #{gt.part_failures}, "
|
||||
if gt[:url]
|
||||
# span link_to 'Download', gt.sign_url(3600)
|
||||
else
|
||||
span 'No track available'
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
span para 'No recorded tracks'
|
||||
end
|
||||
end
|
||||
end
|
||||
column :claimed_recordings do |rec|
|
||||
ul do
|
||||
crs = rec.claimed_recordings
|
||||
if crs.count > 0
|
||||
crs.each do |cr|
|
||||
li do
|
||||
span cr.name
|
||||
span link_to cr.user.to_label, admin_feed_path({feed: {user_id: cr.user.id}})
|
||||
span ", Public: #{cr.is_public}"
|
||||
end
|
||||
end
|
||||
else
|
||||
span para 'No claimed recordings'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
span class: 'text-center' do
|
||||
para 'No recording activities.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
panel "Diagnostics - #{user_name}" do
|
||||
if diagnostics.count > 0 then
|
||||
table_for(diagnostics) do
|
||||
column :user do |d|
|
||||
span link_to d.user.to_label, admin_feed_path({feed: {user_id: d.user.id}})
|
||||
end
|
||||
column :created_at do |d| d.created_at.strftime('%b %d %Y, %H:%M') end
|
||||
column :type
|
||||
column :creator
|
||||
column :data do |d|
|
||||
span style: "white-space: pre;" do
|
||||
begin
|
||||
JSON.pretty_generate(JSON.parse(d.data))
|
||||
rescue
|
||||
d.data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
span class: 'text-center' do
|
||||
para 'No diagnostic activities.'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
div class: 'feed-pagination' do
|
||||
will_paginate @feed_pages
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -103,7 +103,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
autocomplete :user, :email, :full => true, :display_value => :autocomplete_display_name
|
||||
|
||||
def get_autocomplete_items(parameters)
|
||||
items = User.select("DISTINCT email, first_name, last_name, id").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{parameters[:term]}%", "%#{parameters[:term]}%", "%#{parameters[:term]}%"])
|
||||
User.select("email, first_name, last_name, id").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{parameters[:term]}%", "%#{parameters[:term]}%", "%#{parameters[:term]}%"])
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
ActiveAdmin.register JamRuby::LatencyTester, :as => 'LatencyTester' do
|
||||
|
||||
config.filters = true
|
||||
config.per_page = 50
|
||||
config.clear_action_items!
|
||||
config.sort_order = "client_id"
|
||||
menu :parent => 'Operations'
|
||||
|
||||
controller do
|
||||
def scoped_collection
|
||||
@latency_testers ||= end_of_association_chain
|
||||
.order('client_id')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
index :as => :block do |latency_tester|
|
||||
div :for => latency_tester do
|
||||
h3 "#{latency_tester.client_id}"
|
||||
columns do
|
||||
column do
|
||||
panel 'Details' do
|
||||
attributes_table_for(latency_tester) do
|
||||
row :connection do |latency_tester| latency_tester.connection ? "last updated at: #{latency_tester.connection.updated_at}" : "no connection" end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
/*
|
||||
*= require jquery.ui.all
|
||||
*= require custom
|
||||
*/
|
||||
// Active Admin's got SASS!
|
||||
@import "active_admin/mixins";
|
||||
|
|
|
|||
|
|
@ -2,4 +2,24 @@
|
|||
.version-info {
|
||||
font-size:small;
|
||||
color:lightgray;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.feed-pagination {
|
||||
height: 20px;
|
||||
margin-bottom: 15px;
|
||||
.pagination {
|
||||
float: left !important;
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<%= semantic_form_for :feed, url: admin_feed_path, method: :get do |f| %>
|
||||
<%= f.inputs do %>
|
||||
<%= f.input :user, :as => :autocomplete, :url => autocomplete_user_email_admin_users_path, :input_html => { :id_element => "#feed_user_id" } %>
|
||||
<%= f.input :user_id, :as => :hidden %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
@ -28,6 +28,17 @@ FactoryGirl.define do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
factory :connection, :class => JamRuby::Connection do
|
||||
sequence(:client_id) { |n| "Client#{n}" }
|
||||
ip_address "1.1.1.1"
|
||||
as_musician true
|
||||
addr 0
|
||||
locidispid 0
|
||||
client_type 'client'
|
||||
association :user, factory: :user
|
||||
end
|
||||
|
||||
factory :artifact_update, :class => JamRuby::ArtifactUpdate do
|
||||
sequence(:version) { |n| "0.1.#{n}" }
|
||||
uri { "http://somewhere/jkclient.msi" }
|
||||
|
|
@ -46,4 +57,145 @@ FactoryGirl.define do
|
|||
description { |n| "Instrument #{n}" }
|
||||
end
|
||||
|
||||
factory :genre, :class => JamRuby::Genre do
|
||||
description { |n| "Genre #{n}" }
|
||||
end
|
||||
|
||||
factory :music_session, :class => JamRuby::MusicSession do
|
||||
sequence(:name) { |n| "Music Session #{n}" }
|
||||
sequence(:description) { |n| "Music Session Description #{n}" }
|
||||
fan_chat true
|
||||
fan_access true
|
||||
approval_required false
|
||||
musician_access true
|
||||
legal_terms true
|
||||
language 'english'
|
||||
legal_policy 'standard'
|
||||
genre JamRuby::Genre.first
|
||||
association :creator, :factory => :user
|
||||
end
|
||||
|
||||
factory :music_session_user_history, :class => JamRuby::MusicSessionUserHistory do
|
||||
ignore do
|
||||
history nil
|
||||
user nil
|
||||
end
|
||||
|
||||
music_session_id { history.id }
|
||||
user_id { user.id }
|
||||
sequence(:client_id) { |n| "Connection #{n}" }
|
||||
end
|
||||
|
||||
factory :recorded_track, :class => JamRuby::RecordedTrack do
|
||||
instrument JamRuby::Instrument.first
|
||||
sound 'stereo'
|
||||
sequence(:client_id) { |n| "client_id-#{n}"}
|
||||
sequence(:track_id) { |n| "track_id-#{n}"}
|
||||
sequence(:client_track_id) { |n| "client_track_id-#{n}"}
|
||||
md5 'abc'
|
||||
length 1
|
||||
fully_uploaded true
|
||||
association :user, factory: :user
|
||||
association :recording, factory: :recording
|
||||
end
|
||||
|
||||
factory :recording, :class => JamRuby::Recording do
|
||||
|
||||
association :owner, factory: :user
|
||||
association :music_session, factory: :active_music_session
|
||||
|
||||
factory :recording_with_track do
|
||||
before(:create) { |recording, evaluator|
|
||||
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: evaluator.owner)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
factory :claimed_recording, :class => JamRuby::ClaimedRecording do
|
||||
sequence(:name) { |n| "name-#{n}" }
|
||||
sequence(:description) { |n| "description-#{n}" }
|
||||
is_public true
|
||||
association :genre, factory: :genre
|
||||
association :user, factory: :user
|
||||
|
||||
before(:create) { |claimed_recording|
|
||||
claimed_recording.recording = FactoryGirl.create(:recording_with_track, owner: claimed_recording.user)
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
factory :mix, :class => JamRuby::Mix do
|
||||
started_at Time.now
|
||||
completed_at Time.now
|
||||
ogg_md5 'abc'
|
||||
ogg_length 1
|
||||
sequence(:ogg_url) { |n| "recordings/ogg/#{n}" }
|
||||
mp3_md5 'abc'
|
||||
mp3_length 1
|
||||
sequence(:mp3_url) { |n| "recordings/mp3/#{n}" }
|
||||
completed true
|
||||
|
||||
before(:create) {|mix|
|
||||
user = FactoryGirl.create(:user)
|
||||
mix.recording = FactoryGirl.create(:recording_with_track, owner: user)
|
||||
mix.recording.claimed_recordings << FactoryGirl.create(:claimed_recording, user: user, recording: mix.recording)
|
||||
}
|
||||
end
|
||||
|
||||
factory :diagnostic, :class => JamRuby::Diagnostic do
|
||||
type JamRuby::Diagnostic::NO_HEARTBEAT_ACK
|
||||
creator JamRuby::Diagnostic::CLIENT
|
||||
data Faker::Lorem.sentence
|
||||
association :user, factory: :user
|
||||
end
|
||||
|
||||
factory :active_music_session_no_user_history, :class => JamRuby::ActiveMusicSession do
|
||||
|
||||
association :creator, factory: :user
|
||||
|
||||
ignore do
|
||||
name "My Music Session"
|
||||
description "Come Music Session"
|
||||
fan_chat true
|
||||
fan_access true
|
||||
approval_required false
|
||||
musician_access true
|
||||
legal_terms true
|
||||
genre JamRuby::Genre.first
|
||||
band nil
|
||||
end
|
||||
|
||||
|
||||
before(:create) do |session, evaluator|
|
||||
music_session = FactoryGirl.create(:music_session, name: evaluator.name, description: evaluator.description, fan_chat: evaluator.fan_chat,
|
||||
fan_access: evaluator.fan_access, approval_required: evaluator.approval_required, musician_access: evaluator.musician_access,
|
||||
genre: evaluator.genre, creator: evaluator.creator, band: evaluator.band)
|
||||
session.id = music_session.id
|
||||
end
|
||||
|
||||
factory :active_music_session do
|
||||
after(:create) { |session|
|
||||
FactoryGirl.create(:music_session_user_history, :history => session.music_session, :user => session.creator)
|
||||
}
|
||||
|
||||
factory :music_session_with_mount do
|
||||
association :mount, :factory => :icecast_mount
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
factory :latency_tester, :class => JamRuby::LatencyTester do
|
||||
ignore do
|
||||
connection nil
|
||||
make_connection true
|
||||
end
|
||||
|
||||
sequence(:client_id) { |n| "LatencyTesterClientId-#{n}" }
|
||||
|
||||
after(:create) do |latency_tester, evaluator|
|
||||
latency_tester.connection = evaluator.connection if evaluator.connection
|
||||
latency_tester.connection = FactoryGirl.create(:connection, client_type: Connection::TYPE_LATENCY_TESTER, client_id: latency_tester.client_id) if evaluator.make_connection
|
||||
latency_tester.save
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Feeds' do
|
||||
|
||||
subject { page }
|
||||
|
||||
before(:each) do
|
||||
MusicSession.delete_all
|
||||
Recording.delete_all
|
||||
Diagnostic.delete_all
|
||||
User.delete_all
|
||||
end
|
||||
|
||||
let(:admin) { FactoryGirl.create(:admin) }
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
|
||||
let(:music_session) { FactoryGirl.create(:music_session, :creator => user) }
|
||||
let(:recording) { FactoryGirl.create(:recording_with_track, :owner => user) }
|
||||
let(:diagnostic) { FactoryGirl.create(:diagnostic, :user => user) }
|
||||
|
||||
context 'empty dashboard' do
|
||||
before(:each) do
|
||||
visit admin_feed_path
|
||||
end
|
||||
|
||||
it { should have_selector('h2', text: 'Feed') }
|
||||
|
||||
it 'has no feeds' do
|
||||
should have_selector('p', text: 'No session activities.')
|
||||
should have_selector('p', text: 'No recording activities.')
|
||||
should have_selector('p', text: 'No diagnostic activities.')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context 'admin enters a user name' do
|
||||
before(:each) do
|
||||
user.touch
|
||||
visit admin_feed_path
|
||||
end
|
||||
|
||||
it 'auto-completes with email + full name', :js => true do
|
||||
|
||||
within('form.feed') do
|
||||
fill_in 'feed_user', with: user.email[0..3]
|
||||
end
|
||||
|
||||
page.execute_script %Q{ $('form.feed input#feed_user').trigger('focus') }
|
||||
page.execute_script %Q{ $('form.feed input#feed_user').trigger('keydown') }
|
||||
find('a.ui-corner-all', text: user.to_label).trigger(:click)
|
||||
should have_selector('form.feed #feed_user', user.to_label)
|
||||
should have_selector('form.feed #feed_user_id[value="' + user.id + '"]', visible:false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with existing activities' do
|
||||
before(:each) do
|
||||
music_session.touch
|
||||
recording.touch
|
||||
diagnostic.touch
|
||||
visit admin_feed_path
|
||||
end
|
||||
|
||||
it 'shows session, recording, diagnostic' do
|
||||
should have_selector("tr#jam_ruby_music_session_#{music_session.id}")
|
||||
should have_selector("tr#jam_ruby_recording_#{recording.id}")
|
||||
should have_selector("tr#jam_ruby_diagnostic_#{diagnostic.id}")
|
||||
end
|
||||
|
||||
it 'shows activities for one user', :js => true do
|
||||
within('form.feed') do
|
||||
fill_in 'feed_user', with: user.email[0..3]
|
||||
end
|
||||
|
||||
page.execute_script %Q{ $('form.feed input#feed_user').trigger('focus') }
|
||||
page.execute_script %Q{ $('form.feed input#feed_user').trigger('keydown') }
|
||||
find('a.ui-corner-all', text: user.to_label).trigger(:click)
|
||||
should have_selector('form.feed #feed_user', user.to_label)
|
||||
should have_selector('form.feed #feed_user_id[value="' + user.id + '"]', visible:false)
|
||||
|
||||
page.execute_script %Q{ $('form.feed').trigger('submit') }
|
||||
|
||||
should have_selector("tr#jam_ruby_music_session_#{music_session.id}")
|
||||
should have_selector("tr#jam_ruby_recording_#{recording.id}")
|
||||
should have_selector("tr#jam_ruby_diagnostic_#{diagnostic.id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Feeds' do
|
||||
|
||||
subject { page }
|
||||
|
||||
before(:each) do
|
||||
end
|
||||
|
||||
|
||||
describe "latency_tester with connection" do
|
||||
let!(:latency_tester) {FactoryGirl.create(:latency_tester)}
|
||||
|
||||
before(:each) do
|
||||
visit admin_latency_testers_path
|
||||
end
|
||||
|
||||
it "shows connection info" do
|
||||
should have_selector('td', text: "last updated at: #{latency_tester.connection.updated_at}")
|
||||
end
|
||||
end
|
||||
|
||||
describe "latency_tester with no connection" do
|
||||
let!(:latency_tester) {FactoryGirl.create(:latency_tester, client_id: 'abc', make_connection: false)}
|
||||
|
||||
before(:each) do
|
||||
visit admin_latency_testers_path
|
||||
end
|
||||
|
||||
it "shows no connection" do
|
||||
should have_selector('td', text: "no connection")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -22,6 +22,9 @@ require 'rspec/autorun'
|
|||
|
||||
# load capybara
|
||||
require 'capybara/rails'
|
||||
require 'capybara/rspec'
|
||||
require 'capybara-screenshot/rspec'
|
||||
require 'capybara/poltergeist'
|
||||
|
||||
#include Rails.application.routes.url_helpers
|
||||
|
||||
|
|
@ -30,6 +33,11 @@ require 'capybara/rails'
|
|||
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
||||
|
||||
|
||||
Capybara.register_driver :poltergeist do |app|
|
||||
driver = Capybara::Poltergeist::Driver.new(app, { debug: false, phantomjs_logger: File.open('log/phantomjs.out', 'w') })
|
||||
end
|
||||
Capybara.javascript_driver = :poltergeist
|
||||
Capybara.default_wait_time = 10
|
||||
|
||||
RSpec.configure do |config|
|
||||
# ## Mock Framework
|
||||
|
|
@ -46,7 +54,7 @@ RSpec.configure do |config|
|
|||
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
||||
# examples within a transaction, remove the following line or assign false
|
||||
# instead of true.
|
||||
config.use_transactional_fixtures = true
|
||||
config.use_transactional_fixtures = false
|
||||
|
||||
# If true, the base class of anonymous controllers will be inferred
|
||||
# automatically. This will be the default behavior in future versions of
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
module Snapshot
|
||||
|
||||
SS_PATH = 'snapshots.html'
|
||||
|
||||
def set_up_snapshot(filepath = SS_PATH)
|
||||
@size = [1280, 720] #arbitrary
|
||||
@file = File.new(filepath, "w+")
|
||||
@file.puts "<HTML><BODY BGCOLOR=grey>"
|
||||
@file.puts "<H1>Snapshot #{ENV["BUILD_NUMBER"]} - #{@size[0]}x#{@size[1]}</H1>"
|
||||
end
|
||||
|
||||
def snapshot_example
|
||||
page.driver.resize(@size[0], @size[1])
|
||||
@file.puts "<H3>Example name: #{get_description}</H3><BR><BR>"
|
||||
end
|
||||
|
||||
def snap!(title = get_description)
|
||||
base64 = page.driver.render_base64(:png)
|
||||
@file.puts '<H3>' + title + '</H3>'
|
||||
@file.puts '<img alt="' + title +'" src="data:image/png;base64,' + base64 + '" />'
|
||||
@file.puts '<BR><BR><BR>'
|
||||
end
|
||||
|
||||
def tear_down_snapshot
|
||||
@file.puts "</BODY></HTML>"
|
||||
@file.close()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<atlassian-ide-plugin>
|
||||
<project-configuration id="1">
|
||||
<servers id="2" />
|
||||
</project-configuration>
|
||||
</atlassian-ide-plugin>
|
||||
|
|
@ -1 +1,10 @@
|
|||
this is just for getting this maxmind data over there so i can use it.
|
||||
|
||||
source for iso3166-1 data:
|
||||
|
||||
http://dev.maxmind.com/static/csv/codes/iso3166.csv
|
||||
|
||||
source for iso3166-2 data (compatible):
|
||||
|
||||
http://geolite.maxmind.com/download/geoip/misc/region_codes.csv
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
AB,Alberta
|
||||
BC,British Columbia
|
||||
MB,Manitoba
|
||||
NB,New Brunswick
|
||||
NL,Newfoundland and Labrador
|
||||
NS,Nova Scotia
|
||||
NT,Northwest Territories
|
||||
NU,Nunavut
|
||||
ON,Ontario
|
||||
PE,Prince Edward Island
|
||||
QC,Quebec
|
||||
SK,Saskatchewan
|
||||
YT,Yukon
|
||||
|
File diff suppressed because it is too large
Load Diff
|
|
@ -1,57 +0,0 @@
|
|||
AA,Armed Forces America
|
||||
AE,Armed Forces
|
||||
AP,Armed Forces Pacific
|
||||
AK,Alaska
|
||||
AL,Alabama
|
||||
AR,Arkansas
|
||||
AZ,Arizona
|
||||
CA,California
|
||||
CO,Colorado
|
||||
CT,Connecticut
|
||||
DC,District of Columbia
|
||||
DE,Delaware
|
||||
FL,Florida
|
||||
GA,Georgia
|
||||
GU,Guam
|
||||
HI,Hawaii
|
||||
IA,Iowa
|
||||
ID,Idaho
|
||||
IL,Illinois
|
||||
IN,Indiana
|
||||
KS,Kansas
|
||||
KY,Kentucky
|
||||
LA,Louisiana
|
||||
MA,Massachusetts
|
||||
MD,Maryland
|
||||
ME,Maine
|
||||
MI,Michigan
|
||||
MN,Minnesota
|
||||
MO,Missouri
|
||||
MS,Mississippi
|
||||
MT,Montana
|
||||
NC,North Carolina
|
||||
ND,North Dakota
|
||||
NE,Nebraska
|
||||
NH,New Hampshire
|
||||
NJ,New Jersey
|
||||
NM,New Mexico
|
||||
NV,Nevada
|
||||
NY,New York
|
||||
OH,Ohio
|
||||
OK,Oklahoma
|
||||
OR,Oregon
|
||||
PA,Pennsylvania
|
||||
PR,Puerto Rico
|
||||
RI,Rhode Island
|
||||
SC,South Carolina
|
||||
SD,South Dakota
|
||||
TN,Tennessee
|
||||
TX,Texas
|
||||
UT,Utah
|
||||
VA,Virginia
|
||||
VI,Virgin Islands
|
||||
VT,Vermont
|
||||
WA,Washington
|
||||
WI,Wisconsin
|
||||
WV,West Virginia
|
||||
WY,Wyoming
|
||||
|
|
|
@ -161,4 +161,11 @@ scheduled_sessions_2.sql
|
|||
scheduled_sessions_3.sql
|
||||
scheduled_sessions_cancel_all.sql
|
||||
scheduled_sessions_started_at.sql
|
||||
scheduled_sessions_open_rsvps.sql
|
||||
scheduled_sessions_open_rsvps.sql
|
||||
add_last_jam_user_fields.sql
|
||||
remove_lat_lng_user_fields.sql
|
||||
update_get_work_for_larger_radius.sql
|
||||
periodic_emails.sql
|
||||
remember_extra_scoring_data.sql
|
||||
indexing_for_regions.sql
|
||||
latency_tester.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
ALTER TABLE users ADD COLUMN last_jam_addr BIGINT;
|
||||
|
||||
ALTER TABLE users ADD COLUMN last_jam_locidispid BIGINT;
|
||||
|
||||
-- (j)oin session as musician, (r)egister, (f)tue, (n)etwork test
|
||||
ALTER TABLE users ADD COLUMN last_jam_updated_reason CHAR(1);
|
||||
|
||||
ALTER TABLE users ADD COLUMN last_jam_updated_at TIMESTAMP;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
create index regions_countrycode_ndx on regions (countrycode);
|
||||
create unique index regions_countrycode_region_ndx on regions (countrycode, region);
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
CREATE TABLE latency_testers (
|
||||
id VARCHAR(64) PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
|
||||
client_id VARCHAR(64) UNIQUE NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE connections ALTER COLUMN user_id DROP NOT NULL;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
ALTER TABLE email_batches ADD COLUMN type VARCHAR(64) NOT NULL DEFAULT 'JamRuby::EmailBatch';
|
||||
ALTER TABLE email_batches ADD COLUMN sub_type VARCHAR(64);
|
||||
|
||||
ALTER TABLE email_batches ALTER COLUMN body DROP NOT NULL;
|
||||
ALTER TABLE email_batches ALTER COLUMN subject DROP NOT NULL;
|
||||
|
||||
ALTER TABLE email_batch_sets ADD COLUMN trigger_index INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE email_batch_sets ADD COLUMN sub_type VARCHAR(64);
|
||||
ALTER TABLE email_batch_sets ADD COLUMN user_id VARCHAR(64);
|
||||
|
||||
CREATE INDEX email_batch_sets_progress_idx ON email_batch_sets(user_id, sub_type);
|
||||
CREATE INDEX users_musician_email_idx ON users(subscribe_email, musician);
|
||||
|
||||
UPDATE users set first_social_promoted_at = first_liked_us;
|
||||
ALTER TABLE users DROP column first_liked_us;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
-- add column to hold the raw scoring data that the client posted.
|
||||
|
||||
alter table scores add column scoring_data varchar(4000);
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
alter table users drop column lat;
|
||||
alter table users drop column lng;
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
DROP FUNCTION get_work (mylocidispid BIGINT);
|
||||
CREATE FUNCTION get_work (mylocidispid BIGINT, myaddr BIGINT) RETURNS TABLE (client_id VARCHAR(64)) ROWS 5 VOLATILE AS $$
|
||||
BEGIN
|
||||
CREATE TEMPORARY TABLE foo (locidispid BIGINT, locid INT);
|
||||
INSERT INTO foo SELECT DISTINCT locidispid, locidispid/1000000 FROM connections WHERE client_type = 'client';
|
||||
DELETE FROM foo WHERE locidispid IN (SELECT DISTINCT blocidispid FROM current_scores WHERE alocidispid = mylocidispid AND (current_timestamp - score_dt) < INTERVAL '24 hours');
|
||||
DELETE FROM foo WHERE locid NOT IN (SELECT locid FROM geoiplocations WHERE geog && st_buffer((SELECT geog FROM geoiplocations WHERE locid = mylocidispid/1000000), 4023360));
|
||||
CREATE TEMPORARY TABLE bar (client_id VARCHAR(64), locidispid BIGINT, r DOUBLE PRECISION);
|
||||
INSERT INTO bar SELECT l.client_id, l.locidispid, random() FROM connections l, foo f WHERE l.locidispid = f.locidispid AND l.client_type = 'client' AND addr != myaddr;
|
||||
DROP TABLE foo;
|
||||
DELETE FROM bar b WHERE r != (SELECT MAX(r) FROM bar b0 WHERE b0.locidispid = b.locidispid);
|
||||
RETURN QUERY SELECT b.client_id FROM bar b ORDER BY r LIMIT 5;
|
||||
DROP TABLE bar;
|
||||
RETURN;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
--color
|
||||
--format progress
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
gem "rspec"
|
||||
gem "capybara"
|
||||
gem "capybara-screenshot"
|
||||
gem "poltergeist"
|
||||
gem "launchy" # used for opening pages/screenshots when debugging
|
||||
|
||||
# these used only for the Fixnum#seconds method :-/
|
||||
gem "i18n"
|
||||
gem "activesupport"
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (3.1.12)
|
||||
multi_json (~> 1.0)
|
||||
addressable (2.3.6)
|
||||
capybara (2.2.1)
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (~> 2.0)
|
||||
capybara-screenshot (0.3.19)
|
||||
capybara (>= 1.0, < 3)
|
||||
launchy
|
||||
cliver (0.3.2)
|
||||
diff-lcs (1.2.5)
|
||||
i18n (0.6.9)
|
||||
launchy (2.4.2)
|
||||
addressable (~> 2.3)
|
||||
mime-types (2.2)
|
||||
mini_portile (0.5.3)
|
||||
multi_json (1.10.0)
|
||||
nokogiri (1.6.1)
|
||||
mini_portile (~> 0.5.0)
|
||||
nokogiri (1.6.1-x86-mingw32)
|
||||
mini_portile (~> 0.5.0)
|
||||
poltergeist (1.5.0)
|
||||
capybara (~> 2.1)
|
||||
cliver (~> 0.3.1)
|
||||
multi_json (~> 1.0)
|
||||
websocket-driver (>= 0.2.0)
|
||||
rack (1.5.2)
|
||||
rack-test (0.6.2)
|
||||
rack (>= 1.0)
|
||||
rspec (2.14.1)
|
||||
rspec-core (~> 2.14.0)
|
||||
rspec-expectations (~> 2.14.0)
|
||||
rspec-mocks (~> 2.14.0)
|
||||
rspec-core (2.14.8)
|
||||
rspec-expectations (2.14.5)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
rspec-mocks (2.14.6)
|
||||
websocket-driver (0.3.3)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
x86-mingw32
|
||||
|
||||
DEPENDENCIES
|
||||
activesupport
|
||||
capybara
|
||||
capybara-screenshot
|
||||
i18n
|
||||
launchy
|
||||
poltergeist
|
||||
rspec
|
||||
16
web/spec/features/production_spec.rb → monitor/spec/production_spec.rb
Normal file → Executable file
16
web/spec/features/production_spec.rb → monitor/spec/production_spec.rb
Normal file → Executable file
|
|
@ -1,9 +1,14 @@
|
|||
require 'spec_helper'
|
||||
|
||||
# these tests MUST be idempotent and DO use actual production user accounts on www
|
||||
www = 'http://www.jamkazam.com'
|
||||
# these tests should be idempotent, and not spammy to other JK users
|
||||
# because they DO use actual production user accounts on www (see the TestUsers below)
|
||||
|
||||
describe "Production site at #{www}", :test_www => true, :js => true, :type => :feature, :capybara_feature => true do
|
||||
# Jenkins executes rspec on this folder every 15 minutes or so.
|
||||
# SO don't use this to test something like a public session unless you want all the world to see
|
||||
|
||||
www = ENV['MONITOR_URL'] || 'http://www.jamkazam.com'
|
||||
|
||||
describe "Deployed site at #{www}", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
subject { page }
|
||||
|
||||
|
|
@ -12,7 +17,6 @@ describe "Production site at #{www}", :test_www => true, :js => true, :type =>
|
|||
Capybara.current_driver = Capybara.javascript_driver
|
||||
Capybara.app_host = www
|
||||
Capybara.run_server = false
|
||||
Capybara.default_wait_time = 10
|
||||
end
|
||||
|
||||
TestUser = Class.new do
|
||||
|
|
@ -28,7 +32,6 @@ describe "Production site at #{www}", :test_www => true, :js => true, :type =>
|
|||
first_name + ' ' + last_name
|
||||
end
|
||||
end
|
||||
|
||||
user1 = TestUser.new({ email: 'anthony+jim@jamkazam.com', password: 'j4m!t3st3r', first_name: 'Jim', last_name: 'Smith', id: '68e8eea2-140d-44c1-b711-10d07ce70f96' })
|
||||
user2 = TestUser.new({ email: 'anthony+john@jamkazam.com', password: 'j4m!t3st3r', first_name: 'John', last_name: 'Jones', id: '5bbcf689-2f73-452d-815a-c4f44e9e7f3e' })
|
||||
|
||||
|
|
@ -46,7 +49,7 @@ describe "Production site at #{www}", :test_www => true, :js => true, :type =>
|
|||
end
|
||||
|
||||
it "is possible for #{user1} and #{user2} to see each other online, and to send messages" do
|
||||
# this example heavily based on text_message_spec.rb
|
||||
# this example heavily based on text_message_spec.rb in 'web'
|
||||
|
||||
in_client(user1) do
|
||||
sign_in_poltergeist(user1)
|
||||
|
|
@ -89,4 +92,3 @@ describe "Production site at #{www}", :test_www => true, :js => true, :type =>
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
require 'rubygems'
|
||||
require 'active_support/time'
|
||||
require 'capybara'
|
||||
require 'capybara/rspec'
|
||||
require 'capybara-screenshot'
|
||||
require 'capybara-screenshot/rspec'
|
||||
require 'capybara/poltergeist'
|
||||
|
||||
require 'support/client_interactions' #TODO: Strip out the helper methods that production_spec does not use
|
||||
require 'support/utilities'
|
||||
require 'support/stubs' # to make the JamXXXX warnings go away
|
||||
|
||||
# This file was generated by the `rspec --init` command. Conventionally, all
|
||||
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
||||
# Require this file using `require "spec_helper"` to ensure that it is only
|
||||
# loaded once.
|
||||
#
|
||||
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
||||
RSpec.configure do |config|
|
||||
config.treat_symbols_as_metadata_keys_with_true_values = true
|
||||
config.run_all_when_everything_filtered = true
|
||||
config.filter_run :focus
|
||||
|
||||
# Run specs in random order to surface order dependencies. If you find an
|
||||
# order dependency and want to debug it, you can fix the order by providing
|
||||
# the seed, which is printed after each run.
|
||||
# --seed 1234
|
||||
config.order = 'random'
|
||||
|
||||
config.include Capybara::DSL
|
||||
|
||||
config.before(:each) do
|
||||
page.driver.headers = { 'User-Agent' => 'monitor' }
|
||||
end
|
||||
end
|
||||
|
||||
#Capybara.register_driver :poltergeist do |app|
|
||||
# Capybara::Poltergeist::Driver.new(app, { phantomjs_logger: File.open('console.log', 'w') })
|
||||
#end
|
||||
Capybara.javascript_driver = :poltergeist
|
||||
Capybara.default_driver = :poltergeist
|
||||
Capybara.run_server = false # since we're testing an app outside this project
|
||||
Capybara.default_wait_time = 15 # ^^ ditto
|
||||
|
||||
Capybara.configure do |config|
|
||||
config.match = :one
|
||||
config.exact_options = true
|
||||
config.ignore_hidden_elements = true
|
||||
config.visible_text_only = true
|
||||
end
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
|
||||
# methods here all assume you are in /client
|
||||
|
||||
NOTIFICATION_PANEL = '[layout-id="panelNotifications"]'
|
||||
|
||||
# enters text into the search sidebar
|
||||
def site_search(text, options = {})
|
||||
within('#searchForm') do
|
||||
fill_in "search-input", with: text
|
||||
end
|
||||
|
||||
if options[:expand]
|
||||
page.driver.execute_script("jQuery('#searchForm').submit()")
|
||||
find('h1', text:'search results')
|
||||
end
|
||||
end
|
||||
|
||||
# goes to the musician tile, and tries to find a musician
|
||||
def find_musician(user)
|
||||
visit "/client#/musicians"
|
||||
|
||||
timeout = 30
|
||||
|
||||
start = Time.now
|
||||
# scroll by 100px until we find a user with the right id
|
||||
while page.all('#end-of-musician-list').length == 0
|
||||
page.execute_script('jQuery("#musician-filter-results").scrollTo("+=100px", 0, {axis:"y"})')
|
||||
found = page.all(".result-list-button-wrapper[data-musician-id='#{user.id}']")
|
||||
if found.length == 1
|
||||
return found[0]
|
||||
elsif found.length > 1
|
||||
raise "ambiguous results in musician list"
|
||||
end
|
||||
|
||||
if Time.now - start > timeout
|
||||
raise "unable to find musician #{user} within #{timeout} seconds"
|
||||
end
|
||||
end
|
||||
|
||||
raise "unable to find musician #{user}"
|
||||
end
|
||||
|
||||
def initiate_text_dialog(user)
|
||||
|
||||
# verify that the chat window is grayed out
|
||||
site_search(user.first_name, expand: true)
|
||||
|
||||
find("#search-results a[user-id=\"#{user.id}\"][hoveraction=\"musician\"]", text: user.name).hover_intent
|
||||
find('#musician-hover #btnMessage').trigger(:click)
|
||||
find('h1', text: 'conversation with ' + user.name)
|
||||
end
|
||||
|
||||
# sends a text message in the chat interface.
|
||||
def send_text_message(msg, options={})
|
||||
find('#text-message-dialog') # assert that the dialog is showing already
|
||||
|
||||
within('#text-message-dialog form.text-message-box') do
|
||||
fill_in 'new-text-message', with: msg
|
||||
end
|
||||
find('#text-message-dialog .btn-send-text-message').trigger(:click)
|
||||
find('#text-message-dialog .previous-message-text', text: msg) unless options[:should_fail]
|
||||
|
||||
# close the dialog if caller specified close_on_send
|
||||
if options[:close_on_send]
|
||||
find('#text-message-dialog .btn-close-dialog', text: 'CLOSE').trigger(:click) if options[:close_on_send]
|
||||
page.should have_no_selector('#text-message-dialog')
|
||||
end
|
||||
|
||||
if options[:should_fail]
|
||||
find('#notification').should have_text(options[:should_fail])
|
||||
end
|
||||
end
|
||||
|
||||
# sends a chat message during session
|
||||
def send_chat_message(msg)
|
||||
find("[layout-id=\"panelChat\"] .chat-sender").should be_visible
|
||||
|
||||
within("[layout-id=\"panelChat\"] .chat-sender form.chat-message-form") do
|
||||
fill_in 'new-chat-message', with: msg
|
||||
end
|
||||
find("[layout-id=\"panelChat\"] .chat-sender .btn-send-chat-message").trigger(:click)
|
||||
end
|
||||
|
||||
def open_notifications
|
||||
find("#{NOTIFICATION_PANEL} .panel-header").trigger(:click)
|
||||
end
|
||||
|
||||
|
||||
def hover_intent(element)
|
||||
element.hover
|
||||
element.hover
|
||||
end
|
||||
|
||||
# forces document.hasFocus() to return false
|
||||
def document_blur
|
||||
page.evaluate_script(%{(function() {
|
||||
// save original
|
||||
if(!window.documentFocus) { window.documentFocus = window.document.hasFocus; }
|
||||
|
||||
window.document.hasFocus = function() {
|
||||
console.log("document.hasFocus() returns false");
|
||||
return false;
|
||||
}
|
||||
})()})
|
||||
end
|
||||
|
||||
def document_focus
|
||||
page.evaluate_script(%{(function() {
|
||||
// save original
|
||||
if(!window.documentFocus) { window.documentFocus = window.document.hasFocus; }
|
||||
|
||||
window.document.hasFocus = function() {
|
||||
console.log("document.hasFocus() returns true");
|
||||
return true;
|
||||
}
|
||||
})()})
|
||||
end
|
||||
|
||||
# simulates focus event on window
|
||||
def window_focus
|
||||
page.evaluate_script(%{window.jQuery(window).trigger('focus');})
|
||||
end
|
||||
|
||||
def close_websocket
|
||||
page.evaluate_script("window.JK.JamServer.close(true)")
|
||||
end
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
module JamRuby
|
||||
class User
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def signin_path
|
||||
'/signin'
|
||||
end
|
||||
|
|
@ -0,0 +1,481 @@
|
|||
|
||||
# add a hover_intent method to element, so that you can do find(selector).hover_intent
|
||||
module Capybara
|
||||
module Node
|
||||
class Element
|
||||
|
||||
def attempt_hover
|
||||
begin
|
||||
hover
|
||||
rescue => e
|
||||
end
|
||||
end
|
||||
def hover_intent
|
||||
hover
|
||||
sleep 0.3
|
||||
attempt_hover
|
||||
sleep 0.3
|
||||
attempt_hover
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# holds a single test's session name's, mapped to pooled session names
|
||||
$capybara_session_mapper = {}
|
||||
|
||||
# called in before (or after) test, to make sure each test run has it's own map of session names
|
||||
def reset_session_mapper
|
||||
$capybara_session_mapper.clear
|
||||
|
||||
Capybara.session_name = :default
|
||||
end
|
||||
|
||||
# manages the mapped session name
|
||||
def mapped_session_name(session_name)
|
||||
return :default if session_name == :default # special treatment for the built-in session
|
||||
$capybara_session_mapper[session_name] ||= 'session_' + $capybara_session_mapper.length.to_s
|
||||
end
|
||||
|
||||
# in place of ever using Capybara.session_name directly,
|
||||
# this utility is used to handle the mapping of session names in a way across all tests runs
|
||||
def in_client(name)
|
||||
session_name = name.class == JamRuby::User ? name.id : name
|
||||
|
||||
Capybara.session_name = mapped_session_name(session_name)
|
||||
|
||||
yield
|
||||
end
|
||||
|
||||
|
||||
def cookie_jar
|
||||
Capybara.current_session.driver.browser.current_session.instance_variable_get(:@rack_mock_session).cookie_jar
|
||||
end
|
||||
|
||||
|
||||
#see also ruby/spec/support/utilities.rb
|
||||
JAMKAZAM_TESTING_BUCKET = 'jamkazam-testing' #at least, this is the name given in jam-ruby
|
||||
def wipe_s3_test_bucket
|
||||
s3 = AWS::S3.new(:access_key_id => Rails.application.config.aws_access_key_id,
|
||||
:secret_access_key => Rails.application.config.aws_secret_access_key)
|
||||
test_bucket = s3.buckets[JAMKAZAM_TESTING_BUCKET]
|
||||
if test_bucket.name == JAMKAZAM_TESTING_BUCKET
|
||||
test_bucket.objects.each do |obj|
|
||||
obj.delete
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def sign_in(user)
|
||||
visit signin_path
|
||||
fill_in "Email", with: user.email
|
||||
fill_in "Password", with: user.password
|
||||
click_button "SIGN IN"
|
||||
# Sign in when not using Capybara as well.
|
||||
cookie_jar[:remember_token] = user.remember_token
|
||||
end
|
||||
|
||||
def set_cookie(k, v)
|
||||
case Capybara.current_session.driver
|
||||
when Capybara::Poltergeist::Driver
|
||||
page.driver.set_cookie(k,v)
|
||||
when Capybara::RackTest::Driver
|
||||
headers = {}
|
||||
Rack::Utils.set_cookie_header!(headers,k,v)
|
||||
cookie_string = headers['Set-Cookie']
|
||||
Capybara.current_session.driver.browser.set_cookie(cookie_string)
|
||||
when Capybara::Selenium::Driver
|
||||
page.driver.browser.manage.add_cookie(:name=>k, :value=>v)
|
||||
else
|
||||
raise "no cookie-setter implemented for driver #{Capybara.current_session.driver.class.name}"
|
||||
end
|
||||
end
|
||||
|
||||
def sign_in_poltergeist(user, options = {})
|
||||
validate = options[:validate]
|
||||
validate = true if validate.nil?
|
||||
|
||||
visit signin_path
|
||||
fill_in "Email Address:", with: user.email
|
||||
fill_in "Password:", with: user.password
|
||||
click_button "SIGN IN"
|
||||
|
||||
wait_until_curtain_gone
|
||||
|
||||
# presence of this means websocket gateway is not working
|
||||
page.should have_no_selector('.no-websocket-connection') if validate
|
||||
end
|
||||
|
||||
|
||||
def sign_out()
|
||||
if Capybara.javascript_driver == :poltergeist
|
||||
page.driver.remove_cookie(:remember_token)
|
||||
else
|
||||
page.driver.browser.manage.remove_cookie :name => :remember_token
|
||||
end
|
||||
end
|
||||
|
||||
def sign_out_poltergeist(options = {})
|
||||
find('.userinfo').hover()
|
||||
click_link 'Sign Out'
|
||||
should_be_at_root if options[:validate]
|
||||
end
|
||||
|
||||
def should_be_at_root
|
||||
find('h1', text: 'Play music together over the Internet as if in the same room')
|
||||
end
|
||||
|
||||
def leave_music_session_sleep_delay
|
||||
# add a buffer to ensure WSG has enough time to expire
|
||||
sleep_dur = (Rails.application.config.websocket_gateway_connect_time_stale_browser +
|
||||
Rails.application.config.websocket_gateway_connect_time_expire_browser) * 1.4
|
||||
sleep sleep_dur
|
||||
end
|
||||
|
||||
|
||||
def wait_for_ajax(wait=Capybara.default_wait_time)
|
||||
wait = wait * 10 #(because we sleep .1)
|
||||
|
||||
counter = 0
|
||||
while page.execute_script("$.active").to_i > 0
|
||||
counter += 1
|
||||
sleep(0.1)
|
||||
raise "AJAX request took longer than #{wait} seconds." if counter >= wait
|
||||
end
|
||||
end
|
||||
|
||||
# waits until the user object has been requested, which comes after the 'curtain' is lifted
|
||||
# and after a call to /api/user/:id for the current user is called initially
|
||||
def wait_until_user(wait=Capybara.default_wait_time)
|
||||
wait = wait * 10 #(because we sleep .1)
|
||||
|
||||
counter = 0
|
||||
# while page.execute_script("$('.curtain').is(:visible)") == "true"
|
||||
# counter += 1
|
||||
# sleep(0.1)
|
||||
# raise "Waiting for user to populate took longer than #{wait} seconds." if counter >= wait
|
||||
# end
|
||||
end
|
||||
|
||||
def wait_until_curtain_gone
|
||||
page.should have_no_selector('.curtain')
|
||||
end
|
||||
|
||||
def wait_to_see_my_track
|
||||
within('div.session-mytracks') {first('div.session-track.track')}
|
||||
end
|
||||
|
||||
def repeat_for(duration=Capybara.default_wait_time)
|
||||
finish_time = Time.now + duration.seconds
|
||||
loop do
|
||||
yield
|
||||
sleep 1 # by default this will execute the block every 1 second
|
||||
break if (Time.now > finish_time)
|
||||
end
|
||||
end
|
||||
|
||||
def determine_test_name(metadata, test_name_buffer = '')
|
||||
description = metadata[:description_args]
|
||||
if description.kind_of?(Array)
|
||||
description = description[0]
|
||||
end
|
||||
if metadata.has_key? :example_group
|
||||
return determine_test_name(metadata[:example_group], "#{description} #{test_name_buffer}")
|
||||
else
|
||||
return "#{description} #{test_name_buffer}"
|
||||
end
|
||||
end
|
||||
|
||||
def get_description
|
||||
description = example.metadata[:description_args]
|
||||
if description.kind_of?(Array)
|
||||
description = description[0]
|
||||
end
|
||||
return description
|
||||
end
|
||||
|
||||
# will select the value from a easydropdown'ed select element
|
||||
def jk_select(text, select)
|
||||
|
||||
# the approach here is to find the hidden select element, and work way back up to the elements that need to be interacted with
|
||||
find(select, :visible => false).find(:xpath, 'ancestor::div[contains(@class, "dropdown easydropdown")]').trigger(:click)
|
||||
find(select, :visible => false).find(:xpath, 'ancestor::div[contains(@class, "dropdown-wrapper") and contains(@class, "easydropdown-wrapper") and contains(@class, "open")]').find('li', text: text).trigger(:click)
|
||||
|
||||
# works, but is 'cheating' because of visible = false
|
||||
#select(genre, :from => 'genres', :visible => false)
|
||||
end
|
||||
|
||||
# takes, or creates, a unique session description which is returned for subsequent calls to join_session to use
|
||||
# in finding this session)
|
||||
def create_session(options={})
|
||||
creator = options[:creator] || FactoryGirl.create(:user)
|
||||
unique_session_desc = options[:description] || "create_join_session #{SecureRandom.urlsafe_base64}"
|
||||
genre = options[:genre] || 'Rock'
|
||||
musician_access = options[:musician_access].nil? ? true : options[:musician_access]
|
||||
fan_access = options[:fan_access].nil? ? true : options[:fan_access]
|
||||
|
||||
# create session in one client
|
||||
in_client(creator) do
|
||||
page.driver.resize(1500, 800) # makes sure all the elements are visible
|
||||
emulate_client
|
||||
sign_in_poltergeist creator
|
||||
wait_until_curtain_gone
|
||||
visit "/client#/createSession"
|
||||
expect(page).to have_selector('h2', text: 'session info')
|
||||
|
||||
within('#create-session-form') do
|
||||
fill_in('description', :with => unique_session_desc)
|
||||
#select(genre, :from => 'genres', :visible => false) # this works, but is 'cheating' because easydropdown hides the native select element
|
||||
jk_select(genre, '#create-session-form select[name="genres"]')
|
||||
|
||||
jk_select(musician_access ? 'Public' : 'Private', '#create-session-form select#musician-access')
|
||||
jk_select(fan_access ? 'Public' : 'Private', '#create-session-form select#fan-access')
|
||||
find('#create-session-form div.musician-access-false.iradio_minimal').trigger(:click)
|
||||
find('div.intellectual-property ins').trigger(:click)
|
||||
find('#btn-create-session').trigger(:click) # fails if page width is low
|
||||
end
|
||||
|
||||
# verify that the in-session page is showing
|
||||
expect(page).to have_selector('h2', text: 'my tracks')
|
||||
find('#session-screen .session-mytracks .session-track')
|
||||
end
|
||||
|
||||
return creator, unique_session_desc, genre
|
||||
|
||||
end
|
||||
|
||||
# this code assumes that there are no music sessions in the database. it should fail on the
|
||||
# find('.join-link') call if > 1 session exists because capybara will complain of multiple matches
|
||||
def join_session(joiner, options)
|
||||
description = options[:description]
|
||||
|
||||
in_client(joiner) do
|
||||
page.driver.resize(1500, 800) # makes sure all the elements are visible
|
||||
emulate_client
|
||||
sign_in_poltergeist joiner
|
||||
wait_until_curtain_gone
|
||||
visit "/client#/findSession"
|
||||
|
||||
# verify the session description is seen by second client
|
||||
expect(page).to have_text(description)
|
||||
find('.join-link').trigger(:click)
|
||||
find('#btn-accept-terms').trigger(:click)
|
||||
expect(page).to have_selector('h2', text: 'my tracks')
|
||||
find('#session-screen .session-mytracks .session-track')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def emulate_client
|
||||
page.driver.headers = { 'User-Agent' => ' JamKazam ' }
|
||||
end
|
||||
|
||||
def create_join_session(creator, joiners=[], options={})
|
||||
options[:creator] = creator
|
||||
creator, unique_session_desc = create_session(options)
|
||||
|
||||
# find session in second client
|
||||
joiners.each do |joiner|
|
||||
join_session(joiner, description: unique_session_desc)
|
||||
end
|
||||
|
||||
return creator, unique_session_desc
|
||||
end
|
||||
|
||||
def formal_leave_by user
|
||||
in_client(user) do
|
||||
find('#session-leave').trigger(:click)
|
||||
#find('#btn-accept-leave-session').trigger(:click)
|
||||
expect(page).to have_selector('h2', text: 'feed')
|
||||
end
|
||||
end
|
||||
|
||||
def start_recording_with(creator, joiners=[], genre=nil)
|
||||
create_join_session(creator, joiners, {genre: genre})
|
||||
in_client(creator) do
|
||||
find('#recording-start-stop').trigger(:click)
|
||||
find('#recording-status').should have_content 'Stop Recording'
|
||||
end
|
||||
joiners.each do |joiner|
|
||||
in_client(joiner) do
|
||||
find('#notification').should have_content 'started a recording'
|
||||
find('#recording-status').should have_content 'Stop Recording'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def stop_recording
|
||||
find('#recording-start-stop').trigger(:click)
|
||||
end
|
||||
|
||||
def assert_recording_finished
|
||||
find('#recording-status').should have_content 'Make a Recording'
|
||||
should have_selector('h1', text: 'recording finished')
|
||||
end
|
||||
|
||||
def check_recording_finished_for(users=[])
|
||||
users.each do |user|
|
||||
in_client(user) do
|
||||
assert_recording_finished
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def claim_recording(name, description)
|
||||
find('#recording-finished-dialog h1')
|
||||
fill_in "claim-recording-name", with: name
|
||||
fill_in "claim-recording-description", with: description
|
||||
find('#keep-session-recording').trigger(:click)
|
||||
page.should have_no_selector('h1', text: 'recording finished')
|
||||
end
|
||||
|
||||
def set_session_as_private()
|
||||
find('#session-settings-button').trigger(:click)
|
||||
within('#session-settings-dialog') do
|
||||
jk_select("Private", '#session-settings-dialog #session-settings-musician-access')
|
||||
#select('Private', :from => 'session-settings-musician-access')
|
||||
find('#session-settings-dialog-submit').trigger(:click)
|
||||
end
|
||||
# verify it's dismissed
|
||||
page.should have_no_selector('h1', text: 'update session settings')
|
||||
end
|
||||
|
||||
def set_session_as_public()
|
||||
find('#session-settings-button').trigger(:click)
|
||||
within('#session-settings-dialog') do
|
||||
jk_select("Public", '#session-settings-dialog #session-settings-musician-access')
|
||||
# select('Public', :from => 'session-settings-musician-access')
|
||||
find('#session-settings-dialog-submit').trigger(:click)
|
||||
end
|
||||
# verify it's dismissed
|
||||
page.should have_no_selector('h1', text: 'update session settings')
|
||||
end
|
||||
|
||||
def get_options(selector)
|
||||
find(selector, :visible => false).all('option', :visible => false).collect(&:text).uniq
|
||||
end
|
||||
|
||||
def selected_genres(selector='#session-settings-genre')
|
||||
page.evaluate_script("JK.GenreSelectorHelper.getSelectedGenres('#{selector}')")
|
||||
end
|
||||
|
||||
def random_genre
|
||||
['African',
|
||||
'Ambient',
|
||||
'Asian',
|
||||
'Blues',
|
||||
'Classical',
|
||||
'Country',
|
||||
'Electronic',
|
||||
'Folk',
|
||||
'Hip Hop',
|
||||
'Jazz',
|
||||
'Latin',
|
||||
'Metal',
|
||||
'Pop',
|
||||
'R&B',
|
||||
'Reggae',
|
||||
'Religious',
|
||||
'Rock',
|
||||
'Ska',
|
||||
'Other'].sample
|
||||
end
|
||||
|
||||
def change_session_genre #randomly just change it
|
||||
here = 'select.genre-list'
|
||||
#wait_for_ajax
|
||||
find('#session-settings-button').trigger(:click)
|
||||
find('#session-settings-dialog') # ensure the dialog is visible
|
||||
within('#session-settings-dialog') do
|
||||
wait_for_ajax
|
||||
@new_genre = get_options(here).-(["Select Genre"]).-(selected_genres).sample.to_s
|
||||
jk_select(@new_genre, '#session-settings-dialog select[name="genres"]')
|
||||
wait_for_ajax
|
||||
find('#session-settings-dialog-submit').trigger(:click)
|
||||
end
|
||||
return @new_genre
|
||||
end
|
||||
|
||||
def get_session_genre
|
||||
here = 'select.genre-list'
|
||||
find('#session-settings-button').trigger(:click)
|
||||
wait_for_ajax
|
||||
@current_genres = selected_genres
|
||||
find('#session-settings-dialog-submit').trigger(:click)
|
||||
return @current_genres.join(" ")
|
||||
end
|
||||
|
||||
def find_session_contains?(text)
|
||||
visit "/client#/findSession"
|
||||
wait_for_ajax
|
||||
within('#find-session-form') do
|
||||
expect(page).to have_text(text)
|
||||
end
|
||||
end
|
||||
|
||||
def assert_all_tracks_seen(users=[])
|
||||
users.each do |user|
|
||||
in_client(user) do
|
||||
users.reject {|u| u==user}.each do |other|
|
||||
find('div.track-label', text: other.name)
|
||||
#puts user.name + " is able to see " + other.name + "\'s track"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def view_profile_of user
|
||||
id = user.kind_of?(JamRuby::User) ? user.id : user
|
||||
# assume some user signed in already
|
||||
visit "/client#/profile/#{id}"
|
||||
wait_until_curtain_gone
|
||||
end
|
||||
|
||||
def view_band_profile_of band
|
||||
id = band.kind_of?(JamRuby::Band) ? band.id :
|
||||
band.kind_of?(JamRuby::BandMusician) ? band.bands.first.id : band
|
||||
visit "/client#/bandProfile/#{id}"
|
||||
wait_until_curtain_gone
|
||||
end
|
||||
|
||||
def sidebar_search_for string, category
|
||||
visit "/client#/home"
|
||||
find('#search-input')
|
||||
fill_in "search", with: string
|
||||
sleep 1
|
||||
page.execute_script("JK.Sidebar.searchForInput()")
|
||||
wait_for_ajax
|
||||
jk_select(category, "search_text_type")
|
||||
wait_for_ajax
|
||||
end
|
||||
|
||||
def show_user_menu
|
||||
page.execute_script("$('ul.shortcuts').show()")
|
||||
#page.execute_script("JK.UserDropdown.menuHoverIn()")
|
||||
end
|
||||
|
||||
# wait for the easydropdown version of the specified select element to become visible
|
||||
def wait_for_easydropdown(select)
|
||||
find(select, :visible => false).find(:xpath, 'ancestor::div[contains(@class, "dropdown easydropdown")]')
|
||||
end
|
||||
|
||||
# defaults to enter key (13)
|
||||
def send_key(selector, keycode = 13)
|
||||
keypress_script = "var e = $.Event('keyup', { keyCode: #{keycode} }); jQuery('#{selector}').trigger(e);"
|
||||
page.driver.execute_script(keypress_script)
|
||||
|
||||
end
|
||||
|
||||
def special_characters
|
||||
["?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}"]
|
||||
end
|
||||
|
||||
def garbage length
|
||||
output = ''
|
||||
length.times { output << special_characters.sample }
|
||||
output.slice(0, length)
|
||||
end
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh -x
|
||||
dropdb --if-exists jam
|
||||
dropdb --if-exists jam_db_build
|
||||
dropdb --if-exists jam_ruby_test
|
||||
dropdb --if-exists jam_web_test
|
||||
dropdb --if-exists jam_websockets_test
|
||||
createdb -Upostgres jam || sudo su postgres -c "createdb jam"
|
||||
|
||||
|
|
@ -4,7 +4,7 @@ unless ENV["LOCAL_DEV"] == "1"
|
|||
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/'
|
||||
end
|
||||
|
||||
devenv = ENV["BUILD_NUMBER"].nil? || ENV["TEST_WWW"] == "1"
|
||||
devenv = ENV["BUILD_NUMBER"].nil?
|
||||
|
||||
if devenv
|
||||
gem 'jam_db', :path=> "../db/target/ruby_package"
|
||||
|
|
@ -57,6 +57,7 @@ group :test do
|
|||
gem 'faker'
|
||||
gem 'resque_spec' #, :path => "/home/jam/src/resque_spec/"
|
||||
gem 'timecop'
|
||||
gem 'rspec-prof'
|
||||
end
|
||||
|
||||
# Specify your gem's dependencies in jam_ruby.gemspec
|
||||
|
|
|
|||
|
|
@ -42,7 +42,11 @@ require "jam_ruby/resque/scheduled/icecast_config_retry"
|
|||
require "jam_ruby/resque/scheduled/icecast_source_check"
|
||||
require "jam_ruby/resque/scheduled/cleanup_facebook_signup"
|
||||
require "jam_ruby/resque/scheduled/unused_music_notation_cleaner"
|
||||
require "jam_ruby/resque/scheduled/user_progress_emailer"
|
||||
require "jam_ruby/resque/scheduled/daily_session_emailer"
|
||||
require "jam_ruby/resque/scheduled/new_musician_emailer"
|
||||
require "jam_ruby/resque/google_analytics_event"
|
||||
require "jam_ruby/resque/batch_email_job"
|
||||
require "jam_ruby/mq_router"
|
||||
require "jam_ruby/base_manager"
|
||||
require "jam_ruby/connection_manager"
|
||||
|
|
@ -82,6 +86,7 @@ require "jam_ruby/models/band_invitation"
|
|||
require "jam_ruby/models/band_musician"
|
||||
require "jam_ruby/models/connection"
|
||||
require "jam_ruby/models/diagnostic"
|
||||
require "jam_ruby/models/latency_tester"
|
||||
require "jam_ruby/models/friendship"
|
||||
require "jam_ruby/models/active_music_session"
|
||||
require "jam_ruby/models/music_session_comment"
|
||||
|
|
@ -145,10 +150,14 @@ 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_periodic"
|
||||
require "jam_ruby/models/email_batch_new_musician"
|
||||
require "jam_ruby/models/email_batch_progression"
|
||||
require "jam_ruby/models/email_batch_scheduled_sessions"
|
||||
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"
|
||||
require "jam_ruby/app/mailers/progress_mailer"
|
||||
require "jam_ruby/models/affiliate_partner"
|
||||
require "jam_ruby/models/chat_message"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
module JamRuby
|
||||
class BatchMailer < JamRuby::AsyncMailer
|
||||
class BatchMailer < ActionMailer::Base
|
||||
include SendGrid
|
||||
layout "user_mailer"
|
||||
|
||||
sendgrid_category :use_subject_lines
|
||||
|
|
@ -23,10 +24,10 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def send_batch_email(batch_id, user_ids)
|
||||
users = User.find_all_by_id(user_ids)
|
||||
def send_batch_email(batch_id, user_id)
|
||||
user = User.find_by_id(user_id)
|
||||
batch = EmailBatch.find(batch_id)
|
||||
self._send_batch(batch, users)
|
||||
self._send_batch(batch, [user])
|
||||
end
|
||||
|
||||
def send_batch_email_test(batch_id)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
module JamRuby
|
||||
class ProgressMailer < ActionMailer::Base
|
||||
include SendGrid
|
||||
layout "user_mailer"
|
||||
|
||||
sendgrid_category :use_subject_lines
|
||||
sendgrid_unique_args :env => Environment.mode
|
||||
default :from => UserMailer::DEFAULT_SENDER
|
||||
|
||||
def send_reminder(batch_set)
|
||||
user = batch_set.user
|
||||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
sendgrid_substitute(EmailBatchProgression::VAR_FIRST_NAME, [user.first_name])
|
||||
|
||||
mail(:to => user.email,
|
||||
:subject => batch_set.subject,
|
||||
:title => batch_set.title) do |format|
|
||||
format.text { render batch_set.sub_type }
|
||||
format.html { render batch_set.sub_type }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
sendgrid_substitute(EmailBatchProgression::VAR_FIRST_NAME, [user.first_name])
|
||||
|
||||
mail(:to => user.email, :subject => "Welcome to JamKazam") do |format|
|
||||
format.text
|
||||
|
|
@ -101,14 +102,14 @@
|
|||
end
|
||||
end
|
||||
|
||||
def new_musicians(user, new_nearby, host='www.jamkazam.com')
|
||||
@user, @new_nearby, @host = user, new_nearby, host
|
||||
def new_musicians(user, new_musicians, host='www.jamkazam.com')
|
||||
@user, @new_musicians, @host = user, new_musicians, 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|
|
||||
|
||||
mail(:to => user.email, :subject => EmailBatchNewMusician.subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
end
|
||||
|
|
@ -222,7 +223,7 @@
|
|||
subject = "Session Invitation"
|
||||
unique_args = {:type => "scheduled_session_invitation"}
|
||||
@body = msg
|
||||
@session_name = session.description
|
||||
@session_name = session.name
|
||||
@session_date = session.scheduled_start
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -241,7 +242,7 @@
|
|||
subject = "Session RSVP"
|
||||
unique_args = {:type => "scheduled_session_rsvp"}
|
||||
@body = msg
|
||||
@session_name = session.description
|
||||
@session_name = session.name
|
||||
@session_date = session.scheduled_start
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -260,7 +261,7 @@
|
|||
subject = "Session RSVP Approved"
|
||||
unique_args = {:type => "scheduled_session_rsvp_approved"}
|
||||
@body = msg
|
||||
@session_name = session.description
|
||||
@session_name = session.name
|
||||
@session_date = session.scheduled_start
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -279,7 +280,7 @@
|
|||
subject = "Session RSVP Cancelled"
|
||||
unique_args = {:type => "scheduled_session_rsvp_cancelled"}
|
||||
@body = msg
|
||||
@session_name = session.description
|
||||
@session_name = session.name
|
||||
@session_date = session.scheduled_start
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -298,7 +299,7 @@
|
|||
subject = "Your Session RSVP Cancelled"
|
||||
unique_args = {:type => "scheduled_session_rsvp_cancelled_org"}
|
||||
@body = msg
|
||||
@session_name = session.description
|
||||
@session_name = session.name
|
||||
@session_date = session.scheduled_start
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -317,7 +318,7 @@
|
|||
subject = "Session Cancelled"
|
||||
unique_args = {:type => "scheduled_session_cancelled"}
|
||||
@body = msg
|
||||
@session_name = session.description
|
||||
@session_name = session.name
|
||||
@session_date = session.scheduled_start
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -336,7 +337,7 @@
|
|||
subject = "Session Rescheduled"
|
||||
unique_args = {:type => "scheduled_session_rescheduled"}
|
||||
@body = msg
|
||||
@session_name = session.description
|
||||
@session_name = session.name
|
||||
@session_date = session.scheduled_start
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -355,7 +356,7 @@
|
|||
subject = "Session Rescheduled"
|
||||
unique_args = {:type => "scheduled_session_reminder"}
|
||||
@body = msg
|
||||
@session_name = session.description
|
||||
@session_name = session.name
|
||||
@session_date = session.scheduled_start
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -374,7 +375,7 @@
|
|||
subject = "New Session Comment"
|
||||
unique_args = {:type => "scheduled_session_comment"}
|
||||
@body = msg
|
||||
@session_name = session.description
|
||||
@session_name = session.name
|
||||
@session_date = session.scheduled_start
|
||||
@comment = comment
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
|
|
@ -390,6 +391,24 @@
|
|||
end
|
||||
end
|
||||
|
||||
def scheduled_session_daily(receiver, sessions_and_latency)
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => "scheduled_session_daily"
|
||||
|
||||
sendgrid_recipients([receiver.email])
|
||||
sendgrid_substitute('@USERID', [receiver.id])
|
||||
|
||||
@user = receiver
|
||||
@sessions_and_latency = sessions_and_latency
|
||||
|
||||
@title = 'New Scheduled Sessions Matched to You'
|
||||
mail(:to => receiver.email,
|
||||
:subject => EmailBatchScheduledSessions.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"}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p>We noticed that you have downloaded the free JamKazam application, but you have not yet run the app. You can find other musicians and listen to sessions and recordings on our website, but you need to run the JamKazam application to play with other musicians online. If you are having trouble installing or running the app, please visit our JamKazam support center at the link below, and post a request for assistance so that we can help you get up and running.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com/">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
</p>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<%= @title %>
|
||||
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
We noticed that you have downloaded the free JamKazam application, but you have not yet run the app. You can find other musicians and listen to sessions and recordings on our website, but you need to run the JamKazam application to play with other musicians online. If you are having trouble installing or running the app, please visit our JamKazam support center at the link below, and post a request for assistance so that we can help you get up and running.
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p>We noticed that you have registered as a JamKazam musician, but you have not yet downloaded and started using the free JamKazam application. You can find other musicians and listen to sessions and recordings on our website, but you need the free JamKazam application to play with other musicians online. Please click the link below to go to the download page for the free JamKazam application, or visit our JamKazam support center so that we can help you get up and running.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a style="color: #588C98;" href="http://www.jamkazam.com/downloads">Go to Download Page</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com">Go to Support Center</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
</p>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<%= @title %>
|
||||
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
We noticed that you have registered as a JamKazam musician, but you have not yet downloaded and started using the free JamKazam application. You can find other musicians and listen to sessions and recordings on our website, but you need the free JamKazam application to play with other musicians online. Please click the link below to go to the download page for the free JamKazam application, or visit our JamKazam support center so that we can help you get up and running.
|
||||
|
||||
Go to Download Page: http://www.jamkazam.com/downloads
|
||||
|
||||
Go to Support Center: https://jamkazam.desk.com
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p>We noticed that you have not yet successfully set up your audio gear and passed the JamKazam latency and input/output audio gear tests. This means that you cannot yet play in online sessions with other musicians. If you are having trouble with this step, please click the link below for a knowledge base article that can help you get past this hurdle. If the test says your audio gear is not fast enough, or if your audio quality sounds poor, or if you are just confused, it’s very likely the tips in this article will help you get things set up and optimized so you can start playing online.
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="http://bit.ly/1i4Uul4">http://bit.ly/1i4Uul4</a>
|
||||
</p>
|
||||
|
||||
<p>And if this knowledge base article does not get you fixed up, please visit our JamKazam support center at the link below, and post a request for assistance so that we can help you get up and running:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
</p>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<%= @title %>
|
||||
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
We noticed that you have not yet successfully set up your audio gear and passed the JamKazam latency and input/output audio gear tests. This means that you cannot yet play in online sessions with other musicians. If you are having trouble with this step, please click the link below for a knowledge base article that can help you get past this hurdle. If the test says your audio gear is not fast enough, or if your audio quality sounds poor, or if you are just confused, it’s very likely the tips in this article will help you get things set up and optimized so you can start playing online.
|
||||
|
||||
http://bit.ly/1i4Uul4
|
||||
|
||||
And if this knowledge base article does not get you fixed up, please visit our JamKazam support center at the link below, and post a request for assistance so that we can help you get up and running:
|
||||
|
||||
https://jamkazam.desk.com
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p>We noticed that you haven’t yet played in a JamKazam session with multiple musicians that lasted long enough to be productive or fun. Since that’s the whole point of the service, we wanted to reach out to see if we can help you. Please take a quick look at the suggestions below to see if they help you!
|
||||
</p>
|
||||
|
||||
<p>Find Other Musicians on JamKazam<br />
|
||||
It’s still very early in our company’s development, so we don’t have zillions of users online on our service yet. If you click Find Session, you will often not find a good session to join, both due to the number of musicians online at any given time, and also because you won’t see private sessions where groups of musicians don’t want to be interrupted in their sessions.
|
||||
</p>
|
||||
|
||||
<p>If you are having trouble getting into sessions, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a href="http://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
</p>
|
||||
|
||||
<p>This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
</p>
|
||||
|
||||
<p>Invite Your Friends to Play<br />
|
||||
One of the best ways to connect and play with others is to invite your friends from the “real world” to join you on JamKazam, and then set up a time to meet online and get into a session together. To do this, just go to www.jamkazam.com and sign in. Then move your mouse over your picture or name in the upper right corner of the screen. A menu will be displayed. Click the Invite Friends option, and then you can click Facebook, Google, or Email to easily invite your friends from different services to join you on JamKazam.
|
||||
</p>
|
||||
|
||||
<p>Troubleshoot Session Problems<br />
|
||||
If you are having audio quality problems or other issues when you get into a session, please click the link below to visit our support center, and check the knowledge base articles under the Troubleshooting header to find solutions. And if that doesn’t work, please post a request for assistance in the support center so that we can help you get up and running:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
</p>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<%= @title %>
|
||||
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
We noticed that you haven’t yet played in a JamKazam session with multiple musicians that lasted long enough to be productive or fun. Since that’s the whole point of the service, we wanted to reach out to see if we can help you. Please take a quick look at the suggestions below to see if they help you!
|
||||
|
||||
Find Other Musicians on JamKazam
|
||||
It’s still very early in our company’s development, so we don’t have zillions of users online on our service yet. If you click Find Session, you will often not find a good session to join, both due to the number of musicians online at any given time, and also because you won’t see private sessions where groups of musicians don’t want to be interrupted in their sessions.
|
||||
|
||||
If you are having trouble getting into sessions, we’d suggest you click the Musicians tile on the home screen of the app or the website: http://www.jamkazam.com/client#/musicians
|
||||
|
||||
This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
|
||||
Invite Your Friends to Play
|
||||
One of the best ways to connect and play with others is to invite your friends from the “real world” to join you on JamKazam, and then set up a time to meet online and get into a session together. To do this, just go to www.jamkazam.com and sign in. Then move your mouse over your picture or name in the upper right corner of the screen. A menu will be displayed. Click the Invite Friends option, and then you can click Facebook, Google, or Email to easily invite your friends from different services to join you on JamKazam.
|
||||
|
||||
Troubleshoot Session Problems
|
||||
If you are having audio quality problems or other issues when you get into a session, please click the link below to visit our support center, and check the knowledge base articles under the Troubleshooting header to find solutions. And if that doesn’t work, please post a request for assistance in the support center so that we can help you get up and running:
|
||||
|
||||
https://jamkazam.desk.com
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p>We noticed that you haven’t yet connected with any friends on JamKazam. Connecting with friends is the best way to help you get into sessions with other musicians on JamKazam. Here are a couple of good ways to connect with others.
|
||||
</p>
|
||||
|
||||
<p>Find Other Musicians on JamKazam<br />
|
||||
To find and connect with other musicians who are already on JamKazam, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a href="http://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
</p>
|
||||
|
||||
<p>This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that you read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
</p>
|
||||
|
||||
<p>Invite Your Friends to Play<br >
|
||||
One of the best ways to connect and play with others is to invite your friends from the “real world” to join you on JamKazam, and then set up a time to meet online and get into a session together. To do this, just go to www.jamkazam.com and sign in. Then move your mouse over your picture or name in the upper right corner of the screen. A menu will be displayed. Click the Invite Friends option, and then you can click Facebook, Google, or Email to easily invite your friends from different services to join you on JamKazam.
|
||||
</p>
|
||||
|
||||
<p>If you have any trouble, please visit our support center at the link below any time to get help:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com/">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
</p>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<%= @title %>
|
||||
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
We noticed that you haven’t yet connected with any friends on JamKazam. Connecting with friends is the best way to help you get into sessions with other musicians on JamKazam. Here are a couple of good ways to connect with others.
|
||||
|
||||
Find Other Musicians on JamKazam
|
||||
To find and connect with other musicians who are already on JamKazam, we’d suggest you click the Musicians tile on the home screen of the app or the website: http://www.jamkazam.com/client#/musicians
|
||||
|
||||
This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that you read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
|
||||
Invite Your Friends to Play
|
||||
One of the best ways to connect and play with others is to invite your friends from the “real world” to join you on JamKazam, and then set up a time to meet online and get into a session together. To do this, just go to www.jamkazam.com and sign in. Then move your mouse over your picture or name in the upper right corner of the screen. A menu will be displayed. Click the Invite Friends option, and then you can click Facebook, Google, or Email to easily invite your friends from different services to join you on JamKazam.
|
||||
|
||||
If you have any trouble, please visit our support center at the link below any time to get help:
|
||||
|
||||
https://jamkazam.desk.com
|
||||
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p>We noticed that you have not invited any of your friends to join you to play together on JamKazam. It’s still very early in our company’s development, so we don’t have zillions of users online on our service yet. One of the best ways to connect and play with others is to invite your friends from the “real world” to join you on JamKazam, and then set up a time to meet online and get into a session together. To do this, just go to www.jamkazam.com and sign in. Then move your mouse over your picture or name in the upper right corner of the screen. A menu will be displayed. Click the Invite Friends option, and then you can click Facebook, Google, or Email to easily invite your friends from different services to join you on JamKazam.
|
||||
</p>
|
||||
|
||||
<p>If you have any trouble, please visit our support center at the link below any time to get help:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
</p>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<%= @title %>
|
||||
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
We noticed that you have not invited any of your friends to join you to play together on JamKazam. It’s still very early in our company’s development, so we don’t have zillions of users online on our service yet. One of the best ways to connect and play with others is to invite your friends from the “real world” to join you on JamKazam, and then set up a time to meet online and get into a session together. To do this, just go to www.jamkazam.com and sign in. Then move your mouse over your picture or name in the upper right corner of the screen. A menu will be displayed. Click the Invite Friends option, and then you can click Facebook, Google, or Email to easily invite your friends from different services to join you on JamKazam.
|
||||
|
||||
If you have any trouble, please visit our support center at the link below any time to get help:
|
||||
|
||||
https://jamkazam.desk.com
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p>JamKazam is a young company/service built through the sweat and commitment of a small group of music-loving techies. Please help us continue to grow the service and attract more musicians to play online by liking and/or following us on Facebook, Twitter, and Google+. Just click the icons below to give us little push, thanks!
|
||||
</p>
|
||||
|
||||
<% [:twitter, :facebook, :google].each do |site| %>
|
||||
<%= link_to(image_tag("http://www.jamkazam.com/assets/content/icon_#{site}.png", :style => "vertical-align:top"), "http://www.jamkazam.com/endorse/@USERID/#{site}?src=email") %>
|
||||
<% end %>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
</p>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<%= @title %>
|
||||
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
JamKazam is a young company/service built through the sweat and commitment of a small group of music-loving techies. Please help us continue to grow the service and attract more musicians to play online by liking and/or following us on Facebook, Twitter, and Google+. Just click the icons below to give us little push, thanks!
|
||||
|
||||
<% [:twitter, :facebook, :google].each do |site| %>
|
||||
http://www.jamkazam.com/endorse/@USERID/#{site}?src=email
|
||||
|
||||
<% end %>
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p>We noticed that you haven’t yet rated any of your JamKazam sessions as “good”. It may be that you just are not a “rater”, and that is totally fine. But if you are not having good, high quality, productive and fun sessions, we want to help you get there!
|
||||
</p>
|
||||
|
||||
<p>If you are having audio quality problems or other issues when you get into a session, please click the link below to visit our support center, and check the knowledge base articles under the Troubleshooting header to find solutions. And if that doesn’t work, please post a request for assistance in the support center so that we can help you get up and running:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>We really want you to be successful and have fun with this new way of playing music with others, so please reach out and let us help you!
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
</p>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<%= @title %>
|
||||
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
We noticed that you haven’t yet rated any of your JamKazam sessions as “good”. It may be that you just are not a “rater”, and that is totally fine. But if you are not having good, high quality, productive and fun sessions, we want to help you get there!
|
||||
|
||||
If you are having audio quality problems or other issues when you get into a session, please click the link below to visit our support center, and check the knowledge base articles under the Troubleshooting header to find solutions. And if that doesn’t work, please post a request for assistance in the support center so that we can help you get up and running:
|
||||
|
||||
https://jamkazam.desk.com
|
||||
|
||||
We really want you to be successful and have fun with this new way of playing music with others, so please reach out and let us help you!
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p>We noticed that you haven’t yet made a recording during any of your JamKazam sessions. Recordings are extra special on JamKazam because:
|
||||
</p>
|
||||
|
||||
<ul><li>Recordings are made both as a master mix and at the track/stem level.</li>
|
||||
<li>You can easily play along with your recordings when your friends aren’t available.</li>
|
||||
<li>You can share your recordings with family, friends and fans via Facebook, Twitter, etc.</li>
|
||||
</ul>
|
||||
|
||||
<!--<p>To understand all of the things you can do with recordings on JamKazam, watch this YouTube tutorial video:<br />
|
||||
www.youtube.com/blahblahblah
|
||||
</p>-->
|
||||
|
||||
<p>-- Team JamKazam
|
||||
</p>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<%= @title %>
|
||||
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
We noticed that you haven’t yet made a recording during any of your JamKazam sessions. Recordings are extra special on JamKazam because:
|
||||
|
||||
- Recordings are made both as a master mix and at the track/stem level.
|
||||
- You can easily play along with your recordings when your friends aren’t available.
|
||||
- You can share your recordings with family, friends and fans via Facebook, Twitter, etc.
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
<% provide(:title, 'New JamKazam Musicians in your Area') %>
|
||||
<% provide(:title, 'New Musicians You Should Check Out') %>
|
||||
Hi <%= @user.first_name %>,
|
||||
|
||||
<p>The following new musicians have joined JamKazam within the last week, and have Internet connections with low enough latency to you that you can have a good online session together. We'd suggest that you look through the new musicians listed below to see if any match your musical interests, and if so, click through to their profile page on the JamKazam website to send them a message or a request to connect as a JamKazam friend:
|
||||
</p>
|
||||
|
||||
<% link_style = "background-color:#ED3618; margin:0px 8px 0px 8px; border: solid 1px #F27861; outline: solid 2px #ED3618; padding:3px 10px; font-family:Raleway, Arial, Helvetica, sans-serif; font-size:12px; font-weight:300; cursor:pointer; color:#FC9; text-decoration:none;" %>
|
||||
<p>
|
||||
|
|
@ -20,3 +24,8 @@
|
|||
<% end %>
|
||||
</table>
|
||||
</p>
|
||||
<p>There are currently <%= @new_nearby.size%> musicians on JamKazam with low enough latency Internet connections to you to support a good online session. To see ALL the JamKazam musicians with whom you may want to connect and play, view our Musicians page at: <a href="http://www.jamkazam.com/client#/musicians">http://www.jamkazam.com/client#/musicians</a>.
|
||||
</p>
|
||||
|
||||
<p>Best Regards,</p>
|
||||
Team JamKazam
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
New JamKazam Musicians in your Area
|
||||
|
||||
Hi <%= @user.first_name %>,
|
||||
|
||||
The following new musicians have joined JamKazam within the last week, and have Internet connections with low enough latency to you that you can have a good online session together. We'd suggest that you look through the new musicians listed below to see if any match your musical interests, and if so, click through to their profile page on the JamKazam website to send them a message or a request to connect as a JamKazam friend:
|
||||
|
||||
<% @new_nearby.each do |user| %>
|
||||
<%= user.name %> (http://<%= @host %>/client#/profile/<%= user.id %>)
|
||||
<%= user.location %>
|
||||
<% user.instruments.collect { |inst| inst.description }.join(', ') %>
|
||||
<%= user.biography %>
|
||||
|
||||
<% end %>
|
||||
|
||||
There are currently <%= @new_nearby.size%> musicians on JamKazam with low enough latency Internet connections to you to support a good online session. To see ALL the JamKazam musicians with whom you may want to connect and play, view our Musicians page at: http://www.jamkazam.com/client#/musicians.
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
<p>Hello <%= @user.first_name %> --
|
||||
</p>
|
||||
|
||||
<p>The following new sessions that that have been posted during the last 24 hours:
|
||||
</p>
|
||||
<ol>
|
||||
<li>Need someone who plays an instrument that you play</li>
|
||||
<li>Were posted by someone to whom you have either a good or medium latency connection</li>
|
||||
</ol>
|
||||
|
||||
<p>Take a look through these new sessions below, and just click the RSVP button on the far right side of the row for any session in which you'd like to play. This will let the session organizer know you're interested, and you'll be notified if the session organizer accepts your request to play in that session!
|
||||
</p>
|
||||
|
||||
<table style="margin-top:6px; width:98%; font-size:11px; color:#fff; background-color:#262626; border:solid 1px #4d4d4d;" cellspacing="0" cellpadding="0" border="0">
|
||||
<!-- header -->
|
||||
<tr>
|
||||
<th align="left" width="20%">GENRE</th>
|
||||
<th align="left" width="60%">DESCRIPTION</th>
|
||||
<th width="20%" style="text-align:center">LATENCY</th>
|
||||
</tr>
|
||||
<!-- session row goes here -->
|
||||
<% @sessions_and_latency.each do |sess| %>
|
||||
<tr>
|
||||
<td><%= sess.genre.description %></td>
|
||||
<td><%= sess.description %></td>
|
||||
<td style="text-align:center"><%= sess.latency_store %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
<p>To see ALL the scheduled sessions that you might be interested in joining, view our Find Session page at: <a href="http://www.jamkazam.com/client#/findSession">http://www.jamkazam.com/client#/findSession</a>.
|
||||
</p>
|
||||
|
||||
<p>Best Regards,</p>
|
||||
|
||||
Team JamKazam
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<% provide(:title, @title) %>
|
||||
|
||||
Hello <%= @user.first_name %> --
|
||||
|
||||
The following new sessions that that have been posted during the last 24 hours:
|
||||
|
||||
1. Need someone who plays an instrument that you play
|
||||
2. Were posted by someone to whom you have either a good or medium latency connection
|
||||
|
||||
Take a look through these new sessions below, and just click the RSVP button on the far right side of the row for any session in which you'd like to play. This will let the session organizer know you're interested, and you'll be notified if the session organizer accepts your request to play in that session!
|
||||
|
||||
GENRE | DESCRIPTION | LATENCY
|
||||
<% @sessions_and_latency.each do |sess| %>
|
||||
<%= sess.genre.description %> | <%= sess.description %> | <%= sess.latency_store %>
|
||||
<% end %>
|
||||
|
||||
To see ALL the scheduled sessions that you might be interested in joining, view our Find Session page at: http://www.jamkazam.com/client#/findSession.
|
||||
|
||||
Best Regards,
|
||||
|
||||
Team JamKazam
|
||||
|
|
@ -1,27 +1,45 @@
|
|||
<% provide(:title, 'Welcome to JamKazam!') %>
|
||||
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
|
||||
<p> We're delighted that you have decided to try the JamKazam service,
|
||||
and we hope that you will enjoy using JamKazam to play music with others.
|
||||
Following are links to some resources that can help to get you up and running quickly.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Tutorial videos that show you how to use the key features of the product:</br>
|
||||
Getting Started Video<br/>
|
||||
We recommend watching this video before you jump into the service just to get oriented. It will really help you hit the ground running:
|
||||
<a style="color: #588C98;" href="https://www.youtube.com/watch?v=VexH4834o9I">https://www.youtube.com/watch?v=VexH4834o9I</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Other Great Tutorial Videos<br />
|
||||
There are several other very great videos that will help you understand how to find and connect with other musicians on the service, create your own sessions or find and join other musicians’ sessions, play in sessions, record and share your performances, and even live broadcast your sessions to family, friends, and fans. Check these helpful videos out here:
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com/customer/portal/articles/1304097-tutorial-videos">https://jamkazam.desk.com/customer/portal/articles/1304097-tutorial-videos</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Getting Started knowledge base articles:</br>
|
||||
Knowledge Base Articles<br />
|
||||
You can find Getting Started knowledge base articles on things like frequently asked questions (FAQ), minimum system requirements for your Windows or Mac computer, how to troubleshoot audio problems in sessions, and more here:
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com/customer/portal/topics/564807-getting-started/articles">https://jamkazam.desk.com/customer/portal/topics/564807-getting-started/articles</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Support Portal in case you run into trouble and need help:</br>
|
||||
JamKazam Support Portal<br />
|
||||
If you run into trouble and need help, please reach out to us. We will be glad to do everything we can to get you up and running. You can find our support portal here:
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com/">https://jamkazam.desk.com/</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We look forward to seeing - and hearing - you online soon!
|
||||
JamKazam Community Forum<br />
|
||||
And if you just want to chat, share tips and war stories, and hang out with fellow JamKazamers, you can visit our community forum here:
|
||||
<a style="color: #588C98;" href="http://forums.jamkazam.com/">http://forums.jamkazam.com/</a>
|
||||
</p>
|
||||
|
||||
- Team JamKazam
|
||||
<p>
|
||||
Please take a moment to like or follow us by clicking the icons below, and we look forward to seeing – and hearing – you online soon!
|
||||
</p>
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
|
|||
|
|
@ -1,16 +1,27 @@
|
|||
We're delighted that you have decided to try the JamKazam service,
|
||||
and we hope that you will enjoy using JamKazam to play music with others.
|
||||
Following are links to some resources that can help to get you up and running quickly.
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
|
||||
Tutorial videos that show you how to use the key features of the product:
|
||||
We're delighted that you have decided to try the JamKazam service, and we hope that you will enjoy using JamKazam to play music with others. Following are links to some resources that can help to get you up and running quickly.
|
||||
|
||||
Getting Started Video
|
||||
We recommend watching this video before you jump into the service just to get oriented. It will really help you hit the ground running:
|
||||
https://www.youtube.com/watch?v=VexH4834o9I
|
||||
|
||||
Other Great Tutorial Videos
|
||||
There are several other very great videos that will help you understand how to find and connect with other musicians on the service, create your own sessions or find and join other musicians’ sessions, play in sessions, record and share your performances, and even live broadcast your sessions to family, friends, and fans. Check these helpful videos out here:
|
||||
https://jamkazam.desk.com/customer/portal/articles/1304097-tutorial-videos
|
||||
|
||||
Getting Started knowledge base articles:
|
||||
Knowledge Base Articles
|
||||
You can find Getting Started knowledge base articles on things like frequently asked questions (FAQ), minimum system requirements for your Windows or Mac computer, how to troubleshoot audio problems in sessions, and more here:
|
||||
https://jamkazam.desk.com/customer/portal/topics/564807-getting-started/articles
|
||||
|
||||
Support Portal in case you run into trouble and need help:
|
||||
https://jamkazam.desk.com/
|
||||
JamKazam Support Portal
|
||||
If you run into trouble and need help, please reach out to us. We will be glad to do everything we can to get you up and running. You can find our support portal here:
|
||||
https://jamkazam.desk.com
|
||||
|
||||
We look forward to seeing - and hearing - you online soon!
|
||||
JamKazam Community Forum
|
||||
And if you just want to chat, share tips and war stories, and hang out with fellow JamKazamers, you can visit our community forum here:
|
||||
http://forums.jamkazam.com
|
||||
|
||||
- Team JamKazam
|
||||
Please take a moment to like or follow us by clicking the icons below, and we look forward to seeing – and hearing – you online soon!
|
||||
|
||||
-- Team JamKazam
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@
|
|||
<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}") %>
|
||||
<% [:twitter, :facebook, :google].each do |site| %>
|
||||
<%= link_to(image_tag("http://www.jamkazam.com/assets/content/icon_#{site}.png", :style => "vertical-align:top"), "http://www.jamkazam.com/endorse/@USERID/#{site}?src=email") %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -153,11 +153,11 @@ SQL
|
|||
# NOTE this is only used for testing purposes;
|
||||
# actual deletes will be processed in the websocket context which cleans up dependencies
|
||||
def expire_stale_connections()
|
||||
self.stale_connection_client_ids().each { |client| self.delete_connection(client[:client_id]) }
|
||||
self.stale_connection_client_ids.each { |client| self.delete_connection(client[:client_id]) }
|
||||
end
|
||||
|
||||
# expiring connections in stale state, which deletes them
|
||||
def stale_connection_client_ids()
|
||||
def stale_connection_client_ids
|
||||
clients = []
|
||||
ConnectionManager.active_record_transaction do |connection_manager|
|
||||
conn = connection_manager.pg_conn
|
||||
|
|
@ -347,7 +347,7 @@ SQL
|
|||
|
||||
connection = Connection.find_by_client_id_and_user_id!(client_id, user.id)
|
||||
|
||||
connection.join_the_session(music_session, as_musician, tracks)
|
||||
connection.join_the_session(music_session, as_musician, tracks, user)
|
||||
# connection.music_session_id = music_session.id
|
||||
# connection.as_musician = as_musician
|
||||
# connection.joining_session = true
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ module ValidationMessages
|
|||
INVALID_FPFILE = "is not valid"
|
||||
|
||||
#connection
|
||||
|
||||
USER_OR_LATENCY_TESTER_PRESENT = "user or latency_tester must be present"
|
||||
SELECT_AT_LEAST_ONE = "Please select at least one track" # DO NOT CHANGE THIS TEXT MESSAGE UNLESS YOU CHANGE createSession.js.erb, which is looking for it
|
||||
FAN_CAN_NOT_JOIN_AS_MUSICIAN = "A fan can not join a music session as a musician"
|
||||
MUSIC_SESSION_MUST_BE_SPECIFIED = "A music session must be specified"
|
||||
|
|
|
|||
|
|
@ -22,13 +22,11 @@ module JamRuby
|
|||
Jampb::ClientMessage.parse(payload)
|
||||
end
|
||||
|
||||
# create a login message using user/pass
|
||||
def login_with_user_pass(username, password, options = {})
|
||||
# create a login message using client_id (used by latency_tester)
|
||||
def login_with_client_id(client_id)
|
||||
login = Jampb::Login.new(
|
||||
:username => username,
|
||||
:password => password,
|
||||
:client_id => options[:client_id],
|
||||
:client_type => options[:client_type]
|
||||
:client_id => client_id,
|
||||
:client_type => Connection::TYPE_LATENCY_TESTER
|
||||
)
|
||||
|
||||
Jampb::ClientMessage.new(
|
||||
|
|
@ -38,6 +36,22 @@ module JamRuby
|
|||
)
|
||||
end
|
||||
|
||||
# create a login message using user/pass
|
||||
def login_with_user_pass(username, password, options = {})
|
||||
login = Jampb::Login.new(
|
||||
:username => username,
|
||||
:password => password,
|
||||
:client_id => options[:client_id],
|
||||
:client_type => options[:client_type]
|
||||
)
|
||||
|
||||
Jampb::ClientMessage.new(
|
||||
:type => ClientMessage::Type::LOGIN,
|
||||
:route_to => SERVER_TARGET,
|
||||
:login => login
|
||||
)
|
||||
end
|
||||
|
||||
# create a login message using token (a cookie or similar)
|
||||
def login_with_token(token, options = {})
|
||||
login = Jampb::Login.new(
|
||||
|
|
|
|||
|
|
@ -27,7 +27,10 @@ module JamRuby
|
|||
start = params[:start].presence
|
||||
start = start.to_i || 0
|
||||
|
||||
query = ChatMessage.offset(start).limit(limit)
|
||||
music_session_id = params[:music_session]
|
||||
|
||||
query = ChatMessage.where('music_session_id = ?', music_session_id)
|
||||
.offset(start).limit(limit)
|
||||
|
||||
if query.length == 0
|
||||
[query, nil]
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ module JamRuby
|
|||
# client_types
|
||||
TYPE_CLIENT = 'client'
|
||||
TYPE_BROWSER = 'browser'
|
||||
TYPE_LATENCY_TESTER = 'latency_tester'
|
||||
|
||||
attr_accessor :joining_session
|
||||
|
||||
|
|
@ -13,11 +14,14 @@ module JamRuby
|
|||
|
||||
belongs_to :user, :class_name => "JamRuby::User"
|
||||
belongs_to :music_session, :class_name => "JamRuby::ActiveMusicSession", foreign_key: :music_session_id
|
||||
has_one :latency_tester, class_name: 'JamRuby::LatencyTester', foreign_key: :client_id, primary_key: :client_id
|
||||
has_many :tracks, :class_name => "JamRuby::Track", :inverse_of => :connection, :foreign_key => 'connection_id', :dependent => :delete_all
|
||||
|
||||
validates :as_musician, :inclusion => {:in => [true, false]}
|
||||
validates :client_type, :inclusion => {:in => [TYPE_CLIENT, TYPE_BROWSER]}
|
||||
validates :client_type, :inclusion => {:in => [TYPE_CLIENT, TYPE_BROWSER, TYPE_LATENCY_TESTER]}
|
||||
validate :can_join_music_session, :if => :joining_session?
|
||||
validate :user_or_latency_tester_present
|
||||
|
||||
after_save :require_at_least_one_track_when_in_session, :if => :joining_session?
|
||||
after_create :did_create
|
||||
after_save :report_add_participant
|
||||
|
|
@ -134,7 +138,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def did_create
|
||||
self.user.update_lat_lng(self.ip_address) if self.user && self.ip_address
|
||||
# self.user.update_lat_lng(self.ip_address) if self.user && self.ip_address
|
||||
end
|
||||
|
||||
def report_add_participant
|
||||
|
|
@ -148,13 +152,18 @@ module JamRuby
|
|||
true
|
||||
end
|
||||
|
||||
def join_the_session(music_session, as_musician, tracks)
|
||||
def join_the_session(music_session, as_musician, tracks, user)
|
||||
self.music_session_id = music_session.id
|
||||
self.as_musician = as_musician
|
||||
self.joining_session = true
|
||||
self.joined_session_at = Time.now
|
||||
associate_tracks(tracks) unless tracks.nil?
|
||||
self.save
|
||||
|
||||
# if user joins the session as a musician, update their addr and location
|
||||
if as_musician
|
||||
user.update_addr_loc(self, 'j')
|
||||
end
|
||||
end
|
||||
|
||||
def associate_tracks(tracks)
|
||||
|
|
@ -185,5 +194,12 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def user_or_latency_tester_present
|
||||
if user.nil? && client_type != TYPE_LATENCY_TESTER
|
||||
puts client_type
|
||||
errors.add(:connection, ValidationMessages::USER_OR_LATENCY_TESTER_PRESENT)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ module JamRuby
|
|||
# this implies a coding error
|
||||
MISSING_CLIENT_STATE = 'MISSING_CLIENT_STATE'
|
||||
|
||||
# the underlying database connection is gone when the heartbeat comes in
|
||||
MISSING_CONNECTION = 'MISSING_CONNECTION'
|
||||
|
||||
# websocket gateway did not recognize message. indicates out-of-date websocket-gateway
|
||||
UNKNOWN_MESSAGE_TYPE = 'UNKNOWN_MESSAGE_TYPE'
|
||||
|
||||
|
|
@ -26,9 +29,15 @@ module JamRuby
|
|||
# websocket gateway got a client with the same client_id as an already-connected client
|
||||
DUPLICATE_CLIENT = 'DUPLICATE_CLIENT'
|
||||
|
||||
# info about how the test went
|
||||
NETWORK_TEST_RESULT = 'NETWORK_TEST_RESULT'
|
||||
|
||||
# step 2 of the FTUE... could the user select their gear?
|
||||
GEAR_SELECTION = 'GEAR_SELECTION'
|
||||
|
||||
DIAGNOSTIC_TYPES = [NO_HEARTBEAT_ACK, WEBSOCKET_CLOSED_REMOTELY, EXPIRED_STALE_CONNECTION,
|
||||
MISSING_CLIENT_STATE, UNKNOWN_MESSAGE_TYPE, MISSING_ROUTE_TO,
|
||||
DUPLICATE_CLIENT, WEBSOCKET_CLOSED_LOCALLY]
|
||||
DUPLICATE_CLIENT, WEBSOCKET_CLOSED_LOCALLY, NETWORK_TEST_RESULT, GEAR_SELECTION]
|
||||
|
||||
# creator types #
|
||||
CLIENT = 'client'
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module JamRuby
|
|||
VAR_LAST_NAME = '@LASTNAME'
|
||||
|
||||
DEFAULT_SENDER = "noreply@jamkazam.com"
|
||||
BATCH_SIZE = 5
|
||||
BATCH_SIZE = 500
|
||||
|
||||
BODY_TEMPLATE =<<FOO
|
||||
Hello #{VAR_FIRST_NAME},
|
||||
|
|
@ -78,13 +78,26 @@ FOO
|
|||
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: BATCH_SIZE) do |users|
|
||||
self.email_batch_sets << EmailBatchSet.deliver_set(self.id, users.map(&:id))
|
||||
def deliver_batch_sets!
|
||||
User.email_opt_in.find_each do |user|
|
||||
bset = EmailBatchSet.sent_email(self, user.id)
|
||||
if 'test' == Rails.env
|
||||
BatchMailer.send_batch_email(self.id, bset.user_id).deliver!
|
||||
else
|
||||
BatchMailer.send_batch_email(self.id, bset.user_id).deliver
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def deliver_batch
|
||||
self.perform_event('do_batch_run!')
|
||||
self.deliver_batch_sets!
|
||||
end
|
||||
|
||||
def deliver_batch_async
|
||||
BatchEmailJob.enqueue(self.id)
|
||||
end
|
||||
|
||||
def test_count
|
||||
self.test_emails.split(',').count
|
||||
end
|
||||
|
|
@ -195,5 +208,13 @@ FOO
|
|||
})
|
||||
end
|
||||
|
||||
def batch_substitutions(users=[])
|
||||
{}
|
||||
end
|
||||
|
||||
def body_for_users(users=[])
|
||||
self.body
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
module JamRuby
|
||||
class EmailBatchNewMusician < EmailBatchPeriodic
|
||||
|
||||
BATCH_SIZE = 500
|
||||
|
||||
SINCE_DAYS = 14
|
||||
|
||||
VAR_MUSICIAN_COUNT = "@MUSICIAN_COUNT"
|
||||
VAR_MUSICIAN_TABLE = "@MUSICIAN_TABLE"
|
||||
|
||||
TMP_NEW = 'tmp_new_musicians'
|
||||
TMP_CAND = 'tmp_receiver_candidates'
|
||||
TMP_PAIRS = 'tmp_receivers_new_musicians'
|
||||
|
||||
def self.subject
|
||||
"New musicians with good Internet connections to you have joined JamKazam!"
|
||||
end
|
||||
|
||||
# inserts eligible sessions to temp table
|
||||
def _fetch_new_musicians
|
||||
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS #{TMP_NEW}")
|
||||
sql =<<SQL
|
||||
SELECT
|
||||
users.id AS new_user_id, users.last_jam_locidispid AS last_jam_locidispid
|
||||
INTO TEMP TABLE #{TMP_NEW}
|
||||
FROM users
|
||||
WHERE
|
||||
musician = 't' AND
|
||||
last_jam_locidispid IS NOT NULL AND
|
||||
users.created_at > '#{time_since_last_batch(SINCE_DAYS)}'
|
||||
SQL
|
||||
ActiveRecord::Base.connection.execute(sql)
|
||||
end
|
||||
|
||||
def _fetch_receiver_candidates
|
||||
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS #{TMP_CAND}")
|
||||
sql =<<SQL
|
||||
SELECT
|
||||
users.id AS receiver_candidate_id, users.last_jam_locidispid AS last_jam_locidispid
|
||||
INTO TEMP TABLE #{TMP_CAND}
|
||||
FROM users
|
||||
FULL OUTER JOIN #{TMP_NEW} ON users.id = #{TMP_NEW}.new_user_id
|
||||
WHERE
|
||||
users.musician = 't' AND
|
||||
users.subscribe_email = 't' AND
|
||||
users.last_jam_locidispid IS NOT NULL AND
|
||||
(#{TMP_NEW}.new_user_id IS NULL OR users.id IS NULL)
|
||||
SQL
|
||||
ActiveRecord::Base.connection.execute(sql)
|
||||
end
|
||||
|
||||
def _fetch_eligible_receivers
|
||||
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS #{TMP_PAIRS}")
|
||||
# load eligible recipients into tmp table
|
||||
sql =<<SQL
|
||||
SELECT
|
||||
#{TMP_NEW}.new_user_id,
|
||||
#{TMP_CAND}.receiver_candidate_id AS receiver_id,
|
||||
scores.score AS latency
|
||||
INTO TEMP TABLE #{TMP_PAIRS}
|
||||
FROM scores
|
||||
INNER JOIN #{TMP_CAND} ON #{TMP_CAND}.last_jam_locidispid = scores.alocidispid
|
||||
INNER JOIN #{TMP_NEW} ON #{TMP_NEW}.last_jam_locidispid = scores.blocidispid
|
||||
WHERE
|
||||
scores.score < #{Score::MAX_YELLOW_LATENCY}
|
||||
SQL
|
||||
ActiveRecord::Base.connection.execute(sql)
|
||||
end
|
||||
|
||||
def fetch_recipients
|
||||
objs = []
|
||||
# load new musicians into tmp table
|
||||
self._fetch_new_musicians
|
||||
|
||||
# load receiver candidates into tmp table
|
||||
self._fetch_receiver_candidates
|
||||
|
||||
# load email receivers into tmp table
|
||||
self._fetch_eligible_receivers
|
||||
|
||||
sql = "SELECT DISTINCT receiver_id FROM #{TMP_PAIRS} GROUP BY receiver_id"
|
||||
ActiveRecord::Base.connection.execute(sql).each do |result|
|
||||
receiver = User.find_by_id(result['receiver_id'])
|
||||
|
||||
sql = "SELECT new_user_id, latency FROM #{TMP_PAIRS} WHERE receiver_id = '#{receiver.id}'"
|
||||
new_musicians = ActiveRecord::Base.connection.execute(sql).collect do |rr|
|
||||
new_user = User.where(['id = ?',rr['new_user_id']])
|
||||
.limit(1)
|
||||
.includes([:instruments])
|
||||
.first
|
||||
new_user.latency_store = result['latency']
|
||||
new_user
|
||||
end
|
||||
block_given? ? yield(receiver, new_musicians) : objs << [receiver, new_musicians]
|
||||
end
|
||||
objs
|
||||
end
|
||||
|
||||
def deliver_batch_sets!
|
||||
self.opt_in_count = 0
|
||||
self.fetch_recipients do |user, new_musicians|
|
||||
self.opt_in_count += 1
|
||||
bset = EmailBatchSet.new_musician_set(self, user, new_musicians)
|
||||
UserMailer.new_musicians(uu, new_musicians).deliver
|
||||
end
|
||||
self.sent_count = self.opt_in_count
|
||||
self.save
|
||||
self.did_batch_run!
|
||||
end
|
||||
|
||||
def self.send_new_musician_batch
|
||||
oo = self.create
|
||||
oo..deliver_batch
|
||||
oo
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
module JamRuby
|
||||
class EmailBatchPeriodic < EmailBatch
|
||||
self.abstract_class = true
|
||||
|
||||
def time_since_last_batch_query
|
||||
self.class
|
||||
.where(['created_at < ?', self.created_at])
|
||||
.order('created_at DESC')
|
||||
.limit(1)
|
||||
end
|
||||
|
||||
def time_since_last_batch(default_days=2)
|
||||
if previous = self.time_since_last_batch_query.first
|
||||
return previous.created_at
|
||||
end
|
||||
Time.now - default_days.days
|
||||
end
|
||||
|
||||
def fetch_recipients(since=nil)
|
||||
yield([]) if block_given?
|
||||
end
|
||||
|
||||
def self.subject(subtype=nil)
|
||||
''
|
||||
end
|
||||
|
||||
def self.body
|
||||
''
|
||||
end
|
||||
|
||||
def self.new(*args)
|
||||
oo = super
|
||||
oo.body = ''
|
||||
oo.subject = self.subject
|
||||
oo
|
||||
end
|
||||
|
||||
def deliver_batch_sets!
|
||||
end
|
||||
|
||||
def clear_batch_sets!
|
||||
self.email_batch_sets.map(&:destroy)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
module JamRuby
|
||||
class EmailBatchProgression < EmailBatchPeriodic
|
||||
|
||||
BATCH_SIZE = 500
|
||||
SINCE_WEEKS = 2
|
||||
|
||||
SUBTYPES = [:client_notdl, # Registered Musician Has Not Downloaded Client
|
||||
:client_dl_notrun, # Registered Musician Has Downloaded Client But Not Yet Run It
|
||||
:client_run_notgear, # Registered Musician Has Run Client But Not Successfully Qualified Audio Gear
|
||||
:gear_notsess, # Registered Musician Has Successfully Qualified Audio Gear But Has Not Participated in a ‘Real’ Session
|
||||
:sess_notgood, # Registered Musician Has Participated In a "Real" Session But Has Not Had a "Good" Session
|
||||
:sess_notrecord, # Registered Musician Has Participated In a "Real" Session But Has Not Made a Recording
|
||||
:reg_notinvite, # Registered Musician Has Not Invited Friends to Join JamKazam
|
||||
:reg_notconnect, # Registered Musician Has Not Connected with any Friends on JamKazam
|
||||
:reg_notlike, # Registered Musician Has Not Liked Jamkazam
|
||||
]
|
||||
|
||||
SUBTYPE_METADATA = {
|
||||
:client_notdl => {
|
||||
:subject => "Get the free JamKazam app now and start playing with others!",
|
||||
:title => "Download the Free JamKazam App"
|
||||
},
|
||||
:client_dl_notrun => {
|
||||
:subject => "Having trouble running the JamKazam application?",
|
||||
:title => "Running the JamKazam App"
|
||||
},
|
||||
:client_run_notgear => {
|
||||
:subject => "Having trouble setting up your audio gear for JamKazam?",
|
||||
:title => "Setting Up and Qualifying Your Audio Gear on JamKazam"
|
||||
},
|
||||
:gear_notsess => {
|
||||
:subject => "Having trouble getting into a session with other musicians?",
|
||||
:title => "Tips on Getting into Sessions with Other Musicians"
|
||||
},
|
||||
:sess_notgood => {
|
||||
:subject => "Have you played in a “good” session on JamKazam yet?",
|
||||
:title => "Having a Good Session on JamKazam"
|
||||
},
|
||||
:reg_notinvite => {
|
||||
:subject => "Invite your friends to JamKazam, best way to play online!",
|
||||
:title => "Invite Your Friends to Come and Play with You"
|
||||
},
|
||||
:reg_notconnect => {
|
||||
:subject => "Make friends on JamKazam and play more music!",
|
||||
:title => "Connecting with Friends on JamKazam"
|
||||
},
|
||||
:reg_notlike => {
|
||||
:subject => "Please give us a LIKE!",
|
||||
:title => "Like/Follow JamKazam"
|
||||
},
|
||||
:sess_notrecord => {
|
||||
:subject => "Want to make recordings during your JamKazam sessions?",
|
||||
:title => "Making & Sharing Recordings on JamKazam"
|
||||
},
|
||||
}
|
||||
|
||||
def self.subject(subtype=nil)
|
||||
SUBTYPE_METADATA[subtype][:subject] if subtype
|
||||
end
|
||||
|
||||
def self.title(subtype=nil)
|
||||
SUBTYPE_METADATA[subtype][:title] if subtype
|
||||
end
|
||||
|
||||
def self.subtype_trigger_interval(subtype)
|
||||
[:reg_notlike, :sess_notrecord].include?(subtype) ? [7,14,21] : [2,5,14]
|
||||
end
|
||||
|
||||
def self.days_past_for_trigger_index(subtype, idx)
|
||||
self.subtype_trigger_interval(subtype)[idx]
|
||||
end
|
||||
|
||||
def days_diff(tidx)
|
||||
self.class.days_past_for_trigger_index(self.sub_type,tidx) - self.class.days_past_for_trigger_index(self.sub_type, tidx - 1)
|
||||
end
|
||||
|
||||
def days_past_for_trigger_index(idx)
|
||||
self.class.subtype_trigger_interval(self.sub_type)[idx]
|
||||
end
|
||||
|
||||
def make_set(uu, trigger_idx)
|
||||
EmailBatchSet.progress_set(self, uu, trigger_idx)
|
||||
end
|
||||
|
||||
def trigger_date_constraint(trigger_idx, tbl='tt')
|
||||
intervals = self.class.subtype_trigger_interval(self.sub_type)
|
||||
date_constraint = (Time.now - intervals[trigger_idx].days + 1.hour).strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
case self.sub_type.to_sym
|
||||
when :client_notdl, :reg_notconnect, :reg_notinvite, :reg_notlike
|
||||
return "#{tbl}.created_at < '#{date_constraint}'"
|
||||
when :client_dl_notrun
|
||||
return "#{tbl}.first_downloaded_client_at < '#{date_constraint}'"
|
||||
when :client_run_notgear
|
||||
return "#{tbl}.first_ran_client_at < '#{date_constraint}'"
|
||||
when :gear_notsess
|
||||
return "#{tbl}.first_certified_gear_at < '#{date_constraint}'"
|
||||
when :sess_notgood
|
||||
return "#{tbl}.first_real_music_session_at < '#{date_constraint}'"
|
||||
when :sess_notrecord
|
||||
return "#{tbl}.first_real_music_session_at < '#{date_constraint}'"
|
||||
end
|
||||
end
|
||||
|
||||
def progress_column_constraint(tbl='tt')
|
||||
case self.sub_type.to_sym
|
||||
when :client_notdl
|
||||
return "#{tbl}.first_downloaded_client_at IS NULL"
|
||||
when :client_dl_notrun
|
||||
return "#{tbl}.first_downloaded_client_at IS NOT NULL AND #{tbl}.first_ran_client_at IS NULL"
|
||||
when :client_run_notgear
|
||||
return "#{tbl}.first_ran_client_at IS NOT NULL AND #{tbl}.first_certified_gear_at IS NULL"
|
||||
when :gear_notsess
|
||||
return "#{tbl}.first_certified_gear_at IS NOT NULL AND #{tbl}.first_real_music_session_at IS NULL"
|
||||
when :sess_notgood
|
||||
return "#{tbl}.first_real_music_session_at IS NOT NULL AND #{tbl}.first_good_music_session_at IS NULL"
|
||||
when :sess_notrecord
|
||||
return "#{tbl}.first_real_music_session_at IS NOT NULL AND #{tbl}.first_recording_at IS NULL"
|
||||
when :reg_notinvite
|
||||
return "#{tbl}.first_invited_at IS NULL"
|
||||
when :reg_notconnect
|
||||
return "#{tbl}.first_friended_at IS NULL"
|
||||
when :reg_notlike
|
||||
return "#{tbl}.first_social_promoted_at IS NULL"
|
||||
end
|
||||
''
|
||||
end
|
||||
|
||||
def fetch_recipients(trigger_idx=0, per_page=BATCH_SIZE)
|
||||
fetched = []
|
||||
offset = 0
|
||||
if 0==trigger_idx
|
||||
prev_date_sql = 'tt.prev_trigger_date IS NULL'
|
||||
else
|
||||
prev_date_sql = "tt.prev_trigger_date + interval '#{self.days_diff(trigger_idx)} days' <= '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}'"
|
||||
end
|
||||
countsql =<<SQL
|
||||
SELECT COUNT(*)
|
||||
FROM (SELECT "users".*,
|
||||
(SELECT COALESCE(MAX(ebs.trigger_index),-1)
|
||||
FROM email_batch_sets ebs
|
||||
WHERE
|
||||
ebs.sub_type = '#{self.sub_type}' AND
|
||||
ebs.user_id = users.id
|
||||
) AS tidx,
|
||||
(SELECT created_at
|
||||
FROM email_batch_sets ebs
|
||||
WHERE
|
||||
ebs.sub_type = '#{self.sub_type}' AND
|
||||
ebs.user_id = users.id AND trigger_index = #{trigger_idx - 1}
|
||||
) AS prev_trigger_date
|
||||
FROM users) tt
|
||||
WHERE
|
||||
tt."subscribe_email" = 't' AND
|
||||
tt."musician" = 't' AND
|
||||
(#{progress_column_constraint}) AND
|
||||
(#{self.trigger_date_constraint(trigger_idx)}) AND
|
||||
tt.tidx = #{trigger_idx - 1} AND
|
||||
#{prev_date_sql}
|
||||
SQL
|
||||
num_users = User.count_by_sql(countsql)
|
||||
loops = (num_users / per_page) + (num_users % per_page) - 1
|
||||
0.upto(loops) do |nn|
|
||||
offset = nn * per_page
|
||||
sql =<<SQL
|
||||
SELECT tt.*
|
||||
FROM (SELECT "users".*,
|
||||
(SELECT COALESCE(MAX(ebs.trigger_index),-1)
|
||||
FROM email_batch_sets ebs
|
||||
WHERE
|
||||
ebs.sub_type = '#{self.sub_type}' AND
|
||||
ebs.user_id = users.id
|
||||
) AS tidx,
|
||||
(SELECT created_at
|
||||
FROM email_batch_sets ebs
|
||||
WHERE
|
||||
ebs.sub_type = '#{self.sub_type}' AND
|
||||
ebs.user_id = users.id AND trigger_index = #{trigger_idx - 1}
|
||||
) AS prev_trigger_date
|
||||
FROM users) tt
|
||||
WHERE
|
||||
tt."subscribe_email" = 't' AND
|
||||
tt."musician" = 't' AND
|
||||
(#{progress_column_constraint}) AND
|
||||
(#{self.trigger_date_constraint(trigger_idx)}) AND
|
||||
tt.tidx = #{trigger_idx - 1} AND
|
||||
#{prev_date_sql}
|
||||
ORDER BY tt.id
|
||||
ASC LIMIT #{per_page}
|
||||
OFFSET #{offset}
|
||||
SQL
|
||||
users = User.find_by_sql(sql)
|
||||
block_given? ? yield(users) : fetched.concat(users)
|
||||
end
|
||||
fetched
|
||||
end
|
||||
|
||||
def deliver_batch_sets!
|
||||
self.opt_in_count = 0
|
||||
sent = 0
|
||||
3.times do |trigger_idx|
|
||||
self.fetch_recipients(trigger_idx) do |users|
|
||||
users.each do |uu|
|
||||
self.email_batch_sets << (bset = self.make_set(uu, trigger_idx))
|
||||
ProgressMailer.send_reminder(bset).deliver
|
||||
sent += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
self.sent_count = sent
|
||||
self.save
|
||||
self.did_batch_run!
|
||||
end
|
||||
|
||||
def self.send_progress_batch
|
||||
self::SUBTYPES.collect do |stype|
|
||||
ebatch = self.create
|
||||
ebatch.update_attribute(:sub_type, stype.to_s)
|
||||
ebatch
|
||||
end.each do |ebatch|
|
||||
ebatch.deliver_batch
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
module JamRuby
|
||||
class EmailBatchScheduledSessions < EmailBatchPeriodic
|
||||
|
||||
BATCH_SIZE = 500
|
||||
SINCE_DAYS = 2
|
||||
MIN_HOURS_START = 2
|
||||
|
||||
TMP_SNAP = 'tmp_scheduled_session_snapshot'
|
||||
TMP_USER = 'tmp_scheduled_session_user'
|
||||
|
||||
def self.subject
|
||||
"New sessions have been scheduled that may be a good match for you!"
|
||||
end
|
||||
|
||||
# inserts eligible sessions to temp table
|
||||
def _collect_eligible_sessions
|
||||
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS #{TMP_SNAP}")
|
||||
sql =<<SQL
|
||||
SELECT
|
||||
rs.instrument_id AS instrument_id,
|
||||
msess.id AS session_id,
|
||||
msess.user_id AS creator_id,
|
||||
users.last_jam_locidispid AS creator_score_idx
|
||||
INTO TEMP TABLE #{TMP_SNAP}
|
||||
FROM music_sessions msess
|
||||
INNER JOIN rsvp_slots AS rs ON rs.music_session_id = msess.id
|
||||
LEFT JOIN rsvp_requests_rsvp_slots AS rrrs ON rrrs.rsvp_slot_id = rs.id
|
||||
INNER JOIN users ON users.id = msess.user_id
|
||||
WHERE
|
||||
musician_access = 't' AND
|
||||
approval_required = 'f' AND
|
||||
msess.created_at > '#{time_since_last_batch(SINCE_DAYS)}' AND
|
||||
scheduled_start >= '#{Time.now() + MIN_HOURS_START.hours}' AND
|
||||
(rrrs.rsvp_slot_id IS NULL OR rrrs.chosen != 't')
|
||||
SQL
|
||||
ActiveRecord::Base.connection.execute(sql)
|
||||
end
|
||||
|
||||
def _collect_eligible_recipients
|
||||
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS #{TMP_USER}")
|
||||
# load eligible recipients into tmp table
|
||||
sql =<<SQL
|
||||
SELECT
|
||||
users.id AS user_id,
|
||||
users.last_jam_locidispid AS user_score_idx,
|
||||
tmp.session_id AS session_id,
|
||||
tmp.creator_id AS creator_id,
|
||||
tmp.creator_score_idx AS creator_score_idx
|
||||
INTO TEMP TABLE #{TMP_USER}
|
||||
FROM users
|
||||
INNER JOIN musicians_instruments AS mi ON mi.user_id = users.id
|
||||
LEFT JOIN #{TMP_SNAP} AS tmp ON tmp.instrument_id = mi.instrument_id
|
||||
WHERE
|
||||
users.musician = 't' AND
|
||||
users.subscribe_email = 't' AND
|
||||
tmp.session_id IS NOT NULL
|
||||
GROUP BY users.id, tmp.session_id, tmp.creator_id, tmp.creator_score_idx
|
||||
SQL
|
||||
ActiveRecord::Base.connection.execute(sql)
|
||||
end
|
||||
|
||||
# select recipients whose score is below minimum threshold
|
||||
def _select_scored_recipients
|
||||
sql =<<SQL
|
||||
SELECT DISTINCT user_id, scores.score AS latency
|
||||
FROM #{TMP_USER}
|
||||
INNER JOIN scores ON scores.alocidispid = #{TMP_USER}.creator_score_idx AND scores.blocidispid = #{TMP_USER}.user_score_idx
|
||||
WHERE
|
||||
scores.score < #{Score::MAX_YELLOW_LATENCY}
|
||||
SQL
|
||||
ActiveRecord::Base.connection.execute(sql)
|
||||
end
|
||||
|
||||
def fetch_recipients
|
||||
objs = []
|
||||
|
||||
# load eligible sessions into tmp table
|
||||
self._collect_eligible_sessions
|
||||
|
||||
# load eligible mail recipients into tmp table
|
||||
self._collect_eligible_recipients
|
||||
|
||||
# now just get the sessions/latency for each distinct mail recipient
|
||||
_select_scored_recipients.each do |result|
|
||||
user = User.find_by_id(result['user_id'])
|
||||
|
||||
sql = "SELECT session_id FROM #{TMP_USER} WHERE user_id = '#{user.id}'"
|
||||
sessions = ActiveRecord::Base.connection.execute(sql).collect do |rr|
|
||||
msess = MusicSession.where(['id = ?',rr['session_id']])
|
||||
.limit(1)
|
||||
.includes([:genre, :creator])
|
||||
.first
|
||||
msess.latency_store = result['latency']
|
||||
msess
|
||||
end
|
||||
block_given? ? yield(user, sessions) : objs << [user, sessions]
|
||||
end
|
||||
objs
|
||||
end
|
||||
|
||||
def deliver_batch_sets!
|
||||
self.opt_in_count = 0
|
||||
sent = 0
|
||||
self.fetch_recipients do |receiver, sessions_and_latency|
|
||||
self.opt_in_count += 1
|
||||
sent += 1
|
||||
bset = EmailBatchSet.scheduled_session_set(self, receiver, sessions_and_latency)
|
||||
UserMailer.scheduled_session_daily(receiver, sessions_and_latency).deliver
|
||||
end
|
||||
self.sent_count = sent
|
||||
self.save
|
||||
self.did_batch_run!
|
||||
end
|
||||
|
||||
def self.send_daily_session_batch
|
||||
oo = self.create
|
||||
oo..deliver_batch
|
||||
oo
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -3,21 +3,85 @@ module JamRuby
|
|||
self.table_name = "email_batch_sets"
|
||||
|
||||
belongs_to :email_batch, :class_name => 'JamRuby::EmailBatch'
|
||||
belongs_to :user, :class_name => 'JamRuby::User'
|
||||
|
||||
def self.deliver_set(batch_id, user_ids)
|
||||
# def self.load_set(batch, 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!
|
||||
# bset
|
||||
# end
|
||||
|
||||
def self.sent_email(batch, user_id)
|
||||
bset = self.new
|
||||
bset.email_batch_id = batch_id
|
||||
bset.user_ids = user_ids.join(',')
|
||||
bset.email_batch_id = batch.id
|
||||
bset.user_id = user_id
|
||||
bset.started_at = Time.now
|
||||
bset.batch_count = user_ids.size
|
||||
bset.batch_count = 1
|
||||
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
|
||||
|
||||
def self.progress_set(batch, user, trigger_idx)
|
||||
bset = self.new
|
||||
bset.email_batch = batch
|
||||
bset.user = user
|
||||
bset.started_at = Time.now
|
||||
bset.batch_count = 1
|
||||
bset.trigger_index = trigger_idx
|
||||
bset.sub_type = batch.sub_type
|
||||
bset.save!
|
||||
bset
|
||||
end
|
||||
|
||||
def self.scheduled_session_set(batch, receiver, sessions)
|
||||
bset = self.new
|
||||
bset.email_batch = batch
|
||||
bset.user = receiver
|
||||
bset.user_ids = sessions.map(&:id).join(',')
|
||||
bset.started_at = Time.now
|
||||
bset.batch_count = 1
|
||||
bset.save!
|
||||
bset
|
||||
end
|
||||
|
||||
def self.new_musician_set(batch, receiver, new_musicians)
|
||||
bset = self.new
|
||||
bset.email_batch = batch
|
||||
bset.user = receiver
|
||||
bset.user_ids = new_musicians.map(&:id).join(',')
|
||||
bset.started_at = Time.now
|
||||
bset.batch_count = 1
|
||||
bset.save!
|
||||
bset
|
||||
end
|
||||
|
||||
def subject
|
||||
unless sub_type.blank?
|
||||
return EmailBatchProgression.subject(self.sub_type.to_sym)
|
||||
end
|
||||
''
|
||||
end
|
||||
|
||||
def title
|
||||
unless sub_type.blank?
|
||||
return EmailBatchProgression.title(self.sub_type.to_sym)
|
||||
end
|
||||
''
|
||||
end
|
||||
|
||||
def previous_trigger_date
|
||||
return nil if 0 == self.trigger_index.to_i || self.user_id.nil?
|
||||
self.class
|
||||
.where(['email_batch__id = ? AND user_id = ? AND sub_type = ? AND trigger_index = ?',
|
||||
self.email_batch_id, self.user_id, self.sub_type, self.trigger_index - 1])
|
||||
.pluck(:created_at)
|
||||
.limit(1)
|
||||
.first
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
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
|
||||
|
|
@ -3,15 +3,15 @@ module JamRuby
|
|||
|
||||
self.table_name = "connections"
|
||||
|
||||
def self.get_work(mylocidispid)
|
||||
list = self.get_work_list(mylocidispid)
|
||||
def self.get_work(mylocidispid, myaddr)
|
||||
list = self.get_work_list(mylocidispid, myaddr)
|
||||
return nil if list.nil?
|
||||
return nil if list.length == 0
|
||||
return list[0]
|
||||
end
|
||||
|
||||
def self.get_work_list(mylocidispid)
|
||||
r = GetWork.select(:client_id).find_by_sql("select get_work(#{mylocidispid}) as client_id")
|
||||
def self.get_work_list(mylocidispid, myaddr)
|
||||
r = GetWork.select(:client_id).find_by_sql("select get_work(#{mylocidispid}, #{myaddr}) as client_id")
|
||||
#puts("r = #{r}")
|
||||
a = r.map {|i| i.client_id}
|
||||
#puts("a = #{a}")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
module JamRuby
|
||||
class LatencyTester < ActiveRecord::Base
|
||||
|
||||
belongs_to :connection, class_name: 'JamRuby::Connection', foreign_key: :client_id, primary_key: :client_id
|
||||
|
||||
def heartbeat_interval_client
|
||||
nil
|
||||
end
|
||||
|
||||
def connection_expire_time_client
|
||||
nil
|
||||
end
|
||||
|
||||
def self.select_latency_tester
|
||||
LatencyTester.joins(:connection).first!
|
||||
end
|
||||
|
||||
# we need to find that latency_tester with the specified connection (and reconnect it)
|
||||
# or bootstrap a new latency_tester
|
||||
def self.connect(options)
|
||||
client_id = options[:client_id]
|
||||
ip_address = options[:ip_address]
|
||||
connection_stale_time = options[:connection_stale_time]
|
||||
connection_expire_time = options[:connection_expire_time]
|
||||
# first try to find a LatencyTester with that client_id
|
||||
latency_tester = LatencyTester.find_by_client_id(client_id)
|
||||
|
||||
if latency_tester
|
||||
if latency_tester.connection
|
||||
connection = latency_tester.connection
|
||||
else
|
||||
connection = Connection.new
|
||||
connection.client_id = client_id
|
||||
latency_tester.connection = connection
|
||||
end
|
||||
else
|
||||
latency_tester = LatencyTester.new
|
||||
latency_tester.client_id = client_id
|
||||
unless latency_tester.save
|
||||
return latency_tester
|
||||
end
|
||||
connection = Connection.new
|
||||
connection.latency_tester = latency_tester
|
||||
connection.client_id = client_id
|
||||
end
|
||||
|
||||
if ip_address and !ip_address.eql?(connection.ip_address)
|
||||
# locidispid stuff
|
||||
addr = JamIsp.ip_to_num(ip_address)
|
||||
isp = JamIsp.lookup(addr)
|
||||
if isp.nil? then ispid = 0 else ispid = isp.coid end
|
||||
block = GeoIpBlocks.lookup(addr)
|
||||
if block.nil? then locid = 0 else locid = block.locid end
|
||||
location = GeoIpLocations.lookup(locid)
|
||||
if location.nil?
|
||||
# todo what's a better default location?
|
||||
locidispid = 0
|
||||
else
|
||||
locidispid = locid*1000000+ispid
|
||||
end
|
||||
|
||||
connection.ip_address = ip_address
|
||||
connection.addr = addr
|
||||
connection.locidispid = locidispid
|
||||
end
|
||||
|
||||
connection.client_type = 'latency_tester'
|
||||
connection.aasm_state = Connection::CONNECT_STATE.to_s
|
||||
connection.stale_time = connection_stale_time
|
||||
connection.expire_time = connection_expire_time
|
||||
connection.as_musician = false
|
||||
unless connection.save
|
||||
return connection
|
||||
end
|
||||
|
||||
return latency_tester
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -88,35 +88,42 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
end
|
||||
User.find_each { |usr| usr.update_lat_lng }
|
||||
# User.find_each { |usr| usr.update_lat_lng }
|
||||
Band.find_each { |bnd| bnd.update_lat_lng }
|
||||
end
|
||||
|
||||
def self.where_latlng(relation, params, current_user=nil)
|
||||
if 0 < (distance = params[:distance].to_i)
|
||||
latlng = []
|
||||
if location_city = params[:city]
|
||||
if geo = self.where(:city => params[:city]).limit(1).first
|
||||
# this is only valid to call when relation is about bands
|
||||
distance = params[:distance].to_i
|
||||
if distance > 0
|
||||
latlng = nil
|
||||
location_city = params[:city]
|
||||
location_state = params[:state]
|
||||
location_country = params[:country]
|
||||
remote_ip = params[:remote_ip]
|
||||
|
||||
if location_city and location_state and location_country
|
||||
geo = self.where(city: location_city, region: location_state, country: location_country).limit(1).first
|
||||
if geo and geo.lat and geo.lng and (geo.lat != 0 or geo.lng != 0)
|
||||
# it isn't reasonable for both to be 0...
|
||||
latlng = [geo.lat, geo.lng]
|
||||
end
|
||||
elsif current_user
|
||||
if current_user.lat.nil? || current_user.lng.nil?
|
||||
if params[:remote_ip] && (geo = self.ip_lookup(params[:remote_ip]))
|
||||
geo.lat = nil if geo.lat = 0
|
||||
geo.lng = nil if geo.lng = 0
|
||||
latlng = [geo.lat, geo.lng] if geo.lat && geo.lng
|
||||
end
|
||||
else
|
||||
latlng = [current_user.lat, current_user.lng]
|
||||
elsif current_user and current_user.locidispid and current_user.locidispid != 0
|
||||
location = GeoIpLocations.lookup(current_user.locidispid/1000000)
|
||||
if location and location.latitude and location.longitude and (location.latitude != 0 or location.longitude != 0)
|
||||
# it isn't reasonable for both to be 0...
|
||||
latlng = [location.latitude, location.longitude]
|
||||
end
|
||||
elsif remote_ip
|
||||
geo = self.ip_lookup(remote_ip)
|
||||
if geo and geo.lat and geo.lng and (geo.lat != 0 or geo.lng != 0)
|
||||
# it isn't reasonable for both to be 0...
|
||||
latlng = [geo.lat, geo.lng]
|
||||
end
|
||||
elsif params[:remote_ip] && (geo = self.ip_lookup(params[:remote_ip]))
|
||||
geo.lat = nil if geo.lat = 0
|
||||
geo.lng = nil if geo.lng = 0
|
||||
latlng = [geo.lat, geo.lng] if geo.lat && geo.lng
|
||||
end
|
||||
if latlng.present?
|
||||
relation = relation.where(['lat IS NOT NULL AND lng IS NOT NULL'])
|
||||
.within(distance, :origin => latlng)
|
||||
|
||||
if latlng
|
||||
relation = relation.where(['lat IS NOT NULL AND lng IS NOT NULL']).within(distance, origin: latlng)
|
||||
end
|
||||
end
|
||||
relation
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ module JamRuby
|
|||
|
||||
attr_accessor :legal_terms, :recurring_mode, :language_description, :scheduled_start_time, :access_description
|
||||
|
||||
# used for temporary data store of latency between creator and some other user
|
||||
attr_accessor :latency_store
|
||||
|
||||
self.table_name = "music_sessions"
|
||||
|
||||
self.primary_key = 'id'
|
||||
|
|
@ -294,7 +297,17 @@ module JamRuby
|
|||
end
|
||||
|
||||
def language_description
|
||||
ISO_639.find_by_code(self.language).english_name
|
||||
if self.language.blank?
|
||||
self.language = "en"
|
||||
end
|
||||
|
||||
iso639Details = ISO_639.find_by_code(self.language)
|
||||
|
||||
unless iso639Details.blank?
|
||||
return iso639Details.english_name
|
||||
else
|
||||
return "English"
|
||||
end
|
||||
end
|
||||
|
||||
def scheduled_start_time
|
||||
|
|
|
|||
|
|
@ -712,7 +712,7 @@ module JamRuby
|
|||
@@mq_router.publish_to_user(target_user.id, msg)
|
||||
|
||||
begin
|
||||
UserMailer.send_scheduled_session_rsvp_cancelled(target_user.email, notification_msg, music_session).deliver
|
||||
UserMailer.scheduled_session_rsvp_cancelled(target_user.email, notification_msg, music_session).deliver
|
||||
rescue => e
|
||||
@@log.error("Unable to send send_scheduled_session_rsvp_cancelled email to offline user #{target_user.email} #{e}")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,47 +7,50 @@ module JamRuby
|
|||
self.where(countrycode: country).order('regionname asc').all
|
||||
end
|
||||
|
||||
def self.import_from_xx_region(countrycode, file)
|
||||
def self.import_from_region_codes(file)
|
||||
|
||||
# File xx_region.csv
|
||||
# File region_codes.csv
|
||||
# Format:
|
||||
# region,regionname
|
||||
# countrycode,region,regionname
|
||||
|
||||
# what this does is not replace the contents of the table, but rather update the specifies rows with the names.
|
||||
# any rows not specified are left alone. the parameter countrycode denote the country of the region (when uppercased)
|
||||
|
||||
raise "countrycode (#{MaxMindIsp.quote_value(countrycode)}) is missing or invalid (it must be two characters)" unless countrycode and countrycode.length == 2
|
||||
countrycode = countrycode.upcase
|
||||
# what this does is replace the contents of the table with the new data.
|
||||
|
||||
self.transaction do
|
||||
self.connection.execute "update #{self.table_name} set regionname = region where countrycode = #{MaxMindIsp.quote_value(countrycode)}"
|
||||
self.connection.execute "delete from #{self.table_name}"
|
||||
|
||||
File.open(file, 'r:ISO-8859-1') do |io|
|
||||
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0
|
||||
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : -1
|
||||
count = 0
|
||||
|
||||
ncols = 2
|
||||
errors = 0
|
||||
ncols = 3
|
||||
|
||||
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
|
||||
csv.each do |row|
|
||||
raise "file does not have expected number of columns (#{ncols}): #{row.length}" unless row.length == ncols
|
||||
|
||||
region = row[0]
|
||||
regionname = row[1]
|
||||
countrycode = row[0]
|
||||
region = row[1]
|
||||
regionname = row[2]
|
||||
|
||||
stmt = "UPDATE #{self.table_name} SET regionname = #{MaxMindIsp.quote_value(regionname)} WHERE countrycode = #{MaxMindIsp.quote_value(countrycode)} AND region = #{MaxMindIsp.quote_value(region)}"
|
||||
self.connection.execute stmt
|
||||
count += 1
|
||||
if countrycode.length == 2 and region.length == 2 and regionname.length >= 2 and regionname.length <= 64
|
||||
|
||||
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level < Logger::INFO
|
||||
ActiveRecord::Base.logger.debug "... logging updates to #{self.table_name} suspended ..."
|
||||
ActiveRecord::Base.logger.level = Logger::INFO
|
||||
stmt = "INSERT INTO #{self.table_name} (countrycode, region, regionname) VALUES (#{self.connection.quote(countrycode)}, #{self.connection.quote(region)}, #{self.connection.quote(regionname)})"
|
||||
self.connection.execute stmt
|
||||
count += 1
|
||||
|
||||
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level < Logger::INFO
|
||||
ActiveRecord::Base.logger.debug "... logging updates to #{self.table_name} suspended ..."
|
||||
ActiveRecord::Base.logger.level = Logger::INFO
|
||||
end
|
||||
else
|
||||
ActiveRecord::Base.logger.warn("bogus region_codes record '#{countrycode}', '#{region}', '#{regionname}'") if ActiveRecord::Base.logger
|
||||
errors += 1
|
||||
end
|
||||
end
|
||||
|
||||
if ActiveRecord::Base.logger
|
||||
ActiveRecord::Base.logger.level = saved_level
|
||||
ActiveRecord::Base.logger.debug "updated #{count} records in #{self.table_name}"
|
||||
ActiveRecord::Base.logger.debug "inserted #{count} records into #{self.table_name}, #{errors} errors"
|
||||
end
|
||||
end # file
|
||||
end # transaction
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ module JamRuby
|
|||
# verify invitation exists for this user and session
|
||||
invitation = Invitation.where("music_session_id = ? AND receiver_id = ?", music_session.id, user.id)
|
||||
|
||||
if invitation.blank?
|
||||
raise PermissionError, "Only a session invitee can create an RSVP."
|
||||
if invitation.blank? && !music_session.open_rsvps
|
||||
raise PermissionError, "Only a session invitee can create an RSVP for this session."
|
||||
end
|
||||
|
||||
# verify slot IDs exist in request
|
||||
|
|
@ -56,6 +56,7 @@ module JamRuby
|
|||
@rsvp.user = user
|
||||
|
||||
slot_ids = params[:rsvp_slots]
|
||||
|
||||
instruments = []
|
||||
|
||||
# for each slot requested, do the following:
|
||||
|
|
@ -204,9 +205,9 @@ module JamRuby
|
|||
rsvp_request.canceled = true
|
||||
rsvp_request.cancel_all = false
|
||||
|
||||
when 'no'
|
||||
rsvp_request.canceled = false
|
||||
rsvp_request.cancel_all = false
|
||||
# when 'no'
|
||||
# rsvp_request.canceled = false
|
||||
# rsvp_request.cancel_all = false
|
||||
|
||||
when 'all'
|
||||
rsvp_request.canceled = true
|
||||
|
|
|
|||
|
|
@ -3,15 +3,19 @@ require 'ipaddr'
|
|||
module JamRuby
|
||||
class Score < ActiveRecord::Base
|
||||
|
||||
MAX_YELLOW_LATENCY = 40
|
||||
|
||||
self.table_name = 'scores'
|
||||
|
||||
attr_accessible :alocidispid, :anodeid, :aaddr, :blocidispid, :bnodeid, :baddr, :score, :score_dt, :scorer
|
||||
attr_accessible :alocidispid, :anodeid, :aaddr, :blocidispid, :bnodeid, :baddr, :score, :score_dt, :scorer, :scoring_data
|
||||
|
||||
default_scope order('score_dt desc')
|
||||
|
||||
def self.createx(alocidispid, anodeid, aaddr, blocidispid, bnodeid, baddr, score, score_dt)
|
||||
def self.createx(alocidispid, anodeid, aaddr, blocidispid, bnodeid, baddr, score, score_dt=nil, score_data=nil)
|
||||
score_dt = Time.new.utc if score_dt.nil?
|
||||
Score.create(alocidispid: alocidispid, anodeid: anodeid, aaddr: aaddr, blocidispid: blocidispid, bnodeid: bnodeid, baddr: baddr, score: score, scorer: 0, score_dt: score_dt)
|
||||
score = score.ceil
|
||||
raise "score must be positive" if score <= 0
|
||||
Score.create(alocidispid: alocidispid, anodeid: anodeid, aaddr: aaddr, blocidispid: blocidispid, bnodeid: bnodeid, baddr: baddr, score: score, scorer: 0, score_dt: score_dt, scoring_data: score_data)
|
||||
Score.create(alocidispid: blocidispid, anodeid: bnodeid, aaddr: baddr, blocidispid: alocidispid, bnodeid: anodeid, baddr: aaddr, score: score, scorer: 1, score_dt: score_dt) if alocidispid != blocidispid
|
||||
end
|
||||
|
||||
|
|
@ -25,5 +29,10 @@ module JamRuby
|
|||
return -1 if s.nil?
|
||||
return s.score
|
||||
end
|
||||
|
||||
def self.score_conns(c1, c2, score)
|
||||
self.createx(c1.locidispid, c1.client_id, c1.addr, c2.locidispid, c2.client_id, c2.addr, score)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -103,6 +103,18 @@ module JamRuby
|
|||
|
||||
DISTANCE_OPTS = B_DISTANCE_OPTS = M_DISTANCE_OPTS = [['Any', 0], [1000.to_s, 1000], [500.to_s, 500], [250.to_s, 250], [100.to_s, 100], [50.to_s, 50], [25.to_s, 25]]
|
||||
|
||||
# the values for score ranges are raw roundtrip scores. david often talks of one way scores (<= 20 is good), but
|
||||
# the client reports scores as roundtrip and the server uses those values throughout
|
||||
GOOD_SCORE = '.-40'
|
||||
MODERATE_SCORE = '40-80'
|
||||
POOR_SCORE = '80-120'
|
||||
UNACCEPTABLE_SCORE = '120-.'
|
||||
SCORED_SCORE = '.-.' # does not appear in menu choices
|
||||
TEST_SCORE = '.-60' # does not appear in menu choices
|
||||
ANY_SCORE = ''
|
||||
M_SCORE_OPTS = [['Any', ANY_SCORE], ['Good', GOOD_SCORE], ['Moderate', MODERATE_SCORE], ['Poor', POOR_SCORE], ['Unacceptable', UNACCEPTABLE_SCORE]]
|
||||
M_SCORE_DEFAULT = ANY_SCORE
|
||||
|
||||
F_SORT_RECENT = ['Most Recent', :date]
|
||||
F_SORT_OLDEST = ['Most Liked', :likes]
|
||||
F_SORT_LENGTH = ['Most Played', :plays]
|
||||
|
|
@ -120,44 +132,137 @@ module JamRuby
|
|||
ordering.blank? ? keys[0] : keys.detect { |oo| oo.to_s == ordering }
|
||||
end
|
||||
|
||||
def self.musician_filter(params={}, current_user=nil)
|
||||
rel = User.musicians
|
||||
# produce a list of musicians (users where musician is true)
|
||||
# params:
|
||||
# instrument - instrument to search for or blank
|
||||
# score_limit - a range specification for score, see M_SCORE_OPTS above.
|
||||
# handled by relation_pagination:
|
||||
# page - page number to fetch (origin 1)
|
||||
# per_page - number of entries per page
|
||||
# handled by order_param:
|
||||
# orderby - what sort of search, also defines order (followed, plays, playing)
|
||||
# previously handled by where_latlng:
|
||||
# distance - defunct!
|
||||
# city - defunct!
|
||||
# remote_ip - defunct!
|
||||
def self.musician_filter(params={}, user=nil, conn=nil)
|
||||
# puts "================ params #{params.inspect}"
|
||||
# puts "================ user #{user.inspect}"
|
||||
# puts "================ conn #{conn.inspect}"
|
||||
|
||||
rel = User.musicians_geocoded
|
||||
rel = rel.select('users.*')
|
||||
rel = rel.group('users.id')
|
||||
|
||||
unless (instrument = params[:instrument]).blank?
|
||||
rel = rel.joins("RIGHT JOIN musicians_instruments AS minst ON minst.user_id = users.id")
|
||||
.where(['minst.instrument_id = ? AND users.id IS NOT NULL', instrument])
|
||||
rel = rel.joins("inner JOIN musicians_instruments AS minst ON minst.user_id = users.id")
|
||||
.where(['minst.instrument_id = ?', instrument])
|
||||
end
|
||||
|
||||
rel = MaxMindGeo.where_latlng(rel, params, current_user)
|
||||
# to find appropriate musicians we need to join users with scores to get to those with no scores or bad scores
|
||||
# weeded out
|
||||
|
||||
sel_str = 'users.*'
|
||||
case ordering = self.order_param(params)
|
||||
when :plays # FIXME: double counting?
|
||||
sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}"
|
||||
rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.user_id = users.id")
|
||||
.joins("LEFT JOIN recordings AS records ON records.owner_id = users.id")
|
||||
.group("users.id")
|
||||
.order("play_count DESC, users.created_at DESC")
|
||||
when :followed
|
||||
sel_str = "COUNT(follows) AS search_follow_count, #{sel_str}"
|
||||
rel = rel.joins("LEFT JOIN follows ON follows.followable_id = users.id")
|
||||
.group("users.id")
|
||||
.order("COUNT(follows) DESC, users.created_at DESC")
|
||||
when :playing
|
||||
rel = rel.joins("LEFT JOIN connections ON connections.user_id = users.id")
|
||||
.where(['connections.music_session_id IS NOT NULL AND connections.aasm_state != ?',
|
||||
'expired'])
|
||||
.order("users.created_at DESC")
|
||||
# filter on scores using selections from params
|
||||
# see M_SCORE_OPTS
|
||||
score_limit = TEST_SCORE
|
||||
l = params[:score_limit]
|
||||
unless l.nil?
|
||||
score_limit = l
|
||||
end
|
||||
|
||||
rel = rel.select(sel_str)
|
||||
# puts "================ score_limit #{score_limit}"
|
||||
|
||||
locidispid = ((conn and conn.client_type == 'client') ? conn.locidispid : ((user and user.musician) ? user.last_jam_locidispid : nil))
|
||||
|
||||
# puts "================ locidispid #{locidispid}"
|
||||
|
||||
unless locidispid.nil?
|
||||
# score_join of left allows for null scores, whereas score_join of inner requires a score however good or bad
|
||||
# this is ANY_SCORE:
|
||||
score_join = 'left' # or 'inner'
|
||||
score_min = nil
|
||||
score_max = nil
|
||||
case score_limit
|
||||
when GOOD_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = nil
|
||||
score_max = 40
|
||||
when MODERATE_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = 40
|
||||
score_max = 80
|
||||
when POOR_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = 80
|
||||
score_max = 120
|
||||
when UNACCEPTABLE_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = 120
|
||||
score_max = nil
|
||||
when SCORED_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = nil
|
||||
score_max = nil
|
||||
when TEST_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = nil
|
||||
score_max = 60
|
||||
when ANY_SCORE
|
||||
# the default of ANY setup above applies
|
||||
else
|
||||
# the default of ANY setup above applies
|
||||
end
|
||||
|
||||
rel = rel.joins("#{score_join} join scores on scores.alocidispid = users.last_jam_locidispid")
|
||||
.where(['scores.blocidispid = ?', locidispid])
|
||||
|
||||
rel = rel.where(['scores.score > ?', score_min]) unless score_min.nil?
|
||||
rel = rel.where(['scores.score <= ?', score_max]) unless score_max.nil?
|
||||
|
||||
rel = rel.select('scores.score')
|
||||
rel = rel.group('scores.score')
|
||||
end
|
||||
|
||||
ordering = self.order_param(params)
|
||||
# puts "================ ordering #{ordering}"
|
||||
case ordering
|
||||
when :plays # FIXME: double counting?
|
||||
# sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}"
|
||||
rel = rel.select('COUNT(records.id)+COUNT(sessions.id) AS search_play_count')
|
||||
rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.user_id = users.id")
|
||||
rel = rel.joins("LEFT JOIN recordings AS records ON records.owner_id = users.id")
|
||||
rel = rel.order("search_play_count DESC")
|
||||
when :followed
|
||||
rel = rel.joins('left outer join follows on follows.followable_id = users.id')
|
||||
rel = rel.select('count(follows.user_id) as search_follow_count')
|
||||
rel = rel.order('search_follow_count DESC')
|
||||
when :playing
|
||||
rel = rel.joins("inner JOIN connections ON connections.user_id = users.id")
|
||||
rel = rel.where(['connections.aasm_state != ?', 'expired'])
|
||||
end
|
||||
|
||||
unless locidispid.nil?
|
||||
rel = rel.order('scores.score ASC NULLS LAST')
|
||||
end
|
||||
|
||||
rel = rel.order('users.created_at DESC')
|
||||
|
||||
# rel = rel.select(sel_str)
|
||||
rel, page = self.relation_pagination(rel, params)
|
||||
rel = rel.includes([:instruments, :followings, :friends])
|
||||
|
||||
# puts "======================== sql #{rel.to_sql}"
|
||||
objs = rel.all
|
||||
# puts "======================== objs #{objs.inspect}"
|
||||
# if objs.length > 0
|
||||
# puts "======================== attributes #{objs[0].attributes}"
|
||||
# puts "======================== score #{objs[0].score}"
|
||||
# end
|
||||
|
||||
srch = Search.new
|
||||
srch.search_type = :musicians_filter
|
||||
srch.page_num, srch.page_count = page, objs.total_pages
|
||||
srch.musician_results_for_user(objs, current_user)
|
||||
srch.musician_results_for_user(objs, user)
|
||||
end
|
||||
|
||||
def self.relation_pagination(rel, params)
|
||||
|
|
@ -273,13 +378,28 @@ module JamRuby
|
|||
false
|
||||
end
|
||||
|
||||
def self.new_musicians(usr, since_date=Time.now - 1.week, max_count=50, radius=M_MILES_DEFAULT)
|
||||
rel = User.musicians
|
||||
def self.new_musicians(usr, since_date)
|
||||
# this attempts to find interesting musicians to tell another musician about where interesting
|
||||
# is "has a good score and was created recently"
|
||||
# we're sort of depending upon usr being a musicians_geocoded as well...
|
||||
# this appears to only be called from EmailBatchNewMusician#deliver_batch_sets! which is
|
||||
# an offline process and thus uses the last jam location as "home base"
|
||||
|
||||
locidispid = usr.last_jam_locidispid
|
||||
score_limit = 60
|
||||
limit = 50
|
||||
|
||||
rel = User.musicians_geocoded
|
||||
.where(['created_at >= ? AND users.id != ?', since_date, usr.id])
|
||||
.within(radius, :origin => [usr.lat, usr.lng])
|
||||
.order('created_at DESC')
|
||||
.limit(max_count)
|
||||
.joins('inner join scores on users.last_jam_locidispid = scores.alocidispid')
|
||||
.where(['scores.blocidispid = ?', locidispid])
|
||||
.where(['scores.score <= ?', score_limit])
|
||||
.order('scores.score') # best scores first
|
||||
.order('users.created_at DESC') # then most recent
|
||||
.limit(limit)
|
||||
|
||||
objs = rel.all.to_a
|
||||
|
||||
if block_given?
|
||||
yield(objs) if 0 < objs.count
|
||||
else
|
||||
|
|
|
|||
|
|
@ -12,13 +12,16 @@ module JamRuby
|
|||
include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable)
|
||||
acts_as_mappable
|
||||
|
||||
after_save :check_lat_lng
|
||||
# after_save :check_lat_lng
|
||||
|
||||
attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection, :lat, :lng
|
||||
attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection
|
||||
|
||||
# updating_password corresponds to a lost_password
|
||||
attr_accessor :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field, :mods_json
|
||||
|
||||
# used for temporary data store of latency between self and some other user
|
||||
attr_accessor :latency_store
|
||||
|
||||
belongs_to :icecast_server_group, class_name: "JamRuby::IcecastServerGroup", inverse_of: :users, foreign_key: 'icecast_server_group_id'
|
||||
|
||||
# authorizations (for facebook, etc -- omniauth)
|
||||
|
|
@ -140,7 +143,7 @@ module JamRuby
|
|||
|
||||
scope :musicians, where(:musician => true)
|
||||
scope :fans, where(:musician => false)
|
||||
scope :geocoded_users, where(['lat IS NOT NULL AND lng IS NOT NULL'])
|
||||
scope :geocoded_users, where(User.arel_table[:last_jam_locidispid].not_eq(nil))
|
||||
scope :musicians_geocoded, musicians.geocoded_users
|
||||
scope :email_opt_in, where(:subscribe_email => true)
|
||||
|
||||
|
|
@ -221,11 +224,11 @@ module JamRuby
|
|||
end
|
||||
|
||||
def location= location_hash
|
||||
unless location_hash.blank?
|
||||
unless location_hash.nil?
|
||||
self.city = location_hash[:city]
|
||||
self.state = location_hash[:state]
|
||||
self.country = location_hash[:country]
|
||||
end if self.city.blank?
|
||||
end
|
||||
end
|
||||
|
||||
def musician?
|
||||
|
|
@ -290,6 +293,11 @@ module JamRuby
|
|||
self.music_sessions.size
|
||||
end
|
||||
|
||||
def joined_score
|
||||
nil unless has_attribute?(:score)
|
||||
read_attribute(:score).to_i
|
||||
end
|
||||
|
||||
# mods comes back as text; so give ourselves a parsed version
|
||||
def mods_json
|
||||
@mods_json ||= mods ? JSON.parse(mods, symbolize_names: true) : {}
|
||||
|
|
@ -776,12 +784,20 @@ module JamRuby
|
|||
end
|
||||
|
||||
user.admin = false
|
||||
user.city = location[:city]
|
||||
user.state = location[:state]
|
||||
user.country = location[:country]
|
||||
user.location = location
|
||||
# user.city = location[:city]
|
||||
# user.state = location[:state]
|
||||
# user.country = location[:country]
|
||||
user.birth_date = birth_date
|
||||
|
||||
if user.musician # only update instruments if the user is a musician
|
||||
if musician
|
||||
user.last_jam_addr = location[:addr]
|
||||
user.last_jam_locidispid = location[:locidispid]
|
||||
user.last_jam_updated_reason = 'r'
|
||||
user.last_jam_updated_at = Time.now
|
||||
end
|
||||
|
||||
if musician # only update instruments if the user is a musician
|
||||
unless instruments.nil?
|
||||
instruments.each do |musician_instrument_param|
|
||||
instrument = Instrument.find(musician_instrument_param[:instrument_id])
|
||||
|
|
@ -1095,55 +1111,64 @@ module JamRuby
|
|||
!self.city.blank? && (!self.state.blank? || !self.country.blank?)
|
||||
end
|
||||
|
||||
def check_lat_lng
|
||||
if (city_changed? || state_changed? || country_changed?) && !lat_changed? && !lng_changed?
|
||||
update_lat_lng
|
||||
end
|
||||
end
|
||||
# def check_lat_lng
|
||||
# if (city_changed? || state_changed? || country_changed?) && !lat_changed? && !lng_changed?
|
||||
# update_lat_lng
|
||||
# end
|
||||
# end
|
||||
|
||||
def update_lat_lng(ip_addy=nil)
|
||||
if provides_location? # ip_addy argument ignored in this case
|
||||
return false unless ip_addy.nil? # do nothing if attempting to set latlng from an ip address
|
||||
query = { :city => self.city }
|
||||
query[:region] = self.state unless self.state.blank?
|
||||
query[:country] = self.country unless self.country.blank?
|
||||
if geo = MaxMindGeo.where(query).limit(1).first
|
||||
geo.lat = nil if geo.lat = 0
|
||||
geo.lng = nil if geo.lng = 0
|
||||
if geo.lat && geo.lng && (self.lat != geo.lat || self.lng != geo.lng)
|
||||
self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
|
||||
return true
|
||||
end
|
||||
end
|
||||
elsif ip_addy
|
||||
if geo = MaxMindGeo.ip_lookup(ip_addy)
|
||||
geo.lat = nil if geo.lat = 0
|
||||
geo.lng = nil if geo.lng = 0
|
||||
if self.lat != geo.lat || self.lng != geo.lng
|
||||
self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
|
||||
return true
|
||||
end
|
||||
end
|
||||
else
|
||||
if self.lat || self.lng
|
||||
self.update_attributes({ :lat => nil, :lng => nil })
|
||||
return true
|
||||
end
|
||||
end
|
||||
false
|
||||
end
|
||||
# def update_lat_lng(ip_addy=nil)
|
||||
# if provides_location? # ip_addy argument ignored in this case
|
||||
# return false unless ip_addy.nil? # do nothing if attempting to set latlng from an ip address
|
||||
# query = { :city => self.city }
|
||||
# query[:region] = self.state unless self.state.blank?
|
||||
# query[:country] = self.country unless self.country.blank?
|
||||
# if geo = MaxMindGeo.where(query).limit(1).first
|
||||
# geo.lat = nil if geo.lat = 0
|
||||
# geo.lng = nil if geo.lng = 0
|
||||
# if geo.lat && geo.lng && (self.lat != geo.lat || self.lng != geo.lng)
|
||||
# self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
|
||||
# return true
|
||||
# end
|
||||
# end
|
||||
# elsif ip_addy
|
||||
# if geo = MaxMindGeo.ip_lookup(ip_addy)
|
||||
# geo.lat = nil if geo.lat = 0
|
||||
# geo.lng = nil if geo.lng = 0
|
||||
# if self.lat != geo.lat || self.lng != geo.lng
|
||||
# self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
|
||||
# return true
|
||||
# end
|
||||
# end
|
||||
# else
|
||||
# if self.lat || self.lng
|
||||
# self.update_attributes({ :lat => nil, :lng => nil })
|
||||
# return true
|
||||
# end
|
||||
# end
|
||||
# false
|
||||
# end
|
||||
|
||||
def current_city(ip_addy=nil)
|
||||
unless self.city
|
||||
if self.lat && self.lng
|
||||
# todo this is really dumb, you can't compare lat lng for equality
|
||||
return MaxMindGeo.where(['lat = ? AND lng = ?',self.lat,self.lng]).limit(1).first.try(:city)
|
||||
elsif ip_addy
|
||||
return MaxMindGeo.ip_lookup(ip_addy).try(:city)
|
||||
end
|
||||
else
|
||||
return self.city
|
||||
end
|
||||
# unless self.city
|
||||
# if self.lat && self.lng
|
||||
# # todo this is really dumb, you can't compare lat lng for equality
|
||||
# return MaxMindGeo.where(['lat = ? AND lng = ?',self.lat,self.lng]).limit(1).first.try(:city)
|
||||
# elsif ip_addy
|
||||
# return MaxMindGeo.ip_lookup(ip_addy).try(:city)
|
||||
# end
|
||||
# else
|
||||
# return self.city
|
||||
# end
|
||||
self.city
|
||||
end
|
||||
|
||||
def update_addr_loc(connection, reason)
|
||||
self.last_jam_addr = connection.addr
|
||||
self.last_jam_locidispid = connection.locidispid
|
||||
self.last_jam_updated_reason = reason
|
||||
self.last_jam_updated_at = Time.now
|
||||
self.save
|
||||
end
|
||||
|
||||
def top_followings
|
||||
|
|
@ -1153,9 +1178,15 @@ module JamRuby
|
|||
.limit(3)
|
||||
end
|
||||
|
||||
def nearest_musicians
|
||||
# FIXME: replace with Scotts scoring query
|
||||
Search.new_musicians(self, Time.now - 1.week)
|
||||
end
|
||||
|
||||
def self.deliver_new_musician_notifications(since_date=nil)
|
||||
since_date ||= Time.now-1.week
|
||||
self.geocoded_users.find_each do |usr|
|
||||
# return musicians with locidispid not null
|
||||
self.musicians_geocoded.find_each do |usr|
|
||||
Search.new_musicians(usr, since_date) do |new_nearby|
|
||||
UserMailer.new_musicians(usr, new_nearby).deliver
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
require 'resque'
|
||||
require 'resque-lonely_job'
|
||||
|
||||
module JamRuby
|
||||
class BatchEmailJob
|
||||
extend Resque::Plugins::LonelyJob
|
||||
|
||||
@@log = Logging.logger[BatchEmailJob]
|
||||
|
||||
@queue = :batch_emails
|
||||
|
||||
def self.perform(batch_id)
|
||||
if ebatch = EmailBatch.find_by_id(batch_id)
|
||||
ebatch.deliver_batch
|
||||
end
|
||||
end
|
||||
|
||||
def self.enqueue(batch_id)
|
||||
begin
|
||||
Resque.enqueue(self, batch_id)
|
||||
true
|
||||
rescue
|
||||
# implies redis is down. but since there is no retry logic with this, we should at least log a warn in case we've configured something wrong
|
||||
@@log.warn("unable to enqueue")
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
module JamRuby
|
||||
class DailySessionEmailer
|
||||
extend Resque::Plugins::LonelyJob
|
||||
|
||||
@queue = :scheduled_daily_session_emailer
|
||||
@@log = Logging.logger[DailySessionEmailer]
|
||||
|
||||
def self.perform
|
||||
@@log.debug("waking up")
|
||||
EmailBatchScheduledSessions.send_daily_session_batch
|
||||
@@log.debug("done")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
module JamRuby
|
||||
class NewMusicianEmailer
|
||||
extend Resque::Plugins::LonelyJob
|
||||
|
||||
@queue = :scheduled_new_musician_emailer
|
||||
@@log = Logging.logger[NewMusicianEmailer]
|
||||
|
||||
def self.perform
|
||||
@@log.debug("waking up")
|
||||
EmailBatchNewMusician.send_new_musician_batch
|
||||
@@log.debug("done")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
module JamRuby
|
||||
class UserProgressEmailer
|
||||
extend Resque::Plugins::LonelyJob
|
||||
|
||||
@queue = :scheduled_user_progress_emailer
|
||||
@@log = Logging.logger[UserProgressEmailer]
|
||||
|
||||
def self.perform
|
||||
@@log.debug("waking up")
|
||||
EmailBatchProgression.send_progress_batch
|
||||
@@log.debug("done")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -118,6 +118,7 @@ FactoryGirl.define do
|
|||
addr 0
|
||||
locidispid 0
|
||||
client_type 'client'
|
||||
association :user, factory: :user
|
||||
end
|
||||
|
||||
factory :invitation, :class => JamRuby::Invitation do
|
||||
|
|
@ -451,6 +452,15 @@ FactoryGirl.define do
|
|||
test_emails 4.times.collect { Faker::Internet.safe_email }.join(',')
|
||||
end
|
||||
|
||||
factory :email_batch_new_musician, :class => JamRuby::EmailBatchNewMusician do
|
||||
end
|
||||
|
||||
factory :email_batch_progression, :class => JamRuby::EmailBatchProgression do
|
||||
end
|
||||
|
||||
factory :email_batch_scheduled_session, :class => JamRuby::EmailBatchScheduledSessions do
|
||||
end
|
||||
|
||||
factory :notification, :class => JamRuby::Notification do
|
||||
|
||||
factory :notification_text_message do
|
||||
|
|
@ -468,7 +478,7 @@ FactoryGirl.define do
|
|||
factory :rsvp_slot, class: JamRuby::RsvpSlot do
|
||||
association :instrument, factory: :instrument
|
||||
association :music_session, factory: :music_session
|
||||
association :rsvp_request_slot, factory: :rsvp_request_slot
|
||||
# association :rsvp_request_slot, factory: :rsvp_request_slot
|
||||
proficiency_level 'beginner'
|
||||
end
|
||||
|
||||
|
|
@ -482,4 +492,19 @@ FactoryGirl.define do
|
|||
factory :rsvp_request_slot, class: JamRuby::RsvpRequestRsvpSlot do
|
||||
chosen false
|
||||
end
|
||||
|
||||
factory :latency_tester, :class => JamRuby::LatencyTester do
|
||||
ignore do
|
||||
connection nil
|
||||
make_connection true
|
||||
end
|
||||
|
||||
sequence(:client_id) { |n| "LatencyTesterClientId-#{n}" }
|
||||
|
||||
after(:create) do |latency_tester, evaluator|
|
||||
latency_tester.connection = evaluator.connection if evaluator.connection
|
||||
latency_tester.connection = FactoryGirl.create(:connection, client_type: Connection::TYPE_LATENCY_TESTER, client_id: latency_tester.client_id) if evaluator.make_connection
|
||||
latency_tester.save
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ describe ActiveMusicSession do
|
|||
@music_session = FactoryGirl.create(:active_music_session, :creator => @user1, :musician_access => true)
|
||||
# @music_session.connections << @connection
|
||||
@music_session.save!
|
||||
@connection.join_the_session(@music_session, true, nil)
|
||||
@connection.join_the_session(@music_session, true, nil, @user1)
|
||||
end
|
||||
|
||||
describe "not recording" do
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ describe ClaimedRecording do
|
|||
@music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
|
||||
# @music_session.connections << @connection
|
||||
@music_session.save
|
||||
@connection.join_the_session(@music_session, true, nil)
|
||||
@connection.join_the_session(@music_session, true, nil, @user)
|
||||
@recording = Recording.start(@music_session, @user)
|
||||
@recording.stop
|
||||
@recording.reload
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue