diff --git a/db/manifest b/db/manifest index 2f106063b..213ea0970 100755 --- a/db/manifest +++ b/db/manifest @@ -203,4 +203,5 @@ locidispid_in_score_histories.sql define_environment_in_db.sql drop_session_invite_constraint.sql sms_index_single_session.sql -fix_current_scores_user_association.sql \ No newline at end of file +fix_current_scores_user_association.sql +undirected_scores.sql \ No newline at end of file diff --git a/db/up/undirected_scores.sql b/db/up/undirected_scores.sql new file mode 100644 index 000000000..10090e974 --- /dev/null +++ b/db/up/undirected_scores.sql @@ -0,0 +1,86 @@ +-- fix issue with current_scores; only combine user data after the median score has been selected +-- fix issue with both sms_index/ams_index; put DISTINCT on the initial insert into the ams_users_tmp/sms_users_tmp, which is necessary after current_scores change +DROP VIEW current_scores; +DROP VIEW current_network_scores; +CREATE OR REPLACE VIEW current_network_scores AS + +WITH recent_scores AS ( + + SELECT alocidispid, blocidispid, score, created_at, scorer FROM (SELECT *, row_number() OVER (PARTITION BY alocidispid, blocidispid ORDER BY scores.created_at DESC) AS rownum FROM scores) tmp WHERE rownum < 6 + +), ranked_scores AS ( + + SELECT alocidispid, blocidispid, score, created_at, scorer FROM (SELECT percent_rank() over (PARTITION BY alocidispid, blocidispid ORDER BY score ASC) AS pc, * FROM recent_scores) tmp WHERE pc <= .5 ORDER BY pc DESC + +), median_scores AS ( + + SELECT alocidispid, blocidispid, score, created_at, scorer FROM (SELECT * , row_number() OVER (PARTITION BY alocidispid, blocidispid, scorer ORDER BY score DESC) AS pc2 FROM ranked_scores) tmp where pc2 < 2 + +) +SELECT alocidispid, blocidispid, score, created_at, scorer FROM median_scores; + +CREATE OR REPLACE VIEW current_scores AS + + SELECT current_network_scores.*, a_users.id as a_userid, b_users.id as b_userid, (COALESCE(a_users.last_jam_audio_latency, 13) + COALESCE(b_users.last_jam_audio_latency, 13) + 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 current_network_scores + INNER JOIN users as a_users ON a_users.last_jam_locidispid = current_network_scores.alocidispid + INNER JOIN users as b_users ON b_users.last_jam_locidispid = current_network_scores.blocidispid + ORDER BY full_score ASC; + + +CREATE OR REPLACE VIEW nondirected_network_scores AS +WITH recent_scores AS ( + + SELECT alocidispid, blocidispid, score, created_at FROM (SELECT *, row_number() OVER (PARTITION BY alocidispid, blocidispid ORDER BY scores.created_at DESC) AS rownum FROM scores) tmp WHERE rownum < 6 AND scorer = 0 + +), ranked_scores AS ( + + SELECT alocidispid, blocidispid, score, created_at FROM (SELECT percent_rank() over (PARTITION BY alocidispid, blocidispid ORDER BY score ASC) AS pc, * FROM recent_scores) tmp WHERE pc <= .5 ORDER BY pc DESC + +), median_scores AS ( + + SELECT alocidispid, blocidispid, score, created_at FROM (SELECT * , row_number() OVER (PARTITION BY alocidispid, blocidispid ORDER BY score DESC) AS pc2 FROM ranked_scores) tmp WHERE pc2 < 2 + +), forward_scores AS ( + + SELECT alocidispid AS from_location, blocidispid AS to_location, score, created_at FROM median_scores + +), backward_scores AS ( + + SELECT blocidispid AS from_location, alocidispid AS to_location, score, created_at FROM median_scores + +), merged_directions AS ( + + SELECT from_location, to_location, score, created_at FROM forward_scores UNION SELECT from_location, to_location, score, created_at FROM backward_scores + +) +SELECT from_location AS alocidispid, to_location AS blocidispid, score, created_at FROM (SELECT *, row_number() OVER (PARTITION BY from_location, to_location ORDER BY created_at DESC) AS row FROM merged_directions) tmp WHERE row < 2; + + +CREATE OR REPLACE VIEW nondirected_scores AS + + SELECT nondirected_network_scores.*, a_users.id as a_userid, b_users.id as b_userid, (COALESCE(a_users.last_jam_audio_latency, 13) + COALESCE(b_users.last_jam_audio_latency, 13) + 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 nondirected_network_scores + INNER JOIN users as a_users ON a_users.last_jam_locidispid = nondirected_network_scores.alocidispid + INNER JOIN users as b_users ON b_users.last_jam_locidispid = nondirected_network_scores.blocidispid + ORDER BY full_score ASC; + + +CREATE VIEW most_recent_scores AS SELECT * FROM scores s WHERE score_dt = (SELECT max(score_dt) FROM scores s0 WHERE s0.alocidispid = s.alocidispid AND s0.blocidispid = s.blocidispid); + +DROP FUNCTION get_work (mylocidispid BIGINT, myaddr BIGINT); +CREATE FUNCTION get_work (mylocidispid BIGINT, myaddr BIGINT) RETURNS TABLE (client_id VARCHAR(64)) ROWS 5 VOLATILE AS $$ +BEGIN + CREATE TEMPORARY TABLE foo (locidispid BIGINT, locid INT); + INSERT INTO foo SELECT DISTINCT locidispid, locidispid/1000000 FROM connections WHERE client_type = 'client'; + DELETE FROM foo WHERE locidispid IN (SELECT DISTINCT blocidispid FROM most_recent_scores WHERE alocidispid = mylocidispid AND (current_timestamp - score_dt) < INTERVAL '24 hours'); + DELETE FROM foo WHERE locid NOT IN (SELECT locid FROM geoiplocations WHERE geog && st_buffer((SELECT geog FROM geoiplocations WHERE locid = mylocidispid/1000000), 4023360)); + CREATE TEMPORARY TABLE bar (client_id VARCHAR(64), locidispid BIGINT, r DOUBLE PRECISION); + INSERT INTO bar SELECT l.client_id, l.locidispid, random() FROM connections l, foo f WHERE l.locidispid = f.locidispid AND l.client_type = 'client' AND addr != myaddr; + DROP TABLE foo; + DELETE FROM bar b WHERE r != (SELECT MAX(r) FROM bar b0 WHERE b0.locidispid = b.locidispid); + RETURN QUERY SELECT b.client_id FROM bar b ORDER BY r LIMIT 5; + DROP TABLE bar; + RETURN; +END; +$$ LANGUAGE plpgsql; diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 809590bd4..1575c9b20 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -217,16 +217,15 @@ module JamRuby # the default of ANY setup above applies end - rel = rel.joins("#{score_join} join current_scores on current_scores.a_userid = users.id") - .where(['(current_scores.b_userid = ? or current_scores.b_userid is null)', user.id]) + rel = rel.joins("LEFT JOIN nondirected_scores ON nondirected_scores.a_userid = users.id AND nondirected_scores.b_userid = '#{user.id}'") rel = rel.joins('LEFT JOIN regions ON regions.countrycode = users.country AND regions.region = users.state') - 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.where(['nondirected_scores.full_score > ?', score_min]) unless score_min.nil? + rel = rel.where(['nondirected_scores.full_score <= ?', score_max]) unless score_max.nil? - rel = rel.select('current_scores.full_score, current_scores.score, regions.regionname') - rel = rel.group('current_scores.full_score, current_scores.score, regions.regionname') + rel = rel.select('nondirected_scores.full_score, nondirected_scores.score, regions.regionname') + rel = rel.group('nondirected_scores.full_score, nondirected_scores.score, regions.regionname') end ordering = self.order_param(params) @@ -250,7 +249,7 @@ module JamRuby end unless locidispid.nil? - rel = rel.order('current_scores.full_score ASC NULLS LAST') + rel = rel.order('nondirected_scores.full_score ASC NULLS LAST') end rel = rel.order('users.created_at DESC') diff --git a/ruby/spec/jam_ruby/models/affiliate_partner_spec.rb b/ruby/spec/jam_ruby/models/affiliate_partner_spec.rb index 8470f8cee..9b25931d9 100644 --- a/ruby/spec/jam_ruby/models/affiliate_partner_spec.rb +++ b/ruby/spec/jam_ruby/models/affiliate_partner_spec.rb @@ -4,11 +4,12 @@ describe AffiliatePartner do let!(:user) { FactoryGirl.create(:user) } let!(:partner) { - AffiliatePartner.create_with_params({:partner_name => Faker::Company.name, - :partner_code => Faker::Lorem.word, + AffiliatePartner.create_with_params({:partner_name => 'partner', + :partner_code => 'code', :user_email => user.email}) } + # Faker::Lorem.word is tripping up the PARTNER_CODE_REGEX. We should not use it. it 'validates required fields' do pending expect(partner.referral_user_count).to eq(0) diff --git a/ruby/spec/jam_ruby/models/score_spec.rb b/ruby/spec/jam_ruby/models/score_spec.rb index 916f29ff4..5b1268822 100644 --- a/ruby/spec/jam_ruby/models/score_spec.rb +++ b/ruby/spec/jam_ruby/models/score_spec.rb @@ -5,6 +5,7 @@ describe Score do let(:user1) { FactoryGirl.create(:user, last_jam_locidispid: 1234) } let(:user2) { FactoryGirl.create(:user, last_jam_locidispid: 2345) } let(:score_with_user) { s1, s2 = Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo', { auserid: user1.id, buserid: user2.id }); s1 } + let(:score_with_user_reversed) { s1, s2 = Score.createx(2345, 'bnodeid', 0x02030405, 1234, 'anodeid', 0x01020304, 22, nil, 'foo', { buserid: user1.id, auserid: user2.id }); s1 } let(:latency_tester1) { FactoryGirl.create(:latency_tester) } let(:latency_tester2) { FactoryGirl.create(:latency_tester) } @@ -267,8 +268,6 @@ describe Score do result[1]['score'].to_i.should == 30 result[2]['score'].to_i.should == 35 result[3]['score'].to_i.should == 35 - - end it "works with over 6 scores in different locations" do @@ -311,9 +310,17 @@ describe Score do it "resolves user information with a score created for different users" do score_with_user.touch + score_with_user_reversed.touch + 5.times do + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo', { auserid: user1.id, buserid: user2.id }) + Score.createx(2345, 'bnodeid', 0x02030405, 1234, 'anodeid', 0x01020304, 22, nil, 'foo', { buserid: user1.id, auserid: user2.id }) + end + result = Score.connection.execute('SELECT * FROM current_network_scores where scorer = 0') + result.check + result.ntuples.should == 2 result = Score.connection.execute('SELECT * FROM current_scores where scorer = 0') result.check - result.ntuples.should == 1 + result.ntuples.should == 2 # create two new users, in the same locations as user1 and user2, but with lower audio gear latency. They should sort first user3 = FactoryGirl.create(:user, last_jam_locidispid: user1.last_jam_locidispid, last_jam_audio_latency: user1.last_jam_audio_latency - 1) @@ -321,7 +328,7 @@ describe Score do result = Score.connection.execute('SELECT * FROM current_scores where scorer = 0') result.check - result.ntuples.should == 4 + result.ntuples.should == 8 # with this data: # user1 has a score with user2 and user4. @@ -331,8 +338,10 @@ describe Score do result[1]['full_score'].to_i.should == user3.last_jam_audio_latency + user2.last_jam_audio_latency + 20 result[2]['full_score'].to_i.should == user4.last_jam_audio_latency + user1.last_jam_audio_latency + 20 result[3]['full_score'].to_i.should == user2.last_jam_audio_latency + user1.last_jam_audio_latency + 20 + result[4]['full_score'].to_i.should == user3.last_jam_audio_latency + user4.last_jam_audio_latency + 22 + result[5]['full_score'].to_i.should == user3.last_jam_audio_latency + user2.last_jam_audio_latency + 22 + result[6]['full_score'].to_i.should == user4.last_jam_audio_latency + user1.last_jam_audio_latency + 22 + result[7]['full_score'].to_i.should == user2.last_jam_audio_latency + user1.last_jam_audio_latency + 22 end end - - end diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js index 79c50d256..05a39c44f 100644 --- a/web/app/assets/javascripts/findMusician.js +++ b/web/app/assets/javascripts/findMusician.js @@ -1,8 +1,8 @@ -(function(context,$) { - "use strict"; +(function (context, $) { + "use strict"; - context.JK = context.JK || {}; - context.JK.FindMusicianScreen = function(app) { + context.JK = context.JK || {}; + context.JK.FindMusicianScreen = function (app) { var logger = context.JK.logger; var rest = context.JK.Rest(); @@ -10,92 +10,87 @@ var musicianList; var instrument_logo_map = context.JK.getInstrumentIconMap24(); var did_show_musician_page = false; - var page_num=1, page_count=0; + var page_num = 1, page_count = 0; var textMessageDialog = null; + var $screen = null; var $results = null; + var $spinner = null; var helpBubble = context.JK.HelpBubbleHelper; var sessionUtils = context.JK.SessionUtils; - function loadMusicians(queryString) { - // squelch nulls and undefines - queryString = !!queryString ? queryString : ""; - - $.ajax({ - type: "GET", - url: "/api/search.json?" + queryString, - success: afterLoadMusicians, - error: app.ajaxError - }); - } function search() { - did_show_musician_page = true; - var queryString = 'srch_m=1&page='+page_num+'&'; + $spinner.show(); + did_show_musician_page = true; + var queryString = 'srch_m=1&page=' + page_num + '&'; - // order by - var orderby = $('#musician_order_by').val(); - if (typeof orderby != 'undefined' && orderby.length > 0) { - queryString += "orderby=" + orderby + '&'; - } + // order by + var orderby = $('#musician_order_by').val(); + if (typeof orderby != 'undefined' && orderby.length > 0) { + queryString += "orderby=" + orderby + '&'; + } - // instrument filter - var instrument = $('#musician_instrument').val(); - if (typeof instrument != 'undefined' && !(instrument === '')) { - queryString += "instrument=" + instrument + '&'; - } + // instrument filter + var instrument = $('#musician_instrument').val(); + if (typeof instrument != 'undefined' && !(instrument === '')) { + queryString += "instrument=" + instrument + '&'; + } - // score filter - var query_param = $('#musician_query_score').val(); - if (query_param !== null) { - queryString += "score_limit=" + query_param + '&'; - } - loadMusicians(queryString); + // score filter + var query_param = $('#musician_query_score').val(); + if (query_param !== null) { + queryString += "score_limit=" + query_param + '&'; + } + rest.searchMusicians(queryString) + .done(afterLoadMusicians) + .fail(app.ajaxError) + .always(function() {$spinner.hide()}) } function refreshDisplay() { - clearResults(); - search(); + clearResults(); + search(); } function afterLoadMusicians(mList) { - // display the 'no musicians' banner if appropriate - var $noMusiciansFound = $('#musicians-none-found'); - musicianList = mList; + // display the 'no musicians' banner if appropriate + var $noMusiciansFound = $('#musicians-none-found'); + musicianList = mList; - // @FIXME: This needs to pivot on musicianList.musicians.length - if(musicianList.length == 0) { - $noMusiciansFound.show(); - musicians = []; - } - else { - $noMusiciansFound.hide(); - musicians = musicianList['musicians']; - if (!(typeof musicians === 'undefined')) { - $('#musician-filter-city').text(musicianList['city']); - if (0 == page_count) { - page_count = musicianList['page_count']; - } - renderMusicians(); - } + // @FIXME: This needs to pivot on musicianList.musicians.length + if (musicianList.length == 0) { + $noMusiciansFound.show(); + musicians = []; + } + else { + $noMusiciansFound.hide(); + musicians = musicianList['musicians']; + if (!(typeof musicians === 'undefined')) { + $('#musician-filter-city').text(musicianList['city']); + if (0 == page_count) { + page_count = musicianList['page_count']; + } + renderMusicians(); } + } } function score_to_text(score) { - // these are raw scores as reported by client (round trip times) - if (score == null) return "n/a"; - return Math.round(score / 2) + " ms"; + // these are raw scores as reported by client (round trip times) + if (score == null) return "n/a"; + return Math.round(score / 2) + " ms"; } function formatLocation(musician) { - if(musician.city && musician.state) { + if (musician.city && musician.state) { return musician.city + ', ' + musician.regionname } - else if(musician.city) { + else if (musician.city) { return musician.city } - else if(musician.state) { + else if (musician.state) { return musician.regionname } else { @@ -104,160 +99,162 @@ } function renderMusicians() { - var ii, len; - var mTemplate = $('#template-find-musician-row').html(); - var fTemplate = $('#template-musician-follow-info').html(); - var aTemplate = $('#template-musician-action-btns').html(); - var mVals, musician, renderings=''; - var instr_logos, instr; - var follows, followVals, aFollow; - var myAudioLatency = musicianList.my_audio_latency; + var ii, len; + var mTemplate = $('#template-find-musician-row').html(); + var fTemplate = $('#template-musician-follow-info').html(); + var aTemplate = $('#template-musician-action-btns').html(); + 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]; - if (context.JK.currentUserId === musician.id) { - // VRFS-294.3 (David) => skip if current user is musician - continue; - } - instr_logos = ''; - for (var jj=0, ilen=musician['instruments'].length; jj'; - } - follows = ''; - followVals = {}; - for (var jj=0, ilen=musician['followings'].length; jj skip if current user is musician + continue; } + instr_logos = ''; + for (var jj = 0, ilen = musician['instruments'].length; jj < ilen; jj++) { + if (musician['instruments'][jj].instrument_id in instrument_logo_map) { + instr = instrument_logo_map[musician['instruments'][jj].instrument_id].asset; + } + instr_logos += ''; + } + follows = ''; + followVals = {}; + for (var jj = 0, ilen = musician['followings'].length; jj < ilen; jj++) { + aFollow = musician['followings'][jj]; + followVals = { + user_id: aFollow.user_id, + musician_name: aFollow.name, + profile_url: '/client#/profile/' + aFollow.user_id, + avatar_url: context.JK.resolveAvatarUrl(aFollow.photo_url) + }; + follows += context.JK.fillTemplate(fTemplate, followVals); + if (2 == jj) break; + } + var actionVals = { + profile_url: "/client#/profile/" + musician.id, + friend_class: 'button-' + (musician['is_friend'] ? 'grey' : 'orange'), + friend_caption: (musician.is_friend ? 'DIS' : '') + 'CONNECT', + follow_class: 'button-' + (musician['is_following'] ? 'grey' : 'orange'), + follow_caption: (musician.is_following ? 'UN' : '') + 'FOLLOW', + message_class: 'button-orange', + message_caption: 'MESSAGE', + button_message: 'button-orange' + }; + var musician_actions = context.JK.fillTemplate(aTemplate, actionVals); + + var full_score = musician['full_score']; + + var scoreInfo = sessionUtils.scoreInfo(full_score, false) + mVals = { + avatar_url: context.JK.resolveAvatarUrl(musician.photo_url), + profile_url: "/client#/profile/" + musician.id, + musician_name: musician.name, + musician_location: formatLocation(musician), + instruments: instr_logos, + biography: musician['biography'], + follow_count: musician['follow_count'], + friend_count: musician['friend_count'], + recording_count: musician['recording_count'], + session_count: musician['session_count'], + musician_id: musician['id'], + musician_follow_template: follows, + musician_action_template: musician_actions, + musician_one_way_score: score_to_text(full_score), + musician_score_color: scoreInfo.icon_name, + musician_score_color_alt: scoreInfo.description, + latency_style: scoreInfo.latency_style + }; + var $rendering = $(context.JK.fillTemplate(mTemplate, mVals)) + + var $offsetParent = $results.closest('.content'); + var options = {positions: ['top', 'bottom', 'right', 'left'], offsetParent: $offsetParent}; + var scoreOptions = {offsetParent: $offsetParent}; + 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); + helpBubble.scoreBreakdown($('.score-count', $rendering), false, full_score, myAudioLatency, musician['audio_latency'], musician['score'], scoreOptions); + + $results.append($rendering); + } - $('.search-m-friend').on('click', friendMusician); - $('.search-m-follow').on('click', followMusician); - $('.search-m-message').on('click', messageMusician); + $('.search-m-friend').on('click', friendMusician); + $('.search-m-follow').on('click', followMusician); + $('.search-m-message').on('click', messageMusician); - context.JK.bindHoverEvents(); + context.JK.bindHoverEvents(); } function beforeShow(data) { } function afterShow(data) { - if (!did_show_musician_page) { - refreshDisplay(); - } + refreshDisplay(); } function clearResults() { - musicians = {}; - $('#musician-filter-results .musician-list-result').remove(); - page_num = 1; - page_count = 0; + musicians = {}; + $('#musician-filter-results .musician-list-result').remove(); + page_num = 1; + page_count = 0; } - + function friendMusician(evt) { - // if the musician is already a friend, remove the button-orange class, and prevent - // the link from working - if (0 === $(this).closest('.button-orange').size()) { - return false; - } + // if the musician is already a friend, remove the button-orange class, and prevent + // the link from working + if (0 === $(this).closest('.button-orange').size()) { + return false; + } - $(this).click(function(ee) {ee.preventDefault();}); + $(this).click(function (ee) { + ee.preventDefault(); + }); - evt.stopPropagation(); - var uid = $(this).parent().data('musician-id'); - rest.sendFriendRequest(app, uid, friendRequestCallback); + evt.stopPropagation(); + var uid = $(this).parent().data('musician-id'); + rest.sendFriendRequest(app, uid, friendRequestCallback); } function friendRequestCallback(user_id) { - // remove the orange look to indicate it's not selectable + // remove the orange look to indicate it's not selectable // @FIXME -- this will need to be tweaked when we allow unfollowing - $('div[data-musician-id='+user_id+'] .search-m-friend').removeClass('button-orange').addClass('button-grey'); + $('div[data-musician-id=' + user_id + '] .search-m-friend').removeClass('button-orange').addClass('button-grey'); } function followMusician(evt) { - // if the musician is already followed, remove the button-orange class, and prevent - // the link from working - if (0 === $(this).closest('.button-orange').size()) { - return false; - } + // if the musician is already followed, remove the button-orange class, and prevent + // the link from working + if (0 === $(this).closest('.button-orange').size()) { + return false; + } - $(this).click(function(ee) {ee.preventDefault();}); + $(this).click(function (ee) { + ee.preventDefault(); + }); - evt.stopPropagation(); - var newFollowing = {}; - newFollowing.user_id = $(this).parent().data('musician-id'); - var url = "/api/users/" + context.JK.currentUserId + "/followings"; - $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: url, - data: JSON.stringify(newFollowing), - processData: false, - success: function(response) { - // remove the orange look to indicate it's not selectable - // @FIXME -- this will need to be tweaked when we allow unfollowing - $('div[data-musician-id=' + newFollowing.user_id + '] .search-m-follow').removeClass('button-orange').addClass('button-grey'); - }, - error: app.ajaxError - }); + evt.stopPropagation(); + var newFollowing = {}; + newFollowing.user_id = $(this).parent().data('musician-id'); + var url = "/api/users/" + context.JK.currentUserId + "/followings"; + $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: url, + data: JSON.stringify(newFollowing), + processData: false, + success: function (response) { + // remove the orange look to indicate it's not selectable + // @FIXME -- this will need to be tweaked when we allow unfollowing + $('div[data-musician-id=' + newFollowing.user_id + '] .search-m-follow').removeClass('button-orange').addClass('button-grey'); + }, + error: app.ajaxError + }); } function messageMusician() { @@ -266,37 +263,40 @@ return false; } - function events() { - $('#musician_query_score').change(refreshDisplay); - $('#musician_instrument').change(refreshDisplay); - $('#musician_order_by').change(refreshDisplay); - $('#musician-filter-results').closest('.content-body-scroller').bind('scroll', function() { - if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { - if (page_num < page_count) { - page_num += 1; - search(); - } - else { - $('#end-of-musician-list').show() - } - } - }); + function events() { + $('#musician_query_score').change(refreshDisplay); + $('#musician_instrument').change(refreshDisplay); + $('#musician_order_by').change(refreshDisplay); + + $('#musician-filter-results').closest('.content-body-scroller').bind('scroll', function () { + if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { + if (page_num < page_count) { + page_num += 1; + search(); + } + else { + $('#end-of-musician-list').show() + } + } + }); } function initialize(textMessageDialogInstance) { - textMessageDialog = textMessageDialogInstance; + textMessageDialog = textMessageDialogInstance; - var screenBindings = { - 'beforeShow': beforeShow, - 'afterShow': afterShow - }; - app.bindScreen('musicians', screenBindings); + var screenBindings = { + 'beforeShow': beforeShow, + 'afterShow': afterShow + }; + app.bindScreen('musicians', screenBindings); - $results = $('#musician-filter-results'); + $screen = $('#musicians-screen') + $results = $screen.find('#musician-filter-results'); + $spinner = $screen.find('.paginate-wait') - events(); + events(); } this.initialize = initialize; @@ -307,4 +307,4 @@ return this; } -})(window,jQuery); +})(window, jQuery); diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 9d51abb2a..e9eae68c3 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -1176,6 +1176,16 @@ }); } + function searchMusicians(queryString) { + // squelch nulls and undefines + queryString = !!queryString ? queryString : ""; + + return $.ajax({ + type: "GET", + url: "/api/search.json?" + queryString + }); + } + function initialize() { return self; } @@ -1279,6 +1289,7 @@ this.getChatMessages = getChatMessages; this.createDiagnostic = createDiagnostic; this.getLatencyTester = getLatencyTester; + this.searchMusicians = searchMusicians; return this; }; diff --git a/web/app/assets/stylesheets/client/musician.css.scss b/web/app/assets/stylesheets/client/musician.css.scss index 9498cda70..f2b92f8f8 100644 --- a/web/app/assets/stylesheets/client/musician.css.scss +++ b/web/app/assets/stylesheets/client/musician.css.scss @@ -34,6 +34,18 @@ width:150px; } } + + .paginate-wait { + display:none; + margin:auto; + text-align:center; + vertical-align:bottom; + line-height:32px; + .spinner-small { + display:inline-block; + vertical-align:top; + } + } } diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index 93462e736..e5c8c446d 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -47,7 +47,7 @@ if @search.musicians_filter_search? end child(:results => :musicians) { - attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url, :biography, :regionname, :score, :full_score + attributes :id, :first_name, :last_name, :name, :city, :state, :country, :online, :musician, :photo_url, :biography, :regionname, :score, :full_score node :is_friend do |musician| @search.is_friend?(musician) @@ -93,7 +93,7 @@ if @search.bands_filter_search? end child(:results => :bands) { - attributes :id, :name, :city, :state, :country, :email, :photo_url, :biography, :logo_url, :website + attributes :id, :name, :city, :state, :country, :photo_url, :biography, :logo_url, :website node :is_following do |band| @search.is_follower?(band) diff --git a/web/app/views/clients/_musicians.html.erb b/web/app/views/clients/_musicians.html.erb index 6c2a91919..12cbcfb77 100644 --- a/web/app/views/clients/_musicians.html.erb +++ b/web/app/views/clients/_musicians.html.erb @@ -13,6 +13,7 @@ <%= content_tag(:div, :class => 'content-body-scroller') do -%> <%= content_tag(:div, :class => 'content-wrapper musician-wrapper') do -%> <%= content_tag(:div, '', :id => 'musician-filter-results', :class => 'filter-results') %> +
Fetching more results...
<%= content_tag(:div, 'No more results.', :class => 'end-of-list', :id => 'end-of-musician-list') %> <% end -%> <% end -%> diff --git a/web/spec/features/signin_spec.rb b/web/spec/features/signin_spec.rb index d38a7cd3c..689b8251b 100644 --- a/web/spec/features/signin_spec.rb +++ b/web/spec/features/signin_spec.rb @@ -6,10 +6,6 @@ describe "signin" do let(:user) { FactoryGirl.create(:user) } - before(:each) do - visit signin_path - end - it "success" do visit signin_path within('#landing-inner form.signin-form') do @@ -153,6 +149,7 @@ describe "signin" do describe "with javascript", :js => true, :type => :feature, :capybara_feature => true do it "shows signup form when asked" do + visit signin_path find('.show-signup-dialog').trigger(:click) # toggle back to signin find('.show-signin-dialog').trigger(:click) @@ -211,7 +208,6 @@ describe "signin" do it "signout" do - sign_in_poltergeist(user) sign_out_poltergeist