diff --git a/admin/app/admin/score_export.rb b/admin/app/admin/score_export.rb
index ddfcfaec5..2b223a531 100644
--- a/admin/app/admin/score_export.rb
+++ b/admin/app/admin/score_export.rb
@@ -13,7 +13,7 @@ ActiveAdmin.register_page "Download CSV" do
end
start_time = "#{start_time}"
if end_time.blank?
- end_time = Time.now + 1.days
+ end_time = (Time.now + 1.days).strftime('%F')
else
end_time = "#{end_time}"
end
diff --git a/admin/app/admin/score_history.rb b/admin/app/admin/score_history.rb
index 02306ec43..85ed34393 100644
--- a/admin/app/admin/score_history.rb
+++ b/admin/app/admin/score_history.rb
@@ -2,6 +2,7 @@ ActiveAdmin.register JamRuby::ScoreHistory, :as => 'Score History' do
menu :parent => 'Score'
config.batch_actions = false
+ config.sort_order = 'score_dt_desc'
config.clear_action_items!
config.filters = true
config.per_page = 100
diff --git a/admin/app/views/admin/batch_emails/_form.html.erb b/admin/app/views/admin/batch_emails/_form.html.erb
index a9c83f836..18fd10b82 100644
--- a/admin/app/views/admin/batch_emails/_form.html.erb
+++ b/admin/app/views/admin/batch_emails/_form.html.erb
@@ -1,9 +1,9 @@
-<%= semantic_form_for([:admin, resource], :url => resource.new_record? ? admin_batch_emails_path : "/admin/batch_emails/#{resource.id}") do |f| %>
+<%= semantic_form_for([:admin, resource], :url => resource.new_record? ? admin_batch_emails_path : "#{Gon.global.prefix}/admin/batch_emails/#{resource.id}") do |f| %>
<%= f.inputs do %>
<%= f.input(:from_email, :label => "From Email", :input_html => {:maxlength => 64}) %>
<%= f.input(:subject, :label => "Subject", :input_html => {:maxlength => 128}) %>
<%= f.input(:test_emails, :label => "Test Emails", :input_html => {:maxlength => 1024, :size => '3x3'}) %>
- <%= f.input(:body, :label => "Body", :input_html => {:maxlength => 3096, :size => '10x20'}) %>
+ <%= f.input(:body, :label => "Body", :input_html => {:maxlength => 60000, :size => '10x20'}) %>
<% end %>
<%= f.actions %>
<% end %>
diff --git a/db/manifest b/db/manifest
index 0d099803a..004eb74e6 100755
--- a/db/manifest
+++ b/db/manifest
@@ -198,4 +198,7 @@ connection_allow_null_locidispid.sql
track_user_in_scores.sql
median_aggregate.sql
current_scores_use_median.sql
+current_scores_ams_index_sms_index_use_user_instrument.sql
+locidispid_in_score_histories.sql
+define_environment_in_db.sql
drop_session_invite_constraint.sql
\ No newline at end of file
diff --git a/db/up/current_scores_ams_index_sms_index_use_user_instrument.sql b/db/up/current_scores_ams_index_sms_index_use_user_instrument.sql
new file mode 100644
index 000000000..3d8c2b5af
--- /dev/null
+++ b/db/up/current_scores_ams_index_sms_index_use_user_instrument.sql
@@ -0,0 +1,163 @@
+-- this adds the user's latency, if available
+
+DROP VIEW current_scores;
+CREATE OR REPLACE VIEW current_scores AS
+
+ SELECT * FROM (SELECT * , row_number() OVER (PARTITION BY alocidispid, blocidispid, scorer ORDER BY full_score DESC) AS pcnum FROM
+ (SELECT * FROM
+ (SELECT percent_rank() over (PARTITION BY alocidispid, blocidispid ORDER BY full_score ASC) AS pc, * FROM
+ (SELECT tmp.*, (COALESCE(a_users.last_jam_audio_latency, 13) + COALESCE(b_users.last_jam_audio_latency, 13) + tmp.score) AS full_score, a_users.last_jam_audio_latency AS a_audio_latency, b_users.last_jam_audio_latency AS b_audio_latency FROM
+ (SELECT *, row_number() OVER (PARTITION BY alocidispid, blocidispid ORDER BY scores.created_at DESC) AS rownum FROM scores) tmp
+ LEFT JOIN users as a_users ON a_users.id = tmp.auserid
+ LEFT JOIN users as b_users ON b_users.id = tmp.buserid
+ WHERE rownum < 6) AS score_ranked)
+ AS tmp2 WHERE pc <= .5 ORDER BY pc DESC) pcs )
+ AS final WHERE pcnum < 2;
+
+
+-- check that the music_sessions does not currently have an active_music_sessions
+CREATE OR REPLACE FUNCTION sms_index (my_user_id VARCHAR, my_locidispid BIGINT, my_audio_latency INTEGER) RETURNS VOID STRICT VOLATILE AS $$
+ BEGIN
+ -- output table to hold tagged music sessions with latency
+ CREATE TEMPORARY TABLE sms_music_session_tmp (music_session_id VARCHAR(64) NOT NULL, tag INTEGER, latency INTEGER) ON COMMIT DROP;
+
+ -- populate sms_music_session_tmp as all music sessions
+ -- XXX: we should pass in enough info to match pagination/query to reduce the impact of this step
+ INSERT INTO sms_music_session_tmp SELECT DISTINCT id, NULL::INTEGER AS tag, NULL::INTEGER AS latency
+ FROM music_sessions
+ WHERE (scheduled_start IS NULL OR scheduled_start > (NOW() - (interval '15 minute')))
+ AND canceled = FALSE
+ AND id NOT IN (SELECT id FROM active_music_sessions);
+
+ -- tag accepted rsvp as 1
+ UPDATE sms_music_session_tmp q SET tag = 1 FROM rsvp_slots s, rsvp_requests_rsvp_slots rrs, rsvp_requests r WHERE
+ q.music_session_id = s.music_session_id AND
+ s.id = rrs.rsvp_slot_id AND
+ rrs.rsvp_request_id = r.id AND
+ r.user_id = my_user_id AND
+ rrs.chosen = TRUE AND
+ q.tag is NULL;
+
+ -- tag invitation as 2
+ UPDATE sms_music_session_tmp q SET tag = 2 FROM invitations i WHERE
+ q.music_session_id = i.music_session_id AND
+ i.receiver_id = my_user_id AND
+ q.tag IS NULL;
+
+ -- musician access as 3
+ UPDATE sms_music_session_tmp q SET tag = 3 FROM music_sessions m WHERE
+ q.music_session_id = m.id AND
+ m.open_rsvps = TRUE AND
+ q.tag IS NULL;
+
+ -- delete anything not tagged
+ DELETE FROM sms_music_session_tmp WHERE tag IS NULL;
+
+ -- output table to hold users involved in the sms_music_session_tmp sessions and their latency
+ CREATE TEMPORARY TABLE sms_users_tmp (music_session_id VARCHAR(64), user_id VARCHAR(64) NOT NULL, latency INTEGER) ON COMMIT DROP;
+
+ IF my_audio_latency > -1 THEN
+ -- populate sms_users_tmp with users that have an approved RSVP for sessions in the sms_music_session_tmp table, accompanied with full latency and music session
+ INSERT INTO sms_users_tmp SELECT q.music_session_id, users.id, s.full_score/2 AS latency
+ FROM sms_music_session_tmp q
+ INNER JOIN rsvp_slots ON rsvp_slots.music_session_id = q.music_session_id
+ INNER JOIN rsvp_requests_rsvp_slots ON rsvp_requests_rsvp_slots.rsvp_slot_id = rsvp_slots.id
+ INNER JOIN rsvp_requests ON rsvp_requests.id = rsvp_requests_rsvp_slots.rsvp_request_id
+ INNER JOIN users ON rsvp_requests.user_id = users.id
+ LEFT OUTER JOIN current_scores s ON s.alocidispid = users.last_jam_locidispid
+ WHERE
+ s.blocidispid = my_locidispid AND
+ rsvp_requests_rsvp_slots.chosen = TRUE;
+
+ -- populate sms_users_tmp with invited users for session in the sms_music_session_tmp table, accompanied with full latency and music session
+ -- specify NULL for music_session_id, because we don't want RSVP users to affect the AVG computed for each session later
+ INSERT INTO sms_users_tmp SELECT NULL, users.id, s.full_score/2 AS latency
+ FROM sms_music_session_tmp q
+ INNER JOIN invitations ON invitations.music_session_id = q.music_session_id
+ INNER JOIN users ON invitations.receiver_id = users.id
+ LEFT OUTER JOIN current_scores s ON s.alocidispid = users.last_jam_locidispid
+ WHERE
+ s.blocidispid = my_locidispid AND
+ users.id NOT IN (SELECT user_id FROM sms_users_tmp);
+ END IF;
+
+ -- calculate the average latency
+ UPDATE sms_music_session_tmp q SET latency = (select AVG(u.latency) FROM sms_users_tmp u WHERE
+ q.music_session_id = u.music_session_id);
+
+ RETURN;
+ END;
+$$ LANGUAGE plpgsql;
+
+-- my_audio_latency can have a special value of -1, which means 'unknown'.
+CREATE OR REPLACE FUNCTION ams_index (my_user_id VARCHAR, my_locidispid BIGINT, my_audio_latency INTEGER) RETURNS VOID STRICT VOLATILE AS $$
+ BEGIN
+ -- output table to hold tagged music sessions with latency
+ CREATE TEMPORARY TABLE ams_music_session_tmp (music_session_id VARCHAR(64) NOT NULL, tag INTEGER, latency INTEGER) ON COMMIT DROP;
+
+ -- populate ams_music_session_tmp as all music sessions
+ INSERT INTO ams_music_session_tmp SELECT DISTINCT id, NULL::INTEGER AS tag, NULL::INTEGER AS latency
+ FROM active_music_sessions;
+
+ -- TODO worry about active music session where my_user_id is the creator?
+ -- eh, maybe, but if the music session is active and you're the creator wouldn't you already be in it?
+ -- so maybe you're on another computer, so why care? plus seth is talking about auto rsvp'ing the session
+ -- for you, so maybe not a problem.
+
+ -- tag accepted rsvp as 1
+ UPDATE ams_music_session_tmp q SET tag = 1 FROM rsvp_slots s, rsvp_requests_rsvp_slots rrs, rsvp_requests r WHERE
+ q.music_session_id = s.music_session_id AND
+ s.id = rrs.rsvp_slot_id AND
+ rrs.rsvp_request_id = r.id AND
+ r.user_id = my_user_id AND
+ rrs.chosen = TRUE AND
+ q.tag is NULL;
+
+ -- tag invitation as 2
+ UPDATE ams_music_session_tmp q SET tag = 2 FROM invitations i WHERE
+ q.music_session_id = i.music_session_id AND
+ i.receiver_id = my_user_id AND
+ q.tag IS NULL;
+
+ -- musician access as 3
+ UPDATE ams_music_session_tmp q SET tag = 3 FROM music_sessions m WHERE
+ q.music_session_id = m.id AND
+ m.musician_access = TRUE AND
+ q.tag IS NULL;
+
+ -- delete anything not tagged
+ DELETE FROM ams_music_session_tmp WHERE tag IS NULL;
+
+ -- output table to hold users involved in the ams_music_session_tmp sessions and their latency
+ CREATE TEMPORARY TABLE ams_users_tmp (music_session_id VARCHAR(64), user_id VARCHAR(64) NOT NULL, latency INTEGER) ON COMMIT DROP;
+
+ IF my_audio_latency > -1 THEN
+ -- populate ams_users_tmp with users that have a connection for sessions in the ams_music_session_tmp table, accompanied with full latency and music session
+ INSERT INTO ams_users_tmp SELECT c.music_session_id, c.user_id, s.full_score/2 AS latency
+ FROM ams_music_session_tmp q
+ INNER JOIN connections c ON c.music_session_id = q.music_session_id
+ LEFT OUTER JOIN current_scores s ON s.alocidispid = c.locidispid
+ WHERE s.blocidispid = my_locidispid;
+
+ -- populate ams_users_tmp with users that have an approved RSVP for sessions inthe ams_music_session_tmp table, accompanied with full latency and music session
+ -- specify NULL for music_session_id, because we don't want RSVP users to affect the AVG computed for each session later
+ INSERT INTO ams_users_tmp SELECT NULL, users.id, s.full_score/2 AS latency
+ FROM ams_music_session_tmp q
+ INNER JOIN rsvp_slots ON rsvp_slots.music_session_id = q.music_session_id
+ INNER JOIN rsvp_requests_rsvp_slots ON rsvp_requests_rsvp_slots.rsvp_slot_id = rsvp_slots.id
+ INNER JOIN rsvp_requests ON rsvp_requests.id = rsvp_requests_rsvp_slots.rsvp_request_id
+ INNER JOIN users ON rsvp_requests.user_id = users.id
+ LEFT OUTER JOIN current_scores s ON s.alocidispid = users.last_jam_locidispid
+ WHERE
+ s.blocidispid = my_locidispid AND
+ rsvp_requests_rsvp_slots.chosen = TRUE AND
+ users.id NOT IN (SELECT user_id FROM ams_users_tmp);
+ END IF;
+
+ -- calculate the average latency
+ UPDATE ams_music_session_tmp q SET latency = (select AVG(u.latency) FROM ams_users_tmp u WHERE
+ q.music_session_id = u.music_session_id);
+
+ RETURN;
+ END;
+$$ LANGUAGE plpgsql;
\ No newline at end of file
diff --git a/db/up/define_environment_in_db.sql b/db/up/define_environment_in_db.sql
new file mode 100644
index 000000000..a419e8c8a
--- /dev/null
+++ b/db/up/define_environment_in_db.sql
@@ -0,0 +1,3 @@
+-- https://jamkazam.atlassian.net/browse/VRFS-1951
+-- we need to know the environment in the database for advanced behaviors
+ALTER TABLE generic_state ADD COLUMN env VARCHAR(255) NOT NULL DEFAULT 'development';
\ No newline at end of file
diff --git a/db/up/locidispid_in_score_histories.sql b/db/up/locidispid_in_score_histories.sql
new file mode 100644
index 000000000..38846045b
--- /dev/null
+++ b/db/up/locidispid_in_score_histories.sql
@@ -0,0 +1,5 @@
+-- https://jamkazam.atlassian.net/browse/VRFS-1968
+-- store both locids in score_histories
+
+ALTER TABLE score_histories ADD COLUMN from_locidispid BIGINT NOT NULL;
+ALTER TABLE score_histories ADD COLUMN to_locidispid BIGINT NOT NULL;
\ No newline at end of file
diff --git a/db/up/scores_better_test_data.sql b/db/up/scores_better_test_data.sql
index 52a8e9842..0f5935cc6 100644
--- a/db/up/scores_better_test_data.sql
+++ b/db/up/scores_better_test_data.sql
@@ -86,10 +86,10 @@ CREATE OR REPLACE FUNCTION generate_scores_dataset () RETURNS VOID STRICT VOLATI
INSERT INTO cities (city, region, countrycode) select distinct city, region, countrycode from geoiplocations where length(city) > 0 and length(countrycode) > 0;
DELETE FROM regions;
- INSERT INTO regions (region, countrycode) select distinct region, countrycode from cities;
+ INSERT INTO regions (region, regionname, countrycode) select distinct region, region, countrycode from cities;
DELETE FROM countries;
- INSERT INTO countries (countrycode) select distinct countrycode from regions;
+ INSERT INTO countries (countrycode, countryname) select distinct countrycode, countrycode from regions;
END IF;
RETURN;
diff --git a/monitor/spec/production_spec.rb b/monitor/spec/production_spec.rb
index 5236173a5..ded20aec1 100755
--- a/monitor/spec/production_spec.rb
+++ b/monitor/spec/production_spec.rb
@@ -20,6 +20,9 @@ describe "Deployed site at #{www}", :js => true, :type => :feature, :capybara_fe
Capybara.run_server = false
end
+ before { puts "\n" }
+ after { puts "\n\n" }
+
TestUser = Class.new do
attr_accessor :email, :password, :first_name, :last_name, :id
@@ -46,6 +49,7 @@ describe "Deployed site at #{www}", :js => true, :type => :feature, :capybara_fe
it "is possible for #{user1} to sign in and not get disconnected within 30 seconds" do
in_client(user1) do
+ puts "\n *** #{user1}'s client *** \n"
sign_in_poltergeist user1
repeat_for(30.seconds) do
expect(page).to_not have_selector('.no-websocket-connection') #looks for reconnect dialog every 1 second
@@ -57,6 +61,7 @@ describe "Deployed site at #{www}", :js => true, :type => :feature, :capybara_fe
# this example heavily based on text_message_spec.rb in 'web'
in_client(user1) do
+ puts "\n *** #{user1}'s client *** \n"
sign_in_poltergeist(user1)
end
@@ -65,6 +70,7 @@ describe "Deployed site at #{www}", :js => true, :type => :feature, :capybara_fe
test_goodbye = "#{SecureRandom.uuid} - OK bye!"
in_client(user2) do
+ puts "\n *** #{user2}'s client *** \n"
sign_in_poltergeist(user2)
expect(page).to have_xpath(
"//div[@class='friend-name' and @user-id='#{user1.id}']/span[@class='friend-status']",
@@ -78,6 +84,7 @@ describe "Deployed site at #{www}", :js => true, :type => :feature, :capybara_fe
end
in_client(user1) do
+ puts "\n *** #{user1}'s client *** \n"
expect(page).to have_xpath(
"//div[@class='friend-name' and @user-id='#{user2.id}']/span[@class='friend-status']",
:text => "Available" )
@@ -88,12 +95,13 @@ describe "Deployed site at #{www}", :js => true, :type => :feature, :capybara_fe
end
in_client(user2) do
+ puts "\n *** #{user2}'s client *** \n"
find('.previous-message-text', text: test_response)
send_text_message(test_goodbye, close_on_send: true)
end
- in_client(user1) { sign_out_poltergeist }
- in_client(user2) { sign_out_poltergeist }
+ in_client(user1) { puts "\n *** #{user1}'s client *** \n"; sign_out_poltergeist }
+ in_client(user2) { puts "\n *** #{user2}'s client *** \n"; sign_out_poltergeist }
end
let(:queue_limit) { 5 }
diff --git a/monitor/spec/spec_helper.rb b/monitor/spec/spec_helper.rb
index 5b3882d80..93bd9cb49 100755
--- a/monitor/spec/spec_helper.rb
+++ b/monitor/spec/spec_helper.rb
@@ -34,11 +34,11 @@ RSpec.configure do |config|
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.register_driver :poltergeist do |app|
+ Capybara::Poltergeist::Driver.new(app, { :timeout=>120, js_errors: false })
+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
diff --git a/pb/src/client_container.proto b/pb/src/client_container.proto
index 88bd060c2..a85e9e597 100644
--- a/pb/src/client_container.proto
+++ b/pb/src/client_container.proto
@@ -320,6 +320,7 @@ message SessionJoin {
optional string photo_url = 2;
optional string msg = 3;
optional int32 track_changes_counter = 4;
+ optional string source_user_id = 5;
}
message SessionDepart {
diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/scheduled_session_daily.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/scheduled_session_daily.html.erb
index 0d6ba9a6b..a7f70124b 100644
--- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/scheduled_session_daily.html.erb
+++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/scheduled_session_daily.html.erb
@@ -3,35 +3,90 @@
Hello <%= @user.first_name %> --
-The following new sessions that that have been posted during the last 24 hours:
-
-
-Need someone who plays an instrument that you play
-Were posted by someone to whom you have either a good or medium latency connection
-
+The following new sessions have been posted within the last 24 hours, and you have good or acceptable latency to the organizer of each session below. If a session looks interesting, click the Details link to see the session page. You can RSVP to a session from the session page, and you'll be notified if/when the session organizer approves your RSVP.
-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
+ GENRE
+ NAME
+ DESCRIPTION
LATENCY
-
-<% @sessions_and_latency.each do |sess| %>
-
-<%= sess.genre.description %>
-<%= sess.description %>
-<%= sess.latency %>
-
-<% end %>
+
+
+
+ <% @sessions_and_latency.each do |sess| %>
+
+ <%= sess.genre.description %>
+
+ <%= sess.name %>
+ ">Details
+
+ <%= sess.description %>
+
+
+ <%= (sess.latency / 2).round %> ms
+ <% if sess.latency <= (APP_CONFIG.max_good_full_score * 2) %>
+ <%= image_tag("http://www.jamkazam.com/assets/content/icon_green_score.png", alt: 'good score icon') %>
+ <% else %>
+ <%= image_tag("http://www.jamkazam.com/assets/content/icon_yellow_score.png", alt: 'fair score icon') %>
+ <% end %>
+
+
+
+ <% 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 .
-
+To see ALL the scheduled sessions that you might be interested in joining, view our Find Session page .
Best Regards,
diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/scheduled_session_daily.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/scheduled_session_daily.text.erb
index 423c57f44..9720550d5 100644
--- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/scheduled_session_daily.text.erb
+++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/scheduled_session_daily.text.erb
@@ -2,16 +2,11 @@
Hello <%= @user.first_name %> --
-The following new sessions that that have been posted during the last 24 hours:
+The following new sessions have been posted within the last 24 hours, and you have good or acceptable latency to the organizer of each session below. If a session looks interesting, click the Details link to see the session page. You can RSVP to a session from the session page, and you'll be notified if/when the session organizer approves your RSVP.
-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
+GENRE | NAME | DESCRIPTION | LATENCY
<% @sessions_and_latency.each do |sess| %>
-<%= sess.genre.description %> | <%= sess.description %> | <%= sess.latency %>
+<%= sess.genre.description %> | <%= sess.name %> | <%= sess.description %> | <%= sess.latency %> ms
<% 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.
diff --git a/ruby/lib/jam_ruby/app/views/layouts/from_user_mailer.html.erb b/ruby/lib/jam_ruby/app/views/layouts/from_user_mailer.html.erb
index 3d03cec55..8ce59bc6b 100644
--- a/ruby/lib/jam_ruby/app/views/layouts/from_user_mailer.html.erb
+++ b/ruby/lib/jam_ruby/app/views/layouts/from_user_mailer.html.erb
@@ -9,7 +9,6 @@
margin-bottom:0px;
line-height:140%;
}
-
diff --git a/ruby/lib/jam_ruby/database.rb b/ruby/lib/jam_ruby/database.rb
index 9b357405a..90a251a1f 100644
--- a/ruby/lib/jam_ruby/database.rb
+++ b/ruby/lib/jam_ruby/database.rb
@@ -54,5 +54,35 @@ module JamRuby
GeoIpBlocks.connection.execute "CREATE TABLE #{copied_name} (LIKE #{table_name} INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING COMMENTS INCLUDING STORAGE)"
copied_name
end
+
+ def self.dump(query)
+ result = ActiveRecord::Base.connection.execute(query)
+ fields = result.fields
+ header = ""
+ fields.each do |field|
+ header << field
+ header << ', '
+ end
+ header = header[0..header.length - 3]
+ puts header
+
+ result.each do |row|
+ row_out = ''
+ fields.each do |field|
+ if row[field].nil?
+ row_out << 'NULL'
+ else
+ if block_given?
+ row_out << yield(field, row[field]).to_s
+ else
+ row_out << row[field].to_s
+ end
+ end
+ row_out << ', '
+ end
+ row_out = row_out[0..row_out.length - 3]
+ puts row_out
+ end
+ end
end
end
\ No newline at end of file
diff --git a/ruby/lib/jam_ruby/message_factory.rb b/ruby/lib/jam_ruby/message_factory.rb
index 5ade15055..89c4670ff 100644
--- a/ruby/lib/jam_ruby/message_factory.rb
+++ b/ruby/lib/jam_ruby/message_factory.rb
@@ -395,10 +395,11 @@ module JamRuby
)
end
- def session_join(session_id, photo_url, msg, track_changes_counter)
+ def session_join(session_id, photo_url, source_user_id, msg, track_changes_counter)
join = Jampb::SessionJoin.new(
:session_id => session_id,
:photo_url => photo_url,
+ :source_user_id => source_user_id,
:msg => msg,
:track_changes_counter => track_changes_counter
)
diff --git a/ruby/lib/jam_ruby/models/active_music_session.rb b/ruby/lib/jam_ruby/models/active_music_session.rb
index edc98fd9f..b3640ec75 100644
--- a/ruby/lib/jam_ruby/models/active_music_session.rb
+++ b/ruby/lib/jam_ruby/models/active_music_session.rb
@@ -450,7 +450,7 @@ module JamRuby
[music_sessions, user_scores]
end
- def self.participant_create user, music_session_id, client_id, as_musician, tracks
+ def self.participant_create user, music_session_id, client_id, as_musician, tracks, audio_latency
music_session = MusicSession.find(music_session_id)
if music_session.active_music_session
@@ -462,7 +462,7 @@ module JamRuby
active_music_session.with_lock do # VRFS-1297
active_music_session.tick_track_changes
- connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, 10)
+ connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency)
if connection.errors.any?
# rollback the transaction to make sure nothing is disturbed in the database
@@ -519,7 +519,7 @@ module JamRuby
# auto-join this user into the newly created session
as_musician = true
- connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, 10)
+ connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency)
unless connection.errors.any?
user.update_progression_field(:first_music_session_at)
diff --git a/ruby/lib/jam_ruby/models/connection.rb b/ruby/lib/jam_ruby/models/connection.rb
index 27d715238..186635bce 100644
--- a/ruby/lib/jam_ruby/models/connection.rb
+++ b/ruby/lib/jam_ruby/models/connection.rb
@@ -164,7 +164,7 @@ module JamRuby
# if user joins the session as a musician, update their addr and location
if as_musician
user.update_addr_loc(self, User::JAM_REASON_JOIN)
- user.update_audio_latency(self, audio_latency)
+ user.update_audio_latency(self, audio_latency) if audio_latency # try not to let a previously recorded value get nil'ed
end
end
diff --git a/ruby/lib/jam_ruby/models/email_batch_scheduled_sessions.rb b/ruby/lib/jam_ruby/models/email_batch_scheduled_sessions.rb
index 50b542b89..017a22443 100644
--- a/ruby/lib/jam_ruby/models/email_batch_scheduled_sessions.rb
+++ b/ruby/lib/jam_ruby/models/email_batch_scheduled_sessions.rb
@@ -19,16 +19,45 @@ module JamRuby
def persisted?; false; end
end
+ # Temporary Tables created by this class:
+
+ # tmp_candidate_sessions
+ # ----------------------
+ #
+ # These are 'open' sessions that have any open slots left, and fall within a certain start time.
+ # The session creator must also have a locidispid.
+ #
+ # session_id - music_session.id
+ # creator_id - music_session.user_id
+ # creator_score_idx - this is the creator's users.last_jam_locidispid
+ # instrument_id - instruments that are open as gleamed from the RSVP. If this is NULL, it means 'ANY INSTRUMENT'
+ # invited_user_id - the ID of a user who was invited. Can be NULL.
+ #
+ # tmp_candidate_recipients
+ # ------------------------
+ #
+ # These are musicians, that allow email notifications, that have an instrument which matches the session's open RSVP slot's instrument.
+ # The musician must also have a locidispid.
+ #
+ # receiver_id - user ID that could be in the session
+ # receiver_score_idx - the user's last_jam_locidispid
+ # instrument_id - the user's matching instrument for a open session slot. If this is NULL, it means 'ANY INSTRUMENT'
+ # invited_user_id
+ #
+ # tmp_matches
+ # -----------
+ #
+ # These are 'candidate_recipients' that have a decent enough score with the creator of the music sessions in tmp_candidate_sessions
+ #
+ # receiver_id - the user.id that should receive an Daily Session email
+ # session_id - the music_session.id for the email
+ # latency - the score.score between the creator and the candidate (needs to be full score soon)
class EmailBatchScheduledSessions < EmailBatchPeriodic
BATCH_SIZE = 500
SINCE_DAYS = 2
MIN_HOURS_START = 2
- TMP_SESS = 'tmp_candidate_sessions'
- TMP_RECIP = 'tmp_candidate_recipients'
- TMP_MATCH = 'tmp_matches'
-
ENV_MAX_LATENCY = 'env_max_latency'
ENV_QUERY_LIMIT = 'env_query_limit'
SNAPSHOT_QUERY_LIMIT = '500'
@@ -57,18 +86,18 @@ module JamRuby
end
def snapshot_eligible_sessions
- rr = ActiveRecord::Base.connection.execute("SELECT COUNT(*) AS num FROM #{TMP_SESS}")
- [0 < rr.count ? rr[0]['num'].to_i : 0, ResultStub.stubs("SELECT * FROM #{TMP_SESS}")]
+ rr = ActiveRecord::Base.connection.execute("SELECT COUNT(*) AS num FROM tmp_candidate_sessions")
+ [0 < rr.count ? rr[0]['num'].to_i : 0, ResultStub.stubs("SELECT * FROM tmp_candidate_sessions")]
end
def snapshot_eligible_recipients
- rr = ActiveRecord::Base.connection.execute("SELECT COUNT(*) AS num FROM #{TMP_RECIP}")
- [0 < rr.count ? rr[0]['num'].to_i : 0, ResultStub.stubs("SELECT * FROM #{TMP_RECIP}")]
+ rr = ActiveRecord::Base.connection.execute("SELECT COUNT(*) AS num FROM tmp_candidate_recipients")
+ [0 < rr.count ? rr[0]['num'].to_i : 0, ResultStub.stubs("SELECT * FROM tmp_candidate_recipients")]
end
def snapshot_scored_recipients
- rr = ActiveRecord::Base.connection.execute("SELECT COUNT(*) AS num FROM #{TMP_MATCH}")
- [0 < rr.count ? rr[0]['num'].to_i : 0, ResultStub.stubs("SELECT * FROM #{TMP_MATCH}")]
+ rr = ActiveRecord::Base.connection.execute("SELECT COUNT(*) AS num FROM tmp_matches")
+ [0 < rr.count ? rr[0]['num'].to_i : 0, ResultStub.stubs("SELECT * FROM tmp_matches")]
end
def take_snapshot
@@ -77,6 +106,62 @@ module JamRuby
self.update_attribute(:test_emails, @counters.inspect)
end
+ def query
+ ActiveRecord::Base.connection.execute(< '#{earliest_session_create_time}' AND
+ msess.created_at < '#{latest_session_create_time}' AND
+ scheduled_start >= '#{earliest_session_start_time}' AND
+ (rrrs.rsvp_slot_id IS NULL OR rrrs.chosen != TRUE)) AS tmp_candidate_sessions
+INNER JOIN
+ (SELECT
+ users.id AS receiver_id,
+ users.last_jam_locidispid AS receiver_score_idx,
+ mi.instrument_id
+ INTO TEMP TABLE tmp_candidate_recipients
+ FROM users
+ INNER JOIN musicians_instruments AS mi ON mi.user_id = users.id
+ INNER JOIN tmp_candidate_sessions ON tmp_candidate_sessions.instrument_id = mi.instrument_id OR
+ tmp_candidate_sessions.is_unstructured_rsvp = TRUE OR
+ tmp_candidate_sessions.invited_user_id = users.id
+
+ WHERE
+ users.last_jam_locidispid IS NOT NULL AND
+ users.musician = TRUE AND
+ users.subscribe_email = TRUE) AS tmp_candidate_recipients
+INNER JOIN tmp_candidate_sessions ON tmp_candidate_sessions.creator_score_idx = current_scores.alocidispid
+INNER JOIN tmp_candidate_recipients ON tmp_candidate_recipients.receiver_score_idx = current_scores.blocidispid
+WHERE
+ current_scores.full_score < #{max_score} AND
+ tmp_candidate_recipients.receiver_id != tmp_candidate_sessions.creator_id
+GROUP BY
+ tmp_candidate_recipients.receiver_id,
+ tmp_candidate_sessions.session_id,
+ latency
+SQL
+ )
+ end
+
def fetch_recipients(per_page=BATCH_SIZE)
objs = []
@@ -91,9 +176,11 @@ module JamRuby
# now just get the sessions/latency for each distinct mail recipient
_select_scored_recipients(offset).each do |result|
receiver = User.find_by_id(result['receiver_id'])
- sessions = MusicSession.select("music_sessions.*, #{TMP_MATCH}.latency")
- .joins("INNER JOIN #{TMP_MATCH} ON #{TMP_MATCH}.session_id = music_sessions.id")
- .where(["#{TMP_MATCH}.receiver_id = ?", receiver.id])
+ sessions = MusicSession.select("music_sessions.*, tmp_matches.latency")
+ .joins("INNER JOIN tmp_matches ON tmp_matches.session_id = music_sessions.id")
+ .where(["tmp_matches.receiver_id = ?", receiver.id])
+ .order('tmp_matches.latency')
+ .limit(20)
.includes([:genre, :creator])
block_given? ? yield(receiver, sessions) : objs << [receiver, sessions]
end
@@ -126,75 +213,83 @@ module JamRuby
# inserts eligible sessions to temp table
def _collect_eligible_sessions
- ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS #{TMP_SESS}")
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS tmp_candidate_sessions")
limit_sql = (self.snapshot? && 0 < ENV[ENV_QUERY_LIMIT].to_i) ? "LIMIT #{ENV[ENV_QUERY_LIMIT]}" : ''
sql =< '#{earliest_session_create_time}' AND
msess.created_at < '#{latest_session_create_time}' AND
- scheduled_start >= '#{earliest_session_start_time}' AND
- (rrrs.rsvp_slot_id IS NULL OR rrrs.chosen != 't')
+ scheduled_start >= '#{earliest_session_start_time}'
#{limit_sql}
SQL
ActiveRecord::Base.connection.execute(sql)
end
def _collect_eligible_recipients
- ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS #{TMP_RECIP}")
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS tmp_candidate_recipients").check
limit_sql = (self.snapshot? && 0 < ENV[ENV_QUERY_LIMIT].to_i) ? "LIMIT #{ENV[ENV_QUERY_LIMIT]}" : ''
# load eligible recipients into tmp table
sql =< offset
- sql = "SELECT COUNT(DISTINCT receiver_id) AS num FROM #{TMP_MATCH}"
+ sql = "SELECT COUNT(DISTINCT receiver_id) AS num FROM tmp_matches"
rr = ActiveRecord::Base.connection.execute(sql)
return 0 < rr.count ? rr[0]['num'].to_i : 0
else
sql =< {:in => ['development', 'staging', 'production', 'test']}
+
+ def self.allow_emails?
+
+ database_environment = singleton.env
+
+ # if the database says we are in production/staging, then the config has to also agree and say we are in production/staging to send emails
+ # this is to protect against developers loading a staging or production environment and possibly sending emails to
+ # we even go one step further, and make sure ENV['BUILD_NUMBER'] is set, which is something you do in production, but would be very rare in development
+
+ # or if your database says 'development' and config say 'development', then we allow emails to go out too
+ (!ENV['BUILD_NUMBER'].nil? && (Environment.mode == 'production' || Environment.mode == 'staging') && (database_environment == 'production' || database_environment == 'staging')) ||
+ (database_environment == 'development' && Environment.mode == 'development')
+ end
+
def self.singleton
GenericState.find('default')
end
diff --git a/ruby/lib/jam_ruby/models/music_session.rb b/ruby/lib/jam_ruby/models/music_session.rb
index 271bd5863..35a5a7892 100644
--- a/ruby/lib/jam_ruby/models/music_session.rb
+++ b/ruby/lib/jam_ruby/models/music_session.rb
@@ -10,7 +10,7 @@ module JamRuby
RECURRING_MODES = [NO_RECURRING, RECURRING_WEEKLY]
- attr_accessor :legal_terms, :language_description, :access_description
+ attr_accessor :legal_terms, :language_description, :access_description, :scheduling_info_changed
attr_accessor :approved_rsvps, :open_slots, :pending_invitations
@@ -58,11 +58,17 @@ module JamRuby
before_create :generate_share_token
before_create :add_to_feed
#before_save :update_scheduled_start
+ before_save :check_scheduling_info_changed
SHARE_TOKEN_LENGTH = 8
SEPARATOR = '|'
+ def check_scheduling_info_changed
+ @scheduling_info_changed = scheduled_start_changed?
+ true
+ end
+
def add_to_feed
feed = Feed.new
feed.music_session = self
@@ -111,6 +117,7 @@ module JamRuby
new_slot = RsvpSlot.new
new_slot.instrument_id = slot.instrument_id
new_slot.proficiency_level = slot.proficiency_level
+ new_slot.is_unstructured_rsvp = slot.is_unstructured_rsvp
new_session.rsvp_slots << new_slot
# get the request for this slot that was approved (should only be ONE)
@@ -409,7 +416,7 @@ module JamRuby
end
def has_mount?
- active_music_session && active_music_session.mount
+ !active_music_session.nil? && !active_music_session.mount.nil?
end
def can_cancel? user
diff --git a/ruby/lib/jam_ruby/models/notification.rb b/ruby/lib/jam_ruby/models/notification.rb
index f8f59807d..e21e358c8 100644
--- a/ruby/lib/jam_ruby/models/notification.rb
+++ b/ruby/lib/jam_ruby/models/notification.rb
@@ -492,6 +492,7 @@ module JamRuby
msg = @@message_factory.session_join(
music_session.id,
user.photo_url,
+ user.id,
notification_msg,
music_session.track_changes_counter
)
diff --git a/ruby/lib/jam_ruby/models/rsvp_request.rb b/ruby/lib/jam_ruby/models/rsvp_request.rb
index 6ba1d2ab9..3558df969 100644
--- a/ruby/lib/jam_ruby/models/rsvp_request.rb
+++ b/ruby/lib/jam_ruby/models/rsvp_request.rb
@@ -253,7 +253,7 @@ module JamRuby
# send notification
if music_session.creator.id == user.id
- Notification.send_scheduled_session_rsvp_cancelled_org(music_session, user)
+ Notification.send_scheduled_session_rsvp_cancelled_org(music_session, rsvp_request.user)
else
Notification.send_scheduled_session_rsvp_cancelled(music_session, user)
end
diff --git a/ruby/lib/jam_ruby/models/score.rb b/ruby/lib/jam_ruby/models/score.rb
index 7fbf595a2..da3c5d33c 100644
--- a/ruby/lib/jam_ruby/models/score.rb
+++ b/ruby/lib/jam_ruby/models/score.rb
@@ -3,7 +3,7 @@ require 'ipaddr'
module JamRuby
class Score < ActiveRecord::Base
- MAX_YELLOW_LATENCY = 40
+ MAX_YELLOW_LATENCY = 40 # this round-trip internet latency, not full score
self.table_name = 'scores'
diff --git a/ruby/lib/jam_ruby/models/score_history.rb b/ruby/lib/jam_ruby/models/score_history.rb
index ed90892d4..4c82e3326 100644
--- a/ruby/lib/jam_ruby/models/score_history.rb
+++ b/ruby/lib/jam_ruby/models/score_history.rb
@@ -15,14 +15,15 @@ module JamRuby
result = connection.execute(
"INSERT INTO score_histories
- (from_client_id, from_user_id, from_latency_tester_id, from_addr, from_isp, from_country, from_region, from_city, from_postal, from_latitude, from_longitude,
- to_client_id, to_user_id, to_latency_tester_id, to_addr, to_isp, to_country, to_region, to_city, to_postal, to_latitude, to_longitude,
+ (from_client_id, from_user_id, from_latency_tester_id, from_addr, from_locidispid, from_isp, from_country, from_region, from_city, from_postal, from_latitude, from_longitude,
+ to_client_id, to_user_id, to_latency_tester_id, to_addr, to_locidispid, to_isp, to_country, to_region, to_city, to_postal, to_latitude, to_longitude,
score, score_dt, scoring_data)
SELECT
s.anodeid AS from_client_id,
s.auserid AS from_user_id,
s.alatencytestid AS from_latency_tester_id,
s.aaddr AS from_addr,
+ s.alocidispid AS from_locidispid,
x.company AS from_isp,
a.countrycode AS from_country,
a.region AS from_region,
@@ -34,6 +35,7 @@ module JamRuby
s.buserid AS to_user_id,
s.blatencytestid AS to_latency_tester_id,
s.baddr AS to_addr,
+ s.blocidispid AS to_locidispid,
y.company AS to_isp,
b.countrycode AS to_country,
b.region AS to_region,
diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb
index 1f08651ec..761660c84 100644
--- a/ruby/lib/jam_ruby/models/search.rb
+++ b/ruby/lib/jam_ruby/models/search.rb
@@ -185,6 +185,7 @@ module JamRuby
score_join = 'left outer' # or 'inner'
score_min = nil
score_max = nil
+ # these score_min, score_max come from here (doubled): https://jamkazam.atlassian.net/browse/VRFS-1962
case score_limit
when GOOD_SCORE
score_join = 'inner'
@@ -193,14 +194,14 @@ module JamRuby
when MODERATE_SCORE
score_join = 'inner'
score_min = 40
- score_max = 80
+ score_max = 70
when POOR_SCORE
score_join = 'inner'
score_min = 80
- score_max = 120
+ score_max = 100
when UNACCEPTABLE_SCORE
score_join = 'inner'
- score_min = 120
+ score_min = 100
score_max = nil
when SCORED_SCORE
score_join = 'inner'
@@ -221,11 +222,11 @@ module JamRuby
rel = rel.joins('LEFT JOIN regions ON regions.countrycode = users.country AND regions.region = users.state')
- rel = rel.where(['current_scores.score > ?', score_min]) unless score_min.nil?
- rel = rel.where(['current_scores.score <= ?', score_max]) unless score_max.nil?
+ rel = rel.where(['current_scores.full_score > ?', score_min]) unless score_min.nil?
+ rel = rel.where(['current_scores.full_score <= ?', score_max]) unless score_max.nil?
- rel = rel.select('current_scores.score, regions.regionname')
- rel = rel.group('current_scores.score, regions.regionname')
+ rel = rel.select('current_scores.full_score, current_scores.score, current_scores.b_audio_latency as audio_latency, regions.regionname')
+ rel = rel.group('current_scores.full_score, current_scores.score, current_scores.b_audio_latency, regions.regionname')
end
ordering = self.order_param(params)
@@ -249,7 +250,7 @@ module JamRuby
end
unless locidispid.nil?
- rel = rel.order('current_scores.score ASC NULLS LAST')
+ rel = rel.order('current_scores.full_score ASC NULLS LAST')
end
rel = rel.order('users.created_at DESC')
@@ -393,15 +394,15 @@ module JamRuby
# an offline process and thus uses the last jam location as "home base"
locidispid = usr.last_jam_locidispid
- score_limit = 60
+ score_limit = 70
limit = 50
rel = User.musicians_geocoded
.where(['users.created_at >= ? AND users.id != ?', since_date, usr.id])
.joins('inner join current_scores on users.last_jam_locidispid = current_scores.alocidispid')
.where(['current_scores.blocidispid = ?', locidispid])
- .where(['current_scores.score <= ?', score_limit])
- .order('current_scores.score') # best scores first
+ .where(['current_scores.full_score <= ?', score_limit])
+ .order('current_scores.full_score') # best scores first
.order('users.created_at DESC') # then most recent
.limit(limit)
diff --git a/ruby/lib/jam_ruby/resque/scheduled/music_session_scheduler.rb b/ruby/lib/jam_ruby/resque/scheduled/music_session_scheduler.rb
index f54215896..cd706285a 100644
--- a/ruby/lib/jam_ruby/resque/scheduled/music_session_scheduler.rb
+++ b/ruby/lib/jam_ruby/resque/scheduled/music_session_scheduler.rb
@@ -27,8 +27,8 @@ module JamRuby
end
def run
- # get all weekly sessions that have ended in the last 15 minutes
- criteria = "recurring_mode = 'weekly' AND session_removed_at is not null AND canceled = false AND next_session_scheduled = false"
+ # get all weekly sessions that started at least 4 hours ago
+ criteria = "recurring_mode = 'weekly' AND scheduled_start + interval '4hours' < NOW() AND canceled = false AND next_session_scheduled = false"
MusicSession.find_each(:conditions => criteria) do |music_session|
music_session.copy
end
diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb
index 0d321db48..6f6e6f13c 100644
--- a/ruby/spec/factories.rb
+++ b/ruby/spec/factories.rb
@@ -2,6 +2,10 @@ require 'faker'
FactoryGirl.define do
factory :user, :class => JamRuby::User do
+ ignore do
+ specific_instruments nil
+ end
+
sequence(:email) { |n| "person_#{n}@example.com"}
sequence(:first_name) { |n| "Person" }
sequence(:last_name) { |n| "#{n}" }
@@ -17,8 +21,14 @@ FactoryGirl.define do
#u.association :musician_instrument, factory: :musician_instrument, user: u
- before(:create) do |user|
- user.musician_instruments << FactoryGirl.build(:musician_instrument, user: user)
+ before(:create) do |user, evaluator|
+ if evaluator.specific_instruments
+ evaluator.specific_instruments.each do |instrument|
+ user.musician_instruments << FactoryGirl.build(:musician_instrument, user: user, instrument: instrument)
+ end
+ else
+ user.musician_instruments << FactoryGirl.build(:musician_instrument, user: user)
+ end
end
factory :fan do
diff --git a/ruby/spec/jam_ruby/models/active_music_session_spec.rb b/ruby/spec/jam_ruby/models/active_music_session_spec.rb
index b59dd0b45..ab02b8281 100644
--- a/ruby/spec/jam_ruby/models/active_music_session_spec.rb
+++ b/ruby/spec/jam_ruby/models/active_music_session_spec.rb
@@ -354,8 +354,8 @@ describe ActiveMusicSession do
user = FactoryGirl.create(:user, last_jam_locidispid: 1, last_jam_audio_latency: 5)
c3 = FactoryGirl.create(:connection, user: user, locidispid: 1, last_jam_audio_latency: 5)
- Score.createx(c1.locidispid, c1.client_id, c1.addr, c3.locidispid, c3.client_id, c3.addr, 20, nil)
- Score.createx(c2.locidispid, c2.client_id, c2.addr, c3.locidispid, c3.client_id, c3.addr, 30, nil)
+ Score.createx(c1.locidispid, c1.client_id, c1.addr, c3.locidispid, c3.client_id, c3.addr, 20, nil, nil, {auserid: creator.id, buserid: user.id})
+ Score.createx(c2.locidispid, c2.client_id, c2.addr, c3.locidispid, c3.client_id, c3.addr, 30, nil, nil, {auserid: creator2.id, buserid: user.id})
# make a transaction
diff --git a/ruby/spec/jam_ruby/models/email_batch_spec_scheduled_session.rb b/ruby/spec/jam_ruby/models/email_batch_spec_scheduled_session.rb
index b632234bc..0d69c0619 100644
--- a/ruby/spec/jam_ruby/models/email_batch_spec_scheduled_session.rb
+++ b/ruby/spec/jam_ruby/models/email_batch_spec_scheduled_session.rb
@@ -10,36 +10,62 @@ describe EmailBatchScheduledSessions do
UserMailer.deliveries.clear
end
+ def find_user_sessions(obj, user)
+ found = obj.find{|item| item[0] == user}
+ found.should_not be_nil
+ found[1]
+ end
+
describe 'daily scheduled' do
# before { pending }
let (:scheduled_batch) { FactoryGirl.create(:email_batch_scheduled_session) }
- let (:drums) { FactoryGirl.create(:instrument, :description => 'drums') }
- let (:guitar) { FactoryGirl.create(:instrument, :description => 'guitar') }
- let (:bass) { FactoryGirl.create(:instrument, :description => 'bass') }
- let (:vocals) { FactoryGirl.create(:instrument, :description => 'vocal') }
+ let (:drums) { Instrument.find('drums') }
+ let (:guitar) { Instrument.find('acoustic guitar') }
+ let (:bass) { Instrument.find('bass guitar') }
+ let (:vocals) { Instrument.find('voice') }
+ let (:electric_guitar) { Instrument.find('electric guitar')}
- let (:drummer) { FactoryGirl.create(:user, :last_jam_locidispid => 1, :last_jam_addr => 1) }
- let (:guitarist) { FactoryGirl.create(:user, :last_jam_locidispid => 1, :last_jam_addr => 1) }
- let (:bassist) { FactoryGirl.create(:user, :last_jam_locidispid => 1, :last_jam_addr => 1) }
- let (:vocalist) { FactoryGirl.create(:user, :last_jam_locidispid => 1, :last_jam_addr => 1) }
- let (:loser) { FactoryGirl.create(:user, :last_jam_locidispid => 2, :last_jam_addr => 2) }
+ let (:drummer) { FactoryGirl.create(:user, first_name: 'drummer', :last_jam_locidispid => 1, :last_jam_addr => 1, specific_instruments: [drums, guitar]) }
+ let (:guitarist) { FactoryGirl.create(:user, first_name: 'guitarist', :last_jam_locidispid => 1, :last_jam_addr => 1, specific_instruments: [guitar, drums]) }
+ let (:bassist) { FactoryGirl.create(:user, first_name: 'bassist', :last_jam_locidispid => 1, :last_jam_addr => 1, specific_instruments: [bass]) }
+ let (:vocalist) { FactoryGirl.create(:user, first_name: 'vocalist', :last_jam_locidispid => 1, :last_jam_addr => 1, specific_instruments: [vocals, electric_guitar]) }
+ let (:loser) { FactoryGirl.create(:user, first_name: 'loser', :last_jam_locidispid => 2, :last_jam_addr => 2, specific_instruments: [vocals, drums]) }
+
+ let (:session3_creator) {FactoryGirl.create(:user, first_name: 'session3_creator', :last_jam_locidispid => 3, :last_jam_addr => 3, specific_instruments: [vocals]) }
+ let (:session4_creator) {FactoryGirl.create(:user, first_name: 'session4_creator', :last_jam_locidispid => 4, :last_jam_addr => 4, specific_instruments: [vocals]) }
let (:session1) do
FactoryGirl.create(:music_session,
:creator => drummer,
:scheduled_start => Time.now() + 2.days,
- :musician_access => true,
- :approval_required => false,
+ :open_rsvps=> true,
+ :is_unstructured_rsvp => false,
:created_at => Time.now - 1.hour)
end
let (:session2) do
FactoryGirl.create(:music_session,
:creator => drummer,
+ :open_rsvps => false,
+ :is_unstructured_rsvp => false,
+ :scheduled_start => Time.now() + 2.days,
+ :created_at => Time.now - 1.hour)
+ end
+ let (:session3) do
+ FactoryGirl.create(:music_session,
+ :creator => session3_creator,
+ :open_rsvps => true,
+ :is_unstructured_rsvp => true,
+ :scheduled_start => Time.now() + 2.days,
+ :created_at => Time.now - 1.hour)
+ end
+ let (:session4) do
+ FactoryGirl.create(:music_session,
+ :creator => session4_creator,
+ :open_rsvps => true,
+ :is_unstructured_rsvp => true,
:scheduled_start => Time.now() + 2.days,
- :musician_access => true,
- :approval_required => false,
:created_at => Time.now - 1.hour)
end
@@ -49,23 +75,9 @@ describe EmailBatchScheduledSessions do
JamRuby::Score.delete_all
scheduled_batch.reset!
- drummer.musician_instruments << FactoryGirl.build(:musician_instrument, user: drummer, instrument: drums, proficiency_level: 2)
- drummer.musician_instruments << FactoryGirl.build(:musician_instrument, user: drummer, instrument: guitar, proficiency_level: 2)
-
- guitarist.musician_instruments << FactoryGirl.build(:musician_instrument, user: guitarist, instrument: guitar, proficiency_level: 2)
- guitarist.musician_instruments << FactoryGirl.build(:musician_instrument, user: guitarist, instrument: bass, proficiency_level: 2)
-
- bassist.musician_instruments << FactoryGirl.build(:musician_instrument, user: bassist, instrument: bass, proficiency_level: 2)
- bassist.musician_instruments << FactoryGirl.build(:musician_instrument, user: bassist, instrument: guitar, proficiency_level: 2)
-
- vocalist.musician_instruments << FactoryGirl.build(:musician_instrument, user: vocalist, instrument: vocals, proficiency_level: 2)
-
- loser.musician_instruments << FactoryGirl.build(:musician_instrument, user: loser, instrument: vocals, proficiency_level: 2)
- loser.musician_instruments << FactoryGirl.build(:musician_instrument, user: loser, instrument: drums, proficiency_level: 2)
-
- FactoryGirl.create(:rsvp_slot, :instrument => drums, :music_session => session1)
- FactoryGirl.create(:rsvp_slot, :instrument => guitar, :music_session => session1)
- FactoryGirl.create(:rsvp_slot, :instrument => bass, :music_session => session1)
+ @drums_rsvp_slot = FactoryGirl.create(:rsvp_slot, :instrument => drums, :music_session => session1)
+ @guitar_rsvp_slot = FactoryGirl.create(:rsvp_slot, :instrument => guitar, :music_session => session1)
+ @bass_rsvp_slot = FactoryGirl.create(:rsvp_slot, :instrument => bass, :music_session => session1)
FactoryGirl.create(:rsvp_slot, :instrument => drums, :music_session => session2)
FactoryGirl.create(:rsvp_slot, :instrument => guitar, :music_session => session2)
FactoryGirl.create(:rsvp_slot, :instrument => bass, :music_session => session2)
@@ -73,22 +85,176 @@ describe EmailBatchScheduledSessions do
# oo.rsvp_request_slot.update_attributes(chosen: true)
# oo = FactoryGirl.create(:rsvp_request, :user => vocalist, :rsvp_slot => oo)
# oo.rsvp_request_slot.update_attributes(chosen: true)
-
- end
-
- it 'sets up data properly' do
- JamRuby::Score.createx(1, 'a', 1, 1, 'a', 1, 10)
- JamRuby::Score.createx(1, 'a', 1, 2, 'a', 2, Score::MAX_YELLOW_LATENCY + 1)
expect(drummer.instruments.include?(drums)).to eq(true)
expect(drummer.instruments.include?(guitar)).to eq(true)
- obj = scheduled_batch.fetch_recipients
- expect(obj.count).to eq(2)
-
- scheduled_batch.deliver_batch
- expect(UserMailer.deliveries.length).to eq(2)
end
+ describe "everyone but loser has good enough scores" do
+
+ before(:each) do
+ JamRuby::Score.createx(1, 'a', 1, 1, 'a', 1, 10)
+ JamRuby::Score.createx(1, 'a', 1, 2, 'a', 2, (APP_CONFIG.max_yellow_full_score * 2) + 1)
+ @matching_instruments_users = [guitarist, bassist]
+ @good_score_users = [guitarist, bassist, vocalist] # not adding the drummer because he's the creator (he does have a good score to these others though)
+ end
+
+ describe "session1 is_unstructured" do
+ before(:each) do
+ session1.is_unstructured_rsvp = true
+ session1.save!
+ end
+
+ it 'finds anyone with good enough scores' do
+ obj = scheduled_batch.fetch_recipients
+ found_users = obj.map{ |user_and_sessions| user_and_sessions[0]}
+ @good_score_users.should =~ found_users
+
+ scheduled_batch.deliver_batch
+ expect(UserMailer.deliveries.length).to eq(@good_score_users.length)
+ end
+ end
+
+ it 'finds anyone with good enough scores and matching instruments' do
+ obj = scheduled_batch.fetch_recipients
+
+ #Database.dump("SELECT * FROM tmp_candidate_recipients") do |field, value|
+ # if field == 'receiver_id'
+ # User.find(value).first_name
+ # else
+ # value.to_s
+ # end
+ #end
+
+ found_users = obj.map{ |user_and_sessions| user_and_sessions[0]}
+ @matching_instruments_users.should =~ found_users
+
+ scheduled_batch.deliver_batch
+ expect(UserMailer.deliveries.length).to eq(@matching_instruments_users.length)
+ end
+
+ describe "closes a RSVP slot in session1" do
+ before(:each) do
+ request = FactoryGirl.create(:rsvp_request, user: loser)
+ FactoryGirl.create(:rsvp_request_rsvp_slot, chosen: true, rsvp_request: request, rsvp_slot: @bass_rsvp_slot)
+ end
+
+ it "finds one less" do
+ # the bass slot is closed; so we should not longer find the bassist in the results
+ @matching_instruments_users.delete(bassist).should_not be_nil
+
+ obj = scheduled_batch.fetch_recipients
+ found_users = obj.map{ |user_and_sessions| user_and_sessions[0]}
+ @matching_instruments_users.should =~ found_users
+
+ scheduled_batch.deliver_batch
+ expect(UserMailer.deliveries.length).to eq(@matching_instruments_users.length)
+ end
+ end
+
+ describe "2 more open sessions" do
+ before(:each) do
+ JamRuby::Score.createx(1, 'a', 1, session3_creator.last_jam_locidispid, 'a', 1, 5)
+ JamRuby::Score.createx(1, 'a', 1, session4_creator.last_jam_locidispid, 'a', 2, 20)
+ session3.touch
+ session4.touch
+ end
+
+ it "sessions are sorted by latency" do
+ obj = scheduled_batch.fetch_recipients
+ obj.length.should == @matching_instruments_users.length + [drummer, vocalist].length
+
+ # verify that all 4 users have the right sessions, in the right order
+ @matching_instruments_users.each do |user|
+ user_sessions = find_user_sessions(obj, user)
+ user_sessions.should == [session3, session1, session4]
+ end
+
+ user_sessions = find_user_sessions(obj, drummer)
+ user_sessions.should == [session3, session4]
+
+ user_sessions = find_user_sessions(obj, vocalist)
+ user_sessions.should == [session3, session4]
+ end
+ end
+
+ describe "21 more sessions" do
+ before(:each) do
+ 20.times do |i|
+ creator = FactoryGirl.create(:user, :last_jam_locidispid => 1, :last_jam_addr => 1)
+ FactoryGirl.create(:music_session,
+ :creator => creator,
+ :open_rsvps => true,
+ :is_unstructured_rsvp => true,
+ :scheduled_start => Time.now() + 2.days,
+ :created_at => Time.now - 1.hour)
+ end
+ end
+
+ it "prevents more than 20 sessions per user" do
+ obj = scheduled_batch.fetch_recipients
+ obj.length.should == 20 + 4 # 4 is vocalist, drummer, guitarist, and bassist. 20 is the users made in the before block
+
+
+ # the bassist should *potentially* the drummer's session, and these new 20 sessions. But we limit to 20.
+ user_sessions = find_user_sessions(obj, bassist)
+ user_sessions.length.should == 20
+ end
+ end
+
+ it 'finds anyone with good enough scores and matching instruments' do
+ obj = scheduled_batch.fetch_recipients
+
+ #Database.dump("SELECT * FROM tmp_candidate_recipients") do |field, value|
+ # if field == 'receiver_id'
+ # User.find(value).first_name
+ # else
+ # value.to_s
+ # end
+ #end
+
+ found_users = obj.map{ |user_and_sessions| user_and_sessions[0]}
+ @matching_instruments_users.should =~ found_users
+
+ scheduled_batch.deliver_batch
+ expect(UserMailer.deliveries.length).to eq(@matching_instruments_users.length)
+ end
+
+ describe "open_rsvp=false" do
+ before(:each) do
+ session1.open_rsvps = false
+ session1.save!
+ session2.open_rsvps = false
+ session2.save!
+ end
+
+ it "won't find an open_rsvps=false session without an invitation" do
+ obj = scheduled_batch.fetch_recipients
+ expect(obj.count).to eq(0)
+ end
+
+ describe "with invitations" do
+ let(:invitation) {friend(drummer, guitarist); FactoryGirl.create(:invitation, sender: drummer, receiver:guitarist, music_session: session1)}
+
+ before(:each) do
+ invitation.touch
+ end
+
+ it "finds user with the invite" do
+ obj = scheduled_batch.fetch_recipients
+ found_users = obj.map{ |user_and_sessions| user_and_sessions[0]}
+ [guitarist].should =~ found_users
+
+ scheduled_batch.deliver_batch
+ expect(UserMailer.deliveries.length).to eq(1)
+ end
+ end
+ end
+
+ end
+
+
+
it 'handles large batches' do
creators = []
8.downto(1) do |nn|
diff --git a/ruby/spec/jam_ruby/models/generic_state_spec.rb b/ruby/spec/jam_ruby/models/generic_state_spec.rb
new file mode 100644
index 000000000..671daeaba
--- /dev/null
+++ b/ruby/spec/jam_ruby/models/generic_state_spec.rb
@@ -0,0 +1,61 @@
+require 'spec_helper'
+
+describe GenericState do
+
+ def database_env (env)
+ singleton = GenericState.singleton
+ singleton.env = env
+ singleton.save!
+ end
+
+ def rails_env (env)
+ JamRuby::Environment.should_receive(:mode).any_number_of_times.and_return(env)
+ end
+
+ describe "allow_emails?" do
+
+ it "allows emails if database is production and env is production, with build number" do
+ database_env('production')
+ rails_env('production')
+ stub_const("ENV", {'BUILD_NUMBER' => 1})
+
+ GenericState.allow_emails?.should be_true
+ end
+
+ it "no emails if database is production and env is production, no build number" do
+ database_env('production')
+ rails_env('production')
+ stub_const("ENV", {'BUILD_NUMBER' => nil})
+
+ GenericState.allow_emails?.should be_false
+ end
+
+ it "allows emails if database is development and env is development" do
+ database_env('development')
+ rails_env('development')
+
+ GenericState.allow_emails?.should be_true
+ end
+
+ it "no emails if database development, and environment is test" do
+ database_env('development')
+ rails_env('test')
+ GenericState.allow_emails?.should be_false
+ end
+
+ it "no emails if database production, and environment is development" do
+ database_env('production')
+ rails_env('development')
+ stub_const("ENV", {'BUILD_NUMBER' => 1})
+
+ GenericState.allow_emails?.should be_false
+ end
+
+ it "no emails if database production, and environment is test" do
+ database_env('production')
+ rails_env('development')
+
+ GenericState.allow_emails?.should be_false
+ end
+ end
+end
\ No newline at end of file
diff --git a/ruby/spec/jam_ruby/models/music_session_spec.rb b/ruby/spec/jam_ruby/models/music_session_spec.rb
index da8692250..f7b9f2a8f 100644
--- a/ruby/spec/jam_ruby/models/music_session_spec.rb
+++ b/ruby/spec/jam_ruby/models/music_session_spec.rb
@@ -421,7 +421,7 @@ describe MusicSession do
let(:network_score) { 20 }
before(:each) do
- Score.createx(conn.locidispid, conn.client_id, conn.addr, searcher_conn.locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil)
+ Score.createx(conn.locidispid, conn.client_id, conn.addr, searcher_conn.locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil, nil, {auserid: creator.id, buserid: searcher.id})
end
it "no results" do
@@ -499,7 +499,7 @@ describe MusicSession do
FactoryGirl.create(:invitation, receiver:invitee, sender:creator, music_session: music_session)
# create a score between invitee, and searcher
- Score.createx(invitee.last_jam_locidispid, 'immaterial', 1, searcher_conn.locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil)
+ Score.createx(invitee.last_jam_locidispid, 'immaterial', 1, searcher_conn.locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil, nil, {auserid: invitee.id, buserid: searcher.id})
music_sessions, user_scores = sms(searcher, default_opts)
music_sessions.length.should == 1
@@ -580,14 +580,16 @@ describe MusicSession do
end
it "searcher_1" do
+
+
# create a bad score between searcher_1 and creator_1 (but we should still see it sort 1st because it's got an RSVP to the searcher)
- Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_1.locidispid, creator_conn_1.client_id, creator_conn_1.addr, bad_network_score, nil)
+ Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_1.locidispid, creator_conn_1.client_id, creator_conn_1.addr, bad_network_score, nil, nil, {auserid: searcher_1.id, buserid: creator_1.id})
# create a fair score between searcher_1 and creator_2 (but we should still see it sort 2st because it's got an invitation to the searcher)
- Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_2.locidispid, creator_conn_2.client_id, creator_conn_2.addr, fair_network_score, nil)
+ Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_2.locidispid, creator_conn_2.client_id, creator_conn_2.addr, fair_network_score, nil, nil, {auserid: searcher_1.id, buserid: creator_2.id})
# create a good score between searcher_1 and creator_3 (but we should still see it sort last because it's an open session; no affiliation with the searcher)
- Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_3.locidispid, creator_conn_3.client_id, creator_conn_3.addr, good_network_score, nil)
+ Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_3.locidispid, creator_conn_3.client_id, creator_conn_3.addr, good_network_score, nil, nil, {auserid: searcher_1.id, buserid: creator_3.id})
music_sessions, user_scores = sms(searcher_1, {client_id: searcher_conn_1.client_id})
@@ -777,5 +779,20 @@ describe MusicSession do
end
end
end
+
+ describe "scheduled session rescheduled logic" do
+
+ it "detect change to scheduling info" do
+
+ music_session1.description = "Hey!"
+ music_session1.save!
+ music_session1.scheduling_info_changed.should be_false
+
+ music_session1.scheduled_start = Time.now - 1.days
+ music_session1.save!
+ music_session1.scheduling_info_changed.should be_true
+
+ end
+ end
end
diff --git a/ruby/spec/jam_ruby/models/score_history_spec.rb b/ruby/spec/jam_ruby/models/score_history_spec.rb
index 67fcdae11..8c16dfc0c 100644
--- a/ruby/spec/jam_ruby/models/score_history_spec.rb
+++ b/ruby/spec/jam_ruby/models/score_history_spec.rb
@@ -38,6 +38,7 @@ describe ScoreHistory do
score_history.from_user_id.should == score1.auserid
score_history.from_latency_tester_id.should == score1.alatencytestid
score_history.from_addr.should == score1.aaddr
+ score_history.from_locidispid.should == score1.alocidispid
score_history.from_isp.should == austin[:jamisp].jam_company.company
score_history.from_country.should == austin[:geoiplocation].countrycode
score_history.from_region.should == austin[:geoiplocation].region
@@ -49,6 +50,7 @@ describe ScoreHistory do
score_history.to_user_id.should == score1.buserid
score_history.to_latency_tester_id.should == score1.blatencytestid
score_history.to_addr.should == score1.baddr
+ score_history.to_locidispid.should == score1.blocidispid
score_history.to_isp.should == dallas[:jamisp].jam_company.company
score_history.to_country.should == dallas[:geoiplocation].countrycode
score_history.to_region.should == dallas[:geoiplocation].region
diff --git a/ruby/spec/jam_ruby/resque/music_session_scheduler_spec.rb b/ruby/spec/jam_ruby/resque/music_session_scheduler_spec.rb
index ac4d95146..af872943b 100644
--- a/ruby/spec/jam_ruby/resque/music_session_scheduler_spec.rb
+++ b/ruby/spec/jam_ruby/resque/music_session_scheduler_spec.rb
@@ -18,8 +18,8 @@ describe "MusicSessionScheduler" do
MusicSession.all.count.should == 1
- # end the session
- ms.session_removed_at = Time.now
+ # move the session back more than 4 hours
+ ms.scheduled_start = Time.now - 5.hours
ms.save!
# run the scheduler again
@@ -27,7 +27,6 @@ describe "MusicSessionScheduler" do
MusicSession.all.count.should == 2
- MusicSession.where(:session_removed_at => nil).count.should == 1
MusicSession.where(:next_session_scheduled => true).count.should == 1
end
@@ -40,7 +39,7 @@ describe "MusicSessionScheduler" do
@scheduler.run
MusicSession.all.count.should == 1
- ms.session_removed_at = Time.now
+ ms.scheduled_start = Time.now - 3.hours
ms.save!
@scheduler.run
diff --git a/ruby/spec/mailers/render_emails_spec.rb b/ruby/spec/mailers/render_emails_spec.rb
index 9e505d2d1..7119d5db2 100644
--- a/ruby/spec/mailers/render_emails_spec.rb
+++ b/ruby/spec/mailers/render_emails_spec.rb
@@ -63,6 +63,70 @@ describe "RenderMailers", :slow => true do
it { @filename="welcome_betauser"; InvitedUserMailer.welcome_betauser(admin_invited_user).deliver }
end
+ describe "Daily Scheduled Session emails" do
+ let (:scheduled_batch) { FactoryGirl.create(:email_batch_scheduled_session) }
+ let(:music_session) { FactoryGirl.create(:music_session) }
+ let (:drums) { FactoryGirl.create(:instrument, :description => 'drums') }
+ let (:guitar) { FactoryGirl.create(:instrument, :description => 'guitar') }
+ let (:bass) { FactoryGirl.create(:instrument, :description => 'bass') }
+ let (:vocals) { FactoryGirl.create(:instrument, :description => 'vocal') }
+
+ let (:drummer) { FactoryGirl.create(:user, :last_jam_locidispid => 1, :last_jam_addr => 1) }
+ let (:guitarist) { FactoryGirl.create(:user, :last_jam_locidispid => 1, :last_jam_addr => 1) }
+ let (:bassist) { FactoryGirl.create(:user, :last_jam_locidispid => 1, :last_jam_addr => 1) }
+ let (:vocalist) { FactoryGirl.create(:user, :last_jam_locidispid => 1, :last_jam_addr => 1) }
+
+ let (:session1) do
+ FactoryGirl.create(:music_session,
+ :creator => drummer,
+ :scheduled_start => Time.now() + 2.days,
+ :musician_access => true,
+ :approval_required => false,
+ :created_at => Time.now - 1.hour)
+ end
+
+ let (:session2) do
+ FactoryGirl.create(:music_session,
+ :creator => drummer,
+ :scheduled_start => Time.now() + 2.days,
+ :musician_access => true,
+ :approval_required => false,
+ :created_at => Time.now - 1.hour)
+ end
+
+ before(:each) do
+ BatchMailer.deliveries.clear
+ scheduled_batch.reset!
+
+ drummer.musician_instruments << FactoryGirl.build(:musician_instrument, user: drummer, instrument: drums, proficiency_level: 2)
+ drummer.musician_instruments << FactoryGirl.build(:musician_instrument, user: drummer, instrument: guitar, proficiency_level: 2)
+
+ guitarist.musician_instruments << FactoryGirl.build(:musician_instrument, user: guitarist, instrument: guitar, proficiency_level: 2)
+ guitarist.musician_instruments << FactoryGirl.build(:musician_instrument, user: guitarist, instrument: bass, proficiency_level: 2)
+
+ vocalist.musician_instruments << FactoryGirl.build(:musician_instrument, user: vocalist, instrument: vocals, proficiency_level: 2)
+
+ FactoryGirl.create(:rsvp_slot, :instrument => drums, :music_session => session1)
+ FactoryGirl.create(:rsvp_slot, :instrument => guitar, :music_session => session1)
+ FactoryGirl.create(:rsvp_slot, :instrument => bass, :music_session => session1)
+
+ FactoryGirl.create(:rsvp_slot, :instrument => drums, :music_session => session2)
+ FactoryGirl.create(:rsvp_slot, :instrument => guitar, :music_session => session2)
+ FactoryGirl.create(:rsvp_slot, :instrument => bass, :music_session => session2)
+
+ JamRuby::Score.createx(1, 'a', 1, 1, 'a', 1, 10)
+ JamRuby::Score.createx(1, 'a', 1, 2, 'a', 2, Score::MAX_YELLOW_LATENCY + 1)
+ end
+
+ after(:each) do
+ BatchMailer.deliveries.length.should == 1
+ mail = BatchMailer.deliveries[0]
+ save_emails_to_disk(mail, @filename)
+ end
+
+ it "daily sessions" do @filename="daily_sessions"; scheduled_batch.deliver_batch end
+ end
+
end
def save_emails_to_disk(mail, filename)
diff --git a/ruby/spec/support/utilities.rb b/ruby/spec/support/utilities.rb
index 6305da2e7..b9db7f8ac 100644
--- a/ruby/spec/support/utilities.rb
+++ b/ruby/spec/support/utilities.rb
@@ -109,6 +109,19 @@ def app_config
def max_track_part_upload_failures
3
end
+
+ def max_good_full_score
+ 20
+ end
+
+ def max_yellow_full_score
+ 35
+ end
+
+ def max_red_full_score
+ 50
+ end
+
private
def audiomixer_workspace_path
@@ -169,4 +182,9 @@ def fake_geo_124_zip(geoisp_csv)
end
zipfile
+end
+
+def friend(user1, user2)
+ FactoryGirl.create(:friendship, user: user1, friend: user2)
+ FactoryGirl.create(:friendship, user: user2, friend: user1)
end
\ No newline at end of file
diff --git a/web/app/assets/javascripts/accounts_profile.js b/web/app/assets/javascripts/accounts_profile.js
index 5c7cb6123..d904f5f0e 100644
--- a/web/app/assets/javascripts/accounts_profile.js
+++ b/web/app/assets/javascripts/accounts_profile.js
@@ -4,7 +4,9 @@
context.JK = context.JK || {};
context.JK.AccountProfileScreen = function(app) {
+ var $document = $(document);
var logger = context.JK.logger;
+ var EVENTS = context.JK.EVENTS;
var api = context.JK.Rest();
var userId;
var user = {};
@@ -63,6 +65,7 @@
$('select#user_birth_date_1i', content_root).val(parseInt(birthDateYear));
$('select#user_birth_date_2i', content_root).val(parseInt(birthDateMonth));
$('select#user_birth_date_3i', content_root).val(parseInt(birthDateDay));
+
}
// update instruments
@@ -87,6 +90,7 @@
}
context.JK.dropdown($('select', content_root));
+
}
function isUserInstrument(instrument, userInstruments) {
@@ -317,7 +321,9 @@
.always(function() { loadingCitiesData = false;})
}
}
+
})
+ context.JK.dropdown($('select'));
}
function navToAccount() {
@@ -366,6 +372,9 @@
},
null,
true);
+
+ $document.triggerHandler(EVENTS.USER_UPDATED, response);
+
}
function postUpdateProfileFailure(xhr, textStatus, errorMessage) {
diff --git a/web/app/assets/javascripts/accounts_profile_avatar.js b/web/app/assets/javascripts/accounts_profile_avatar.js
index 388bed37c..c89039d97 100644
--- a/web/app/assets/javascripts/accounts_profile_avatar.js
+++ b/web/app/assets/javascripts/accounts_profile_avatar.js
@@ -6,6 +6,7 @@
context.JK.AccountProfileAvatarScreen = function(app) {
var self = this;
var logger = context.JK.logger;
+ var EVENTS = context.JK.EVENTS;
var rest = context.JK.Rest();
var user = {};
var tmpUploadPath = null;
@@ -381,9 +382,9 @@
self.userDetail = response;
// notify any listeners that the avatar changed
- userDropdown.loadMe();
+ // userDropdown.loadMe();
// $('.avatar_large img').trigger('avatar_changed', [self.userDetail.photo_url]);
-
+ $(document).triggerHandler(EVENTS.USER_UPDATED, response);
app.notify(
{ title: "Avatar Changed",
text: "You have updated your avatar successfully."
diff --git a/web/app/assets/javascripts/dialog/rsvpSubmitDialog.js b/web/app/assets/javascripts/dialog/rsvpSubmitDialog.js
index 228b0077f..895927135 100644
--- a/web/app/assets/javascripts/dialog/rsvpSubmitDialog.js
+++ b/web/app/assets/javascripts/dialog/rsvpSubmitDialog.js
@@ -28,11 +28,15 @@
$('.schedule-recurrence', $dialog).html("Recurs " + response.recurring_mode + " on this day at this time");
}
+ var hasOpenSlots = response.open_slots && response.open_slots.length > 0;
+
+
if (response['is_unstructured_rsvp?']) {
- $('.rsvp-instruments', $dialog).append(' Any Instrument ');
+ var checkedState = hasOpenSlots ? '' : 'checked="checked"'
+ $('.rsvp-instruments', $dialog).append(' Play Any Instrument You Like ');
}
- if (response.open_slots && response.open_slots.length > 0) {
+ if (hasOpenSlots) {
$.each(response.open_slots, function(index, val) {
var instrument = val.instrument_id;
diff --git a/web/app/assets/javascripts/dialog/textMessageDialog.js b/web/app/assets/javascripts/dialog/textMessageDialog.js
index f2e67a0c0..78107a7f9 100644
--- a/web/app/assets/javascripts/dialog/textMessageDialog.js
+++ b/web/app/assets/javascripts/dialog/textMessageDialog.js
@@ -201,13 +201,13 @@
}
function renderNotConnected() {
- console.log("RENDER NOT CONNECTED!!!!!!!!!")
+ logger.debug("text-message dialog: render not connected")
$interactionBlocker.addClass('active');
$disconnectedMsg.addClass('active');
}
function renderConnected() {
- console.log("RENDER CONNECTED!!!!!!!!!")
+ logger.debug("text-message dialog: render connected")
$interactionBlocker.removeClass('active');
$disconnectedMsg.removeClass('active');
}
diff --git a/web/app/assets/javascripts/faderHelpers.js b/web/app/assets/javascripts/faderHelpers.js
index 98b901626..9da5eb923 100644
--- a/web/app/assets/javascripts/faderHelpers.js
+++ b/web/app/assets/javascripts/faderHelpers.js
@@ -203,6 +203,19 @@
return temp;
},
+
+ convertPercentToAudioTaper: function (input) {
+
+ // composite function resembling audio taper
+ if (input <= 1) { return -80; }
+ if (input <= 28) { return (2 * input - 80); }
+ if (input <= 79) { return (0.5 * input - 38); }
+ if (input < 99) { return (0.875 * input - 67.5); }
+ if (input >= 99) { return 20; }
+
+ },
+
+
setFaderValue: function (faderId, faderValue) {
var $fader = $('[fader-id="' + faderId + '"]');
this.setHandlePosition($fader, faderValue);
diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js
index 7750d836c..ea8b9f564 100644
--- a/web/app/assets/javascripts/findMusician.js
+++ b/web/app/assets/javascripts/findMusician.js
@@ -89,8 +89,8 @@
// these are raw scores as reported by client (round trip times)
if (score == null) return "purple";
if (0 < score && score <= 40) return "green";
- if (40 < score && score <= 80) return "yellow";
- if (80 < score && score <= 120) return "red";
+ if (40 < score && score <= 70) return "yellow";
+ if (70 < score && score <= 100) return "red";
return "blue";
}
@@ -98,8 +98,8 @@
// these are raw scores as reported by client (round trip times)
if (score == null) return "missing";
if (0 < score && score <= 40) return "good";
- if (40 < score && score <= 80) return "moderate";
- if (80 < score && score <= 120) return "poor";
+ if (40 < score && score <= 70) return "moderate";
+ if (70 < score && score <= 100) return "poor";
return "unacceptable";
}
@@ -126,6 +126,7 @@
var mVals, musician, renderings='';
var instr_logos, instr;
var follows, followVals, aFollow;
+ var myAudioLatency = musicianList.my_audio_latency;
for (ii=0, len=musicians.length; ii < len; ii++) {
musician = musicians[ii];
@@ -165,7 +166,7 @@
};
var musician_actions = context.JK.fillTemplate(aTemplate, actionVals);
- var joined_score = musician['joined_score']
+ var full_score = musician['full_score'];
mVals = {
avatar_url: context.JK.resolveAvatarUrl(musician.photo_url),
profile_url: "/client#/profile/" + musician.id,
@@ -180,22 +181,27 @@
musician_id: musician['id'],
musician_follow_template: follows,
musician_action_template: musician_actions,
- musician_one_way_score: score_to_text(joined_score),
- musician_score_color: score_to_color(joined_score),
- musician_score_color_alt: score_to_color_alt(joined_score)
+ musician_one_way_score: score_to_text(full_score),
+ musician_score_color: score_to_color(full_score),
+ musician_score_color_alt: score_to_color_alt(full_score)
+
};
- var musician_row = context.JK.fillTemplate(mTemplate, mVals);
- renderings += musician_row;
+ var $rendering = $(context.JK.fillTemplate(mTemplate, mVals))
+
+ var $offsetParent = $results.closest('.content');
+ var options = {positions: ['top', 'bottom', 'right', 'left'], offsetParent: $offsetParent};
+ var scoreOptions = {positions: ['right', 'top', 'bottom', 'left'], offsetParent: $offsetParent, width:'600px'};
+ context.JK.helpBubble($('.follower-count', $rendering), 'musician-follower-count', {}, options);
+ context.JK.helpBubble($('.friend-count', $rendering), 'musician-friend-count', {}, options);
+ context.JK.helpBubble($('.recording-count', $rendering), 'musician-recording-count', {}, options);
+ context.JK.helpBubble($('.session-count', $rendering), 'musician-session-count', {}, options);
+ context.JK.helpBubble($('.score-count', $rendering), 'musician-score-count',
+ {full_score: full_score ? Math.round(full_score / 2) : null, my_gear_latency: myAudioLatency, their_gear_latency:musician['audio_latency'], internet_latency: musician['score']},
+ scoreOptions)
+
+ $results.append($rendering);
}
- var $renderings = $(renderings);
- var $offsetParent = $results.closest('.content');
- var options = {positions: ['top', 'bottom', 'right', 'left'], offsetParent: $offsetParent}
- context.JK.helpBubble($('.follower-count', $renderings), 'musician-follower-count', {}, options);
- context.JK.helpBubble($('.friend-count', $renderings), 'musician-friend-count', {}, options);
- context.JK.helpBubble($('.recording-count', $renderings), 'musician-recording-count', {}, options);
- context.JK.helpBubble($('.session-count', $renderings), 'musician-session-count', {}, options);
- $results.append($renderings);
$('.search-m-friend').on('click', friendMusician);
$('.search-m-follow').on('click', followMusician);
diff --git a/web/app/assets/javascripts/findSession.js b/web/app/assets/javascripts/findSession.js
index 2d8141a8e..80e0fa67f 100644
--- a/web/app/assets/javascripts/findSession.js
+++ b/web/app/assets/javascripts/findSession.js
@@ -273,11 +273,11 @@
}
function clearResults() {
- $('table#sessions-active').empty();
+ $('table#sessions-active').find("tr:gt(0)").remove();
currentScheduledSessionsPage = 0;
$ssScroller.infinitescroll('resume');
- $('table#sessions-scheduled').empty();
+ $('table#sessions-scheduled').find("tr:gt(0)").remove();
$ssNoMoreEntries.hide();
}
diff --git a/web/app/assets/javascripts/globals.js b/web/app/assets/javascripts/globals.js
index 087e0213d..309c40509 100644
--- a/web/app/assets/javascripts/globals.js
+++ b/web/app/assets/javascripts/globals.js
@@ -32,8 +32,9 @@
SHOW_SIGNUP : 'show_signup',
SHOW_SIGNIN : 'show_signin',
RSVP_SUBMITTED: 'rsvp_submitted',
- RSVP_CANCELED : 'rsvp_canceled'
- }
+ RSVP_CANCELED : 'rsvp_canceled',
+ USER_UPDATED : 'user_updated'
+ };
context.JK.ALERT_NAMES = {
NO_EVENT : 0,
diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js
index 36cdcffc7..619ea3036 100644
--- a/web/app/assets/javascripts/jam_rest.js
+++ b/web/app/assets/javascripts/jam_rest.js
@@ -883,11 +883,7 @@
dataType: "json",
contentType: 'application/json',
url: "/api/users/progression/certified_gear",
- processData: false,
- data: JSON.stringify({
- success: options.success,
- reason: options.reason
- })
+ data: JSON.stringify(options)
});
}
@@ -1184,17 +1180,6 @@
});
}
- function updateAudioLatency(options) {
- var id = getId(options);
- return $.ajax({
- type: "POST",
- url: '/api/users/' + id + '/audio_latency',
- dataType: "json",
- contentType: 'application/json',
- data: options,
- });
- }
-
function initialize() {
return self;
}
@@ -1298,7 +1283,6 @@
this.getChatMessages = getChatMessages;
this.createDiagnostic = createDiagnostic;
this.getLatencyTester = getLatencyTester;
- this.updateAudioLatency = updateAudioLatency;
return this;
};
diff --git a/web/app/assets/javascripts/notificationPanel.js b/web/app/assets/javascripts/notificationPanel.js
index 6c43937f1..e1d7f955d 100644
--- a/web/app/assets/javascripts/notificationPanel.js
+++ b/web/app/assets/javascripts/notificationPanel.js
@@ -218,9 +218,10 @@
hoveraction: val.session_id ? "session" : "",
avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
text: val.formatted_msg,
- date: $.timeago(val.created_at)
+ date: $.timeago(val.created_at),
+ userId: val.source_user_id
});
-
+
$list.append(notificationHtml);
// val.description contains the notification record's description value from the DB (i.e., type)
@@ -307,10 +308,15 @@
}
var $action_btn = $notification.find($btnNotificationAction);
- $action_btn.text(actionText);
- $action_btn.click(function() {
- callback(payload);
- });
+ if (actionText === '') {
+ $action_btn.hide();
+ }
+ else {
+ $action_btn.text(actionText);
+ $action_btn.click(function() {
+ callback(payload);
+ });
+ }
}
else if (type === context.JK.MessageType.MUSICIAN_RECORDING_SAVED || type === context.JK.MessageType.BAND_RECORDING_SAVED) {
diff --git a/web/app/assets/javascripts/scheduled_session.js b/web/app/assets/javascripts/scheduled_session.js
index 63c9713b4..4075157cb 100644
--- a/web/app/assets/javascripts/scheduled_session.js
+++ b/web/app/assets/javascripts/scheduled_session.js
@@ -117,14 +117,14 @@
var firstSession = function() {
var $firstSession = $scheduledSessions.children().first().find('input[name="scheduled-session-info"]');
$firstSession.attr('checked', 'checked');
- createSessionSettings.selectedSessionId = $firstSession.attr('id');
+ createSessionSettings.selectedSessionId = $firstSession.attr('data-session-id');
};
if (createSessionSettings.selectedSessionId == null) {
firstSession();
}
else {
- var $selectedSession = $scheduledSessions.children().first().find('input[name="scheduled-session-info"][id="' + createSessionSettings.selectedSessionId + '"]');
+ var $selectedSession = $scheduledSessions.children().first().find('input[name="scheduled-session-info"][data-session-id="' + createSessionSettings.selectedSessionId + '"]');
if ($selectedSession.length)
$selectedSession.attr('checked', 'checked');
else
@@ -349,6 +349,7 @@
function beforeMoveStep1() {
if (createSessionSettings.createType == 'start-scheduled') {
+ createSessionSettings.selectedSessionId = $scheduledSessions.find('.iradio_minimal.checked input[name="scheduled-session-info"]').attr('data-session-id');
var session = scheduledSessions[createSessionSettings.selectedSessionId];
if(session == null) {
@@ -382,7 +383,7 @@
var startTime = new Date(session.scheduled_start);
var diffTime = startTime.getTime() - currentTime.getTime();
if (diffTime > ONE_HOUR) {
- var confirmDialog = new context.JK.ConfirmDialog(app, "Start Session Now",
+ var confirmDialog = new context.JK.ConfirmDialog(app, "START SESSION NOW",
"You are starting a session that is scheduled to begin more than one hour from now. Are you sure you want to do this?",
"Future Session", moveToFinish);
confirmDialog.initialize();
@@ -416,7 +417,7 @@
createSessionSettings.startTime = $startTimeList.val();
createSessionSettings.endTime = $endTimeList.val();
createSessionSettings.notations = [];
- createSessionSettings.selectedSessionId = $scheduledSessions.find('input[name="scheduled-session-info"][checked="checked"]').attr('id');
+ createSessionSettings.selectedSessionId = $scheduledSessions.find('.iradio_minimal.checked input[name="scheduled-session-info"]').attr('data-session-id');
createSessionSettings.timezone.value = $timezoneList.val();
createSessionSettings.timezone.label = $timezoneList.get(0).options[$timezoneList.get(0).selectedIndex].text;
createSessionSettings.recurring_mode.label = $recurringModeList.get(0).options[$recurringModeList.get(0).selectedIndex].text;
@@ -569,22 +570,28 @@
}
function startSessionClicked() {
+ var $btn = $(this);
+ if($btn.is('.disabled')) { return false; }
+ $btn.addClass('disabled')
if(willOptionStartSession()) {
gearUtils.guardAgainstInvalidConfiguration(app)
.fail(function() {
+ $btn.removeClass('disabled')
app.notify(
{ title: "Unable to Start New Session",
text: "You can only start a session once you have working audio gear and a tested internet connection."
})
})
.done(function(){
- startSession();
+ startSession($btn);
});
}
else {
- startSession();
+ startSession($btn);
}
+
+ return false;
}
// did the user have to pick the RSVP slots explicitely?
@@ -592,7 +599,7 @@
return createType == "immediately" || createType == "schedule-future" || createType == "rsvp";
}
- function startSession() {
+ function startSession($startBtn) {
var data = {};
@@ -682,36 +689,12 @@
}
var joinSession = function(sessionId) {
- var tracks = context.JK.TrackHelpers.getUserTracks(context.jamClient);
-
- var options = {};
- options.client_id = app.clientId;
- options.session_id = sessionId;
- options.as_musician = true;
- options.tracks = tracks;
- rest.joinSession(options)
- .done(function(response) {
- var invitationCount = data.invitations.length;
-
- context.location = '/client#/session/' + sessionId;
-
- context.JK.GA.trackSessionCount(data.musician_access, data.fan_access, invitationCount);
- context.JK.GA.trackSessionMusicians(context.JK.GA.SessionCreationTypes.create);
- })
- .fail(function(jqXHR) {
- var handled = false;
- if(jqXHR.status = 422) {
- var response = JSON.parse(jqXHR.responseText);
- if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") {
- app.notifyAlert("No Inputs Configured", $('You will need to reconfigure your audio device. '));
- handled = true;
- }
- }
- if(!handled) {
- app.notifyServerError(jqXHR, "Unable to Create Session");
- }
- })
+ var invitationCount = data.invitations.length;
+ context.JK.GA.trackSessionCount(data.musician_access, data.fan_access, invitationCount);
+ // we redirect to the session screen, which handles the REST call to POST /participants.
+ logger.debug("joining session screen: " + sessionId)
+ context.location = '/client#/session/' + sessionId;
};
if (createSessionSettings.createType == 'start-scheduled') {
@@ -734,9 +717,10 @@
}
})
.fail(function(jqXHR){
+ $startBtn.removeClass('disabled');
logger.debug("unable to schedule a session")
app.notifyServerError(jqXHR, "Unable to schedule a session");
- });
+ })
}
}
diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js
index 25a5e0915..51f28cf5c 100644
--- a/web/app/assets/javascripts/session.js
+++ b/web/app/assets/javascripts/session.js
@@ -315,6 +315,12 @@
null,
true);
}
+ else if(xhr.status == 422) {
+ var response = JSON.parse(jqXHR.responseText);
+ if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") {
+ app.notifyAlert("No Inputs Configured", $('You will need to reconfigure your audio device. '));
+ }
+ }
else {
app.notifyServerError(xhr, 'Unable to Join Session');
}
@@ -569,6 +575,7 @@
$voiceChat.show();
$voiceChat.attr('mixer-id', mixer.id);
var $voiceChatGain = $voiceChat.find('.voicechat-gain');
+ $voiceChatGain.attr('mixer-id', mixer.id);
var $voiceChatMute = $voiceChat.find('.voicechat-mute').attr('mixer-id', mixer.id);
var gainPercent = percentFromMixerValue(
mixer.range_low, mixer.range_high, mixer.volume_left);
@@ -1147,8 +1154,8 @@
// volumes on trackVolumeObject, and call SetControlState to stick.
var sliderValue = percentToMixerValue(
currentMixerRangeMin, currentMixerRangeMax, volumePercent);
- context.trackVolumeObject.volL = sliderValue;
- context.trackVolumeObject.volR = sliderValue;
+ context.trackVolumeObject.volL = context.JK.FaderHelpers.convertPercentToAudioTaper(volumePercent);
+ context.trackVolumeObject.volR = context.JK.FaderHelpers.convertPercentToAudioTaper(volumePercent);
// Special case for L2M mix:
if (mixerId === '__L2M__') {
logger.debug("L2M volumePercent=" + volumePercent);
diff --git a/web/app/assets/javascripts/sessionList.js b/web/app/assets/javascripts/sessionList.js
index b471e5a1f..4321cc183 100644
--- a/web/app/assets/javascripts/sessionList.js
+++ b/web/app/assets/javascripts/sessionList.js
@@ -21,9 +21,9 @@
var LATENCY = {
GOOD : {description: "GOOD", style: "latency-green", min: 0.0, max: 20.0},
- MEDIUM : {description: "MEDIUM", style: "latency-yellow", min: 20.0, max: 40.0},
- POOR : {description: "POOR", style: "latency-red", min: 40.0, max: 10000000000.0},
- UNREACHABLE: {description: "UNREACHABLE", style: "latency-grey", min: -1, max: -1},
+ MEDIUM : {description: "MEDIUM", style: "latency-yellow", min: 20.0, max: 35.0},
+ POOR : {description: "POOR", style: "latency-red", min: 35.0, max: 50},
+ UNACCEPTABLE: {description: "UNACCEPTABLE", style: "latency-grey", min: 50, max: 10000000},
UNKNOWN: {description: "UNKNOWN", style: "latency-grey", min: -2, max: -2}
};
@@ -350,7 +350,10 @@
}
function createLatency(user) {
- var latencyStyle = LATENCY.UNREACHABLE.style, latencyDescription = LATENCY.UNREACHABLE.description
+
+ var latencyStyle;
+ var latencyDescription;
+
if (user.id === context.JK.currentUserId) {
latencyStyle = LATENCY.GOOD.style, latencyDescription = LATENCY.GOOD.description;
}
@@ -358,24 +361,25 @@
else {
var latency = user.latency;
- if (!latency || latency === 1000) {
- // 1000 is a magical number returned by new scoring API to indicate one or more people in the session have an unknown score
+ if (!latency) {
latencyDescription = LATENCY.UNKNOWN.description;
latencyStyle = LATENCY.UNKNOWN.style;
}
+ else if (latency <= LATENCY.GOOD.max) {
+ latencyDescription = LATENCY.GOOD.description;
+ latencyStyle = LATENCY.GOOD.style;
+ }
+ else if (latency > LATENCY.MEDIUM.min && latency <= LATENCY.MEDIUM.max) {
+ latencyDescription = LATENCY.MEDIUM.description;
+ latencyStyle = LATENCY.MEDIUM.style;
+ }
+ else if (latency > LATENCY.POOR.min && latency <= LATENCY.UNACCEPTABLE.max) {
+ latencyDescription = LATENCY.POOR.description;
+ latencyStyle = LATENCY.POOR.style;
+ }
else {
- if (latency <= LATENCY.GOOD.max) {
- latencyDescription = LATENCY.GOOD.description;
- latencyStyle = LATENCY.GOOD.style;
- }
- else if (latency > LATENCY.MEDIUM.min && latency <= LATENCY.MEDIUM.max) {
- latencyDescription = LATENCY.MEDIUM.description;
- latencyStyle = LATENCY.MEDIUM.style;
- }
- else {
- latencyDescription = LATENCY.POOR.description;
- latencyStyle = LATENCY.POOR.style;
- }
+ latencyStyle = LATENCY.UNREACHABLE.style
+ latencyDescription = LATENCY.UNREACHABLE.description
}
}
diff --git a/web/app/assets/javascripts/sessionModel.js b/web/app/assets/javascripts/sessionModel.js
index 0adb1fdc9..d7fb0a424 100644
--- a/web/app/assets/javascripts/sessionModel.js
+++ b/web/app/assets/javascripts/sessionModel.js
@@ -87,17 +87,22 @@
var deferred = joinSessionRest(sessionId);
deferred
- .done(function(){
+ .done(function(response){
logger.debug("calling jamClient.JoinSession");
+ // on temporary disconnect scenarios, a user may already be in a session when they enter this path
+ // so we avoid double counting
if(!alreadyInSession()) {
- // on temporary disconnect scenarios, a user may already be in a session when they enter this path
- // so we avoid double counting
+ if(response.music_session.participant_count == 1) {
+ context.JK.GA.trackSessionMusicians(context.JK.GA.SessionCreationTypes.create);
+ }
+ else {
context.JK.GA.trackSessionMusicians(context.JK.GA.SessionCreationTypes.join);
+ }
}
recordingModel.reset();
client.JoinSession({ sessionID: sessionId });
- refreshCurrentSession();
+ refreshCurrentSession(true);
server.registerMessageCallback(context.JK.MessageType.SESSION_JOIN, trackChanges);
server.registerMessageCallback(context.JK.MessageType.SESSION_DEPART, trackChanges);
server.registerMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
diff --git a/web/app/assets/javascripts/user_dropdown.js b/web/app/assets/javascripts/user_dropdown.js
index 656ce71ab..3242ec824 100644
--- a/web/app/assets/javascripts/user_dropdown.js
+++ b/web/app/assets/javascripts/user_dropdown.js
@@ -6,7 +6,7 @@
context.JK = context.JK || {};
context.JK.UserDropdown = function (app) {
-
+ var EVENTS = context.JK.EVENTS;
var logger = context.JK.logger;
var rest = new JK.Rest();
var userMe = null;
@@ -53,12 +53,16 @@
$('.shortcuts .test-network').on('click', function(e) {
app.layout.showDialog('network-test');
return false;
- })
+ });
$('#header-avatar').on('avatar_changed', function (event, newAvatarUrl) {
updateAvatar(newAvatarUrl);
event.preventDefault();
return false;
+ });
+ $(document).on(EVENTS.USER_UPDATED, function(e, data) {
+ userMe = data;
+ updateHeader();
})
}
@@ -115,5 +119,8 @@
loadMe();
}
this.loadMe = loadMe;
+
}
-})(window, jQuery);
\ No newline at end of file
+})(window, jQuery);
+
+
diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js
index 3270cc59e..38785e099 100644
--- a/web/app/assets/javascripts/utils.js
+++ b/web/app/assets/javascripts/utils.js
@@ -185,7 +185,7 @@
cornerRadius: 0,
cssStyles: {
fontSize: '11px',
- color: 'white',
+ color: '#cccccc',
whiteSpace: 'normal'
}
};
diff --git a/web/app/assets/javascripts/web/session_info.js b/web/app/assets/javascripts/web/session_info.js
index 7e8ef3dac..d95684437 100644
--- a/web/app/assets/javascripts/web/session_info.js
+++ b/web/app/assets/javascripts/web/session_info.js
@@ -174,7 +174,10 @@
$('.call-to-action').html('Tell the session organizer if you can no longer join this session');
$btnAction.html('CANCEL RSVP');
$btnAction.click(function(e) {
- ui.launchRsvpCancelDialog(musicSessionId, rsvp.id);
+ ui.launchRsvpCancelDialog(musicSessionId, rsvp.id)
+ .one(EVENTS.RSVP_CANCELED, function() {
+ location.reload();
+ });
});
}
}
@@ -184,7 +187,10 @@
$('.call-to-action').html("Tell the session organizer you'd like to play in this session");
$btnAction.html('RSVP NOW!');
$btnAction.click(function(e) {
- ui.launchRsvpSubmitDialog(musicSessionId);
+ ui.launchRsvpSubmitDialog(musicSessionId)
+ .one(EVENTS.RSVP_SUBMITTED, function() {
+ location.reload();
+ })
});
}
})
@@ -201,14 +207,6 @@
});
addLatencyDetails();
-
- $(document).on(EVENTS.RSVP_SUBMITTED, function() {
- location.reload();
- });
-
- $(document).on(EVENTS.RSVP_CANCELED, function() {
- location.reload();
- });
}
this.initialize = initialize;
diff --git a/web/app/assets/javascripts/wizard/gear_test.js b/web/app/assets/javascripts/wizard/gear_test.js
index 032a427f2..c6c897daf 100644
--- a/web/app/assets/javascripts/wizard/gear_test.js
+++ b/web/app/assets/javascripts/wizard/gear_test.js
@@ -433,7 +433,7 @@
context.JK.GA.trackAudioTestData(uniqueDeviceName(), context.JK.GA.AudioTestDataReasons.pass, latencyScore);
- rest.userCertifiedGear({success: true, client_id: app.clientId, audio_latency: getLatencyScore()});
+ rest.userCertifiedGear({success: true, client_id: app.clientId, audio_latency: getLatencyScore().latency});
}
function onGearTestFail(e, data) {
diff --git a/web/app/assets/javascripts/wizard/gear_utils.js b/web/app/assets/javascripts/wizard/gear_utils.js
index 6eb7aa2eb..13e182582 100644
--- a/web/app/assets/javascripts/wizard/gear_utils.js
+++ b/web/app/assets/javascripts/wizard/gear_utils.js
@@ -269,14 +269,6 @@
return result;
}
- gearUtils.updateAudioLatency = function(app) {
- var latency = jamClient.FTUEGetExpectedLatency().latency;
- return rest.updateAudioLatency({client_id: app.clientId, audio_latency: latency})
- .fail(function(jqXHR) {
- app.notifyServerError(jqXHR, "Unable to sync audio latency")
- });
- }
-
// if the user has a good user network score, immediately returns with a resolved deferred object.
// if not, the user will have the network test dialog prompted... once it's closed, then you'll be told reject() if score is still bad, or resolve() if now good
gearUtils.guardAgainstBadNetworkScore = function(app) {
diff --git a/web/app/assets/stylesheets/client/client.css b/web/app/assets/stylesheets/client/client.css
index d6325a7c0..68b4073ce 100644
--- a/web/app/assets/stylesheets/client/client.css
+++ b/web/app/assets/stylesheets/client/client.css
@@ -53,6 +53,7 @@
*= require ./searchResults
*= require ./clientUpdate
*= require ./musician
+ *= require ./help
*= require ./jquery-ui-overrides
*= require web/audioWidgets
*= require web/recordings
diff --git a/web/app/assets/stylesheets/client/help.css.scss b/web/app/assets/stylesheets/client/help.css.scss
new file mode 100644
index 000000000..691bc7c74
--- /dev/null
+++ b/web/app/assets/stylesheets/client/help.css.scss
@@ -0,0 +1,43 @@
+.screen {
+ .bt-wrapper {
+ .bt-content {
+
+ color:#cccccc;
+
+ font-size:14px;
+
+ p {
+ font-size:14px;
+ }
+ ul {
+ font-size:14px;
+ }
+
+ li {
+ margin-left:1em;
+ margin-bottom:.5em;
+ }
+
+ .definition {
+ font-weight:bold;
+ }
+
+ .help-musician-score-count {
+ .measurement {
+
+ }
+
+ .measurement-value {
+ font-size:24px;
+ }
+
+ .measurement-absent {
+ font-style:italic;
+ font-size:12px;
+ display:block;
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/web/app/assets/stylesheets/client/sidebar.css.scss b/web/app/assets/stylesheets/client/sidebar.css.scss
index ff21873e4..f934b0cf3 100644
--- a/web/app/assets/stylesheets/client/sidebar.css.scss
+++ b/web/app/assets/stylesheets/client/sidebar.css.scss
@@ -312,5 +312,14 @@
.more-text-available {
}
}
+ .wrapword{
+ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* css-3 */
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+ word-break: break-all;
+ white-space: normal;
+ }
}
diff --git a/web/app/assets/stylesheets/web/main.css.scss b/web/app/assets/stylesheets/web/main.css.scss
index d3725237e..ab7a08f43 100644
--- a/web/app/assets/stylesheets/web/main.css.scss
+++ b/web/app/assets/stylesheets/web/main.css.scss
@@ -599,9 +599,6 @@ strong {
}
}
-body.jam.web.welcome .no-websocket-connection {
- display:none;
-}
-body.jam.web.register .no-websocket-connection {
+body.jam.web .no-websocket-connection {
display:none;
}
\ No newline at end of file
diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb
index ca84595f0..eae4ec2fb 100644
--- a/web/app/controllers/api_music_sessions_controller.rb
+++ b/web/app/controllers/api_music_sessions_controller.rb
@@ -224,7 +224,8 @@ class ApiMusicSessionsController < ApiController
response.status = :unprocessable_entity
respond_with @music_session
else
- Notification.send_scheduled_session_rescheduled(@music_session)
+ Notification.send_scheduled_session_rescheduled(@music_session) if @music_session.scheduling_info_changed
+
respond_with @music_session, responder: ApiResponder, :location => api_session_history_detail_url(@music_session)
end
else
@@ -287,7 +288,8 @@ class ApiMusicSessionsController < ApiController
params[:id],
params[:client_id],
params[:as_musician],
- params[:tracks]
+ params[:tracks],
+ params[:audio_latency]
)
if @connection.errors.any?
diff --git a/web/app/controllers/api_scoring_controller.rb b/web/app/controllers/api_scoring_controller.rb
index 34420e355..a72f5e579 100644
--- a/web/app/controllers/api_scoring_controller.rb
+++ b/web/app/controllers/api_scoring_controller.rb
@@ -24,6 +24,9 @@ class ApiScoringController < ApiController
conn = Connection.where(client_id: clientid, user_id: current_user.id).first
if conn.nil? then render :json => {message: 'session not found'}, :status => 404; return end
+
+ if conn.locidispid.nil? then render :json => {message: 'no locidispid for connection'}, :status => 404; return end
+
# if !current_user.id.eql?(conn.user.id) then render :json => {message: 'session not owned by user'}, :status => 403; return end
result_client_ids = JamRuby::GetWork.get_work_list(conn.locidispid, conn.addr)
diff --git a/web/app/controllers/api_users_controller.rb b/web/app/controllers/api_users_controller.rb
index 27f5f268d..30d507bc7 100644
--- a/web/app/controllers/api_users_controller.rb
+++ b/web/app/controllers/api_users_controller.rb
@@ -534,7 +534,7 @@ class ApiUsersController < ApiController
if !@user.errors.any?
# update audio gear latency information
- @user.update_audio_latency(connection, params[:audio_latency])
+ @user.update_audio_latency(connection, params[:audio_latency]) if params[:audio_latency]
end
else
@user.failed_qualification(params[:reason])
diff --git a/web/app/controllers/users_controller.rb b/web/app/controllers/users_controller.rb
index 8859fcbe4..c2d92c062 100644
--- a/web/app/controllers/users_controller.rb
+++ b/web/app/controllers/users_controller.rb
@@ -197,11 +197,11 @@ class UsersController < ApplicationController
@slides = [
Slide.new("JamKazam Overview", "web/carousel_musicians.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
- Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/VexH4834o9I?autoplay=1"),
- Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
+ Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/DBo--aj_P1w?autoplay=1"),
+ Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/zJ68hA8-fLA?autoplay=1"),
Slide.new("JamKazam Overview", "web/carousel_musicians.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
- Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/VexH4834o9I?autoplay=1"),
- Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1")
+ Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/DBo--aj_P1w?autoplay=1"),
+ Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/zJ68hA8-fLA?autoplay=1")
]
@promo_buzz = PromoBuzz.active
@@ -228,9 +228,6 @@ class UsersController < ApplicationController
if !@user.nil? && !@user.errors.any?
UserMailer.welcome_message(@user).deliver
- sign_in @user
- redirect_to :client
- return
elsif !@user.nil?
# new user with validation errors;
logger.debug("#{@user} has errors. can not sign in until remedied. #{@user.errors.inspect}")
@@ -463,6 +460,9 @@ JS
end
def load_location(remote_ip, location = nil)
+ # useful if you need to repro something on 127.0.0.1
+ # remote_ip = ' 23.119.29.89'
+
@location = location
if @location.nil?
@@ -471,7 +471,6 @@ JS
@location[:country] = "US" if @location[:country].nil?
- # right now we only accept US signups for beta
@countriesx = MaxMindManager.countries
# populate regions based on current country
@regions = MaxMindManager.regions(@location[:country])
diff --git a/web/app/views/api_feeds/show.rabl b/web/app/views/api_feeds/show.rabl
index 140828833..e502fcbf7 100644
--- a/web/app/views/api_feeds/show.rabl
+++ b/web/app/views/api_feeds/show.rabl
@@ -60,7 +60,7 @@ glue :music_session do
attributes :id, :name, :location, :photo_url
}
- child(:active_music_session => :music_session) do
+ child(:active_music_session => :active_music_session) do
# only show mount info if fan_access is public. Eventually we'll also need to show this in other scenarios, like if invited
child({:mount => :mount}, :if => lambda { |music_session| music_session.fan_access}) {
attributes :id, :name, :sourced, :listeners, :bitrate, :subtype, :url
diff --git a/web/app/views/api_music_sessions/participant_create.rabl b/web/app/views/api_music_sessions/participant_create.rabl
new file mode 100644
index 000000000..5c8fa8ea7
--- /dev/null
+++ b/web/app/views/api_music_sessions/participant_create.rabl
@@ -0,0 +1,13 @@
+object @connection
+
+extends "api_music_sessions/participant_show"
+
+attributes :music_session_id
+
+child(:music_session => :music_session) {
+ attributes :id
+
+ node :participant_count do |music_session|
+ music_session.connections.length
+ end
+}
\ No newline at end of file
diff --git a/web/app/views/api_music_sessions/participant_show.rabl b/web/app/views/api_music_sessions/participant_show.rabl
index cbbf29c87..1805cf45d 100644
--- a/web/app/views/api_music_sessions/participant_show.rabl
+++ b/web/app/views/api_music_sessions/participant_show.rabl
@@ -1,11 +1,8 @@
object @connection
-attributes :ip_address, :client_id
+attributes :ip_address, :client_id, :user_id
attribute :aasm_state => :connection_state
-node(:user_id, :if => lambda { |connection| connection.user.friends?(current_user) }) do |connection|
- connection.user_id
-end
child(:tracks => :tracks) {
attributes :id, :instrument_id, :sound
}
\ No newline at end of file
diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl
index 5c1f8b002..e7120fca6 100644
--- a/web/app/views/api_search/index.rabl
+++ b/web/app/views/api_search/index.rabl
@@ -41,9 +41,13 @@ if @search.musicians_filter_search?
node :page_count do |foo|
@search.page_count
end
+
+ node :my_audio_latency do |user|
+ current_user.last_jam_audio_latency
+ end
child(:results => :musicians) {
- attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url, :biography, :joined_score, :regionname
+ attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url, :biography, :regionname, :score, :full_score, :audio_latency
node :is_friend do |musician|
@search.is_friend?(musician)
diff --git a/web/app/views/clients/_account_profile.html.erb b/web/app/views/clients/_account_profile.html.erb
index bf1ec484f..c297b0f7b 100644
--- a/web/app/views/clients/_account_profile.html.erb
+++ b/web/app/views/clients/_account_profile.html.erb
@@ -79,7 +79,7 @@
Birth Date:
- <%= date_select("user", "birth_date", :use_short_month => true, :start_year => 1900, :end_year => Time.now.year - 18, :order => [:month, :day, :year], :default => -25.years.from_now) %>
+ <%= date_select("user", "birth_date", :use_short_month => true, :start_year => 1900, :end_year => Time.now.year - 18, :order => [:month, :day, :year], :default => -25.years.from_now, :html=>{:class => "account-profile-birthdate"} ) %>
diff --git a/web/app/views/clients/_account_session_detail.html.haml b/web/app/views/clients/_account_session_detail.html.haml
index 4d6ee95c0..7057069b8 100644
--- a/web/app/views/clients/_account_session_detail.html.haml
+++ b/web/app/views/clients/_account_session_detail.html.haml
@@ -89,7 +89,7 @@
%td
{{data.latency}}
.right
- %a{href: "/client#/profile/{{data.user_id}}", class: 'button-orange left', 'user-id' => "{{data.user_id}}", target: "_blank"} PROFILE
+ %a{href: "/client#/profile/{{data.user_id}}", class: 'button-orange left', 'user-id' => "{{data.user_id}}"} PROFILE
%a{href: "#", class: 'button-orange left approveRsvpRequest', 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}"} APPROVE
%a{href: "#", class: 'button-orange left declineRsvpRequest', 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}"} DECLINE
.clearall
diff --git a/web/app/views/clients/_account_session_properties.html.haml b/web/app/views/clients/_account_session_properties.html.haml
index 16d59f872..69a6364d5 100644
--- a/web/app/views/clients/_account_session_properties.html.haml
+++ b/web/app/views/clients/_account_session_properties.html.haml
@@ -80,7 +80,6 @@
Fan Access:
.right-column
%select#session-prop-fans-access
- %option{value: "listen-chat-band"} Fans may listen, chat with the band
%option{value: "listen-chat-each", selected: "selected"} Fans may listen, chat with each other
%option{value: "no-listen-chat"} Fans may not listen to session
.clearall.right-no-left
@@ -95,7 +94,6 @@
%option{value: "Standard"} Standard
%option{value: "Creative Commons"} Creative Commons
%option{value: "Offline"} Offline
- %option{value: "Jamtracks"} Jamtracks
.clearall.left-column
Notation Files:
.right-column
diff --git a/web/app/views/clients/_help.html.erb b/web/app/views/clients/_help.html.erb
index a476f3e24..1a531a89b 100644
--- a/web/app/views/clients/_help.html.erb
+++ b/web/app/views/clients/_help.html.erb
@@ -56,4 +56,26 @@
+
+
\ No newline at end of file
diff --git a/web/app/views/clients/_musicians.html.erb b/web/app/views/clients/_musicians.html.erb
index bbb81888e..df1b044b4 100644
--- a/web/app/views/clients/_musicians.html.erb
+++ b/web/app/views/clients/_musicians.html.erb
@@ -23,7 +23,7 @@
<% end -%>
-