From bedb377be8a0bae5de614e32c4dfdf38f9ae9fb5 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Fri, 13 Jun 2014 03:45:45 -0400 Subject: [PATCH 1/6] VRFS-1749 session info tests wip --- ruby/lib/jam_ruby/models/rsvp_request.rb | 2 +- .../assets/javascripts/web/session_info.js | 27 ++++- web/app/views/api_rsvp_requests/show.rabl | 10 +- web/spec/features/session_info_spec.rb | 114 +++++++++--------- 4 files changed, 81 insertions(+), 72 deletions(-) diff --git a/ruby/lib/jam_ruby/models/rsvp_request.rb b/ruby/lib/jam_ruby/models/rsvp_request.rb index 0b6a94e85..58cbe9ec7 100644 --- a/ruby/lib/jam_ruby/models/rsvp_request.rb +++ b/ruby/lib/jam_ruby/models/rsvp_request.rb @@ -154,7 +154,7 @@ module JamRuby raise StateError, "Slot does not exist" end - if rsvp_slot.chosen + if rsvp_slot.chosen && r[:accept] raise StateError, "The #{rsvp_slot.instrument_id} slot has already been approved for another user." end diff --git a/web/app/assets/javascripts/web/session_info.js b/web/app/assets/javascripts/web/session_info.js index ec86025cc..004fc8b23 100644 --- a/web/app/assets/javascripts/web/session_info.js +++ b/web/app/assets/javascripts/web/session_info.js @@ -83,18 +83,33 @@ rest.getRsvpRequests(musicSessionId) .done(function(rsvps) { if (rsvps && rsvps.length > 0) { - // should only be 1 RSVP for this session + // should only be 1 RSVP for this session and user var rsvp = rsvps[0]; if (rsvp.canceled) { $('.call-to-action').html('Your RSVP request to this session has been cancelled.'); $btnAction.hide(); } else { - $('.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); - }); + var declined = true; + if (rsvp.rsvp_requests_rsvp_slots) { + for (var x=0; x < rsvp.rsvp_requests_rsvp_slots.length; x++) { + if (rsvp.rsvp_requests_rsvp_slots[x].chosen) { + declined = false; + } + } + } + + if (declined) { + $('.call-to-action').html('Your RSVP request to this session has been declined.'); + $btnAction.hide(); + } + else { + $('.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); + }); + } } } // no RSVP diff --git a/web/app/views/api_rsvp_requests/show.rabl b/web/app/views/api_rsvp_requests/show.rabl index 0f113d7f7..8e9760e34 100644 --- a/web/app/views/api_rsvp_requests/show.rabl +++ b/web/app/views/api_rsvp_requests/show.rabl @@ -1,15 +1,15 @@ object @rsvp_request -attributes :id, :canceled, :created_at +attributes :id, :canceled, :cancel_all, :created_at child(:user => :user) { attributes :id, :name, :photo_url } -child(:rsvp_slots => :rsvp_slots) { - attributes :id, :instrument_id, :proficiency_level, :music_session_id +child(:rsvp_requests_rsvp_slots => :rsvp_requests_rsvp_slots) { + attributes :id, :chosen - child(:rsvp_requests_rsvp_slots => :rsvp_requests_rsvp_slots) { - attributes :id, :chosen + child(:rsvp_slot => :rsvp_slot) { + attributes :id, :instrument_id, :proficiency_level, :music_session_id } } \ No newline at end of file diff --git a/web/spec/features/session_info_spec.rb b/web/spec/features/session_info_spec.rb index 61159af6a..ad5e9f717 100644 --- a/web/spec/features/session_info_spec.rb +++ b/web/spec/features/session_info_spec.rb @@ -12,8 +12,11 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr MusicSession.delete_all User.delete_all - @rsvp_user = FactoryGirl.create(:user) - @rsvp_user.save + @rsvp_approved_user = FactoryGirl.create(:user) + @rsvp_approved_user.save + + @rsvp_declined_user = FactoryGirl.create(:user) + @rsvp_declined_user.save @session_invitee = FactoryGirl.create(:user) @session_invitee.save @@ -28,12 +31,17 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr FactoryGirl.create(:friendship, :user => @session_invitee, :friend => @session_creator) FactoryGirl.create(:friendship, :user => @session_creator, :friend => @session_invitee) - FactoryGirl.create(:friendship, :user => @rsvp_user, :friend => @session_creator) - FactoryGirl.create(:friendship, :user => @session_creator, :friend => @rsvp_user) + FactoryGirl.create(:friendship, :user => @rsvp_approved_user, :friend => @session_creator) + FactoryGirl.create(:friendship, :user => @session_creator, :friend => @rsvp_approved_user) + + FactoryGirl.create(:friendship, :user => @rsvp_declined_user, :friend => @session_creator) + FactoryGirl.create(:friendship, :user => @session_creator, :friend => @rsvp_declined_user) @music_session = FactoryGirl.build(:music_session, :creator => @session_creator) @music_session.save + @url = "/sessions/#{@music_session.id}/details" + @slot1 = FactoryGirl.build(:rsvp_slot, :music_session => @music_session, :instrument => JamRuby::Instrument.find('electric guitar')) @slot1.save @@ -43,17 +51,27 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr @invitation = FactoryGirl.build(:invitation, :sender => @session_creator, :receiver => @session_invitee, :music_session => @music_session) @invitation.save - @invitation = FactoryGirl.build(:invitation, :sender => @session_creator, :receiver => @rsvp_user, :music_session => @music_session) + @invitation = FactoryGirl.build(:invitation, :sender => @session_creator, :receiver => @rsvp_approved_user, :music_session => @music_session) @invitation.save - # create RSVP request - rsvp = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id, @slot2.id], :message => "Let's Jam!"}, @rsvp_user) + @invitation = FactoryGirl.build(:invitation, :sender => @session_creator, :receiver => @rsvp_declined_user, :music_session => @music_session) + @invitation.save + + # create RSVP request 1 + @rsvp1 = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id, @slot2.id], :message => "Let's Jam!"}, @rsvp_approved_user) + + # create RSVP request 2 + @rsvp2 = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id, @slot2.id], :message => "Let's Jam!"}, @rsvp_declined_user) # approve slot1 - rs1 = RsvpRequestRsvpSlot.find_by_rsvp_slot_id(@slot1.id) - rs2 = RsvpRequestRsvpSlot.find_by_rsvp_slot_id(@slot2.id) - RsvpRequest.update({:id => rsvp.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => true}, {:request_slot_id => rs2.id, :accept => false}]}, @session_creator) + rs1 = RsvpRequestRsvpSlot.find_by_rsvp_request_id_and_rsvp_slot_id(@rsvp1.id, @slot1.id) + rs2 = RsvpRequestRsvpSlot.find_by_rsvp_request_id_and_rsvp_slot_id(@rsvp1.id, @slot2.id) + RsvpRequest.update({:id => @rsvp1.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => true}, {:request_slot_id => rs2.id, :accept => false}]}, @session_creator) + # reject slot1 and slot2 + rs1 = RsvpRequestRsvpSlot.find_by_rsvp_request_id_and_rsvp_slot_id(@rsvp2.id, @slot1.id) + rs2 = RsvpRequestRsvpSlot.find_by_rsvp_request_id_and_rsvp_slot_id(@rsvp2.id, @slot2.id) + RsvpRequest.update({:id => @rsvp2.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => false}, {:request_slot_id => rs2.id, :accept => false}]}, @session_creator) end def ensure_success(options = {}) @@ -64,7 +82,11 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr find('div.creator-name', text: @session_creator.name) # action button - find('#btn-action') if options[:show_cta] + if options[:show_cta] + find('#btn-action', :text => options[:button_text]) + else + expect {find('#btn-action')}.to raise_error(Capybara::ElementNotFound) + end # session details find('div.scheduled_start') @@ -78,13 +100,13 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr # right sidebar - RSVPs find('div.rsvp-details .avatar-tiny') - find('div.rsvp-details .rsvp-name', text: @rsvp_user.name) + find('div.rsvp-details .rsvp-name', text: @rsvp_approved_user.name) find('div.rsvp-details img.instrument-icon') # right sidebar - Still Needed find('div.still-needed', text: @slot2.instrument.id.capitalize) - # right sidebar - Invited + # right sidebar - Pending Invitations find('div[user-id="' + @session_invitee.id + '"]') # comments @@ -103,30 +125,34 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr @music_session.save # attempt to access with musician who was invited but didn't RSVP - sign_in_poltergeist(@session_invitee) - url = "/sessions/#{@music_session.id}/details" - visit url - ensure_success({:show_cta => true}) + sign_in_poltergeist(@session_invitee) + visit @url + ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'}) sign_out_poltergeist - # attempt to access with musician who wasn't invited sign_in_poltergeist(@non_session_invitee) - + visit @url + ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'}) sign_out_poltergeist + # attempt to access with musician who RSVP'ed but wasn't approved + sign_in_poltergeist(@rsvp_declined_user) + visit @url + ensure_success({:show_cta => false}) + sign_out_poltergeist + + # attempt to access with musician who RSVP'ed and was approved + sign_in_poltergeist(@rsvp_approved_user) + visit @url + ensure_success({:show_cta => true, :button_text => 'CANCEL RSVP'}) + sign_out_poltergeist # attempt to access with session creator sign_in_poltergeist(@session_creator) - + visit @url + ensure_success({:show_cta => false}) sign_out_poltergeist - - - - # attempt to access with musician who RSVP'ed but wasn't approved - - - # attempt to access with musician who RSVP'ed and was approved end it "should render only for session invitees for sessions with closed RSVPs before session starts" do @@ -184,45 +210,13 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr # attempt to access with musician who RSVP'ed and was approved end - it "should render all required information" do - # access with a user who was invited but hasn't RSVPed yet - - - # session creator - - # date/time - - # genre - - # name - - # description - - # notation files - - # language - - # access - - # legal info - - # view comments - - - # sidebar - Approved RSVPs - - # sidebar - Open Slots - - # sidebar - Pending Invitations - end - it "should allow only RSVP approvals or session invitees to add comments" do end it "should show no call to action button if user has not RSVPed and all slots are taken" do end - it "should show no call to action button if the session organizer is viewing" do + it "should show no call to action button for session organizer" do end end From 715442b745ca9b4c8616084d81648a090777093b Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Fri, 13 Jun 2014 03:58:32 -0400 Subject: [PATCH 2/6] VRFS-1749 session info tests wip --- web/spec/features/session_info_spec.rb | 31 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/web/spec/features/session_info_spec.rb b/web/spec/features/session_info_spec.rb index ad5e9f717..1890a1a99 100644 --- a/web/spec/features/session_info_spec.rb +++ b/web/spec/features/session_info_spec.rb @@ -37,7 +37,7 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr FactoryGirl.create(:friendship, :user => @rsvp_declined_user, :friend => @session_creator) FactoryGirl.create(:friendship, :user => @session_creator, :friend => @rsvp_declined_user) - @music_session = FactoryGirl.build(:music_session, :creator => @session_creator) + @music_session = FactoryGirl.build(:music_session, :creator => @session_creator, :scheduled_start => Time.now.utc + 2.days) @music_session.save @url = "/sessions/#{@music_session.id}/details" @@ -114,7 +114,7 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr end def ensure_failure - find('div.not-found', text: "SESSION NOT FOUND") + find('strong.not-found', text: "SESSION NOT FOUND") end describe "view" do @@ -156,16 +156,35 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr end it "should render only for session invitees for sessions with closed RSVPs before session starts" do - # attempt to access with musician who wasn't invited - - # attempt to access with musician who was invited but didn't RSVP + sign_in_poltergeist(@session_invitee) + visit @url + ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'}) + sign_out_poltergeist + # attempt to access with musician who wasn't invited + sign_in_poltergeist(@non_session_invitee) + visit @url + ensure_failure # NON-INVITEE SHOULD NOT BE ABLE TO VIEW FOR CLOSED RSVPs + sign_out_poltergeist # attempt to access with musician who RSVP'ed but wasn't approved - + sign_in_poltergeist(@rsvp_declined_user) + visit @url + ensure_success({:show_cta => false}) + sign_out_poltergeist # attempt to access with musician who RSVP'ed and was approved + sign_in_poltergeist(@rsvp_approved_user) + visit @url + ensure_success({:show_cta => true, :button_text => 'CANCEL RSVP'}) + sign_out_poltergeist + + # attempt to access with session creator + sign_in_poltergeist(@session_creator) + visit @url + ensure_success({:show_cta => false}) + sign_out_poltergeist end # musician_access = false, approval_required = false From 691f0c1a6536ad386f8164f7ebcb94e4793bc04c Mon Sep 17 00:00:00 2001 From: Scott Comer Date: Fri, 13 Jun 2014 10:22:29 -0500 Subject: [PATCH 3/6] first cut at ams_index stored procedure --- db/up/ams_index.sql | 62 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 db/up/ams_index.sql diff --git a/db/up/ams_index.sql b/db/up/ams_index.sql new file mode 100644 index 000000000..56c060414 --- /dev/null +++ b/db/up/ams_index.sql @@ -0,0 +1,62 @@ +-- DROP FUNCTION IF EXISTS ams_index (my_user_id VARCHAR, my_locidispid BIGINT, my_audio_latency INTEGER, poff INTEGER, plim INTEGER); +CREATE OR REPLACE FUNCTION ams_index (my_user_id VARCHAR, my_locidispid BIGINT, my_audio_latency INTEGER) +RETURNS VOID +LANGUAGE plpgsql +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) NOT NULL, user_id VARCHAR(64) NOT NULL, latency INTEGER NOT NULL) ON COMMIT DROP; + + -- populate ams_users_tmp as all musicians in the ams_music_session_tmp sessions with audio latency and score + INSERT INTO ams_users_tmp SELECT c.music_session_id, c.user_id, (s.score+my_audio_latency+c.last_jam_audio_latency)/2 AS latency + FROM ams_music_session_tmp q, connections c, current_scores s WHERE + q.music_session_id = c.music_session_id AND + c.locidispid = s.alocidispid AND + s.blocidispid = my_locidispid AND + c.last_jam_audio_latency IS NOT NULL; + + -- 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; +$$; From beca3b5608bfb6bcda717aa52a6228ea6f01f097 Mon Sep 17 00:00:00 2001 From: Scott Comer Date: Fri, 13 Jun 2014 12:38:36 -0500 Subject: [PATCH 4/6] stub out active_music_sessions#ams_index --- .../jam_ruby/models/active_music_session.rb | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/ruby/lib/jam_ruby/models/active_music_session.rb b/ruby/lib/jam_ruby/models/active_music_session.rb index 75d49e5d0..197ea3300 100644 --- a/ruby/lib/jam_ruby/models/active_music_session.rb +++ b/ruby/lib/jam_ruby/models/active_music_session.rb @@ -314,6 +314,73 @@ module JamRuby return query end + # Generate a list of active music sessions filtered by genre, language, keyword, and sorted + # (and tagged) by rsvp'd (1st), invited (2nd), and musician can join (3rd). within a group + # tagged the same, sorted by score. date seems irrelevant as these are active sessions. + def self.ams_index(current_user, options = {}) + client_id = options[:client_id] + genre = options[:genre] + lang = options[:lang] + keyword = options[:keyword] + offset = options[:offset] + limit = options[:limit] + + connection = Connection.where(user_id: current_user.id, client_id: client_id).first! + my_locidispid = connection.locidispid + my_audio_latency = connection.last_jam_audio_latency + + query = ActiveMusicSession + .select('active_music_sessions.*, 1 as tag, 15 as latency') + .joins( + %Q{ + INNER JOIN + music_sessions + ON + music_sessions.id = active_music_sessions.id + } + ) + + # TODO integrate ams_music_session_tmp into the processing + # query = query.joins( + # %Q{ + # INNER JOIN + # ams_music_session_tmp + # ON + # ams_music_session_tmp.music_session_id = active_music_sessions.id + # } + # ) + + query = query.order( + %Q{ + tag, latency + } + ) + + if (offset) + query = query.offset(offset) + end + + if (limit) + query = query.limit(limit) + end + + # cleanse keyword so it is only word characters. ignore if less than 3 characters long or too long + # TODO do we want to force match of whole words only? this just picks the first word out... + + unless keyword.nil? or keyword.length < 3 or keyword.length > 100 + w = keyword.split(/\W+/) + if w.length > 0 and w.length >= 3 + query = query.where("music_sessions.description like '%#{w[0]}%'") + end + end + + query = query.where("music_sessions.genre_id in (?)", genres) unless genres.nil? + + # TODO filter by lang + + return query + end + def self.participant_create user, music_session_id, client_id, as_musician, tracks music_session = MusicSession.find(music_session_id) From b918d24d32005d675d599e3096a7781e61fec0cf Mon Sep 17 00:00:00 2001 From: Scott Comer Date: Fri, 13 Jun 2014 19:47:34 -0500 Subject: [PATCH 5/6] reverse query ams_index to produce list of augmented music_sessions --- .../jam_ruby/models/active_music_session.rb | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/ruby/lib/jam_ruby/models/active_music_session.rb b/ruby/lib/jam_ruby/models/active_music_session.rb index 197ea3300..57449ec49 100644 --- a/ruby/lib/jam_ruby/models/active_music_session.rb +++ b/ruby/lib/jam_ruby/models/active_music_session.rb @@ -314,7 +314,7 @@ module JamRuby return query end - # Generate a list of active music sessions filtered by genre, language, keyword, and sorted + # Generate a list of music sessions (that are active) filtered by genre, language, keyword, and sorted # (and tagged) by rsvp'd (1st), invited (2nd), and musician can join (3rd). within a group # tagged the same, sorted by score. date seems irrelevant as these are active sessions. def self.ams_index(current_user, options = {}) @@ -329,18 +329,23 @@ module JamRuby my_locidispid = connection.locidispid my_audio_latency = connection.last_jam_audio_latency - query = ActiveMusicSession - .select('active_music_sessions.*, 1 as tag, 15 as latency') - .joins( + query = MusicSession + .select('music_sessions.*') + + # TODO this is not really needed when ams_music_session_tmp is joined + # unless there is something specific we need out of active_music_sessions + query = query.joins( %Q{ INNER JOIN - music_sessions + active_music_sessions ON - music_sessions.id = active_music_sessions.id + active_music_sessions.id = music_sessions.id } ) + .select('1::integer as tag, 15::integer as latency') # TODO integrate ams_music_session_tmp into the processing + # then we can join ams_music_session_tmp and not join active_music_sessions # query = query.joins( # %Q{ # INNER JOIN @@ -349,6 +354,7 @@ module JamRuby # ams_music_session_tmp.music_session_id = active_music_sessions.id # } # ) + # .select('ams_music_session_tmp.tag, ams_music_session_tmp.latency') query = query.order( %Q{ @@ -364,8 +370,9 @@ module JamRuby query = query.limit(limit) end - # cleanse keyword so it is only word characters. ignore if less than 3 characters long or too long - # TODO do we want to force match of whole words only? this just picks the first word out... + # cleanse keyword so it is only word characters. ignore if less than 3 characters long or greater than 100 + # TODO do we want to force match of whole words only? this matches any substring... + # TODO do we want to match more than one word in the phrase? this matches only the first word... unless keyword.nil? or keyword.length < 3 or keyword.length > 100 w = keyword.split(/\W+/) @@ -374,7 +381,7 @@ module JamRuby end end - query = query.where("music_sessions.genre_id in (?)", genres) unless genres.nil? + query = query.where("music_sessions.genre_id = ?", genre) unless genre.nil? # TODO filter by lang From 2799a6443e24d7dbc4f441ff717a71264035afac Mon Sep 17 00:00:00 2001 From: Scott Comer Date: Fri, 13 Jun 2014 23:51:54 -0500 Subject: [PATCH 6/6] added asm_index method to controller and fix a few issues with asm_index and included a simple test --- .../jam_ruby/models/active_music_session.rb | 9 ++++-- .../models/active_music_session_spec.rb | 30 +++++++++++++++++++ .../api_music_sessions_controller.rb | 15 ++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/ruby/lib/jam_ruby/models/active_music_session.rb b/ruby/lib/jam_ruby/models/active_music_session.rb index 57449ec49..838606798 100644 --- a/ruby/lib/jam_ruby/models/active_music_session.rb +++ b/ruby/lib/jam_ruby/models/active_music_session.rb @@ -330,7 +330,7 @@ module JamRuby my_audio_latency = connection.last_jam_audio_latency query = MusicSession - .select('music_sessions.*') + .select('music_sessions.*') # TODO this is not really needed when ams_music_session_tmp is joined # unless there is something specific we need out of active_music_sessions @@ -358,7 +358,12 @@ module JamRuby query = query.order( %Q{ - tag, latency + tag, latency, music_sessions.id + } + ) + .group( + %Q{ + tag, latency, music_sessions.id } ) 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 4f2a1122a..4e838add1 100644 --- a/ruby/spec/jam_ruby/models/active_music_session_spec.rb +++ b/ruby/spec/jam_ruby/models/active_music_session_spec.rb @@ -332,6 +332,36 @@ describe ActiveMusicSession do end end + describe "ams_index" do + it "does not crash" do + + creator = FactoryGirl.create(:user) + creator2 = FactoryGirl.create(:user) + + earlier_session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Earlier Session") + c1 = FactoryGirl.create(:connection, user: creator, music_session: earlier_session, addr: 0x01020304, locidispid: 1) + + later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session") + c2 = FactoryGirl.create(:connection, user: creator2, music_session: later_session, addr: 0x21020304, locidispid: 2) + + user = FactoryGirl.create(:user) + c3 = FactoryGirl.create(:connection, user: user, locidispid: 3) + + 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); + + music_sessions = ActiveMusicSession.ams_index(user, client_id: c3.client_id).take(100) + music_sessions.should_not be_nil + music_sessions.length.should == 2 + end + + # todo we need more tests: + # rsvp'd user (chosen and not chosen) + # invited user + # creator (who should be automatically rsvp'd) + # musician_access and not + end + it 'uninvited users cant join approval-required sessions without invitation' do user1 = FactoryGirl.create(:user) # in the jam session diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index 07722f646..5ee8dbd85 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -60,6 +60,21 @@ class ApiMusicSessionsController < ApiController limit: params[:limit]) end + def ams_index + # returns a relation which will produce a list of music_sessions which are active and augmented with attributes + # tag and latency, then sorted by tag, latency, and finally music_sessions.id (for stability). the list is + # filtered by genre, lang, and keyword, then paged by offset and limit (those are record numbers not page numbers). + # tag is 1 for chosen rsvp'd sessions, 2 for invited sessions, 3 for all others (musician_access). if you're the + # creator of a session it will be treated the same as if you had rsvp'd and been accepted. + @music_sessions = ActiveMusicSession.ams_index(current_user, + client_id: params[:client_id], + genre: params[:genre], + lang: params[:lang], + keyword: params[:keyword], + offset: params[:offset], + limit: params[:limit]) + end + def scheduled @music_sessions = MusicSession.scheduled(current_user) end