From 2dd6153ed86191a2a752fb11f5e2ef08eead3054 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sat, 26 Jul 2014 14:18:17 -0500 Subject: [PATCH 01/35] * wip on score export --- admin/app/admin/score_export.rb | 68 ++++++++++++++++++ admin/app/admin/score_history.rb | 88 ++++++++++++++++------- ruby/lib/jam_ruby/models/score_history.rb | 3 + ruby/lib/jam_ruby/models/user.rb | 3 + 4 files changed, 137 insertions(+), 25 deletions(-) create mode 100644 admin/app/admin/score_export.rb diff --git a/admin/app/admin/score_export.rb b/admin/app/admin/score_export.rb new file mode 100644 index 000000000..d593f2b58 --- /dev/null +++ b/admin/app/admin/score_export.rb @@ -0,0 +1,68 @@ +ActiveAdmin.register_page "Score Exports" do + menu :parent => 'Score' + + page_action :create_csv, :method => :post do + + puts params.inspect + + start_time = params[:score_exports][:start] + end_time = params[:score_exports][:end] + + if start_time.blank? + start_time = '1900-01-01' + end + start_time = "DATE '#{start_time}'" + if end_time.blank? + end_time = 'NOW()' + else + end_time = "DATE '#{end_time}'" + end + + @users = User.find(:all) + Fetching all user details and assigned on @users + csv_string = CSV.generate do |csv| + Using CSV class generate method to create csv file + csv << ["Id", "Name", "Email","Role"] + Creating header of CSV file + + @users.each do |user| + csv << [user.id, user.name, user.name, user.role] + end + Retrieving each rows and assigning on csv_string variable. + + + send_data csv_string, + :type => 'text/csv; charset=iso-8859-1; header=present', + :disposition => "attachment; +filename=users.csv" + + render 'hi' + # redirect_to admin_bootstrap_path, :notice => "Server created. If you start a job worker (bundle exec rake all_jobs in /web), it should update your icecast config." + end + + + content :title => "Score Exports" do + + semantic_form_for :score_exports, :url => admin_score_exports_create_csv_path, :builder => ActiveAdmin::FormBuilder do |f| + f.inputs do + f.input :start, :as => :datepicker + f.input :end, :as => :datepicker + end + f.buttons + end + + #panel "Upaid Registrations" do + # table_for Registration.unpaid.limit(10).order('created_at desc') do + # column "Registration" do |registration| + # link_to registration.id, admin_registration_path(registration) + # end + # column :user + # column :tour + # column "Payment" do |registration| + # status_tag((registration.paid? ? "Received" : "Pending"), (registration.paid? ? :ok : :warning)) + # end + # end + #end + + end +end \ No newline at end of file diff --git a/admin/app/admin/score_history.rb b/admin/app/admin/score_history.rb index ccd827eac..3fb0c5d17 100644 --- a/admin/app/admin/score_history.rb +++ b/admin/app/admin/score_history.rb @@ -4,34 +4,72 @@ ActiveAdmin.register JamRuby::ScoreHistory, :as => 'Score History' do config.batch_actions = false config.clear_action_items! config.filters = true + config.per_page = 10 + + filter :score filter :score_dt + filter :from_user_id, as: :string + filter :from_latency_tester_id + filter :from_isp + filter :from_country + filter :from_region + filter :from_city + filter :from_postal + filter :from_latitude + filter :from_latitude + filter :from_longitude + filter :to_user_id, as: :string + filter :to_latency_tester_id + filter :to_isp + filter :to_country + filter :to_region + filter :to_city + filter :to_postal + filter :to_latitude + filter :to_latitude + filter :to_longitude + + before_filter only: :index do + @per_page = 1_000_000 if request.format == 'text/csv' + end index do - column :score - column :score_dt + column "Score", :score + column "When", :score_dt + column "From User", :from_user_id do |score| + link_to score.from_user, admin_user_path(score.from_user) if score.from_user_id + end + column "From Latency Tester", :from_latency_tester_id do |score| + link_to score.from_latency_tester_id, admin_latency_testers_path if score.from_latency_tester_id + end + column "From IP", :from_addr do |score| + IPAddr.new(score.from_addr, Socket::AF_INET).to_s if score.from_addr + end + column "From ISP", :from_isp + column "From Country", :from_country + column "From Region", :from_region + column "From City", :from_city + column "From Postal", :from_postal + column "From Lat", :from_latitude + column "From Long", :from_longitude + column "From Client", :from_client_id - column :from_client_id - column :from_user_id - column :from_latency_tester_id - column :from_addr - column :from_isp - column :from_country - column :from_region - column :from_city - column :from_postal - column :from_latitude - column :from_longitude - - column :to_client_id - column :to_user_id - column :to_latency_tester_id - column :to_addr - column :to_isp - column :to_country - column :to_region - column :to_city - column :to_postal - column :to_latitude - column :to_longitude + column "To User", :to_user_id do |score| + link_to score.to_user, admin_user_path(score.to_user) if score.to_user_id + end + column "To Latency Tester", :to_latency_tester_id do |score| + link_to score.to_latency_tester_id, admin_latency_testers_path if score.to_latency_tester_id + end + column "To IP", :to_addr do |score| + IPAddr.new(score.to_addr, Socket::AF_INET).to_s if score.to_addr + end + column "To ISP", :to_isp + column "To Country", :to_country + column "To Region", :to_region + column "To City", :to_city + column "To Postal", :to_postal + column "To Lat", :to_latitude + column "To Long", :to_longitude + column "To Client", :to_client_id end end diff --git a/ruby/lib/jam_ruby/models/score_history.rb b/ruby/lib/jam_ruby/models/score_history.rb index 5c17640f6..ed90892d4 100644 --- a/ruby/lib/jam_ruby/models/score_history.rb +++ b/ruby/lib/jam_ruby/models/score_history.rb @@ -4,6 +4,9 @@ module JamRuby self.table_name = 'score_histories' + belongs_to :from_user, class_name: 'JamRuby::User', foreign_key: 'from_user_id' + belongs_to :to_user, class_name: 'JamRuby::User', foreign_key: 'to_user_id' + def self.migrate_scores generic_state = GenericState.singleton diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 5f241d71b..06d7d97e4 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -116,6 +116,9 @@ module JamRuby # diagnostics has_many :diagnostics, :class_name => "JamRuby::Diagnostic" + # score history + has_many :from_score_histories, :class_name => "JamRuby::ScoreHistory", foreign_key: 'from_user_id' + has_many :to_score_histories, :class_name => "JamRuby::ScoreHistory", foreign_key: 'to_user_id' # This causes the authenticate method to be generated (among other stuff) #has_secure_password From 44ba9ef441be524ac6740d59362a7299cbcaf6bc Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 27 Jul 2014 11:45:46 -0500 Subject: [PATCH 02/35] * VRFS-1496 - export CSV --- admin/app/admin/score_export.rb | 82 +++++++++++++++++++++++---------- db/manifest | 3 +- db/up/median_aggregate.sql | 23 +++++++++ 3 files changed, 83 insertions(+), 25 deletions(-) create mode 100644 db/up/median_aggregate.sql diff --git a/admin/app/admin/score_export.rb b/admin/app/admin/score_export.rb index d593f2b58..5e4802a0d 100644 --- a/admin/app/admin/score_export.rb +++ b/admin/app/admin/score_export.rb @@ -11,46 +11,80 @@ ActiveAdmin.register_page "Score Exports" do if start_time.blank? start_time = '1900-01-01' end - start_time = "DATE '#{start_time}'" + start_time = "#{start_time}" if end_time.blank? - end_time = 'NOW()' + end_time = Time.now + 1.days else - end_time = "DATE '#{end_time}'" + end_time = "#{end_time}" end - @users = User.find(:all) - Fetching all user details and assigned on @users + puts "start_time #{start_time}, end_time #{end_time}" + + scores = ScoreHistory + .select("from_city, from_regions.regionname as from_region_name, from_countries.countryname as from_country_name, from_isp, + to_city, to_regions.regionname as to_region_name, to_countries.countryname as to_country_name, to_isp, + min(score_histories.score) as min_latency, max(score_histories.score) as max_latency, avg(score_histories.score) as mean_latency, median(CAST(score_histories.score AS NUMERIC)) as median_latency, count(score_histories.score) as score_count") + .joins('LEFT JOIN countries AS from_countries ON from_countries.countrycode = from_country') + .joins('LEFT JOIN countries AS to_countries ON to_countries.countrycode = to_country') + .joins('LEFT JOIN regions AS from_regions ON from_regions.region = from_region') + .joins('LEFT JOIN regions AS to_regions ON to_regions.region = to_region') + .where("score_dt BETWEEN DATE '#{start_time}' AND DATE '#{end_time}'") + .order('from_city, from_regions.regionname, from_countries.countryname, from_isp, to_city, to_regions.regionname, to_countries.countryname, to_isp') + .group('from_city, from_regions.regionname, from_countries.countryname, from_isp, to_city, to_regions.regionname, to_countries.countryname, to_isp') + .limit(1_000_000) + + csv_string = CSV.generate do |csv| - Using CSV class generate method to create csv file - csv << ["Id", "Name", "Email","Role"] - Creating header of CSV file + csv << ["From Country", "From Region", "From City", "From ISP", "To Country", "To Region", "To City", "To ISP", "Min Latency", "Max Latency", "Median Latency", "Mean Latency", 'Score Count'] - @users.each do |user| - csv << [user.id, user.name, user.name, user.role] + scores.each do |score| + puts score.inspect + csv << [score.from_country_name, score.from_region_name, score.from_city, score.from_isp, + score.to_country_name, score.to_region_name, score.to_city, score.to_isp, + score[:min_latency], score[:max_latency], score[:median_latency], score[:mean_latency], score[:score_count]] end - Retrieving each rows and assigning on csv_string variable. + end - send_data csv_string, - :type => 'text/csv; charset=iso-8859-1; header=present', - :disposition => "attachment; -filename=users.csv" - - render 'hi' - # redirect_to admin_bootstrap_path, :notice => "Server created. If you start a job worker (bundle exec rake all_jobs in /web), it should update your icecast config." + send_data csv_string, + :type => 'text/csv; charset=iso-8859-1; header=present', + :disposition => "attachment; filename=score_export-#{start_time}-#{end_time}.csv" end content :title => "Score Exports" do - - semantic_form_for :score_exports, :url => admin_score_exports_create_csv_path, :builder => ActiveAdmin::FormBuilder do |f| - f.inputs do - f.input :start, :as => :datepicker - f.input :end, :as => :datepicker + columns do + column do + semantic_form_for :score_exports, :url => admin_score_exports_create_csv_path, :builder => ActiveAdmin::FormBuilder do |f| + f.inputs do + f.input :start, :as => :datepicker + f.input :end, :as => :datepicker + end + f.actions do + f.action :submit, :label => 'Download CSV' + end + end + end + column do + panel "Usage" do + span "Select a start day, and end day to generate a CSV with a score summary." + end + panel "Limitation 1" do + div do + span do "The system limits the number of rows exported to 1,000,000" end + end + end + panel "Limitation 2" do + div do + span do "This report uses the score_histories table, which can lag up to 1 hour behind data. You can force a score_history sweep by going to" end + span do link_to "Resque", "#{Gon.global.prefix}resque/schedule" end + span do " and then running ScoreHistorySweeper. When the job count goes from 1 to 0, the score_histories table is now completely up-to-date, and you can make a 'fresh' CSV." end + end + end end - f.buttons end + #panel "Upaid Registrations" do # table_for Registration.unpaid.limit(10).order('created_at desc') do # column "Registration" do |registration| diff --git a/db/manifest b/db/manifest index 65fbf8688..e3db60d29 100755 --- a/db/manifest +++ b/db/manifest @@ -195,4 +195,5 @@ max_mind_releases.sql score_histories.sql update_sms_index.sql connection_allow_null_locidispid.sql -track_user_in_scores.sql \ No newline at end of file +track_user_in_scores.sql +median_aggregate.sql \ No newline at end of file diff --git a/db/up/median_aggregate.sql b/db/up/median_aggregate.sql new file mode 100644 index 000000000..63bf77d96 --- /dev/null +++ b/db/up/median_aggregate.sql @@ -0,0 +1,23 @@ +-- from here: https://wiki.postgresql.org/wiki/Aggregate_Median +CREATE OR REPLACE FUNCTION _final_median(numeric[]) + RETURNS numeric +AS +$body$ + SELECT AVG(val) + FROM ( + SELECT val + FROM unnest($1) val + ORDER BY 1 + LIMIT 2 - MOD(array_upper($1, 1), 2) + OFFSET CEIL(array_upper($1, 1) / 2.0) - 1 + ) sub; +$body$ +LANGUAGE sql ; +-- IMMUTABLE not accepted by pg migrate + +CREATE AGGREGATE median(numeric) ( + SFUNC=array_append, + STYPE=numeric[], + FINALFUNC=_final_median, + INITCOND='{}' +); From 2716211b18c443f30ad4818db9dea78e583beb77 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 27 Jul 2014 11:49:26 -0500 Subject: [PATCH 03/35] * VRFS-1496 fixing up help text and header text --- admin/app/admin/score_export.rb | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/admin/app/admin/score_export.rb b/admin/app/admin/score_export.rb index 5e4802a0d..85d1aac0c 100644 --- a/admin/app/admin/score_export.rb +++ b/admin/app/admin/score_export.rb @@ -1,4 +1,4 @@ -ActiveAdmin.register_page "Score Exports" do +ActiveAdmin.register_page "Download CSV" do menu :parent => 'Score' page_action :create_csv, :method => :post do @@ -18,20 +18,18 @@ ActiveAdmin.register_page "Score Exports" do end_time = "#{end_time}" end - puts "start_time #{start_time}, end_time #{end_time}" - scores = ScoreHistory - .select("from_city, from_regions.regionname as from_region_name, from_countries.countryname as from_country_name, from_isp, - to_city, to_regions.regionname as to_region_name, to_countries.countryname as to_country_name, to_isp, - min(score_histories.score) as min_latency, max(score_histories.score) as max_latency, avg(score_histories.score) as mean_latency, median(CAST(score_histories.score AS NUMERIC)) as median_latency, count(score_histories.score) as score_count") - .joins('LEFT JOIN countries AS from_countries ON from_countries.countrycode = from_country') - .joins('LEFT JOIN countries AS to_countries ON to_countries.countrycode = to_country') - .joins('LEFT JOIN regions AS from_regions ON from_regions.region = from_region') - .joins('LEFT JOIN regions AS to_regions ON to_regions.region = to_region') - .where("score_dt BETWEEN DATE '#{start_time}' AND DATE '#{end_time}'") - .order('from_city, from_regions.regionname, from_countries.countryname, from_isp, to_city, to_regions.regionname, to_countries.countryname, to_isp') - .group('from_city, from_regions.regionname, from_countries.countryname, from_isp, to_city, to_regions.regionname, to_countries.countryname, to_isp') - .limit(1_000_000) + .select("from_city, from_regions.regionname as from_region_name, from_countries.countryname as from_country_name, from_isp, + to_city, to_regions.regionname as to_region_name, to_countries.countryname as to_country_name, to_isp, + min(score_histories.score) as min_latency, max(score_histories.score) as max_latency, avg(score_histories.score) as mean_latency, median(CAST(score_histories.score AS NUMERIC)) as median_latency, count(score_histories.score) as score_count") + .joins('LEFT JOIN countries AS from_countries ON from_countries.countrycode = from_country') + .joins('LEFT JOIN countries AS to_countries ON to_countries.countrycode = to_country') + .joins('LEFT JOIN regions AS from_regions ON from_regions.region = from_region') + .joins('LEFT JOIN regions AS to_regions ON to_regions.region = to_region') + .where("score_dt BETWEEN DATE '#{start_time}' AND DATE '#{end_time}'") + .order('from_city, from_regions.regionname, from_countries.countryname, from_isp, to_city, to_regions.regionname, to_countries.countryname, to_isp') + .group('from_city, from_regions.regionname, from_countries.countryname, from_isp, to_city, to_regions.regionname, to_countries.countryname, to_isp') + .limit(1_000_000) csv_string = CSV.generate do |csv| @@ -52,10 +50,10 @@ ActiveAdmin.register_page "Score Exports" do end - content :title => "Score Exports" do + content :title => "Export Score" do columns do column do - semantic_form_for :score_exports, :url => admin_score_exports_create_csv_path, :builder => ActiveAdmin::FormBuilder do |f| + semantic_form_for :score_exports, :url => admin_download_csv_create_csv_path, :builder => ActiveAdmin::FormBuilder do |f| f.inputs do f.input :start, :as => :datepicker f.input :end, :as => :datepicker @@ -78,7 +76,7 @@ ActiveAdmin.register_page "Score Exports" do div do span do "This report uses the score_histories table, which can lag up to 1 hour behind data. You can force a score_history sweep by going to" end span do link_to "Resque", "#{Gon.global.prefix}resque/schedule" end - span do " and then running ScoreHistorySweeper. When the job count goes from 1 to 0, the score_histories table is now completely up-to-date, and you can make a 'fresh' CSV." end + span do " and then clicking 'Queue Now' for ScoreHistorySweeper. When the job count goes from 1 to 0, the score_histories table is now completely up-to-date, and you can make a 'fresh' CSV." end end end end From c65b05993b5cbb59712d521e4cecffe020fcafbe Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 27 Jul 2014 12:22:35 -0500 Subject: [PATCH 04/35] * adding migrate script to admin --- admin/migrate.sh | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 admin/migrate.sh diff --git a/admin/migrate.sh b/admin/migrate.sh new file mode 100755 index 000000000..a9afa1578 --- /dev/null +++ b/admin/migrate.sh @@ -0,0 +1,2 @@ +#!/bin/bash +bundle exec jam_db up --connopts=dbname:jam host:localhost user:postgres password:postgres --verbose From 750bceec2e5f8a0aec1d40a93b347ce46a517b8b Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 27 Jul 2014 12:23:15 -0500 Subject: [PATCH 05/35] * turn on more debugging for build server --- web/build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/build b/web/build index 622605d89..40175dcf2 100755 --- a/web/build +++ b/web/build @@ -1,7 +1,7 @@ #!/bin/bash set -e - +set -x DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # 'target' is the output directory From 2f76a82bd308145bfb822fe28ccd2996a698f1b1 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 27 Jul 2014 12:46:20 -0500 Subject: [PATCH 06/35] * fix changes to resque-scheduler includes --- web/Rakefile | 3 +++ web/app/views/clients/_web_filter.html.erb | 2 +- web/build | 1 - web/lib/tasks/scheduler.rake | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/web/Rakefile b/web/Rakefile index d120b3602..f4019acfc 100644 --- a/web/Rakefile +++ b/web/Rakefile @@ -2,7 +2,10 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. +#require 'resque/tasks' +#require 'resque/scheduler/tasks' require 'resque/tasks' +require 'resque/scheduler/tasks' require File.expand_path('../config/application', __FILE__) SampleApp::Application.load_tasks diff --git a/web/app/views/clients/_web_filter.html.erb b/web/app/views/clients/_web_filter.html.erb index 6baa9cfc7..a493402b5 100644 --- a/web/app/views/clients/_web_filter.html.erb +++ b/web/app/views/clients/_web_filter.html.erb @@ -16,7 +16,7 @@ <% else %> - <%= content_tag(:div, 'Filter By:', :class => 'filter-element desc') %> + <%= content_tag(:div, 'Order By:', :class => 'filter-element desc') %> <%= select_tag("#{filter_label}_order_by", options_for_select(Search::ORDERINGS), {:class => "#{filter_label}-order-by easydropdown"} ) %> <% end %> diff --git a/web/build b/web/build index 40175dcf2..87f8dccd9 100755 --- a/web/build +++ b/web/build @@ -1,7 +1,6 @@ #!/bin/bash set -e -set -x DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # 'target' is the output directory diff --git a/web/lib/tasks/scheduler.rake b/web/lib/tasks/scheduler.rake index 55e00cfdf..099d915dc 100644 --- a/web/lib/tasks/scheduler.rake +++ b/web/lib/tasks/scheduler.rake @@ -1,8 +1,8 @@ # Resque tasks require 'resque/tasks' -require 'resque_scheduler/tasks' +require 'resque/scheduler/tasks' require 'resque' -require 'resque_scheduler' +require 'resque-scheduler' task :scheduler => :environment do From 45a48daae08ff7054779ac81446a3813dd71ae86 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Sun, 27 Jul 2014 23:39:11 +0000 Subject: [PATCH 07/35] VRFS-1939 VRFS-1936 fixed session and scheduled musician invite dialog --- .../assets/javascripts/accounts_session_detail.js | 13 ++++++++++++- web/app/assets/javascripts/inviteMusicians.js | 4 +++- web/app/assets/javascripts/session.js | 9 ++++++++- .../views/clients/_account_session_detail.html.haml | 4 ++-- web/app/views/clients/_session.html.erb | 2 +- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/web/app/assets/javascripts/accounts_session_detail.js b/web/app/assets/javascripts/accounts_session_detail.js index 76f9b2401..a148f4241 100644 --- a/web/app/assets/javascripts/accounts_session_detail.js +++ b/web/app/assets/javascripts/accounts_session_detail.js @@ -21,6 +21,8 @@ var $templateOpenSlots = null; var instrument_logo_map = context.JK.getInstrumentIconMap24(); var invitationDialog = null; + var inviteMusiciansUtil = null; + var friendInput=null; var LATENCY = { @@ -42,7 +44,11 @@ function inviteMusicians(e) { e.preventDefault(); - invitationDialog.showEmailDialog(); + friendInput = inviteMusiciansUtil.inviteSessionUpdate('#update-session-invite-musicians', + sessionId); + inviteMusiciansUtil.loadFriends(); + $(friendInput).show(); + // invitationDialog.showEmailDialog(); } function cancelRsvpRequest(e) { @@ -120,6 +126,7 @@ $sessionPageBtn.on('click', openSessionPage); $screen.find(".approveRsvpRequest").on('click', approveRsvpRequest); $screen.find(".declineRsvpRequest").on('click', declineRsvpRequest); + $(friendInput).focus(function() { $(this).val(''); }) $screen.find(".cancelSessionRsvp").on('click', function(e) { e.preventDefault(); @@ -393,6 +400,10 @@ $sessionDetail = $screen.find("#account-session-detail-div"); $shareUrl = $screen.find('.share-url'); invitationDialog = invitationDlg; + + inviteMusiciansUtil = new JK.InviteMusiciansUtil(JK.app); + inviteMusiciansUtil.initialize(JK.FriendSelectorDialogInstance); + $templateOpenSlots = $('#template-open-slots'); } diff --git a/web/app/assets/javascripts/inviteMusicians.js b/web/app/assets/javascripts/inviteMusicians.js index 604641e1d..60d60b067 100644 --- a/web/app/assets/javascripts/inviteMusicians.js +++ b/web/app/assets/javascripts/inviteMusicians.js @@ -59,6 +59,8 @@ addInvitation(dd.name, dd.id); }); }).fail(app.ajaxError); + + return friendInput; } this.clearSelections = function() { @@ -133,7 +135,7 @@ } else { $(friendInput).select(); - context.alert('Invitation already exists for this musician.'); + // context.alert('Invitation already exists for this musician.'); } } diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 323a0ee84..25a5e0915 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -32,6 +32,7 @@ var playbackControls = null; var promptLeave = false; var rateSessionDialog = null; + var friendInput=null; var rest = context.JK.Rest(); @@ -133,6 +134,7 @@ .done(function(){ initializeSession(); }) + } function notifyWithUserInfo(title , text, clientId) { @@ -1354,7 +1356,10 @@ } function inviteMusicians() { - inviteMusiciansUtil.inviteSessionUpdate('#update-session-invite-musicians', sessionId); + friendInput = inviteMusiciansUtil.inviteSessionUpdate('#update-session-invite-musicians', + sessionId); + inviteMusiciansUtil.loadFriends(); + $(friendInput).show(); } function events() { @@ -1365,6 +1370,7 @@ $('#recording-start-stop').on('click', startStopRecording); $('#open-a-recording').on('click', openRecording); $('#session-invite-musicians').on('click', inviteMusicians); + $('#session-invite-musicians2').on('click', inviteMusicians); $('#track-settings').click(function() { configureTrackDialog.refresh(); configureTrackDialog.showVoiceChatPanel(true); @@ -1376,6 +1382,7 @@ .on('pause', onPause) .on('play', onPlay) .on('change-position', onChangePlayPosition); + $(friendInput).focus(function() { $(this).val(''); }) } this.initialize = function(localRecordingsDialogInstance, recordingFinishedDialogInstance, friendSelectorDialog) { diff --git a/web/app/views/clients/_account_session_detail.html.haml b/web/app/views/clients/_account_session_detail.html.haml index 6f14962e8..4d6ee95c0 100644 --- a/web/app/views/clients/_account_session_detail.html.haml +++ b/web/app/views/clients/_account_session_detail.html.haml @@ -16,7 +16,7 @@ .right %a.cancel-rsvp.button-orange{href: "#"} CANCEL RSVP %a.session-detail-page.button-orange{href: "#", rel:'external'} SESSION PAGE - %a.invite-others.button-orange{href: "#"} INVITE OTHERS + %a.invite-others.button-orange{'layout-link' => 'select-invites','href' => "#"} INVITE OTHERS .clearall #account-session-detail-div @@ -160,4 +160,4 @@ %script{type: 'text/template', id: 'template-account-session-latency'} .latency{class: "{{data.latency_style}}"} - {{data.latency_text}} \ No newline at end of file + {{data.latency_text}} diff --git a/web/app/views/clients/_session.html.erb b/web/app/views/clients/_session.html.erb index 04cdd236d..6865d987f 100644 --- a/web/app/views/clients/_session.html.erb +++ b/web/app/views/clients/_session.html.erb @@ -78,7 +78,7 @@

No Live Tracks:
- Invite Other Musicians to
+ Invite Other Musicians to
Add Live Tracks

From c28e932c2d840c7f8aa9c170a988308f46f3274c Mon Sep 17 00:00:00 2001 From: Anthony Davis Date: Mon, 28 Jul 2014 21:14:09 -0500 Subject: [PATCH 08/35] VRFS-1933 - integration tests for all ways of creating a session - might fail on Jenkins --- web/spec/features/create_session_flow_spec.rb | 49 +--- web/spec/features/create_session_spec.rb | 231 ++++++++++++++++++ web/spec/support/utilities.rb | 45 ++-- 3 files changed, 264 insertions(+), 61 deletions(-) create mode 100644 web/spec/features/create_session_spec.rb diff --git a/web/spec/features/create_session_flow_spec.rb b/web/spec/features/create_session_flow_spec.rb index f8e672f0e..d61b9f213 100644 --- a/web/spec/features/create_session_flow_spec.rb +++ b/web/spec/features/create_session_flow_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Create Session Flow", :js => true, :type => :feature, :capybara_feature => true do +describe "Create Session UI", :js => true, :type => :feature, :capybara_feature => true do let(:user1) { FactoryGirl.create(:user) } let(:user2) { FactoryGirl.create(:user) } @@ -13,8 +13,7 @@ describe "Create Session Flow", :js => true, :type => :feature, :capybara_featur page.driver.resize(1500, 800) # makes sure all the elements are visible emulate_client sign_in_poltergeist user1 - wait_until_curtain_gone - visit "/client#/createSession" + page.find('.createsession').trigger(:click) end end @@ -211,48 +210,4 @@ describe "Create Session Flow", :js => true, :type => :feature, :capybara_featur end end end - - context "create session flow backend" do - describe "schedule a session" do - it "schedule a session" do - schedule_session({creator: user1}) - end - - it "start a session after scheduling" do - MusicSession.delete_all - - schedule_session({creator: user1}) - - in_client(user1) do - visit "/client#/createSession" - - find('li[create-type="start-scheduled"] ins').trigger(:click) - - find('.btn-next').trigger(:click) - find('.btn-next').trigger(:click) - - expect(page).to have_selector('h2', text: 'my tracks') - find('#session-screen .session-mytracks .session-track') - end - end - end - - it "start quick session" do - page.driver.resize(1500, 800) # makes sure all the elements are visible - emulate_client - sign_in_poltergeist user1 - wait_until_curtain_gone - visit "/client#/createSession" - expect(page).to have_selector('h1', text: 'create session') - - find('li[create-type="quick-start"] ins').trigger(:click) - find('div[info-id="quick-start"]') - - find('.btn-next').trigger(:click) - find('.btn-next', text: 'START SESSION').trigger(:click) - - expect(page).to have_selector('h2', text: 'my tracks') - find('#session-screen .session-mytracks .session-track') - end - end end \ No newline at end of file diff --git a/web/spec/features/create_session_spec.rb b/web/spec/features/create_session_spec.rb new file mode 100644 index 000000000..85a839916 --- /dev/null +++ b/web/spec/features/create_session_spec.rb @@ -0,0 +1,231 @@ +require 'spec_helper' + +describe "Create Session", :js => true, :type => :feature, :capybara_feature => true do + let(:user1) { FactoryGirl.create(:user) } + let(:user2) { FactoryGirl.create(:user) } + + context "functionally test all ways to Create Session" do + + context "I have already scheduled a session..." do + let (:now) { Time.now - 5.hours } + let (:first_session) { FactoryGirl.create(:music_session, creator: user1, name: "First one", scheduled_start: now + 5.minutes) } + let (:second_session) { FactoryGirl.create(:music_session, creator: user1, name: "Second one", scheduled_start: now + 2.hours) } + let (:third_session) { FactoryGirl.create(:music_session, creator: user1, name: "Third one", scheduled_start: now + 17.days) } + let (:not_my_session) { FactoryGirl.create(:music_session, creator: user2, name: "Who cares", scheduled_start: now + 30.minutes) } + + before do + #instantiate these test sessions in non-sequential order + third_session.touch; first_session.touch; not_my_session.touch; second_session.touch; + #[first_session, second_session, third_session, not_my_session].each { |s| puts "#{s.name}: #{s.id}" } + + emulate_client + page.driver.resize(1500, 800) #purely aesthetic + sign_in_poltergeist user1 + find('.createsession').trigger(:click) + wait_for_ajax + expect(page).to have_selector 'li[create-type="start-scheduled"] ins' + end + + it "sessions are shown in schedule order on the Create Session screen" do + sleep 2 #arg + radio_buttons = page.all('ul#scheduled-session-list li') + first, second, third = *radio_buttons[0..2] + expect(first.text).to include first_session.name + expect(second.text).to include second_session.name + expect(third.text).to include third_session.name + expect(first).to have_selector 'input[checked=checked]' + expect(page).to_not have_text not_my_session.name + end + + it "future sessions can be edited from the Create Session screen" do + #pending "possible bug, does not occur when testing manually" + page.find('a#edit_scheduled_sessions').trigger(:click) + #expect(page).to have_selector "div[data-id='#{first_session.id}']" #see pending note + expect(page).to have_selector "div[data-id='#{second_session.id}']" + expect(page).to have_selector "div[data-id='#{third_session.id}']" + expect(page).to_not have_selector "div[data-id='#{not_my_session.id}']" + end + + context "...and I want to start it now" do + it "starts the first one" do + sleep 1 + find('.btn-next').trigger(:click) + sleep 1 + expect(page).to have_selector('.session-step-title', text: 'Review & Confirm') + expect(page).to have_content first_session.name + find('.btn-next').trigger(:click) + expect(page).to have_selector('h2', text: 'my tracks') + find('#session-screen .session-mytracks .session-track') + end + + context "attempt to start a session more than an hour from now" do + let (:first_session) { FactoryGirl.create(:music_session, creator: user1, scheduled_start: now + 65.minutes) } + + it "warns the user that session starts in the future, and user can start session" do + sleep 1 + find('.btn-next').trigger(:click) + sleep 1 + expect(page).to have_selector('h1', text: 'Future Session') + expect(page).to have_content "Are you sure" + find('#btn-confirm-ok', text: 'Start Session Now').trigger(:click) + sleep 1 + expect(page).to have_selector('.session-step-title', text: 'Review & Confirm') + expect(page).to have_content first_session.name + find('.btn-next').trigger(:click) + expect(page).to have_selector('h2', text: 'my tracks') + find('#session-screen .session-mytracks .session-track') + end + end + end + end + + + shared_examples_for :a_future_session do + specify "creator can see the session on Create Session page" do + in_client(creator) do + page.find('.createsession').trigger(:click) + expect(page).to have_selector('h1', text: 'create session') + sessions = page.first('ul#scheduled-session-list li') + expect(sessions.text).to include session_name + end + end + + specify "creator can see the session on Find Session page" do + in_client(creator) do + visit "/client#/findSession" + wait_until_curtain_gone + expect(page).to have_selector('#session-name-disp', text: "#{session_name} (#{session_genre})") + #expect(page).to have_selector('#session-name-disp', text: @session_genre) + end + end + + specify "another user can see the session on Find Session page" do + in_client(someone_else) do + emulate_client + page.driver.resize(1500, 800) + sign_in_poltergeist someone_else + visit "/client#/findSession" + wait_until_curtain_gone + expect(find('table#sessions-scheduled')).to have_content session_name + expect(find('table#sessions-scheduled')).to have_content session_genre + end + end + + specify "another user can RSVP to the session" do + in_client(someone_else) do + emulate_client + page.driver.resize(1500, 800) + sign_in_poltergeist someone_else + visit "/client#/findSession" + wait_until_curtain_gone + + within('table#sessions-scheduled') do + find('a.rsvp-link').trigger(:click) + end + + within('div.dialog-inner') do + find('div.session-name').should have_content session_name + find('div.slot-instructions').should have_content "Check the box(es) next to the track(s) you want to play" + # fill_in '.txtComment', with: "Looking forward to the session" + #first('div.rsvp-instruments input').trigger(:click) + sleep 1 + find('#btnSubmitRsvp').trigger(:click) + sleep 2 + end + end + end + + specify "creator can start the session" do + in_client(creator) do + page.find('.createsession').trigger(:click) + expect(page).to have_selector('h1', text: 'create session') + expect(page).to have_content session_name + find('li[create-type="start-scheduled"] ins').trigger(:click) + find('.btn-next').trigger(:click) + find('.btn-next').trigger(:click) + expect(page).to have_selector('h2', text: 'my tracks') + find('#session-screen .session-mytracks .session-track') + end + end + end + + context "I want to schedule a session for a specific future time" do + before do + MusicSession.delete_all + @creator, @session_name, @session_genre = schedule_session(creator: user1) + end + + it_should_behave_like :a_future_session do + let(:creator) { @creator } + let(:session_name) { @session_name } + let(:session_genre) { @session_genre } + let(:someone_else) { FactoryGirl.create(:user) } + end + end + + context "I want to choose the time after others RSVP to my session" do + before do + MusicSession.delete_all + @creator, @session_name, @session_genre = schedule_session(creator: user1, rsvp: true) + end + + it_should_behave_like :a_future_session do + let(:creator) { @creator } + let(:session_name) { @session_name } + let(:session_genre) { @session_genre } + let(:someone_else) { FactoryGirl.create(:user) } + end + end + + context "I want to start a new session right now for others to join" do + before do + MusicSession.delete_all + @creator, @session_name, @session_genre = schedule_session(creator: user1, immediate: true) + end + + specify "creator is in the session" do + in_client @creator do + expect(page).to have_selector('h2', text: 'my tracks') + find('#session-screen .session-mytracks .session-track') + end + end + + specify "another user can see the session on Find Session page" do + in_client(user2) do + emulate_client + page.driver.resize(1500, 800) + sign_in_poltergeist user2 + visit "/client#/findSession" + wait_until_curtain_gone + expect(find('table#sessions-scheduled')).to have_content @session_name + expect(find('table#sessions-scheduled')).to have_content @session_genre + end + end + end + + context "I want to quick start a test session just for me" do + before do + MusicSession.delete_all + @creator, @session_name, @session_genre = schedule_session(creator: user1, quickstart: true) + end + + specify "creator is in the session" do + in_client @creator do + expect(page).to have_selector('h2', text: 'my tracks') + find('#session-screen .session-mytracks .session-track') + end + end + + specify "another user does NOT see the session on Find Session page" do + in_client(user2) do + emulate_client + page.driver.resize(1500, 800) + sign_in_poltergeist user2 + visit "/client#/findSession" + wait_until_curtain_gone + expect(find('table#sessions-scheduled')).to_not have_content @session_name + end + end + end + end +end \ No newline at end of file diff --git a/web/spec/support/utilities.rb b/web/spec/support/utilities.rb index 3fa667adb..27b50ad35 100644 --- a/web/spec/support/utilities.rb +++ b/web/spec/support/utilities.rb @@ -335,6 +335,9 @@ def schedule_session(options = {}) fan_chat = options[:fan_chat].nil? ? false : options[:fan_chat] musician_access_value = 'Musicians may join by approval' fan_permission_value = 'Fans may listen, chat with each other' + rsvp = options[:rsvp] + immediate = options[:immediate] + quickstart = options[:quickstart] if musician_access && !approval_required musician_access_value = 'Musicians may join at will' @@ -356,26 +359,40 @@ def schedule_session(options = {}) expect(page).to have_selector('h1', text: 'create session') within('#create-session-form') do - - find('li[create-type="schedule-future"] ins').trigger(:click) - find('.btn-next').trigger(:click) - - jk_select(genre, '#create-session-form select[name="genres"]') - fill_in('session-name', :with => unique_session_name) - fill_in('session-description', :with => unique_session_desc) - find('.btn-next').trigger(:click) + if rsvp + find('li[create-type="rsvp"] ins').trigger(:click) + elsif immediate + find('li[create-type="immediately"] ins').trigger(:click) + elsif quickstart + find('li[create-type="quick-start"] ins').trigger(:click) + else + find('li[create-type="schedule-future"] ins').trigger(:click) + end find('.btn-next').trigger(:click) - find('div#divSessionPolicy ins').trigger(:click) - jk_select(musician_access_value, '#session-musician-access') - jk_select(fan_permission_value, '#session-fans-access') - find('.btn-next').trigger(:click) + unless quickstart + jk_select(genre, '#create-session-form select[name="genres"]') + fill_in('session-name', :with => unique_session_name) + fill_in('session-description', :with => unique_session_desc) + find('.btn-next').trigger(:click) - find('.btn-next', text: 'PUBLISH SESSION').trigger(:click) + find('.btn-next').trigger(:click) + + find('div#divSessionPolicy ins').trigger(:click) + jk_select(musician_access_value, '#session-musician-access') + jk_select(fan_permission_value, '#session-fans-access') + find('.btn-next').trigger(:click) + end + + unless quickstart || immediate + find('.btn-next', text: 'PUBLISH SESSION').trigger(:click) + else + find('.btn-next', text: 'START SESSION').trigger(:click) + end end - find('h2', text: 'create session') + # find('h2', text: 'create session') unless quickstart || immediate sleep 1 # to get rid of this, we need to verify that the URL is /client#/home.. otherwise intermittent fails end From 50c611d7291ea6edf01266daccdeaa5019be7caa Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 28 Jul 2014 09:49:56 -0500 Subject: [PATCH 09/35] * removing debugger gem from admin gemfile for now --- admin/Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/Gemfile b/admin/Gemfile index fe8c1df52..751e53b9b 100644 --- a/admin/Gemfile +++ b/admin/Gemfile @@ -97,7 +97,7 @@ end # gem 'capistrano' # To use debugger -gem 'debugger' +#gem 'debugger' # not working with 2.1.2p95 group :development, :test do gem 'capybara' From ef87d635e262a229b92c52cf1444b61b16381216 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 28 Jul 2014 10:05:16 -0500 Subject: [PATCH 10/35] * fixing some admin pathing/url issues --- admin/app/admin/score_export.rb | 4 ++-- admin/app/admin/score_history.rb | 8 +++++++- admin/app/assets/javascripts/admin_rest.js | 2 +- admin/app/assets/javascripts/mix_again.js | 2 +- admin/config/initializers/gon.rb | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/admin/app/admin/score_export.rb b/admin/app/admin/score_export.rb index 85d1aac0c..ddfcfaec5 100644 --- a/admin/app/admin/score_export.rb +++ b/admin/app/admin/score_export.rb @@ -65,7 +65,7 @@ ActiveAdmin.register_page "Download CSV" do end column do panel "Usage" do - span "Select a start day, and end day to generate a CSV with a score summary." + span "Select a start day and end day to generate a CSV with a score summary. Both fields are optional." end panel "Limitation 1" do div do @@ -75,7 +75,7 @@ ActiveAdmin.register_page "Download CSV" do panel "Limitation 2" do div do span do "This report uses the score_histories table, which can lag up to 1 hour behind data. You can force a score_history sweep by going to" end - span do link_to "Resque", "#{Gon.global.prefix}resque/schedule" end + span do link_to "Resque", "#{Gon.global.prefix}/resque/schedule" end span do " and then clicking 'Queue Now' for ScoreHistorySweeper. When the job count goes from 1 to 0, the score_histories table is now completely up-to-date, and you can make a 'fresh' CSV." end end end diff --git a/admin/app/admin/score_history.rb b/admin/app/admin/score_history.rb index 3fb0c5d17..02306ec43 100644 --- a/admin/app/admin/score_history.rb +++ b/admin/app/admin/score_history.rb @@ -4,10 +4,16 @@ ActiveAdmin.register JamRuby::ScoreHistory, :as => 'Score History' do config.batch_actions = false config.clear_action_items! config.filters = true - config.per_page = 10 + config.per_page = 100 filter :score filter :score_dt + #filter :from_user_id_eq, :as => :autocomplete, :url => "#{Gon.global.prefix}/admin/users/autocomplete_user_email", + # :label => "From User", :required => false, + # :wrapper_html => { :style => "list-style: none" } + + #autocomplete :user, :email, :full => true, :display_value => :autocomplete_display_name + filter :from_user_id, as: :string filter :from_latency_tester_id filter :from_isp diff --git a/admin/app/assets/javascripts/admin_rest.js b/admin/app/assets/javascripts/admin_rest.js index e41ea253a..64f49efdf 100644 --- a/admin/app/assets/javascripts/admin_rest.js +++ b/admin/app/assets/javascripts/admin_rest.js @@ -17,7 +17,7 @@ return $.ajax({ type: "POST", dataType: "json", - url: gon.global.prefix + 'api/mix/' + mixId + '/enqueue', + url: gon.global.prefix + '/api/mix/' + mixId + '/enqueue', contentType: 'application/json', processData: false }); diff --git a/admin/app/assets/javascripts/mix_again.js b/admin/app/assets/javascripts/mix_again.js index 5086e7a14..0272941f9 100644 --- a/admin/app/assets/javascripts/mix_again.js +++ b/admin/app/assets/javascripts/mix_again.js @@ -9,7 +9,7 @@ var $link = $(this); restAdmin.tryMixAgain({mix_id: $link.attr('data-mix-id')}) .done(function(response) { - $link.closest('div.mix-again').find('div.mix-again-dialog').html('
Mix enqueued
Resque Web').dialog(); + $link.closest('div.mix-again').find('div.mix-again-dialog').html('
Mix enqueued
Resque Web').dialog(); }) .error(function(jqXHR) { $link.closest('div.mix-again').find('div.mix-again-dialog').html('Mix failed: ' + jqXHR.responseText).dialog(); diff --git a/admin/config/initializers/gon.rb b/admin/config/initializers/gon.rb index 9eb7ab9da..d8e7bd43f 100644 --- a/admin/config/initializers/gon.rb +++ b/admin/config/initializers/gon.rb @@ -1 +1 @@ -Gon.global.prefix = ENV['RAILS_RELATIVE_URL_ROOT'] || '/' \ No newline at end of file +Gon.global.prefix = ENV['RAILS_RELATIVE_URL_ROOT'] || '' \ No newline at end of file From e9a4f33420e2d0527c6ecfc0b0a6a8e91c3648e7 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 28 Jul 2014 17:37:47 -0500 Subject: [PATCH 11/35] * VRFS-1957 - use median instead of just most recent for current_scores --- db/manifest | 3 +- db/up/current_scores_use_median.sql | 13 + ruby/lib/jam_ruby/models/search.rb | 2 +- ruby/spec/jam_ruby/models/score_spec.rb | 426 ++++++++++++++++-------- 4 files changed, 311 insertions(+), 133 deletions(-) create mode 100644 db/up/current_scores_use_median.sql diff --git a/db/manifest b/db/manifest index e3db60d29..e23c3243d 100755 --- a/db/manifest +++ b/db/manifest @@ -196,4 +196,5 @@ score_histories.sql update_sms_index.sql connection_allow_null_locidispid.sql track_user_in_scores.sql -median_aggregate.sql \ No newline at end of file +median_aggregate.sql +current_scores_use_median.sql \ No newline at end of file diff --git a/db/up/current_scores_use_median.sql b/db/up/current_scores_use_median.sql new file mode 100644 index 000000000..44a02e0f8 --- /dev/null +++ b/db/up/current_scores_use_median.sql @@ -0,0 +1,13 @@ +-- this results in a rough median; the only problem is that we don't avg if it's an even number. not a big deal truthfully, since eventually you'll have > 5 + +DROP VIEW current_scores; +CREATE OR REPLACE VIEW current_scores AS + + SELECT * FROM (SELECT * , row_number() OVER (PARTITION BY alocidispid, blocidispid, scorer ORDER BY score DESC) AS pcnum FROM + (SELECT * FROM + (SELECT percent_rank() over (PARTITION BY alocidispid, blocidispid ORDER BY score ASC) AS pc, * FROM + (SELECT * FROM + (SELECT *, row_number() OVER (PARTITION BY alocidispid, blocidispid ORDER BY created_at DESC) AS rownum FROM scores) tmp + WHERE rownum < 6) AS score_ranked) + AS tmp2 WHERE pc <= .5 ORDER BY pc DESC) pcs ) + AS final WHERE pcnum < 2; diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 4b1d1868b..409d0744a 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -390,7 +390,7 @@ module JamRuby limit = 50 rel = User.musicians_geocoded - .where(['created_at >= ? AND users.id != ?', since_date, usr.id]) + .where(['users.created_at >= ? AND users.id != ?', since_date, usr.id]) .joins('inner join current_scores on users.last_jam_locidispid = current_scores.alocidispid') .where(['current_scores.blocidispid = ?', locidispid]) .where(['current_scores.score <= ?', score_limit]) diff --git a/ruby/spec/jam_ruby/models/score_spec.rb b/ruby/spec/jam_ruby/models/score_spec.rb index c360cf881..195642167 100644 --- a/ruby/spec/jam_ruby/models/score_spec.rb +++ b/ruby/spec/jam_ruby/models/score_spec.rb @@ -10,141 +10,305 @@ describe Score do let(:latency_tester2) { FactoryGirl.create(:latency_tester) } let(:score_with_latency_tester) { s1, s2 = Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo', { alatencytestid: latency_tester1.id, blatencytestid: latency_tester2.id}); s1 } - before do - Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') - Score.createx(1234, 'anodeid', 0x01020304, 3456, 'cnodeid', 0x03040506, 30, nil) - Score.createx(1234, 'anodeid', 0x01020304, 3456, 'cnodeid', 0x03040506, 40, Time.new.utc-3600) - end - it "count" do - Score.count.should == 6 - end - it 'a to b' do - s = Score.where(alocidispid: 1234, blocidispid: 2345).limit(1).first - s.should_not be_nil - s.alocidispid.should == 1234 - s.anodeid.should eql('anodeid') - s.aaddr.should == 0x01020304 - s.blocidispid.should == 2345 - s.bnodeid.should eql('bnodeid') - s.baddr.should == 0x02030405 - s.score.should == 20 - s.scorer.should == 0 - s.score_dt.should_not be_nil - s.scoring_data.should eq('foo') - end - - it 'b to a' do - s = Score.where(alocidispid: 2345, blocidispid: 1234).limit(1).first - s.should_not be_nil - s.alocidispid.should == 2345 - s.anodeid.should eql('bnodeid') - s.aaddr.should == 0x02030405 - s.blocidispid.should == 1234 - s.bnodeid.should eql('anodeid') - s.baddr.should == 0x01020304 - s.score.should == 20 - s.scorer.should == 1 - s.score_dt.should_not be_nil - s.scoring_data.should be_nil - end - - it 'a to c' do - s = Score.where(alocidispid: 1234, blocidispid: 3456).limit(1).first - s.should_not be_nil - s.alocidispid.should == 1234 - s.anodeid.should eql('anodeid') - s.aaddr.should == 0x01020304 - s.blocidispid.should == 3456 - s.bnodeid.should eql('cnodeid') - s.baddr.should == 0x03040506 - s.score.should == 30 - s.scorer.should == 0 - s.score_dt.should_not be_nil - s.scoring_data.should be_nil - end - - it 'c to a' do - s = Score.where(alocidispid: 3456, blocidispid: 1234).limit(1).first - s.should_not be_nil - s.alocidispid.should == 3456 - s.anodeid.should eql('cnodeid') - s.aaddr.should == 0x03040506 - s.blocidispid.should == 1234 - s.bnodeid.should eql('anodeid') - s.baddr.should == 0x01020304 - s.score.should == 30 - s.scorer.should == 1 - s.score_dt.should_not be_nil - s.scoring_data.should be_nil - end - - it 'delete a to c' do - Score.deletex(1234, 3456) - Score.count.should == 2 - Score.where(alocidispid: 1234, blocidispid: 3456).limit(1).first.should be_nil - Score.where(alocidispid: 3456, blocidispid: 1234).limit(1).first.should be_nil - Score.where(alocidispid: 1234, blocidispid: 2345).limit(1).first.should_not be_nil - Score.where(alocidispid: 2345, blocidispid: 1234).limit(1).first.should_not be_nil - end - - it 'findx' do - Score.findx(1234, 1234).should == -1 - Score.findx(1234, 2345).should == 20 - Score.findx(1234, 3456).should == 30 - - Score.findx(2345, 1234).should == 20 - Score.findx(2345, 2345).should == -1 - Score.findx(2345, 3456).should == -1 - - Score.findx(3456, 1234).should == 30 - Score.findx(3456, 2345).should == -1 - Score.findx(3456, 3456).should == -1 - end - - it "test shortcut for making scores from connections" do - user1 = FactoryGirl.create(:user) - conn1 = FactoryGirl.create(:connection, user: user1, addr: 0x01020304, locidispid: 5) - user2 = FactoryGirl.create(:user) - conn2 = FactoryGirl.create(:connection, user: user2, addr: 0x11121314, locidispid: 6) - user3 = FactoryGirl.create(:user) - conn3 = FactoryGirl.create(:connection, user: user3, addr: 0x21222324, locidispid: 7) - - Score.findx(5, 6).should == -1 - Score.findx(6, 5).should == -1 - Score.findx(5, 7).should == -1 - Score.findx(7, 5).should == -1 - Score.findx(6, 7).should == -1 - Score.findx(7, 6).should == -1 - - Score.score_conns(conn1, conn2, 12) - Score.score_conns(conn1, conn3, 13) - Score.score_conns(conn2, conn3, 23) - - Score.findx(5, 6).should == 12 - Score.findx(6, 5).should == 12 - Score.findx(5, 7).should == 13 - Score.findx(7, 5).should == 13 - Score.findx(6, 7).should == 23 - Score.findx(7, 6).should == 23 - end - - describe "createx" do - it "creates with user info" do - score_with_user.touch - score_with_user.auserid.should == user1.id - score_with_user.buserid.should == user2.id - score_with_user.alatencytestid.should be_nil - score_with_user.blatencytestid.should be_nil + describe "with default scores" do + before do + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 3456, 'cnodeid', 0x03040506, 30, nil) + Score.createx(1234, 'anodeid', 0x01020304, 3456, 'cnodeid', 0x03040506, 40, Time.new.utc-3600) end - it "creates with latency-tester info" do - score_with_latency_tester.touch - score_with_latency_tester.auserid.should be_nil - score_with_latency_tester.buserid.should be_nil - score_with_latency_tester.alatencytestid.should == latency_tester1.id - score_with_latency_tester.blatencytestid.should == latency_tester2.id + + it "count" do + Score.count.should == 6 + end + + it 'a to b' do + s = Score.where(alocidispid: 1234, blocidispid: 2345).limit(1).first + s.should_not be_nil + s.alocidispid.should == 1234 + s.anodeid.should eql('anodeid') + s.aaddr.should == 0x01020304 + s.blocidispid.should == 2345 + s.bnodeid.should eql('bnodeid') + s.baddr.should == 0x02030405 + s.score.should == 20 + s.scorer.should == 0 + s.score_dt.should_not be_nil + s.scoring_data.should eq('foo') + end + + it 'b to a' do + s = Score.where(alocidispid: 2345, blocidispid: 1234).limit(1).first + s.should_not be_nil + s.alocidispid.should == 2345 + s.anodeid.should eql('bnodeid') + s.aaddr.should == 0x02030405 + s.blocidispid.should == 1234 + s.bnodeid.should eql('anodeid') + s.baddr.should == 0x01020304 + s.score.should == 20 + s.scorer.should == 1 + s.score_dt.should_not be_nil + s.scoring_data.should be_nil + end + + it 'a to c' do + s = Score.where(alocidispid: 1234, blocidispid: 3456).limit(1).first + s.should_not be_nil + s.alocidispid.should == 1234 + s.anodeid.should eql('anodeid') + s.aaddr.should == 0x01020304 + s.blocidispid.should == 3456 + s.bnodeid.should eql('cnodeid') + s.baddr.should == 0x03040506 + s.score.should == 30 + s.scorer.should == 0 + s.score_dt.should_not be_nil + s.scoring_data.should be_nil + end + + it 'c to a' do + s = Score.where(alocidispid: 3456, blocidispid: 1234).limit(1).first + s.should_not be_nil + s.alocidispid.should == 3456 + s.anodeid.should eql('cnodeid') + s.aaddr.should == 0x03040506 + s.blocidispid.should == 1234 + s.bnodeid.should eql('anodeid') + s.baddr.should == 0x01020304 + s.score.should == 30 + s.scorer.should == 1 + s.score_dt.should_not be_nil + s.scoring_data.should be_nil + end + + it 'delete a to c' do + Score.deletex(1234, 3456) + Score.count.should == 2 + Score.where(alocidispid: 1234, blocidispid: 3456).limit(1).first.should be_nil + Score.where(alocidispid: 3456, blocidispid: 1234).limit(1).first.should be_nil + Score.where(alocidispid: 1234, blocidispid: 2345).limit(1).first.should_not be_nil + Score.where(alocidispid: 2345, blocidispid: 1234).limit(1).first.should_not be_nil + end + + it 'findx' do + Score.findx(1234, 1234).should == -1 + Score.findx(1234, 2345).should == 20 + Score.findx(1234, 3456).should == 30 + + Score.findx(2345, 1234).should == 20 + Score.findx(2345, 2345).should == -1 + Score.findx(2345, 3456).should == -1 + + Score.findx(3456, 1234).should == 30 + Score.findx(3456, 2345).should == -1 + Score.findx(3456, 3456).should == -1 + end + + it "test shortcut for making scores from connections" do + user1 = FactoryGirl.create(:user) + conn1 = FactoryGirl.create(:connection, user: user1, addr: 0x01020304, locidispid: 5) + user2 = FactoryGirl.create(:user) + conn2 = FactoryGirl.create(:connection, user: user2, addr: 0x11121314, locidispid: 6) + user3 = FactoryGirl.create(:user) + conn3 = FactoryGirl.create(:connection, user: user3, addr: 0x21222324, locidispid: 7) + + Score.findx(5, 6).should == -1 + Score.findx(6, 5).should == -1 + Score.findx(5, 7).should == -1 + Score.findx(7, 5).should == -1 + Score.findx(6, 7).should == -1 + Score.findx(7, 6).should == -1 + + Score.score_conns(conn1, conn2, 12) + Score.score_conns(conn1, conn3, 13) + Score.score_conns(conn2, conn3, 23) + + Score.findx(5, 6).should == 12 + Score.findx(6, 5).should == 12 + Score.findx(5, 7).should == 13 + Score.findx(7, 5).should == 13 + Score.findx(6, 7).should == 23 + Score.findx(7, 6).should == 23 + end + + describe "createx" do + it "creates with user info" do + score_with_user.touch + score_with_user.auserid.should == user1.id + score_with_user.buserid.should == user2.id + score_with_user.alatencytestid.should be_nil + score_with_user.blatencytestid.should be_nil + end + + it "creates with latency-tester info" do + score_with_latency_tester.touch + score_with_latency_tester.auserid.should be_nil + score_with_latency_tester.buserid.should be_nil + score_with_latency_tester.alatencytestid.should == latency_tester1.id + score_with_latency_tester.blatencytestid.should == latency_tester2.id + end + end + end + + # current_scores is a view that tries to take the median of up to the last 5 entries + describe "current_scores" do + it "works with empty data set" do + result = Score.connection.execute('SELECT * FROM current_scores') + result.check + result.ntuples.should == 0 + end + + it "works with one score" do + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') + result = Score.connection.execute('SELECT * FROM current_scores') + result.check + result.ntuples.should == 2 + result[0]['alocidispid'].to_i.should == 1234 + result[0]['scorer'].to_i.should == 0 + result[1]['alocidispid'].to_i.should == 2345 + result[1]['scorer'].to_i.should == 1 + end + + it "works with two scores in same location" do + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') # median + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 25, nil, 'foo') + + result = Score.connection.execute('SELECT * FROM current_scores') + result.check + result.ntuples.should == 2 + result[0]['score'].to_i.should == 20 + result[1]['score'].to_i.should == 20 + end + + it "works with three scores in same location" do + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 25, nil, 'foo') # median + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 30, nil, 'foo') + + result = Score.connection.execute('SELECT * FROM current_scores') + result.check + result.ntuples.should == 2 + result[0]['score'].to_i.should == 25 + result[1]['score'].to_i.should == 25 + end + + it "works with six scores in same location" do + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') # we'll make sure this is old, so it won't be in the set + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 25, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 30, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 31, nil, 'foo')# median + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 32, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 33, nil, 'foo') + + Score.connection.execute("UPDATE scores set created_at = TIMESTAMP '#{1.days.ago}' WHERE score = 20").cmdtuples.should == 2 + + result = Score.connection.execute('SELECT * FROM current_scores') + result.check + result.ntuples.should == 2 + result[0]['score'].to_i.should == 31 + result[1]['score'].to_i.should == 31 + + # now push back score with 33 to the very back, which will shift the median up to 30 + Score.connection.execute("UPDATE scores set created_at = TIMESTAMP '#{2.days.ago}' WHERE score = 33").check + + result = Score.connection.execute('SELECT * FROM current_scores') + result.check + result.ntuples.should == 2 + result[0]['score'].to_i.should == 30 + result[1]['score'].to_i.should == 30 + end + + it "works with one score each in different locations" do + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') # median + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 25, nil, 'foo') + + result = Score.connection.execute('SELECT * FROM current_scores ORDER BY score') + result.check + result.ntuples.should == 4 + + result[0]['score'].to_i.should == 20 + result[1]['score'].to_i.should == 20 + result[2]['score'].to_i.should == 25 + result[3]['score'].to_i.should == 25 + end + + it "works with multiple scores in different locations" do + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') # median + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 25, nil, 'foo') # median + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 30, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 35, nil, 'foo') + + result = Score.connection.execute('SELECT * FROM current_scores ORDER BY score') + result.check + result.ntuples.should == 4 + + result[0]['score'].to_i.should == 20 + result[1]['score'].to_i.should == 20 + result[2]['score'].to_i.should == 25 + result[3]['score'].to_i.should == 25 + end + + it "works with multiple scores in different locations" do + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 25, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 30, nil, 'foo') # median + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 35, nil, 'foo') # median + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 40, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 45, nil, 'foo') + + result = Score.connection.execute('SELECT * FROM current_scores ORDER BY score') + result.check + result.ntuples.should == 4 + + result[0]['score'].to_i.should == 30 + 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 + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 20, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 25, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 30, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 35, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 40, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 45, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 45, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 50, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 55, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 60, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2345, 'bnodeid', 0x02030405, 65, nil, 'foo') + Score.createx(1234, 'anodeid', 0x01020304, 2346, 'bnodeid', 0x02030405, 70, nil, 'foo') + + Score.connection.execute("UPDATE scores set created_at = TIMESTAMP '#{1.days.ago}' WHERE score = 20 OR score = 25").cmdtuples.should == 4 + + result = Score.connection.execute('SELECT * FROM current_scores ORDER BY score') + result.check + result.ntuples.should == 4 + + result[0]['score'].to_i.should == 45 + result[1]['score'].to_i.should == 45 + result[2]['score'].to_i.should == 50 + result[3]['score'].to_i.should == 50 + + + Score.connection.execute("UPDATE scores set created_at = TIMESTAMP '#{2.days.ago}' WHERE score = 65 OR score = 70").cmdtuples.should == 4 + + result = Score.connection.execute('SELECT * FROM current_scores ORDER BY score') + result.check + result.ntuples.should == 4 + + result[0]['score'].to_i.should == 40 + result[1]['score'].to_i.should == 40 + result[2]['score'].to_i.should == 45 + result[3]['score'].to_i.should == 45 + + end end From 313616507673e2994d42184cc196b39cd5cc8064 Mon Sep 17 00:00:00 2001 From: Anthony Davis Date: Mon, 28 Jul 2014 22:04:19 -0500 Subject: [PATCH 12/35] VRFS-1933 - fixing Jenkins failures --- web/spec/features/create_session_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/spec/features/create_session_spec.rb b/web/spec/features/create_session_spec.rb index 85a839916..4772aa869 100644 --- a/web/spec/features/create_session_spec.rb +++ b/web/spec/features/create_session_spec.rb @@ -46,7 +46,7 @@ describe "Create Session", :js => true, :type => :feature, :capybara_feature => expect(page).to_not have_selector "div[data-id='#{not_my_session.id}']" end - context "...and I want to start it now" do + context "...start it now" do it "starts the first one" do sleep 1 find('.btn-next').trigger(:click) @@ -59,12 +59,12 @@ describe "Create Session", :js => true, :type => :feature, :capybara_feature => end context "attempt to start a session more than an hour from now" do - let (:first_session) { FactoryGirl.create(:music_session, creator: user1, scheduled_start: now + 65.minutes) } + let (:first_session) { FactoryGirl.create(:music_session, creator: user1, scheduled_start: now + 75.minutes) } it "warns the user that session starts in the future, and user can start session" do sleep 1 find('.btn-next').trigger(:click) - sleep 1 + sleep 2 expect(page).to have_selector('h1', text: 'Future Session') expect(page).to have_content "Are you sure" find('#btn-confirm-ok', text: 'Start Session Now').trigger(:click) @@ -190,15 +190,15 @@ describe "Create Session", :js => true, :type => :feature, :capybara_feature => end end - specify "another user can see the session on Find Session page" do + specify "another user can see this active session on Find Session page" do in_client(user2) do emulate_client page.driver.resize(1500, 800) sign_in_poltergeist user2 visit "/client#/findSession" wait_until_curtain_gone - expect(find('table#sessions-scheduled')).to have_content @session_name - expect(find('table#sessions-scheduled')).to have_content @session_genre + expect(find('table#sessions-active')).to have_content @session_name + expect(find('table#sessions-active')).to have_content @session_genre end end end From 1e6524e534b1116a0eb7094ca9296a0c0a469381 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 28 Jul 2014 23:04:56 -0500 Subject: [PATCH 13/35] * VRFS-1956 - fixes for musicians page --- ruby/lib/jam_ruby/models/search.rb | 21 ++++--- .../jam_ruby/models/musician_search_spec.rb | 58 ++++++++++--------- web/app/assets/javascripts/findMusician.js | 30 +++++++++- web/app/assets/javascripts/utils.js | 6 +- .../stylesheets/client/musician.css.scss | 12 ++++ web/app/views/api_search/index.rabl | 2 +- web/app/views/clients/_help.html.erb | 16 +++++ web/app/views/clients/_musicians.html.erb | 16 ++--- web/app/views/clients/_web_filter.html.erb | 4 +- 9 files changed, 116 insertions(+), 49 deletions(-) diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 409d0744a..1f08651ec 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -98,8 +98,11 @@ module JamRuby M_ORDER_FOLLOWS = ['Most Followed', :followed] M_ORDER_PLAYS = ['Most Plays', :plays] M_ORDER_PLAYING = ['Playing Now', :playing] - ORDERINGS = B_ORDERINGS = M_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING] - B_ORDERING_KEYS = M_ORDERING_KEYS = M_ORDERINGS.collect { |oo| oo[1] } + M_ORDER_LATENCY = ['Latency To Me', :latency] + M_ORDERINGS = [M_ORDER_LATENCY, M_ORDER_FOLLOWS, M_ORDER_PLAYS] + ORDERINGS = B_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING] + M_ORDERING_KEYS = M_ORDERINGS.collect { |oo| oo[1] } + B_ORDERING_KEYS = B_ORDERINGS.collect { |oo| oo[1] } DISTANCE_OPTS = B_DISTANCE_OPTS = M_DISTANCE_OPTS = [['Any', 0], [1000.to_s, 1000], [500.to_s, 500], [250.to_s, 250], [100.to_s, 100], [50.to_s, 50], [25.to_s, 25]] @@ -150,7 +153,7 @@ module JamRuby # puts "================ user #{user.inspect}" # puts "================ conn #{conn.inspect}" - rel = User.musicians_geocoded + rel = User.musicians # not musicians_geocoded on purpose; we allow 'unknowns' to surface in the search page rel = rel.select('users.*') rel = rel.group('users.id') @@ -164,7 +167,7 @@ module JamRuby # filter on scores using selections from params # see M_SCORE_OPTS - score_limit = TEST_SCORE + score_limit = ANY_SCORE l = params[:score_limit] unless l.nil? score_limit = l @@ -216,16 +219,20 @@ module JamRuby rel = rel.joins("#{score_join} join current_scores on current_scores.alocidispid = users.last_jam_locidispid") .where(['(current_scores.blocidispid = ? or current_scores.blocidispid is null)', locidispid]) + rel = rel.joins('LEFT JOIN regions ON regions.countrycode = users.country AND regions.region = users.state') + rel = rel.where(['current_scores.score > ?', score_min]) unless score_min.nil? rel = rel.where(['current_scores.score <= ?', score_max]) unless score_max.nil? - rel = rel.select('current_scores.score') - rel = rel.group('current_scores.score') + rel = rel.select('current_scores.score, regions.regionname') + rel = rel.group('current_scores.score, regions.regionname') end ordering = self.order_param(params) # puts "================ ordering #{ordering}" case ordering + when :latency + # nothing to do. the sort added below 'current_scores.score ASC NULLS LAST' handles this when :plays # FIXME: double counting? # sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}" rel = rel.select('COUNT(records.id)+COUNT(sessions.id) AS search_play_count') @@ -418,7 +425,7 @@ module JamRuby rel = GeoIpLocations.where_latlng(rel, params, current_user) sel_str = 'bands.*' - case ordering = self.order_param(params) + case ordering = self.order_param(params, B_ORDERING_KEYS) when :plays # FIXME: double counting? sel_str = "COUNT(records)+COUNT(msh) AS play_count, #{sel_str}" rel = rel.joins("LEFT JOIN music_sessions AS msh ON msh.band_id = bands.id") diff --git a/ruby/spec/jam_ruby/models/musician_search_spec.rb b/ruby/spec/jam_ruby/models/musician_search_spec.rb index a98985b17..f1cafa067 100644 --- a/ruby/spec/jam_ruby/models/musician_search_spec.rb +++ b/ruby/spec/jam_ruby/models/musician_search_spec.rb @@ -30,7 +30,10 @@ describe 'Musician search' do @geomusicians << @user4 @geomusicians << @user5 - Score.delete_all + # from these scores: + # user1 has scores other users in user1 location, and with user2, user3, user4 + # user2 has scores with users in user3 and user4 location + # Score.delete_all Score.createx(1, 'a', 1, 1, 'a', 1, 10) Score.createx(1, 'a', 1, 2, 'b', 2, 20) Score.createx(1, 'a', 1, 3, 'c', 3, 30) @@ -43,46 +46,46 @@ describe 'Musician search' do it "finds all musicians" do # expects all the musicians (geocoded) - results = Search.musician_filter + results = Search.musician_filter({score_limit: Search::TEST_SCORE}) results.search_type.should == :musicians_filter - results.results.count.should == @geomusicians.length - results.results.should eq @geomusicians.reverse + results.results.count.should == @musicians.length + results.results.should eq @musicians.reverse end it "finds all musicians page 1" do # expects all the musicians - results = Search.musician_filter({page: 1}) + results = Search.musician_filter({page: 1, score_limit: Search::TEST_SCORE}) results.search_type.should == :musicians_filter - results.results.count.should == @geomusicians.length - results.results.should eq @geomusicians.reverse + results.results.count.should == @musicians.length + results.results.should eq @musicians.reverse end it "finds all musicians page 2" do # expects no musicians (all fit on page 1) - results = Search.musician_filter({page: 2}) + results = Search.musician_filter({page: 2, score_limit: Search::TEST_SCORE}) results.search_type.should == :musicians_filter results.results.count.should == 0 end it "finds all musicians page 1 per_page 3" do # expects three of the musicians - results = Search.musician_filter({per_page: 3}) + results = Search.musician_filter({per_page: 3, score_limit: Search::TEST_SCORE}) results.search_type.should == :musicians_filter results.results.count.should == 3 - results.results.should eq @geomusicians.reverse.slice(0, 3) + results.results.should eq @musicians.reverse.slice(0, 3) end it "finds all musicians page 2 per_page 3" do # expects two of the musicians - results = Search.musician_filter({page: 2, per_page: 3}) + results = Search.musician_filter({page: 2, per_page: 3, score_limit: Search::TEST_SCORE}) results.search_type.should == :musicians_filter - results.results.count.should == 2 - results.results.should eq @geomusicians.reverse.slice(3, 3) + results.results.count.should == 3 + results.results.should eq @musicians.reverse.slice(3, 3) end it "finds all musicians page 3 per_page 3" do # expects two of the musicians - results = Search.musician_filter({page: 3, per_page: 3}) + results = Search.musician_filter({page: 3, per_page: 3, score_limit: Search::TEST_SCORE}) results.search_type.should == :musicians_filter results.results.count.should == 0 end @@ -146,7 +149,7 @@ describe 'Musician search' do f3.save # @user2.followers.concat([@user3, @user4, @user2]) - results = Search.musician_filter({ :per_page => @musicians.size }, @user3) + results = Search.musician_filter({ :per_page => @musicians.size, score_limit: Search::TEST_SCORE, orderby: 'followed'}, @user3) expect(results.results[0].id).to eq(@user2.id) # check the follower count for given entry @@ -157,7 +160,7 @@ describe 'Musician search' do it 'paginates properly' do # make sure pagination works right - params = { :per_page => 2, :page => 1 } + params = { :per_page => 2, :page => 1 , score_limit: Search::TEST_SCORE} results = Search.musician_filter(params) expect(results.results.count).to be 2 end @@ -218,7 +221,7 @@ describe 'Musician search' do # create friendship record Friendship.save(@user1.id, @user2.id) # search on user2 - results = Search.musician_filter({}, @user2) + results = Search.musician_filter({score_limit: Search::TEST_SCORE}, @user2) friend = results.results.detect { |mm| mm.id == @user1.id } expect(friend).to_not be_nil expect(results.friend_count(friend)).to be 1 @@ -239,7 +242,7 @@ describe 'Musician search' do expect(recording.claimed_recordings.length).to be 1 expect(@user1.recordings.detect { |rr| rr == recording }).to_not be_nil - results = Search.musician_filter({},@user1) + results = Search.musician_filter({score_limit: Search::TEST_SCORE},@user1) # puts "====================== results #{results.inspect}" uu = results.results.detect { |mm| mm.id == @user1.id } expect(uu).to_not be_nil @@ -257,7 +260,7 @@ describe 'Musician search' do make_recording(@user1) # order results by num recordings - results = Search.musician_filter({ :orderby => 'plays' }, @user2) + results = Search.musician_filter({ orderby: 'plays', score_limit: Search::TEST_SCORE}, @user2) # puts "========= results #{results.inspect}" expect(results.results.length).to eq(2) expect(results.results[0].id).to eq(@user1.id) @@ -266,23 +269,24 @@ describe 'Musician search' do # add more data and make sure order still correct make_recording(@user3) make_recording(@user3) - results = Search.musician_filter({ :orderby => 'plays' }, @user2) + results = Search.musician_filter({ :orderby => 'plays', score_limit: Search::TEST_SCORE }, @user2) expect(results.results.length).to eq(2) expect(results.results[0].id).to eq(@user3.id) expect(results.results[1].id).to eq(@user1.id) end it "by now playing" do + pending "these tests worked, so leaving them in, but we don't currently have 'Now Playing' in the find musicians screen" # should get 1 result with 1 active session make_session(@user1) - results = Search.musician_filter({ :orderby => 'playing' }, @user2) + results = Search.musician_filter({ :orderby => 'playing', score_limit: Search::TEST_SCORE}, @user2) expect(results.results.count).to be 1 expect(results.results.first.id).to eq(@user1.id) # should get 2 results with 2 active sessions # sort order should be created_at DESC make_session(@user3) - results = Search.musician_filter({ :orderby => 'playing' }, @user2) + results = Search.musician_filter({ :orderby => 'playing', score_limit: Search::TEST_SCORE}, @user2) expect(results.results.count).to be 2 expect(results.results[0].id).to eq(@user3.id) expect(results.results[1].id).to eq(@user1.id) @@ -299,7 +303,7 @@ describe 'Musician search' do @user1.reload ii = @user1.instruments.detect { |inst| inst.id == 'tuba' } expect(ii).to_not be_nil - results = Search.musician_filter({ :instrument => ii.id }) + results = Search.musician_filter({ :instrument => ii.id, score_limit: Search::TEST_SCORE }) results.results.each do |rr| expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id) end @@ -313,13 +317,13 @@ describe 'Musician search' do # short distance results = Search.musician_filter({ :per_page => num, :distance => 10, - :city => 'Apex' }, @user1) + :city => 'Apex', score_limit: Search::TEST_SCORE }, @user1) expect(results.results.count).to be num # long distance results = Search.musician_filter({ :per_page => num, :distance => 1000, :city => 'Miami', - :state => 'FL' }, @user1) + :state => 'FL', score_limit: Search::TEST_SCORE }, @user1) expect(results.results.count).to be num end @@ -327,14 +331,14 @@ describe 'Musician search' do pending 'distance search changes' expect(@user1.lat).to_not be_nil # uses the location of @user1 - results = Search.musician_filter({ :distance => 10, :per_page => User.musicians.count }, @user1) + results = Search.musician_filter({ :distance => 10, :per_page => User.musicians.count, score_limit: Search::TEST_SCORE }, @user1) expect(results.results.count).to be User.musicians.count end it "finds no musicians within a given distance of location" do pending 'distance search changes' expect(@user1.lat).to_not be_nil - results = Search.musician_filter({ :distance => 10, :city => 'San Francisco' }, @user1) + results = Search.musician_filter({ :distance => 10, :city => 'San Francisco', score_limit: Search::TEST_SCORE }, @user1) expect(results.results.count).to be 0 end diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js index f29dc9afb..7750d836c 100644 --- a/web/app/assets/javascripts/findMusician.js +++ b/web/app/assets/javascripts/findMusician.js @@ -12,6 +12,7 @@ var did_show_musician_page = false; var page_num=1, page_count=0; var textMessageDialog = null; + var $results = null; function loadMusicians(queryString) { // squelch nulls and undefines @@ -102,6 +103,21 @@ return "unacceptable"; } + function formatLocation(musician) { + if(musician.city && musician.state) { + return musician.city + ', ' + musician.regionname + } + else if(musician.city) { + return musician.city + } + else if(musician.state) { + return musician.regionname + } + else { + return 'Location Unavailable' + } + } + function renderMusicians() { var ii, len; var mTemplate = $('#template-find-musician-row').html(); @@ -154,7 +170,7 @@ avatar_url: context.JK.resolveAvatarUrl(musician.photo_url), profile_url: "/client#/profile/" + musician.id, musician_name: musician.name, - musician_location: musician.city + ', ' + musician.state, + musician_location: formatLocation(musician), instruments: instr_logos, biography: musician['biography'], follow_count: musician['follow_count'], @@ -171,7 +187,15 @@ var musician_row = context.JK.fillTemplate(mTemplate, mVals); renderings += musician_row; } - $('#musician-filter-results').append(renderings); + + var $renderings = $(renderings); + var $offsetParent = $results.closest('.content'); + var options = {positions: ['top', 'bottom', 'right', 'left'], offsetParent: $offsetParent} + context.JK.helpBubble($('.follower-count', $renderings), 'musician-follower-count', {}, options); + context.JK.helpBubble($('.friend-count', $renderings), 'musician-friend-count', {}, options); + context.JK.helpBubble($('.recording-count', $renderings), 'musician-recording-count', {}, options); + context.JK.helpBubble($('.session-count', $renderings), 'musician-session-count', {}, options); + $results.append($renderings); $('.search-m-friend').on('click', friendMusician); $('.search-m-follow').on('click', followMusician); @@ -279,6 +303,8 @@ }; app.bindScreen('musicians', screenBindings); + $results = $('#musician-filter-results'); + events(); } diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js index 872825c79..3270cc59e 100644 --- a/web/app/assets/javascripts/utils.js +++ b/web/app/assets/javascripts/utils.js @@ -106,12 +106,14 @@ if (!data) { data = {} } + if(!options) { + options = {} + } + var helpText = context._.template($('#template-help-' + templateName).html(), data, { variable: 'data' }); - var holder = $('
'); holder.append(helpText); - context.JK.hoverBubble($element, helpText, options); } diff --git a/web/app/assets/stylesheets/client/musician.css.scss b/web/app/assets/stylesheets/client/musician.css.scss index 54a310ee9..9498cda70 100644 --- a/web/app/assets/stylesheets/client/musician.css.scss +++ b/web/app/assets/stylesheets/client/musician.css.scss @@ -24,6 +24,18 @@ } } +#musicians-screen { + + .filter-element.desc.instrument-selector { + margin-left:2px; + float:left; + + & + .dropdown-wrapper .dropdown-container { + width:150px; + } + } +} + #musician-filter-results { margin: 0 10px 0px 10px; diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index fd53ba9c2..5c1f8b002 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -43,7 +43,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, :joined_score + attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url, :biography, :joined_score, :regionname node :is_friend do |musician| @search.is_friend?(musician) diff --git a/web/app/views/clients/_help.html.erb b/web/app/views/clients/_help.html.erb index 9aad16a7c..a476f3e24 100644 --- a/web/app/views/clients/_help.html.erb +++ b/web/app/views/clients/_help.html.erb @@ -40,4 +40,20 @@ + + + + + + + + \ No newline at end of file diff --git a/web/app/views/clients/_musicians.html.erb b/web/app/views/clients/_musicians.html.erb index 47da7d626..bbb81888e 100644 --- a/web/app/views/clients/_musicians.html.erb +++ b/web/app/views/clients/_musicians.html.erb @@ -1,5 +1,5 @@ -<%= content_tag(:div, :layout => 'screen', 'layout-id' => 'musicians', :class => "screen secondary") do -%> +<%= content_tag(:div, :layout => 'screen', 'layout-id' => 'musicians', :class => "screen secondary", id: 'musicians-screen') do -%> <%= content_tag(:div, :class => :content) do -%> <%= content_tag(:div, :class => 'content-head') do -%> <%= content_tag(:div, image_tag("content/icon_musicians.png", {:height => 19, :width => 19}), :class => 'content-icon') %> @@ -23,7 +23,7 @@ <% end -%> - + + \ No newline at end of file diff --git a/web/app/views/clients/_musicians.html.erb b/web/app/views/clients/_musicians.html.erb index bbb81888e..df1b044b4 100644 --- a/web/app/views/clients/_musicians.html.erb +++ b/web/app/views/clients/_musicians.html.erb @@ -23,7 +23,7 @@ <% end -%> -