From 362b60cbe90b6a092acdb4e4525a689b944c9d22 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 24 Oct 2013 12:25:27 -0500 Subject: [PATCH 01/34] vrfs-774: musicians page --- web/app/assets/javascripts/findMusician.js | 145 ++++++++++++++++++ .../assets/javascripts/instrumentSelector.js | 87 +++++++++++ .../clients/_instrumentSelector.html.erb | 3 + .../views/clients/_musician_filter.html.erb | 20 +++ web/app/views/clients/_musicians.html.erb | 17 +- 5 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 web/app/assets/javascripts/findMusician.js create mode 100644 web/app/assets/javascripts/instrumentSelector.js create mode 100644 web/app/views/clients/_instrumentSelector.html.erb create mode 100644 web/app/views/clients/_musician_filter.html.erb diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js new file mode 100644 index 000000000..78acdfe3e --- /dev/null +++ b/web/app/assets/javascripts/findMusician.js @@ -0,0 +1,145 @@ +(function(context,$) { + "use strict"; + + context.JK = context.JK || {}; + context.JK.FindMusicianScreen = function(app) { + + var logger = context.JK.logger; + var musicians = {}; + var musicianCounts = [0, 0, 0]; + var musicianList; + + function removeSpinner() { + $('') + } + + function loadMusicians(queryString) { + addSpinner(); + + // squelch nulls and undefines + queryString = !!queryString ? queryString : ""; + + $.ajax({ + type: "GET", + url: "/api/musicians?" + queryString, + async: true, + success: afterLoadMusicians, + complete: removeSpinner, + error: app.ajaxError + }); + } + + function search() { + logger.debug("Searching for musicians..."); + clearResults(); + var queryString = ''; + + // instrument filter + var instruments = context.JK.InstrumentSelectorHelper.getSelectedInstruments('#find-musician-instrument'); + if (instruments !== null && instruments.length > 0) { + queryString += "instruments=" + instruments.join(','); + } + + // keyword filter + var keyword = $('#musician-keyword-srch').val(); + if (keyword !== null && keyword.length > 0 && keyword !== 'Search by Keyword') { + if (queryString.length > 0) { + queryString += "&"; + } + queryString += "keyword=" + $('#musician-keyword-srch').val(); + } + loadMusicians(queryString); + } + + function refreshDisplay() { + var priorVisible; + } + + function afterLoadMusicians(musicianList) { + // display the 'no musicians' banner if appropriate + var $noMusiciansFound = $('#musicians-none-found'); + if(musicianList.length == 0) { + $noMusiciansFound.show(); + } + else { + $noMusiciansFound.hide(); + } + + startMusicianLatencyChecks(musicianList); + context.JK.GA.trackFindMusicians(musicianList.length); + } + + /** + * Render a single musician line into the table. + * It will be inserted at the appropriate place according to the + * sortScore in musicianLatency. + */ + function renderMusician(musicianId) { + // store musician in the appropriate bucket and increment category counts + var musician = musicians[musicianId]; + + refreshDisplay(); + } + + function beforeShow(data) { + context.JK.InstrumentSelectorHelper.render('#find-musician-instrument'); + } + + function afterShow(data) { + clearResults(); + refreshDisplay(); + loadMusicians(); + } + + function clearResults() { + musicians = {}; + } + + function events() { + $('#musician-keyword-srch').focus(function() { + $(this).val(''); + }); + + $("#musician-keyword-srch").keypress(function(evt) { + if (evt.which === 13) { + evt.preventDefault(); + search(); + } + }); + $('#btn-refresh').on("click", search); + } + + /** + * Initialize, providing an instance of the MusicianLatency class. + */ + function initialize(latency) { + + var screenBindings = { + 'beforeShow': beforeShow, + 'afterShow': afterShow + }; + app.bindScreen('findMusician', screenBindings); + + musicianList = new context.JK.MusicianList(app); + + events(); + } + + this.initialize = initialize; + this.renderMusician = renderMusician; + this.afterShow = afterShow; + + // Following exposed for easier testing. + this.setMusician = setMusician; + this.clearResults = clearResults; + this.getCategoryEnum = getCategoryEnum; + + return this; + }; + + })(window,jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/instrumentSelector.js b/web/app/assets/javascripts/instrumentSelector.js new file mode 100644 index 000000000..0c75e8575 --- /dev/null +++ b/web/app/assets/javascripts/instrumentSelector.js @@ -0,0 +1,87 @@ +(function(context,$) { + + /** + * Javascript for managing genre selectors. + */ + + "use strict"; + + context.JK = context.JK || {}; + context.JK.GenreSelectorHelper = (function() { + + var logger = context.JK.logger; + var _genres = []; // will be list of structs: [ {label:xxx, value:yyy}, {...}, ... ] + + function loadGenres() { + var url = "/api/genres"; + $.ajax({ + type: "GET", + url: url, + async: false, // do this synchronously so the event handlers in events() can be wired up + success: genresLoaded + }); + } + + function reset(parentSelector, defaultGenre) { + defaultGenre = typeof(defaultGenre) == 'undefined' ? '' : defaultGenre; + $('select', parentSelector).val(defaultGenre); + } + + function genresLoaded(response) { + $.each(response, function(index) { + _genres.push({ + value: this.id, + label: this.description + }); + }); + } + + function render(parentSelector) { + $('select', parentSelector).empty(); + $('select', parentSelector).append(''); + var template = $('#template-genre-option').html(); + $.each(_genres, function(index, value) { + // value will be a dictionary entry from _genres: + // { value: xxx, label: yyy } + var genreOptionHtml = context.JK.fillTemplate(template, value); + $('select', parentSelector).append(genreOptionHtml); + }); + } + + function getSelectedGenres(parentSelector) { + var selectedGenres = []; + var selectedVal = $('select', parentSelector).val(); + if (selectedVal !== '') { + selectedGenres.push(selectedVal); + } + return selectedGenres; + } + + function setSelectedGenres(parentSelector, genreList) { + if (!genreList) { + return; + } + var values = []; + $.each(genreList, function(index, value) { + values.push(value.toLowerCase()); + }); + var selectedVal = $('select', parentSelector).val(values); + } + + function initialize() { + loadGenres(); + } + + var me = { // This will be our singleton. + initialize: initialize, + getSelectedGenres: getSelectedGenres, + setSelectedGenres: setSelectedGenres, + reset: reset, + render: render, + loadGenres: loadGenres + }; + + return me; + + })(); +})(window,jQuery); diff --git a/web/app/views/clients/_instrumentSelector.html.erb b/web/app/views/clients/_instrumentSelector.html.erb new file mode 100644 index 000000000..2455a2079 --- /dev/null +++ b/web/app/views/clients/_instrumentSelector.html.erb @@ -0,0 +1,3 @@ + diff --git a/web/app/views/clients/_musician_filter.html.erb b/web/app/views/clients/_musician_filter.html.erb new file mode 100644 index 000000000..83eb139f6 --- /dev/null +++ b/web/app/views/clients/_musician_filter.html.erb @@ -0,0 +1,20 @@ +
+
Filter Musician List:
+ + +
+ <%= render "instrumentSelector" %> +
+ + + +
+ REFRESH +
+
diff --git a/web/app/views/clients/_musicians.html.erb b/web/app/views/clients/_musicians.html.erb index 4a6eac046..ce50ff6ad 100644 --- a/web/app/views/clients/_musicians.html.erb +++ b/web/app/views/clients/_musicians.html.erb @@ -1,7 +1,7 @@
+
-
<%= image_tag "content/icon_musicians.png", {:height => 19, :width => 19} %>
@@ -9,5 +9,18 @@

musicians

<%= render "screen_navigation" %>
-

This feature not yet implemented

+
+
+ <%= render :partial => "musician_filter" %> +
+
+
+
+
+
+ +
+ There are no musicians found. +
+
From 72e7193e1c8b8ef19631e6b6132a6563a627ca34 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 24 Oct 2013 12:25:55 -0500 Subject: [PATCH 02/34] vrfs-774: added geokit gems --- ruby/Gemfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruby/Gemfile b/ruby/Gemfile index 86c0ca399..a715c99a3 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -24,6 +24,9 @@ gem 'aasm', '3.0.16' gem 'devise', '>= 1.1.2' gem 'postgres-copy' +gem 'geokit', :git => 'https://github.com/imajes/geokit.git' +gem 'geokit-rails3' + if devenv gem 'jam_db', :path=> "../db/target/ruby_package" gem 'jampb', :path => "../pb/target/ruby/jampb" From 1d168257d0bca830d3a9f41576c317df6276337d Mon Sep 17 00:00:00 2001 From: Jonathon Wilson Date: Sun, 27 Oct 2013 18:37:55 -0600 Subject: [PATCH 03/34] Visual work for new FTUE screen --- .../assets/stylesheets/client/ftue.css.scss | 119 ++++++++++++++++++ web/app/views/clients/_ftue.html.erb | 119 +++++++++++++++++- 2 files changed, 237 insertions(+), 1 deletion(-) diff --git a/web/app/assets/stylesheets/client/ftue.css.scss b/web/app/assets/stylesheets/client/ftue.css.scss index 9af975c1a..fe158c0b2 100644 --- a/web/app/assets/stylesheets/client/ftue.css.scss +++ b/web/app/assets/stylesheets/client/ftue.css.scss @@ -110,6 +110,125 @@ div.dialog.ftue { margin-top: 12px; } + p.intro { + margin-top:0px; + } + .ftue-new { + clear:both; + position:relative; + width:100%; + height: 54px; + margin-top: 12px; + select { + font-size: 15px; + padding: 3px; + } + .latency { + position: absolute; + top: 120px; + font-size: 12px; + .report { + color:#fff; + position: absolute; + top: 20px; + left: 0px; + width: 105px; + height: 50px; + background-color: #72a43b; + padding: 10px; + text-align: center; + .ms-label { + padding-top: 10px; + font-size: 34px; + font-family: Arial, sans-serif; + } + p { + margin-top: 4px; + } + } + .instructions { + color:#fff; + position: absolute; + top: 20px; + left: 125px; + width: 595px; + height: 36px; + padding: 10px; + padding-top: 24px; + background-color: #666; + } + } + .column { + position:absolute; + width: 220px; + height: 50px; + margin-right:8px; + } + .settings-2-device { + left:0px; + } + .settings-2-center { + left:50%; + margin-left: -110px; + .buttons { + margin-top: 14px; + a { + margin-right: 0px; + } + } + } + .settings-2-voice { + top: 0px; + right:0px; + } + .controls { + margin-top: 16px; + background-color: #222; + height: 48px; + width: 220px; + } + .ftue-vu-left { + position:relative; + top: 0px; + } + .ftue-vu-right { + position:relative; + top: 22px; + } + .ftue-fader { + position:relative; + top: 14px; + left: 8px; + } + .gain-label { + color: $ColorScreenPrimary; + position:absolute; + top: 76px; + right: 6px; + } + + .subcolumn { + position:absolute; + top: 60px; + font-size: 12px !important; + width: 68px; + height: 48px; + } + .subcolumn select { + width: 68px; + } + .subcolumn.first { + left:0px; + } + .subcolumn.second { + left:50%; + margin-left:-34px; + } + .subcolumn.third { + right:0px; + } + } + .asio-settings { clear:both; position:relative; diff --git a/web/app/views/clients/_ftue.html.erb b/web/app/views/clients/_ftue.html.erb index ddb4d244b..9c90073b4 100644 --- a/web/app/views/clients/_ftue.html.erb +++ b/web/app/views/clients/_ftue.html.erb @@ -7,8 +7,125 @@
+ + +
+

+ Choose a device to capture and play your session audio. If + you’re not using a mic with this device, then also choose a + voice chat input to talk with others during sessions. Then play + and speak, and adjust the gain faders so that you hear both your + instrument and voice in your headphones at comfortable volumes. +

+ + +
+
+ Session Audio Device:
+ + +
+ +
+
+
GAIN
+
+
+
+
+ +
+ Frame
+ +
+
+ Buffer/In
+ +
+
+ Buffer/Out
+ +
+
+ + +
+ Voice Chat Input:
+ +
+
+
+
GAIN
+
+
+
+ + +
+ Latency:
+
+
9.83
+

milliseconds

+
+
+ Your audio speed is good. When done with settings, click Save Settings to continue. +
+
+
+ + + +
+ + -
+

Please identify which of the three types of audio gear below you are going to use with the JamKazam service, and click one to From fe5dc2c6ab42ef7e5244c1e50c057c02faefb155 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 28 Oct 2013 09:22:06 -0500 Subject: [PATCH 04/34] vrfs-774: incremental commit --- ruby/Gemfile | 4 +- ruby/lib/jam_ruby.rb | 5 +- ruby/lib/jam_ruby/models/max_mind_geo.rb | 15 ++--- ruby/lib/jam_ruby/models/search.rb | 11 ++++ ruby/lib/jam_ruby/models/user.rb | 65 ++++++++++++++++++- .../jam_ruby/models/musician_search_spec.rb | 44 +++++++++++++ 6 files changed, 129 insertions(+), 15 deletions(-) create mode 100644 ruby/spec/jam_ruby/models/musician_search_spec.rb diff --git a/ruby/Gemfile b/ruby/Gemfile index a715c99a3..907ca1b79 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -24,8 +24,8 @@ gem 'aasm', '3.0.16' gem 'devise', '>= 1.1.2' gem 'postgres-copy' -gem 'geokit', :git => 'https://github.com/imajes/geokit.git' -gem 'geokit-rails3' +gem 'geokit-rails' +gem 'postgres_ext' if devenv gem 'jam_db', :path=> "../db/target/ruby_package" diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index baea30286..763a6ccbc 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -11,6 +11,9 @@ require "action_mailer" require "devise" require "sendgrid" require "postgres-copy" +require "geokit-rails" +require "postgres_ext" + require "jam_ruby/lib/module_overrides" require "jam_ruby/constants/limits" require "jam_ruby/constants/notification_types" @@ -82,4 +85,4 @@ include Jampb module JamRuby -end \ No newline at end of file +end diff --git a/ruby/lib/jam_ruby/models/max_mind_geo.rb b/ruby/lib/jam_ruby/models/max_mind_geo.rb index 0c8f2c082..47e6610a8 100644 --- a/ruby/lib/jam_ruby/models/max_mind_geo.rb +++ b/ruby/lib/jam_ruby/models/max_mind_geo.rb @@ -5,24 +5,17 @@ module JamRuby def self.import_from_max_mind(file) - # File Geo-124 + # File Geo-139 # Format: # startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode MaxMindGeo.transaction do MaxMindGeo.delete_all File.open(file, 'r:ISO-8859-1') do |io| - MaxMindGeo.pg_copy_from io, :map => { 'startIpNum' => 'ip_bottom', 'endIpNum' => 'ip_top', 'country' => 'country', 'region' => 'region', 'city' => 'city'}, :columns => [:startIpNum, :endIpNum, :country, :region, :city] do |row| - row[0] = ip_address_to_int(row[0]) - row[1] = ip_address_to_int(row[1]) - row.delete_at(5) - row.delete_at(5) - row.delete_at(5) - row.delete_at(5) - row.delete_at(5) - end + MaxMindGeo.pg_copy_from io, :map => { 'startIpNum' => 'ip_start', 'endIpNum' => 'ip_end', 'country' => 'country', 'region' => 'region', 'city' => 'city', 'latitude' => 'lat', 'longitude' => 'lng'}, :columns => [:startIpNum, :endIpNum, :country, :region, :city, :latitude, :longitude] end end + User.find_each { |usr| usr.update_lat_lng } end @@ -35,4 +28,4 @@ module JamRuby end -end \ No newline at end of file +end diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index c3c33c7e2..da3209923 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -5,6 +5,17 @@ module JamRuby LIMIT = 10 + ORDER_LIKED = ['Most Liked', :liked] + ORDER_FOLLOWS = ['Most Followed', :followed] + ORDER_PLAYING = ['Playing Now', :playing] + ORDERINGS = [ORDER_LIKED, ORDER_FOLLOWS, ORDER_PLAYING] + ORDERING_KEYS = ORDERINGS.collect { |oo| oo[1] } + + def self.order_param(params) + ordering = params[:orderby] + ordering.blank? ? ORDERING_KEYS[0] : ordering + end + # performs a site-white search def self.search(query, user_id = nil) diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 7af848254..28b08db71 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -8,8 +8,12 @@ module JamRuby devise :database_authenticatable, :recoverable, :rememberable + # include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable) + # acts_as_mappable - attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_s3_path, :photo_url, :crop_selection + after_update :check_lat_lng + + attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_s3_path, :photo_url, :crop_selection, :lat, :lng # updating_password corresponds to a lost_password attr_accessor :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field @@ -896,6 +900,39 @@ module JamRuby end end + def self.musician_search(params={}, current_user=nil) + rel = User.where(:musician => true) + unless (instrument = params[:instrument]).blank? + rel = rel.joins("INNER JOIN musicians_instruments AS minst ON minst.user_id = users.id") + .where(['minst.instrument_id = ?', instrument]) + end + + location_distance, location_city = params[:distance], params[:city] + if location_distance && location_city + citylatlng = [] # FIXME: get the lat/lng for the city + rel = rel.within(location_distance, :origin => citylatlng) + + elsif current_user + latlng = [] + if current_user.lat.nil? + # FIXME: Lookup latlng from params[:remote_ip] + else + latlng = [current_user.lat, current_user.lng] + end + distance = location_distance || 50 + rel = rel.within(distance, :origin => latlng) + end + + case ordering = Search.order_param(params) + when :liked + rel = rel.order("SELECT COUNT(*) FROM users_likers WHERE users_likers.user_id = ") + when :followed + when :playing + end + + rel.page(params[:page].to_i) + end + def self.search(query, options = { :limit => 10 }) # only issue search if at least 2 characters are specified @@ -921,6 +958,32 @@ module JamRuby .limit(options[:limit]) end + def provides_location? + !self.city.blank? && (!self.state.blank? || !self.country.blank?) + end + + def check_lat_lng + update_lat_lng if city_changed? || state_changed? || country_changed? + end + + def update_lat_lng(ip_addy=nil) + yn = false + if provides_location? # ip_addy argument ignored in this case + query = {:city => self.city} + query[:state] = self.state unless self.state.blank? + query[:country] = self.country unless self.country.blank? + geo = MaxMindGeo.where(query).limit(1).first + self.update_attributes({:lat => geo.lat, :lng => geo.lng}) + yn = true + elsif ip_addy + if geo = MaxMindGeo.where(['ip_start >= ? AND ip_end <= ?',ip_addy,ip_addy]).limit(1).first + self.update_attributes({:lat => geo.lat, :lng => geo.lng}) + yn = true + end + end + yn + end + # devise compatibility #def encrypted_password diff --git a/ruby/spec/jam_ruby/models/musician_search_spec.rb b/ruby/spec/jam_ruby/models/musician_search_spec.rb new file mode 100644 index 000000000..7d3a9a47e --- /dev/null +++ b/ruby/spec/jam_ruby/models/musician_search_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe User do + + before(:each) do + params = { + first_name: "Example", + last_name: "User", + email: "user1@example.com", + password: "foobar", + password_confirmation: "foobar", + musician: true, + email_confirmed: true, + city: "Apex", + state: "NC", + country: "USA" + } + @user1 = FactoryGirl.create(:user, params) + params[:email] = "user2@example.com" + @user2 = FactoryGirl.create(:user, params) + end + + it "should find all musicians sorted by likes with pagination" do + pending + User.musician_search + end + + it "should find all musicians sorted by follows with pagination" do + pending + end + + it "should find all musicians sorted by now playing" do + pending + end + + it "should find musicians with an instrument" do + pending + end + + it "should find musicians within a given distance of location" do + pending + end + +end From 5d4ab429064e83d92f006bc22a46dda495f1308b Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 28 Oct 2013 12:03:58 -0500 Subject: [PATCH 05/34] vrfs-774: first musician searches working properly --- ruby/lib/jam_ruby/models/search.rb | 4 +- ruby/lib/jam_ruby/models/user.rb | 15 ++++--- .../jam_ruby/models/musician_search_spec.rb | 39 ++++++++++++++++--- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index da3209923..7a2cead22 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -5,10 +5,10 @@ module JamRuby LIMIT = 10 - ORDER_LIKED = ['Most Liked', :liked] ORDER_FOLLOWS = ['Most Followed', :followed] + ORDER_LIKED = ['Most Liked', :liked] ORDER_PLAYING = ['Playing Now', :playing] - ORDERINGS = [ORDER_LIKED, ORDER_FOLLOWS, ORDER_PLAYING] + ORDERINGS = [ORDER_FOLLOWS, ORDER_LIKED, ORDER_PLAYING] ORDERING_KEYS = ORDERINGS.collect { |oo| oo[1] } def self.order_param(params) diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 28b08db71..5fd2224c5 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -8,8 +8,8 @@ module JamRuby devise :database_authenticatable, :recoverable, :rememberable - # include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable) - # acts_as_mappable + include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable) + acts_as_mappable after_update :check_lat_lng @@ -925,12 +925,17 @@ module JamRuby case ordering = Search.order_param(params) when :liked - rel = rel.order("SELECT COUNT(*) FROM users_likers WHERE users_likers.user_id = ") when :followed + rel = rel.select("COUNT(follows) AS fcount, users.id") + rel = rel.joins("LEFT JOIN users_followers AS follows ON follows.user_id = users.id") + rel = rel.group("users.id") + rel = rel.order("COUNT(follows) DESC") when :playing end - - rel.page(params[:page].to_i) + perpage = params[:per_page] || 20 + page = [params[:page].to_i, 1].max + rel = rel.paginate(:page => page, :per_page => perpage) + rel end def self.search(query, options = { :limit => 10 }) diff --git a/ruby/spec/jam_ruby/models/musician_search_spec.rb b/ruby/spec/jam_ruby/models/musician_search_spec.rb index 7d3a9a47e..61e9d0285 100644 --- a/ruby/spec/jam_ruby/models/musician_search_spec.rb +++ b/ruby/spec/jam_ruby/models/musician_search_spec.rb @@ -15,14 +15,43 @@ describe User do state: "NC", country: "USA" } - @user1 = FactoryGirl.create(:user, params) + @users = [] + @users << @user1 = FactoryGirl.create(:user, params) params[:email] = "user2@example.com" - @user2 = FactoryGirl.create(:user, params) + @users << @user2 = FactoryGirl.create(:user, params) + params[:email] = "user3@example.com" + @users << @user3 = FactoryGirl.create(:user, params) + params[:email] = "user4@example.com" + @users << @user4 = FactoryGirl.create(:user, params) end - it "should find all musicians sorted by likes with pagination" do - pending - User.musician_search + it "should find all musicians sorted by followers with pagination" do + # establish sorting order + @user4.followers.concat([@user2, @user3, @user4]) + @user3.followers.concat([@user3, @user4]) + @user2.followers.concat([@user1]) + @user4.followers.count.should == 3 + + UserFollower.count.should == 6 + + # get all the users in correct order + params = { :per_page => @users.size } + results = User.musician_search(params) + results.all.count.should == @users.size + + results.each_with_index do |uu, idx| + uu.id.should == @users.reverse[idx].id + end + + # refresh the order to ensure it works right + @user2.followers.concat([@user3, @user4, @user2]) + results = User.musician_search(params) + results[0].id.should == @user2.id + + # make sure pagination works right + params = { :per_page => 2, :page => 1 } + results = User.musician_search(params) + results.all.count.should == 2 end it "should find all musicians sorted by follows with pagination" do From 72d6d4e699c2d0c55fcf0a8247afbc12af5cde52 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 28 Oct 2013 12:21:07 -0500 Subject: [PATCH 06/34] vrfs-774: second musician searches working properly (likers) --- ruby/lib/jam_ruby/models/user.rb | 4 ++++ .../jam_ruby/models/musician_search_spec.rb | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 5fd2224c5..a042f1fae 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -925,6 +925,10 @@ module JamRuby case ordering = Search.order_param(params) when :liked + rel = rel.select("COUNT(likers) AS lcount, users.id") + rel = rel.joins("LEFT JOIN users_likers AS likers ON likers.user_id = users.id") + rel = rel.group("users.id") + rel = rel.order("COUNT(likers) DESC") when :followed rel = rel.select("COUNT(follows) AS fcount, users.id") rel = rel.joins("LEFT JOIN users_followers AS follows ON follows.user_id = users.id") diff --git a/ruby/spec/jam_ruby/models/musician_search_spec.rb b/ruby/spec/jam_ruby/models/musician_search_spec.rb index 61e9d0285..94d18343d 100644 --- a/ruby/spec/jam_ruby/models/musician_search_spec.rb +++ b/ruby/spec/jam_ruby/models/musician_search_spec.rb @@ -54,8 +54,23 @@ describe User do results.all.count.should == 2 end - it "should find all musicians sorted by follows with pagination" do - pending + it "should find all musicians sorted by likes with pagination" do + # establish sorting order + [@user2, @user3, @user1].each { |uu| User.create_user_like(@user4.id, uu.id) } + [@user2, @user4].each { |uu| User.create_user_like(@user3.id, uu.id) } + [@user2].each { |uu| User.create_user_like(@user2.id, uu.id) } + + # get all the users in correct order + params = { :per_page => @users.size, :orderby => :liked } + results = User.musician_search(params) + results.all.count.should == @users.size + results.each_with_index do |uu, idx| + uu.id.should == @users.reverse[idx].id + end + # refresh the order to ensure it works right + [@user3, @user4, @user1].each { |uu| User.create_user_like(@user2.id, uu.id) } + results = User.musician_search(params) + results[0].id.should == @user2.id end it "should find all musicians sorted by now playing" do From f6674cfc64959b752eb8924422c41f3b03acb6ce Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 28 Oct 2013 13:44:56 -0500 Subject: [PATCH 07/34] vrfs-774: second musician searches working properly (likers) --- ruby/lib/jam_ruby/models/search.rb | 4 ++-- ruby/lib/jam_ruby/models/user.rb | 6 +---- .../jam_ruby/models/musician_search_spec.rb | 23 ++++--------------- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 7a2cead22..809183f1e 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -6,9 +6,9 @@ module JamRuby LIMIT = 10 ORDER_FOLLOWS = ['Most Followed', :followed] - ORDER_LIKED = ['Most Liked', :liked] + ORDER_LIKED = ['Most Plays', :plays] ORDER_PLAYING = ['Playing Now', :playing] - ORDERINGS = [ORDER_FOLLOWS, ORDER_LIKED, ORDER_PLAYING] + ORDERINGS = [ORDER_FOLLOWS, ORDER_PLAYS, ORDER_PLAYING] ORDERING_KEYS = ORDERINGS.collect { |oo| oo[1] } def self.order_param(params) diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index a042f1fae..a7c443f29 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -924,11 +924,7 @@ module JamRuby end case ordering = Search.order_param(params) - when :liked - rel = rel.select("COUNT(likers) AS lcount, users.id") - rel = rel.joins("LEFT JOIN users_likers AS likers ON likers.user_id = users.id") - rel = rel.group("users.id") - rel = rel.order("COUNT(likers) DESC") + when :plays when :followed rel = rel.select("COUNT(follows) AS fcount, users.id") rel = rel.joins("LEFT JOIN users_followers AS follows ON follows.user_id = users.id") diff --git a/ruby/spec/jam_ruby/models/musician_search_spec.rb b/ruby/spec/jam_ruby/models/musician_search_spec.rb index 94d18343d..475bab272 100644 --- a/ruby/spec/jam_ruby/models/musician_search_spec.rb +++ b/ruby/spec/jam_ruby/models/musician_search_spec.rb @@ -54,23 +54,8 @@ describe User do results.all.count.should == 2 end - it "should find all musicians sorted by likes with pagination" do - # establish sorting order - [@user2, @user3, @user1].each { |uu| User.create_user_like(@user4.id, uu.id) } - [@user2, @user4].each { |uu| User.create_user_like(@user3.id, uu.id) } - [@user2].each { |uu| User.create_user_like(@user2.id, uu.id) } - - # get all the users in correct order - params = { :per_page => @users.size, :orderby => :liked } - results = User.musician_search(params) - results.all.count.should == @users.size - results.each_with_index do |uu, idx| - uu.id.should == @users.reverse[idx].id - end - # refresh the order to ensure it works right - [@user3, @user4, @user1].each { |uu| User.create_user_like(@user2.id, uu.id) } - results = User.musician_search(params) - results[0].id.should == @user2.id + it "should find all musicians sorted by plays with pagination" do + pending end it "should find all musicians sorted by now playing" do @@ -78,7 +63,9 @@ describe User do end it "should find musicians with an instrument" do - pending + @user1.musician_instruments << FactoryGirl.build(:musician_instrument, user: @user1) + ii = @user1.instruments[0] + ii.should not_be nil end it "should find musicians within a given distance of location" do From 4ccd3b9091cf1cba2e933efe5acb3b7f4a99ef30 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 28 Oct 2013 17:19:36 -0500 Subject: [PATCH 08/34] vrfs-774: instrument query filtering --- ruby/lib/jam_ruby/models/search.rb | 2 +- ruby/lib/jam_ruby/models/user.rb | 3 ++- ruby/spec/factories.rb | 6 ++++++ ruby/spec/jam_ruby/models/musician_search_spec.rb | 12 ++++++++---- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 809183f1e..377b9fb32 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -6,7 +6,7 @@ module JamRuby LIMIT = 10 ORDER_FOLLOWS = ['Most Followed', :followed] - ORDER_LIKED = ['Most Plays', :plays] + ORDER_PLAYS = ['Most Plays', :plays] ORDER_PLAYING = ['Playing Now', :playing] ORDERINGS = [ORDER_FOLLOWS, ORDER_PLAYS, ORDER_PLAYING] ORDERING_KEYS = ORDERINGS.collect { |oo| oo[1] } diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index a7c443f29..1e9d8f4b3 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -903,7 +903,7 @@ module JamRuby def self.musician_search(params={}, current_user=nil) rel = User.where(:musician => true) unless (instrument = params[:instrument]).blank? - rel = rel.joins("INNER JOIN musicians_instruments AS minst ON minst.user_id = users.id") + rel = rel.joins("RIGHT JOIN musicians_instruments AS minst ON minst.user_id = users.id") .where(['minst.instrument_id = ?', instrument]) end @@ -935,6 +935,7 @@ module JamRuby perpage = params[:per_page] || 20 page = [params[:page].to_i, 1].max rel = rel.paginate(:page => page, :per_page => perpage) + # puts rel.to_sql rel end diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb index 951cd7232..337a47e6e 100644 --- a/ruby/spec/factories.rb +++ b/ruby/spec/factories.rb @@ -110,6 +110,12 @@ FactoryGirl.define do priority 0 end + factory :musician_instrument2, :class => JamRuby::MusicianInstrument do + instrument { Instrument.find('tuba') } + proficiency_level 1 + priority 0 + end + factory :invited_user, :class => JamRuby::InvitedUser do sequence(:email) { |n| "user#{n}@someservice.com" } autofriend false diff --git a/ruby/spec/jam_ruby/models/musician_search_spec.rb b/ruby/spec/jam_ruby/models/musician_search_spec.rb index 475bab272..bfd372f91 100644 --- a/ruby/spec/jam_ruby/models/musician_search_spec.rb +++ b/ruby/spec/jam_ruby/models/musician_search_spec.rb @@ -54,7 +54,7 @@ describe User do results.all.count.should == 2 end - it "should find all musicians sorted by plays with pagination" do + it "should find all musicians sorted by plays " do pending end @@ -63,9 +63,13 @@ describe User do end it "should find musicians with an instrument" do - @user1.musician_instruments << FactoryGirl.build(:musician_instrument, user: @user1) - ii = @user1.instruments[0] - ii.should not_be nil + @user1.musician_instruments << FactoryGirl.build(:musician_instrument2, user: @user1) + ii = @user1.instruments.detect { |inst| inst.id == 'tuba' } + ii.should_not be_nil + params = { :instrument => ii.id } + results = User.musician_search(params) + results.all[0].instruments.detect {|inst| inst.id=='tuba'}.id.should == ii.id + results.all.count.should == 1 end it "should find musicians within a given distance of location" do From 9af93fda1ec5e3f54cdc85bd78c49e12977f5a20 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 28 Oct 2013 21:41:05 -0500 Subject: [PATCH 09/34] vrfs-774: updating max_mind_geo/users data model for geocoded searches --- ruby/lib/jam_ruby/models/max_mind_geo.rb | 1 + ruby/lib/jam_ruby/models/max_mind_isp.rb | 15 ++++----------- ruby/spec/jam_ruby/models/max_mind_geo_spec.rb | 18 +++++++++--------- ruby/spec/jam_ruby/models/max_mind_isp_spec.rb | 18 +++++++++--------- 4 files changed, 23 insertions(+), 29 deletions(-) diff --git a/ruby/lib/jam_ruby/models/max_mind_geo.rb b/ruby/lib/jam_ruby/models/max_mind_geo.rb index 47e6610a8..9cdde962f 100644 --- a/ruby/lib/jam_ruby/models/max_mind_geo.rb +++ b/ruby/lib/jam_ruby/models/max_mind_geo.rb @@ -15,6 +15,7 @@ module JamRuby MaxMindGeo.pg_copy_from io, :map => { 'startIpNum' => 'ip_start', 'endIpNum' => 'ip_end', 'country' => 'country', 'region' => 'region', 'city' => 'city', 'latitude' => 'lat', 'longitude' => 'lng'}, :columns => [:startIpNum, :endIpNum, :country, :region, :city, :latitude, :longitude] end end + byebug User.find_each { |usr| usr.update_lat_lng } end diff --git a/ruby/lib/jam_ruby/models/max_mind_isp.rb b/ruby/lib/jam_ruby/models/max_mind_isp.rb index 2c7d6ed9a..3bb7b15bc 100644 --- a/ruby/lib/jam_ruby/models/max_mind_isp.rb +++ b/ruby/lib/jam_ruby/models/max_mind_isp.rb @@ -13,9 +13,9 @@ module JamRuby MaxMindIsp.delete_all File.open(file, 'r:ISO-8859-1') do |io| io.gets # eat the copyright line. gah, why do they have that in their file?? - MaxMindIsp.pg_copy_from io, :map => { 'beginIp' => 'ip_bottom', 'endIp' => 'ip_top', 'countryCode' => 'country', 'ISP' => 'isp'}, :columns => [:beginIp, :endIp, :countryCode, :ISP] do |row| - row[0] = ip_address_to_int(strip_quotes(row[0])) - row[1] = ip_address_to_int(strip_quotes(row[1])) + MaxMindIsp.pg_copy_from io, :map => { 'beginIp' => 'ip_start', 'endIp' => 'ip_end', 'countryCode' => 'country', 'ISP' => 'isp'}, :columns => [:beginIp, :endIp, :countryCode, :ISP] do |row| + row[0] = strip_quotes(row[0]) + row[1] = strip_quotes(row[1]) row[2] = row[2] row[3] = row[3..-1].join(',') # this is because the parser just cuts on any ',' and ignores double quotes. essentially postgres-copy isn't a great csv parser -- or I need to configure it better while row.length > 4 @@ -27,13 +27,6 @@ module JamRuby end end - # Make an IP address fit in a signed int. Just divide it by 2, as the least significant part - # just can't possibly matter. We can verify this if needed. My guess is the entire bottom octet is - # actually irrelevant - def self.ip_address_to_int(ip) - ip.split('.').inject(0) {|total,value| (total << 8 ) + value.to_i} / 2 - end - private def self.strip_quotes str @@ -54,4 +47,4 @@ module JamRuby str.gsub(/\"/, '""') end end -end \ No newline at end of file +end diff --git a/ruby/spec/jam_ruby/models/max_mind_geo_spec.rb b/ruby/spec/jam_ruby/models/max_mind_geo_spec.rb index ba49462de..2f4d1c0e4 100644 --- a/ruby/spec/jam_ruby/models/max_mind_geo_spec.rb +++ b/ruby/spec/jam_ruby/models/max_mind_geo_spec.rb @@ -18,22 +18,22 @@ describe MaxMindGeo do MaxMindGeo.import_from_max_mind(GEO_CSV) end - let(:first) { MaxMindGeo.find_by_ip_bottom(MaxMindGeo.ip_address_to_int('0.116.0.0')) } - let(:second) { MaxMindGeo.find_by_ip_bottom(MaxMindGeo.ip_address_to_int('1.0.0.0')) } - let(:third) { MaxMindGeo.find_by_ip_bottom(MaxMindGeo.ip_address_to_int('1.0.1.0')) } + let(:first) { MaxMindGeo.find_by_ip_start('0.116.0.0') } + let(:second) { MaxMindGeo.find_by_ip_start('1.0.0.0') } + let(:third) { MaxMindGeo.find_by_ip_start('1.0.1.0') } it { MaxMindGeo.count.should == 3 } it { first.country.should == 'AT' } - it { first.ip_bottom.should == MaxMindGeo.ip_address_to_int('0.116.0.0') } - it { first.ip_top.should == MaxMindGeo.ip_address_to_int('0.119.255.255') } + it { first.ip_start.should == '0.116.0.0' } + it { first.ip_end.should == '0.119.255.255' } it { second.country.should == 'AU' } - it { second.ip_bottom.should == MaxMindGeo.ip_address_to_int('1.0.0.0') } - it { second.ip_top.should == MaxMindGeo.ip_address_to_int('1.0.0.255') } + it { second.ip_start.should == '1.0.0.0' } + it { second.ip_end.should == '1.0.0.255' } it { third.country.should == 'CN' } - it { third.ip_bottom.should == MaxMindGeo.ip_address_to_int('1.0.1.0') } - it { third.ip_top.should == MaxMindGeo.ip_address_to_int('1.0.1.255') } + it { third.ip_start.should == '1.0.1.0' } + it { third.ip_end.should == '1.0.1.255' } end diff --git a/ruby/spec/jam_ruby/models/max_mind_isp_spec.rb b/ruby/spec/jam_ruby/models/max_mind_isp_spec.rb index b61f86cfc..b9365896b 100644 --- a/ruby/spec/jam_ruby/models/max_mind_isp_spec.rb +++ b/ruby/spec/jam_ruby/models/max_mind_isp_spec.rb @@ -19,25 +19,25 @@ describe MaxMindIsp do MaxMindIsp.import_from_max_mind(ISP_CSV) end - let(:first) { MaxMindIsp.find_by_ip_bottom(MaxMindIsp.ip_address_to_int('1.0.0.0')) } - let(:second) { MaxMindIsp.find_by_ip_bottom(MaxMindIsp.ip_address_to_int('1.0.1.0')) } - let(:third) { MaxMindIsp.find_by_ip_bottom(MaxMindIsp.ip_address_to_int('1.0.4.0')) } + let(:first) { MaxMindIsp.find_by_ip_start('1.0.0.0') } + let(:second) { MaxMindIsp.find_by_ip_start('1.0.1.0') } + let(:third) { MaxMindIsp.find_by_ip_start('1.0.4.0') } it { MaxMindIsp.count.should == 3 } it { first.country.should == 'AU' } - it { first.ip_bottom.should == MaxMindIsp.ip_address_to_int('1.0.0.0') } - it { first.ip_top.should == MaxMindIsp.ip_address_to_int('1.0.0.255') } + it { first.ip_start.should == '1.0.0.0' } + it { first.ip_end.should == '1.0.0.255' } it { first.isp.should == 'APNIC Debogon Project' } it { second.country.should == 'CN' } - it { second.ip_bottom.should == MaxMindIsp.ip_address_to_int('1.0.1.0') } - it { second.ip_top.should == MaxMindIsp.ip_address_to_int('1.0.1.255') } + it { second.ip_start.should == '1.0.1.0' } + it { second.ip_end.should == '1.0.1.255' } it { second.isp.should == 'Chinanet Fujian Province Network' } it { third.country.should == 'AU' } - it { third.ip_bottom.should == MaxMindIsp.ip_address_to_int('1.0.4.0') } - it { third.ip_top.should == MaxMindIsp.ip_address_to_int('1.0.7.255') } + it { third.ip_start.should == '1.0.4.0' } + it { third.ip_end.should == '1.0.7.255' } it { third.isp.should == 'Bigred,inc' } end From dd5be13e9f65e41c2ed2cbd3259e4ea7d12c4d4b Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 28 Oct 2013 21:41:52 -0500 Subject: [PATCH 10/34] vrfs-774: updated max_mind_geo/users table for geocoded searches --- db/manifest | 1 + db/up/users_geocoding.sql | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 db/up/users_geocoding.sql diff --git a/db/manifest b/db/manifest index 4bc66447b..c56e9d29b 100755 --- a/db/manifest +++ b/db/manifest @@ -74,3 +74,4 @@ crash_dumps_idx.sql music_sessions_user_history_add_session_removed_at.sql user_progress_tracking.sql whats_next.sql +users_geocoding.sql diff --git a/db/up/users_geocoding.sql b/db/up/users_geocoding.sql new file mode 100644 index 000000000..6fd83edfe --- /dev/null +++ b/db/up/users_geocoding.sql @@ -0,0 +1,9 @@ +ALTER TABLE users ADD COLUMN lat NUMERIC(15,10); +ALTER TABLE users ADD COLUMN lng NUMERIC(15,10); + +ALTER TABLE max_mind_geo ADD COLUMN lat NUMERIC(15,10); +ALTER TABLE max_mind_geo ADD COLUMN lng NUMERIC(15,10); +ALTER TABLE max_mind_geo DROP COLUMN ip_bottom; +ALTER TABLE max_mind_geo DROP COLUMN ip_top; +ALTER TABLE max_mind_geo ADD COLUMN ip_start INET; +ALTER TABLE max_mind_geo ADD COLUMN ip_end INET; From e1bce5eed8c840fdab88290200bac2bbdf78d405 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 28 Oct 2013 21:42:36 -0500 Subject: [PATCH 11/34] vrfs-774: impl musician searches --- web/app/assets/javascripts/findMusician.js | 42 ++++++++++++------- .../assets/stylesheets/client/search.css.scss | 18 ++++++++ web/app/controllers/api_users_controller.rb | 11 ++++- .../clients/_instrumentSelector.html.erb | 3 -- .../views/clients/_musician_filter.html.erb | 22 +++++----- web/lib/max_mind_manager.rb | 25 ++++------- 6 files changed, 74 insertions(+), 47 deletions(-) delete mode 100644 web/app/views/clients/_instrumentSelector.html.erb diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js index 78acdfe3e..03852dc25 100644 --- a/web/app/assets/javascripts/findMusician.js +++ b/web/app/assets/javascripts/findMusician.js @@ -6,7 +6,6 @@ var logger = context.JK.logger; var musicians = {}; - var musicianCounts = [0, 0, 0]; var musicianList; function removeSpinner() { @@ -26,7 +25,7 @@ $.ajax({ type: "GET", - url: "/api/musicians?" + queryString, + url: "/api/users?" + queryString, async: true, success: afterLoadMusicians, complete: removeSpinner, @@ -37,21 +36,34 @@ function search() { logger.debug("Searching for musicians..."); clearResults(); - var queryString = ''; + var queryString = 'musicians=1&'; - // instrument filter - var instruments = context.JK.InstrumentSelectorHelper.getSelectedInstruments('#find-musician-instrument'); - if (instruments !== null && instruments.length > 0) { - queryString += "instruments=" + instruments.join(','); + // order by + var orderby = $('.musician-order-by').val(); + if (orderby !== null && orderby.length() > 0) { + queryString += "orderby=" + orderby + '&'; } - - // keyword filter - var keyword = $('#musician-keyword-srch').val(); - if (keyword !== null && keyword.length > 0 && keyword !== 'Search by Keyword') { - if (queryString.length > 0) { - queryString += "&"; - } - queryString += "keyword=" + $('#musician-keyword-srch').val(); + // instrument filter + var instrument = $('.instrument-list').val(); + if (instruments !== null && instruments.length() > 0) { + queryString += "instrument=" + instrument; + } + // distance filter + var query_param = $('#musician-query-distance').val(); + if (query_param !== null && query_param.length > 0) { + var matches = query_param.match(/(\d)/); + if (0 < matches.length()) { + var distance = matches[0]; + query_param = $('#musician-query-center').val(); + if (query_param !== null && query_param.length > 0) { + matches = query_param.match(/\\d{5}(-\\d{4})?/); + if (0 < matches.length()) { + var zip = matches[0]; + queryString += "zip=" + query_param + '&'; + queryString += "distance=" + query_param + '&'; + } + } + } } loadMusicians(queryString); } diff --git a/web/app/assets/stylesheets/client/search.css.scss b/web/app/assets/stylesheets/client/search.css.scss index 488e053c0..56cd7368d 100644 --- a/web/app/assets/stylesheets/client/search.css.scss +++ b/web/app/assets/stylesheets/client/search.css.scss @@ -55,3 +55,21 @@ font-size: 90%; } +.query-distance-params { + float:left; + width:140px; + margin-left: 10px; + -webkit-border-radius: 6px; + border-radius: 6px; + background-color:$ColorTextBoxBackground; + border: none; + color:#333; + font-weight:400; + padding:0px 0px 0px 8px; + height:18px; + line-height:18px; + overflow:hidden; + -webkit-box-shadow: inset 2px 2px 3px 0px #888; + box-shadow: inset 2px 2px 3px 0px #888; +} + diff --git a/web/app/controllers/api_users_controller.rb b/web/app/controllers/api_users_controller.rb index 40a96b869..427a2647a 100644 --- a/web/app/controllers/api_users_controller.rb +++ b/web/app/controllers/api_users_controller.rb @@ -14,8 +14,15 @@ class ApiUsersController < ApiController respond_to :json def index - @users = User.paginate(page: params[:page]) - respond_with @users, responder: ApiResponder, :status => 200 + if 1 == params[:musicians].to_i + query = params.clone + query[:remote_ip] = request.remote_ip + @users = User.musician_search(query, current_user) + respond_with @users, responder: ApiResponder, :status => 200 + else + @users = User.paginate(page: params[:page]) + respond_with @users, responder: ApiResponder, :status => 200 + end end def show diff --git a/web/app/views/clients/_instrumentSelector.html.erb b/web/app/views/clients/_instrumentSelector.html.erb deleted file mode 100644 index 2455a2079..000000000 --- a/web/app/views/clients/_instrumentSelector.html.erb +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/web/app/views/clients/_musician_filter.html.erb b/web/app/views/clients/_musician_filter.html.erb index 83eb139f6..1de14836e 100644 --- a/web/app/views/clients/_musician_filter.html.erb +++ b/web/app/views/clients/_musician_filter.html.erb @@ -1,18 +1,20 @@

Filter Musician List:
- + + <%= select_tag(:musician_order_by, options_for_select(Search::ORDERINGS), {:class => 'musician-order-by'} ) %> -
- <%= render "instrumentSelector" %> +
+ <%= select_tag(:instrument, + options_for_select(['Select Instrument', ''].concat(JamRuby::Instrument.all.collect { |ii| [ii.description, ii.id] })), + {:class => 'instrument-list'} ) %>
- - From e2c59d6543514135cfb48bb4e21a8e5024486204 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 4 Nov 2013 22:53:44 -0500 Subject: [PATCH 31/34] VRFS-687 fix issue with band profile social tab, added logging --- web/app/assets/javascripts/bandProfile.js | 4 ++-- web/app/assets/javascripts/jam_rest.js | 8 ++++++++ web/app/assets/javascripts/profile.js | 10 +++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/web/app/assets/javascripts/bandProfile.js b/web/app/assets/javascripts/bandProfile.js index d03ce3bdf..54d0130d1 100644 --- a/web/app/assets/javascripts/bandProfile.js +++ b/web/app/assets/javascripts/bandProfile.js @@ -245,7 +245,7 @@ $('#band-profile-biography').html(band.biography); } else { - + logger.debug("No band found with bandId = " + bandId); } } @@ -266,7 +266,7 @@ function bindSocial() { // FOLLOWERS - url = "/api/bands/" + bandId + "/followers"; + var url = "/api/bands/" + bandId + "/followers"; $.ajax({ type: "GET", dataType: "json", diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index ea66bcbec..341e0d284 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -168,6 +168,14 @@ }); } + function getMusicianFollowers(userId) { + + } + + function getBandFollowers(bandId) { + + } + function getClientDownloads(options) { return $.ajax({ diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js index fc69c53bc..17f07bff2 100644 --- a/web/app/assets/javascripts/profile.js +++ b/web/app/assets/javascripts/profile.js @@ -307,22 +307,22 @@ $('#profile-location').html(user.location); // stats - var text = user.friend_count > 1 || user.friend_count == 0 ? " Friends" : " Friend"; + var text = user.friend_count > 1 || user.friend_count === 0 ? " Friends" : " Friend"; $('#profile-friend-stats').html(user.friend_count + text); - text = user.follower_count > 1 || user.follower_count == 0 ? " Followers" : " Follower"; + text = user.follower_count > 1 || user.follower_count === 0 ? " Followers" : " Follower"; $('#profile-follower-stats').html(user.follower_count + text); - text = user.session_count > 1 || user.session_count == 0 ? " Sessions" : " Session"; + text = user.session_count > 1 || user.session_count === 0 ? " Sessions" : " Session"; $('#profile-session-stats').html(user.session_count + text); - text = user.recording_count > 1 || user.recording_count == 0 ? " Recordings" : " Recording"; + text = user.recording_count > 1 || user.recording_count === 0 ? " Recordings" : " Recording"; $('#profile-recording-stats').html(user.recording_count + text); $('#profile-biography').html(user.biography); } else { - + logger.debug("No user found with userId = " + userId); } } From 1aeb358d2964b3916ba4496fd2b4aaa4bd005a25 Mon Sep 17 00:00:00 2001 From: Jonathon Wilson Date: Tue, 5 Nov 2013 15:44:40 -0700 Subject: [PATCH 32/34] Add proper showing of FTUE on Create/Join session if id hasn't been done. --- web/app/assets/javascripts/createSession.js | 9 ++++++++- web/app/assets/javascripts/ftue.js | 9 +++++++++ web/app/assets/javascripts/jamkazam.js | 9 +++------ web/app/assets/javascripts/layout.js | 10 +++++++++- web/app/assets/javascripts/sessionList.js | 13 ++++++++++--- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/web/app/assets/javascripts/createSession.js b/web/app/assets/javascripts/createSession.js index fe19afe00..9f697366f 100644 --- a/web/app/assets/javascripts/createSession.js +++ b/web/app/assets/javascripts/createSession.js @@ -178,6 +178,13 @@ function submitForm(evt) { evt.preventDefault(); + // If user hasn't completed FTUE - do so now. + if (!(context.jamClient.FTUEGetStatus())) { + app.afterFtue = function() { submitForm(evt); }; + app.layout.showDialog('ftue'); + return; + } + var isValid = validateForm(); if (!isValid) { // app.notify({ @@ -435,4 +442,4 @@ return this; }; - })(window,jQuery); + })(window,jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/ftue.js b/web/app/assets/javascripts/ftue.js index d58be61da..6ae1ec829 100644 --- a/web/app/assets/javascripts/ftue.js +++ b/web/app/assets/javascripts/ftue.js @@ -422,7 +422,16 @@ return false; } jamClient.FTUESave(true); + jamClient.FTUESetStatus(true); // No FTUE wizard next time + rest.userCertifiedGear({success:true}); app.layout.closeDialog('ftue'); + if (app.afterFtue) { + // If there's a function to invoke, invoke it. + logger.dbg("afterFTUE function:"); + logger.dbg(app.afterFtue); + app.afterFtue(); + app.afterFtue = null; + } return false; } diff --git a/web/app/assets/javascripts/jamkazam.js b/web/app/assets/javascripts/jamkazam.js index 5448088e7..61da06700 100644 --- a/web/app/assets/javascripts/jamkazam.js +++ b/web/app/assets/javascripts/jamkazam.js @@ -255,12 +255,6 @@ } logger.debug("Changing screen to " + url); context.location = url; - - if (!(context.jamClient.FTUEGetStatus())) { - app.layout.showDialog('ftue'); - } - // TODO FIXME REMOVE ME - Testing Only - app.layout.showDialog('ftue'); } this.unloadFunction = function() { @@ -296,6 +290,9 @@ } }; + // Holder for a function to invoke upon successfully completing the FTUE. + // See createSession.submitForm as an example. + this.afterFtue = null; // enable temporary suspension of heartbeat for fine-grained control this.heartbeatActive = true; diff --git a/web/app/assets/javascripts/layout.js b/web/app/assets/javascripts/layout.js index e210e3477..6958bf426 100644 --- a/web/app/assets/javascripts/layout.js +++ b/web/app/assets/javascripts/layout.js @@ -383,12 +383,20 @@ function linkClicked(evt) { evt.preventDefault(); + var $currentTarget = $(evt.currentTarget); // allow links to be disabled - if($(evt.currentTarget).hasClass("disabled") ) { + if($currentTarget.hasClass("disabled") ) { return; } + // If link requires FTUE, show that first. + if ($currentTarget.hasClass("requires-ftue")) { + if (!(context.jamClient.FTUEGetStatus())) { + app.layout.showDialog('ftue'); + } + } + var destination = $(evt.currentTarget).attr('layout-link'); var destinationType = $('[layout-id="' + destination + '"]').attr("layout"); if (destinationType === "screen") { diff --git a/web/app/assets/javascripts/sessionList.js b/web/app/assets/javascripts/sessionList.js index 49af23e00..8aaa83249 100644 --- a/web/app/assets/javascripts/sessionList.js +++ b/web/app/assets/javascripts/sessionList.js @@ -138,7 +138,14 @@ var $parentRow = $('tr[id=' + session.id + ']', tbGroup); $('#join-link', $parentRow).click(function(evt) { - joinClick(session.id); + // If no FTUE, show that first. + if (!(context.jamClient.FTUEGetStatus())) { + app.afterFtue = function() { joinClick(session.id); }; + app.layout.showDialog('ftue'); + return; + } else { + joinClick(session.id); + } }); } } @@ -201,7 +208,7 @@ } function openAlert(sessionId) { - var alertDialog = new context.JK.AlertDialog(app, "YES", + var alertDialog = new context.JK.AlertDialog(app, "YES", "You must be approved to join this session. Would you like to send a request to join?", sessionId, onCreateJoinRequest); @@ -210,7 +217,7 @@ } function sessionNotJoinableAlert() { - var alertDialog = new context.JK.AlertDialog(app, "OK", + var alertDialog = new context.JK.AlertDialog(app, "OK", "This session is over or is no longer public and cannot be joined. Please click Refresh to update the session list.", null, function(evt) { From cfb6a6133f69777f9b1c474317a6922396608d82 Mon Sep 17 00:00:00 2001 From: Anthony Davis Date: Tue, 5 Nov 2013 20:03:43 -0600 Subject: [PATCH 33/34] adding optional 'fog' dependency 'unf' to suppress warnings --- admin/Gemfile | 1 + web/Gemfile | 1 + 2 files changed, 2 insertions(+) diff --git a/admin/Gemfile b/admin/Gemfile index 47096903d..f80ab1d01 100644 --- a/admin/Gemfile +++ b/admin/Gemfile @@ -41,6 +41,7 @@ gem 'rails3-jquery-autocomplete' gem 'activeadmin' gem "meta_search", '>= 1.1.0.pre' gem 'fog', "~> 1.3.1" +gem 'unf' #optional fog dependency gem 'country-select' gem 'aasm', '3.0.16' gem 'postgres-copy' diff --git a/web/Gemfile b/web/Gemfile index 4a4ae6449..ab19237e8 100644 --- a/web/Gemfile +++ b/web/Gemfile @@ -47,6 +47,7 @@ gem 'aws-sdk', '1.8.0' gem 'aasm', '3.0.16' gem 'carrierwave' gem 'fog' +gem 'unf' #optional fog dependency gem 'devise', '>= 1.1.2' #gem 'thin' # the presence of this gem on mac seems to prevent normal startup of rails. gem 'postgres-copy' From c6802c4e4091624c60f93d81d90f3d2c4f4679b3 Mon Sep 17 00:00:00 2001 From: Jonathon Wilson Date: Tue, 5 Nov 2013 19:50:32 -0700 Subject: [PATCH 34/34] New FTUE: Prevent save if bad or unknown latency. If unknown, link to old FTUE. --- web/app/assets/javascripts/ftue.js | 16 ++++++++++------ web/app/assets/javascripts/session.js | 4 +--- web/app/assets/stylesheets/client/ftue.css.scss | 6 +++++- web/app/views/clients/_ftue.html.erb | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/web/app/assets/javascripts/ftue.js b/web/app/assets/javascripts/ftue.js index 6ae1ec829..21414246b 100644 --- a/web/app/assets/javascripts/ftue.js +++ b/web/app/assets/javascripts/ftue.js @@ -412,8 +412,11 @@ */ function newFtueSaveSettingsHandler(evt) { evt.preventDefault(); + var $saveButton = $('#btn-ftue-2-save'); + if ($saveButton.hasClass('disabled')) { + return; + } var selectedAudioDevice = $('.ftue-new .settings-2-device select').val(); - logger.dbg('newFtueSave. selectedAudioDevice:' + selectedAudioDevice); if (!(selectedAudioDevice)) { app.notify({ title: "Please select an audio device", @@ -427,8 +430,6 @@ app.layout.closeDialog('ftue'); if (app.afterFtue) { // If there's a function to invoke, invoke it. - logger.dbg("afterFTUE function:"); - logger.dbg(app.afterFtue); app.afterFtue(); app.afterFtue = null; } @@ -485,7 +486,6 @@ // TODO FIXME - how to handle a driver selection where we are unable to // autoset both inputs and outputs? (I'd think this could happen if either // the input or output side returned no values) - context.alert("TODO - handle 'unable to set both inputs/outputs' case"); return; } @@ -601,20 +601,24 @@ var $instructions = $('.ftue-new .latency .instructions'); var latencyClass = "neutral"; var latencyValue = "N/A"; + var $saveButton = $('#btn-ftue-2-save'); if (latency && latency.latencyknown) { latencyValue = latency.latency; // Round latency to two decimal places. latencyValue = Math.round(latencyValue * 100) / 100; if (latency.latency <= 10) { latencyClass = "good"; + $saveButton.removeClass('disabled'); } else if (latency.latency <= 20) { latencyClass = "acceptable"; + $saveButton.removeClass('disabled'); } else { latencyClass = "bad"; + $saveButton.addClass('disabled'); } } else { - // TODO FIXME - handle unknown expected latency - // latency unknown... + latencyClass = "unknown"; + $saveButton.addClass('disabled'); } $('.ms-label', $report).html(latencyValue); diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 3eaf1574e..278f733b8 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -621,8 +621,6 @@ $connection.addClass(connectionClass); } else if (eventName === 'add' || eventName === 'remove') { - //logger.dbg('non-vu event: ' + eventName + ',' + mixerId + ',' + value); - // TODO - _renderSession. Note I get streams of these in // sequence, so have Nat fix, or buffer/spam protect // Note - this is already handled from websocket events. @@ -632,7 +630,7 @@ } else { // Examples of other events // Add media file track: "add", "The_Abyss_4T", 0 - logger.dbg('non-vu event: ' + eventName + ',' + mixerId + ',' + value); + logger.debug('non-vu event: ' + eventName + ',' + mixerId + ',' + value); } } } diff --git a/web/app/assets/stylesheets/client/ftue.css.scss b/web/app/assets/stylesheets/client/ftue.css.scss index 0dfbdc4e8..02b4d1f27 100644 --- a/web/app/assets/stylesheets/client/ftue.css.scss +++ b/web/app/assets/stylesheets/client/ftue.css.scss @@ -146,7 +146,7 @@ div.dialog.ftue { margin-top: 4px; } } - .report.neutral, .report.start { + .report.neutral, .report.start, .report.unknown { background-color: #666; } .report.good { @@ -171,6 +171,10 @@ div.dialog.ftue { .instructions p.start, .instructions p.neutral { padding-top: 4px; } + .instructions p.unknown { + margin-top:0px; + padding-top: 4px; + } .instructions p.good { padding-top: 4px; } diff --git a/web/app/views/clients/_ftue.html.erb b/web/app/views/clients/_ftue.html.erb index 5417766aa..4084acb51 100644 --- a/web/app/views/clients/_ftue.html.erb +++ b/web/app/views/clients/_ftue.html.erb @@ -109,7 +109,7 @@

Choose an audio device to continue...

- +