From ce3bf635f0c36a101be99e86ac4519c3baf7e644 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 12:55:13 +0000 Subject: [PATCH 01/66] VRFS-3036 refactoring musician_search into base_search for band_search --- ruby/lib/jam_ruby.rb | 1 + ruby/lib/jam_ruby/models/base_search.rb | 183 ++++++++++++++++++++ ruby/lib/jam_ruby/models/musician_search.rb | 136 ++------------- 3 files changed, 195 insertions(+), 125 deletions(-) create mode 100644 ruby/lib/jam_ruby/models/base_search.rb diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index 8fbdb9efd..e3af96834 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -219,6 +219,7 @@ require "jam_ruby/jmep_manager" require "jam_ruby/models/performance_sample" require "jam_ruby/models/online_presence" require "jam_ruby/models/json_store" +require "jam_ruby/models/base_search" require "jam_ruby/models/musician_search" include Jampb diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb new file mode 100644 index 000000000..84b5c9833 --- /dev/null +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -0,0 +1,183 @@ +module JamRuby + class BaseSearch < JsonStore + + attr_accessor :page_count, :results, :page_number + + ANY_VAL_STR = 'any' + ANY_VAL_INT = -1 + + PER_PAGE = 10 + PG_SMALLINT_MAX = 32767 + + KEY_SKILL = 'skill_level' + KEY_GENRES = 'genres' + KEY_INSTRUMENTS = 'instruments' + KEY_GIGS = 'concert_gigs' + KEY_SORT_ORDER = 'sort_order' + + SORT_VALS = %W{ latency distance } + SORT_ORDERS = { + SORT_VALS[0] => 'Latency to Me', + SORT_VALS[1] => 'Distance to Me' + } + + SKILL_VALS = [ANY_VAL_INT, 1, 2] + SKILL_LEVELS = { + SKILL_VALS[0] => 'Any', + SKILL_VALS[1] => 'Amateur', + SKILL_VALS[2] => 'Pro', + } + + GIG_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4] + GIG_LABELS = { + GIG_COUNTS[0] => 'Any', + GIG_COUNTS[1] => 'under 10', + GIG_COUNTS[2] => '10 to 50', + GIG_COUNTS[3] => '50 to 100', + GIG_COUNTS[4] => 'over 100' + } + + INSTRUMENT_PROFICIENCY = { + 1 => 'Beginner', + 2 => 'Intermediate', + 3 => 'Expert', + } + + JSON_SCHEMA = { + KEY_SORT_ORDER => SORT_VALS[0], + KEY_INSTRUMENTS => [], + KEY_GENRES => [], + KEY_SKILL => SKILL_VALS[0].to_s, + KEY_GIGS => GIG_COUNTS[0].to_s, + } + JSON_SCHEMA_KEYS = JSON_SCHEMA.keys + MULTI_VALUE_KEYS = JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact + SINGLE_VALUE_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS + + SEARCH_FILTER_META = { + per_page: PER_PAGE, + filter_keys: { + keys: JSON_SCHEMA_KEYS, + multi: MULTI_VALUE_KEYS, + single: SINGLE_VALUE_KEYS, + }, + sort_order: { keys: SORT_VALS, map: SORT_ORDERS }, + } + + def self.user_search_filter(user) + unless ss = user.send(self.name.demodulize.tableize.singularize) + ss = self.create_search(user) + end + ss + end + + def self.search_filter_json(user) + self.user_search_filter(user).json + end + + def self.create_search(user) + ms = self.new + ms.user = user + ms.data_blob = self::JSON_SCHEMA + ms.save! + ms + end + + def self.search_target_class + end + + def _genres(rel) + gids = json[KEY_GENRES] + unless gids.blank? + gidsql = gids.join("','") + gpsql = "SELECT player_id FROM genre_players WHERE (player_type = '#{self.class.search_target_class.name}' AND genre_id IN ('#{gidsql}'))" + rel = rel.where("#{self.class.search_target_class.table_name}.id IN (#{gpsql})") + end + rel + end + + def _instruments(rel) + rel + end + + def _gigs(rel) + gg = json[KEY_GIGS].to_i + rel = rel.where('concert_count = ?',gg) if 0 <= gg + rel + end + + def _skills(rel) + if 0 < (val = json[KEY_SKILL].to_i) + rel = rel.where(['skill_level = ?', val]) + end + rel + end + + def _sort_order(rel) + val = json[KEY_SORT_ORDER] + if SORT_VALS[1] == val + locidispid = self.user.last_jam_locidispid || 0 + my_locid = locidispid / 1000000 + rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") + rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid") + rel = rel.group("users.id, my_geo.geog, other_geo.geog") + rel = rel.order('st_distance(my_geo.geog, other_geo.geog)') + else + rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{self.user.id}'") + rel = rel.order('current_scores.full_score ASC') + end + rel + end + + def do_search(params={}) + end + + def process_results_page(objs) + end + + def search_includes(rel) + rel + end + + def search_results_page(filter=nil, page=1) + if filter + self.data_blob = filter + self.save + else + filter = self.data_blob + end + + rel = do_search(filter) + + @page_number = [page.to_i, 1].max + rel = rel.paginate(:page => @page_number, :per_page => PER_PAGE) + + rel = self.search_includes(rel) + @page_count = rel.total_pages + + process_results_page(rel.all) + end + + def reset_filter + self.data_blob = JSON_SCHEMA + self.save + end + + def reset_search_results + reset_filter + search_results_page + end + + def search_type + self.class.to_s + end + + def is_blank? + self.data_blob == JSON_SCHEMA + end + + def description + end + + end +end diff --git a/ruby/lib/jam_ruby/models/musician_search.rb b/ruby/lib/jam_ruby/models/musician_search.rb index 5dbb465db..8482ee623 100644 --- a/ruby/lib/jam_ruby/models/musician_search.rb +++ b/ruby/lib/jam_ruby/models/musician_search.rb @@ -1,22 +1,11 @@ module JamRuby - class MusicianSearch < JsonStore + class MusicianSearch < BaseSearch - attr_accessor :page_count, :results, :user_counters, :page_number + attr_accessor :user_counters - ANY_VAL_STR = 'any' - ANY_VAL_INT = -1 - - PER_PAGE = 10 - PG_SMALLINT_MAX = 32767 - - KEY_GIGS = 'concert_gigs' KEY_STUDIOS = 'studio_sessions' KEY_AGES = 'ages' - KEY_SKILL = 'skill_level' - KEY_GENRES = 'genres' - KEY_INSTRUMENTS = 'instruments' KEY_INTERESTS = 'interests' - KEY_SORT_ORDER = 'sort_order' SORT_VALS = %W{ latency distance } SORT_ORDERS = { @@ -24,22 +13,6 @@ module JamRuby SORT_VALS[1] => 'Distance to Me' } - SKILL_VALS = [ANY_VAL_INT, 1, 2] - SKILL_LEVELS = { - SKILL_VALS[0] => 'Any', - SKILL_VALS[1] => 'Amateur', - SKILL_VALS[2] => 'Pro', - } - - GIG_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4] - GIG_LABELS = { - GIG_COUNTS[0] => 'Any', - GIG_COUNTS[1] => 'under 10', - GIG_COUNTS[2] => '10 to 50', - GIG_COUNTS[3] => '50 to 100', - GIG_COUNTS[4] => 'over 100' - } - STUDIO_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4] STUDIOS_LABELS = { STUDIO_COUNTS[0] => 'Any', @@ -74,65 +47,19 @@ module JamRuby INTEREST_VALS[5] => 'Co-Writing' } - INSTRUMENT_PROFICIENCY = { - 1 => 'Beginner', - 2 => 'Intermediate', - 3 => 'Expert', - } - - JSON_SCHEMA = { - KEY_SORT_ORDER => SORT_VALS[0], - KEY_INSTRUMENTS => [], + JSON_SCHEMA = BaseSearch::JSON_SCHEMA.merge({ KEY_INTERESTS => INTEREST_VALS[0], - KEY_GENRES => [], - KEY_GIGS => GIG_COUNTS[0].to_s, KEY_STUDIOS => STUDIO_COUNTS[0].to_s, - KEY_SKILL => SKILL_VALS[0].to_s, KEY_AGES => [] - } - JSON_SCHEMA_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS = JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact - SINGLE_VALUE_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS + }) - SEARCH_FILTER_META = { - per_page: PER_PAGE, - filter_keys: { - keys: JSON_SCHEMA_KEYS, - multi: MULTI_VALUE_KEYS, - single: SINGLE_VALUE_KEYS, - }, - sort_order: { keys: SORT_VALS, map: SORT_ORDERS }, + SEARCH_FILTER_META = BaseSearch::SEARCH_FILTER_META.merge({ interests: { keys: INTEREST_VALS, map: INTERESTS }, ages: { keys: AGE_COUNTS, map: AGES } - } + }) - def self.user_search_filter(user) - unless ms = user.musician_search - ms = self.create_search(user) - end - ms - end - - def self.search_filter_json(user) - self.user_search_filter(user).json - end - - def self.create_search(user) - ms = self.new - ms.user = user - ms.data_blob = JSON_SCHEMA - ms.save! - ms - end - - def _genres(rel) - gids = json[KEY_GENRES] - unless gids.blank? - gidsql = gids.join("','") - gpsql = "SELECT player_id FROM genre_players WHERE (player_type = 'JamRuby::User' AND genre_id IN ('#{gidsql}'))" - rel = rel.where("users.id IN (#{gpsql})") - end - rel + def self.search_target_class + User end def _instruments(rel) @@ -204,22 +131,6 @@ module JamRuby rel end - def _sort_order(rel) - val = json[KEY_SORT_ORDER] - if SORT_VALS[1] == val - locidispid = self.user.last_jam_locidispid || 0 - my_locid = locidispid / 1000000 - rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") - rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid") - rel = rel.group("users.id, my_geo.geog, other_geo.geog") - rel = rel.order('st_distance(my_geo.geog, other_geo.geog)') - else - rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{self.user.id}'") - rel = rel.order('current_scores.full_score ASC') - end - rel - end - def do_search(params={}) rel = User.musicians.where('users.id <> ?', self.user.id) rel = self._genres(rel) @@ -233,33 +144,8 @@ module JamRuby rel end - def search_results_page(filter=nil, page=1) - if filter - self.data_blob = filter - self.save - else - filter = self.data_blob - end - - rel = do_search(filter) - - @page_number = [page.to_i, 1].max - rel = rel.paginate(:page => @page_number, :per_page => PER_PAGE) - - rel = rel.includes([:instruments, :followings, :friends]) - @page_count = rel.total_pages - - musician_results(rel.all) - end - - def reset_filter - self.data_blob = JSON_SCHEMA - self.save - end - - def reset_search_results - reset_filter - search_results_page + def search_includes(rel) + rel.includes([:instruments, :followings, :friends]) end RESULT_FOLLOW = :follows @@ -271,7 +157,7 @@ module JamRuby COUNT_SESSION = :count_session COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] - def musician_results(_results) + def process_results_page(_results) @results = _results @user_counters = {} and return self unless user From 749c58f37777a94d5048f31b4a96ca7cd60af746 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 13:21:53 +0000 Subject: [PATCH 02/66] VRFS-3036 refactoring band search --- ruby/lib/jam_ruby/models/base_search.rb | 9 +++++++++ ruby/lib/jam_ruby/models/musician_search.rb | 9 --------- web/app/helpers/client_helper.rb | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 84b5c9833..d6244b355 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -64,6 +64,15 @@ module JamRuby sort_order: { keys: SORT_VALS, map: SORT_ORDERS }, } + RESULT_FOLLOW = :follows + RESULT_FRIEND = :friends + + COUNT_FRIEND = :count_friend + COUNT_FOLLOW = :count_follow + COUNT_RECORD = :count_record + COUNT_SESSION = :count_session + COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] + def self.user_search_filter(user) unless ss = user.send(self.name.demodulize.tableize.singularize) ss = self.create_search(user) diff --git a/ruby/lib/jam_ruby/models/musician_search.rb b/ruby/lib/jam_ruby/models/musician_search.rb index 8482ee623..d796439d6 100644 --- a/ruby/lib/jam_ruby/models/musician_search.rb +++ b/ruby/lib/jam_ruby/models/musician_search.rb @@ -148,15 +148,6 @@ module JamRuby rel.includes([:instruments, :followings, :friends]) end - RESULT_FOLLOW = :follows - RESULT_FRIEND = :friends - - COUNT_FRIEND = :count_friend - COUNT_FOLLOW = :count_follow - COUNT_RECORD = :count_record - COUNT_SESSION = :count_session - COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] - def process_results_page(_results) @results = _results @user_counters = {} and return self unless user diff --git a/web/app/helpers/client_helper.rb b/web/app/helpers/client_helper.rb index c39e42878..c520cff52 100644 --- a/web/app/helpers/client_helper.rb +++ b/web/app/helpers/client_helper.rb @@ -49,6 +49,7 @@ module ClientHelper gon.ftue_network_test_max_clients = Rails.application.config.ftue_network_test_max_clients gon.ftue_maximum_gear_latency = Rails.application.config.ftue_maximum_gear_latency gon.musician_search_meta = MusicianSearch::SEARCH_FILTER_META + gon.band_search_meta = BandSearch::SEARCH_FILTER_META # is this the native client or browser? @nativeClient = is_native_client? From 4658f72f984d532785f08c72b4dc929daeefc9bd Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 14:41:27 +0000 Subject: [PATCH 03/66] VRFS-3036 refactoring musician_search into base_search for band_search --- ruby/lib/jam_ruby/models/band_search.rb | 172 ++++++++++++++++++++++++ ruby/lib/jam_ruby/models/base_search.rb | 23 ++-- 2 files changed, 184 insertions(+), 11 deletions(-) create mode 100644 ruby/lib/jam_ruby/models/band_search.rb diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb new file mode 100644 index 000000000..927049d5b --- /dev/null +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -0,0 +1,172 @@ +module JamRuby + class MusicianSearch < BaseSearch + + attr_accessor :user_counters + + KEY_BAND_SEARCH_TYPE = 'band_search_type' + KEY_BAND_TYPE = 'band_type' + KEY_PLAY_COMMIT = 'play_commit' + KEY_TOUR_OPTION = 'tour_option' + + BAND_SEARCH_TYPE_VALS = %W{ to_join to_hire } + BAND_SEARCH_TYPES = { + BAND_SEARCH_TYPE_VALS[0] => 'search bands', + BAND_SEARCH_TYPE_VALS[1] => 'search bands to hire', + } + + SORT_VALS = %W{ distance latency } + SORT_ORDERS = { + SORT_VALS[0] => 'Distance to Me' + SORT_VALS[1] => 'Latency to Me', + } + + BAND_TYPE_VALS = [ANY_VAL_STR, + GenrePlayer::VIRTUAL_BAND, + GenrePlayer::TRADITIONAL_BAND, + ] + BAND_TYPES = { + INTEREST_VALS[0] => 'Any', + INTEREST_VALS[1] => 'Virtual Band', + INTEREST_VALS[2] => 'Traditional Band', + } + + PLAY_COMMIT_VALS = [ANY_VAL_STR, + '0', + '1', + '2', + ] + PLAY_COMMITS = { + PLAY_COMMIT_VALS[0] => 'Any', + PLAY_COMMIT_VALS[1] => 'Infrequent', + PLAY_COMMIT_VALS[2] => 'Once a week', + PLAY_COMMIT_VALS[3] => 'More than once a week', + } + + TOUR_OPTION_VALS = [ANY_VAL_STR, + 'yes', + 'no', + ] + TOUR_OPTIONS = { + TOUR_OPTION_VALS[0] => 'Any', + TOUR_OPTION_VALS[1] => 'Yes', + TOUR_OPTION_VALS[1] => 'No', + } + + JSON_SCHEMA = BaseSearch::JSON_SCHEMA.merge({ + KEY_BAND_SEARCH_TYPE => BAND_SEARCH_TYPES[0], + KEY_BAND_TYPE => BAND_TYPE_VALS[0], + KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0], + KEY_TOUR_OPTION => TOUR_OPTION_VALS[0], + }) + + SEARCH_FILTER_META = BaseSearch::SEARCH_FILTER_META.merge({ + sort_order: { keys: self::SORT_VALS, map: self::SORT_ORDERS }, + band_type: { keys: BAND_TYPE_VALS, map: BAND_TYPES }, + play_commit: { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS }, + tour_option: { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS } + }) + + def self.search_target_class + User + end + + def do_search(params={}) + rel = User.musicians.where('users.id <> ?', self.user.id) + rel = self._sort_order(rel) + rel + end + + def search_includes(rel) + rel.includes([:instruments, :followings, :friends]) + end + + def process_results_page(_results) + @results = _results + if user + @user_counters = @results.inject({}) { |hh,val| hh[val.id] = []; hh } + mids = "'#{@results.map(&:id).join("','")}'" + + # this gets counts for each search result + @results.each do |bb| + counters = { } + counters[COUNT_FOLLOW] = Follow.where(:followable_id => bb.id).count + counters[COUNT_RECORD] = Recording.where(:band_id => bb.id).count + counters[COUNT_SESSION] = MusicSession.where(:band_id => bb.id).count + @user_counters[bb.id] << counters + end + + # this section determines follow/like/friend status for each search result + # so that action links can be activated or not + + rel = Band.select("bands.id AS bid") + rel = rel.joins("LEFT JOIN follows ON follows.user_id = '#{user.id}'") + rel = rel.where(["bands.id IN (#{mids}) AND follows.followable_id = bands.id"]) + rel.all.each { |val| @user_counters[val.bid] << RESULT_FOLLOW } + + else + @user_counters = {} + end + self + end + + private + + def _count(musician, key) + if mm = @user_counters[musician.id] + return mm.detect { |ii| ii.is_a?(Hash) }[key] + end if @user_counters + 0 + end + + public + + def follow_count(musician) + _count(musician, COUNT_FOLLOW) + end + + def friend_count(musician) + _count(musician, COUNT_FRIEND) + end + + def record_count(musician) + _count(musician, COUNT_RECORD) + end + + def session_count(musician) + _count(musician, COUNT_SESSION) + end + + def is_friend?(musician) + if mm = @user_counters[musician.id] + return mm.include?(RESULT_FRIEND) + end if @user_counters + false + end + + def is_follower?(musician) + if mm = @user_counters[musician.id] + return mm.include?(RESULT_FOLLOW) + end if @user_counters + false + end + + def search_type + self.class.to_s + end + + def is_blank? + self.data_blob == JSON_SCHEMA + end + + def description + if self.is_blank? + return 'Click search button to look for musicians with similar interests, skill levels, etc.' + end + jj = self.json + str = 'Current Search: ' + str += "Sort = #{SORT_ORDERS[json_value(BandSearch::KEY_SORT_ORDER)]}" + str + end + + end +end diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index d6244b355..950dab57b 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -44,24 +44,25 @@ module JamRuby } JSON_SCHEMA = { - KEY_SORT_ORDER => SORT_VALS[0], + KEY_SORT_ORDER => self::SORT_VALS[0], KEY_INSTRUMENTS => [], KEY_GENRES => [], - KEY_SKILL => SKILL_VALS[0].to_s, - KEY_GIGS => GIG_COUNTS[0].to_s, + KEY_SKILL => self::SKILL_VALS[0].to_s, + KEY_GIGS => self::GIG_COUNTS[0].to_s, } - JSON_SCHEMA_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS = JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact - SINGLE_VALUE_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS + + JSON_SCHEMA_KEYS = self::JSON_SCHEMA.keys + MULTI_VALUE_KEYS = self::JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact + SINGLE_VALUE_KEYS = self::JSON_SCHEMA.keys - self::MULTI_VALUE_KEYS SEARCH_FILTER_META = { - per_page: PER_PAGE, + per_page: self::PER_PAGE, filter_keys: { - keys: JSON_SCHEMA_KEYS, - multi: MULTI_VALUE_KEYS, - single: SINGLE_VALUE_KEYS, + keys: self::JSON_SCHEMA_KEYS, + multi: self::MULTI_VALUE_KEYS, + single: self::SINGLE_VALUE_KEYS, }, - sort_order: { keys: SORT_VALS, map: SORT_ORDERS }, + sort_order: { keys: self::SORT_VALS, map: self::SORT_ORDERS }, } RESULT_FOLLOW = :follows From 4cf7f208449a36037c7d80f8486babf144915095 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 15:21:39 +0000 Subject: [PATCH 04/66] VRFS-3036 refactoring musician_search into base_search --- .../javascripts/base_search_filter.js.coffee | 226 ++++++++++++++++++ .../musician_search_filter.js.coffee | 198 ++------------- 2 files changed, 251 insertions(+), 173 deletions(-) create mode 100644 web/app/assets/javascripts/base_search_filter.js.coffee diff --git a/web/app/assets/javascripts/base_search_filter.js.coffee b/web/app/assets/javascripts/base_search_filter.js.coffee new file mode 100644 index 000000000..efc876b77 --- /dev/null +++ b/web/app/assets/javascripts/base_search_filter.js.coffee @@ -0,0 +1,226 @@ +$ = jQuery +context = window +context.JK ||= {}; + +context.JK.BaseSearchFilter = class BaseSearchFilter + + constructor: () -> + @rest = context.JK.Rest() + @logger = context.JK.logger + @searchFilter = null + @profileUtils = context.JK.ProfileUtils + @helpBubble = context.JK.HelpBubbleHelper + @searchResults = null + @isSearching = false + @pageNumber = 1 + @instrument_logo_map = context.JK.getInstrumentIconMap24() + @searchType = '' + @searchTypeS = '' + @restGet = null + @restPost = null + @searchMeta = null + + init: (app) => + @app = app + @screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide } + @app.bindScreen(@searchTypeS, @screenBindings) + + @screen = $('#'+@searchTypeS+'-screen') + @resultsListContainer = @screen.find('#'+@searchType+'-search-filter-results-list') + @spinner = @screen.find('.paginate-wait') + + this.registerResultsPagination() + + @screen.find('#btn-'+@searchType+'-search-builder').on 'click', => + this.showBuilder() + + @screen.find('#btn-'+@searchType+'-search-reset').on 'click', => + this.resetFilter() + + afterShow: () => + @screen.find('#'+@searchType+'-search-filter-results').show() + @screen.find('#'+@searchType+'-search-filter-builder').hide() + this.getUserFilterResults() + + showBuilder: () => + @screen.find('#'+@searchType+'-search-filter-results').hide() + @screen.find('#'+@searchType+'-search-filter-builder').show() + @resultsListContainer.empty() + + afterHide: () => + @resultsListContainer.empty() + + renderSearchFilter: () => + + loadSearchFilter: (sFilter) => + + + _populateSelectWithKeys: (struct, selection, keys, element) => + element.children().remove() + $.each keys, (idx, value) => + label = struct[value] + blankOption = $ '' + blankOption.text label + blankOption.attr 'value', value + blankOption.attr 'selected', '' if value == selection + element.append(blankOption) + context.JK.dropdown(element) + + _populateSelectIdentifier: (identifier) => + elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' + struct = gon.band_search_meta[identifier]['map'] + keys = gon.band_search_meta[identifier]['keys'] + this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) + + _populateSelectWithInt: (sourceStruct, selection, element) => + struct = + '-1': 'Any' + $.extend(struct, sourceStruct) + this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element) + + _populateSortOrder: () => + this._populateSelectIdentifier('sort_order') + + _populateGenres: () => + @screen.find('#search-filter-genres').empty() + @rest.getGenres().done (genres) => + genreTemplate = @screen.find('#template-search-filter-setup-genres').html() + selected = '' + $.each genres, (index, genre) => + if 0 < @searchFilter.data_blob.genres.length + genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) -> + n == genre.id) + else + genreMatch = [] + selected = 'checked' if genreMatch.length > 0 + genreHtml = context.JK.fillTemplate(genreTemplate, + id: genre.id + description: genre.description + checked: selected) + @screen.find('#search-filter-genres').append genreHtml + + _populateInstruments: () => + @screen.find('#search-filter-instruments').empty() + @rest.getInstruments().done (instruments) => + $.each instruments, (index, instrument) => + instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html() + selected = '' + proficiency = '1' + if 0 < @searchFilter.data_blob.instruments.length + instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) -> + yn = inst.instrument_id == instrument.id + proficiency = inst.proficiency_level if yn + yn) + selected = 'checked' if instMatch.length > 0 + instrumentHtml = context.JK.fillTemplate(instrumentTemplate, + id: instrument.id + description: instrument.description + checked: selected) + @screen.find('#search-filter-instruments').append instrumentHtml + profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select' + jprofsel = @screen.find(profsel) + jprofsel.val(proficiency) + context.JK.dropdown(jprofsel) + return true + + _builderSelectValue: (identifier) => + elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' + elem.val() + + _builderSelectMultiValue: (identifier) => + vals = [] + elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked' + if 'instruments' == identifier + elem.each (idx) -> + row = $(this).parent().parent() + instrument = + instrument_id: row.data('instrument-id') + proficiency_level: row.find('select').val() + vals.push instrument + else + elem.each (idx) -> + vals.push $(this).val() + vals + + willSearch: (reload) => + return false if @isSearching + @isSearching = true + if reload + @pageNumber = 1 + @screen.find('#'+@searchType+'-search-filter-spinner').show() + @resultsListContainer.empty() + @screen.find('#'+@searchType+'-search-filter-builder').hide() + @screen.find('#'+@searchType+'-search-filter-results').show() + true + + didSearch: (response) => + this.loadSearchFilter(response.filter_json) + @searchResults = response + @screen.find('#'+@searchType+'-search-filter-spinner').hide() + this.renderResultsPage() + @screen.find('.paginate-wait').hide() + @isSearching = false + + resetFilter: () => + if this.willSearch(true) + @restPost({ filter: 'reset' }).done(this.didSearch) + + cancelFilter: () => + this.resetFilter() + + getUserFilterResults: () => + if this.willSearch(true) + @restGet('results=true').done(this.didSearch) + + performSearch: () => + if this.willSearch(true) + $.each @searchMeta.filter_keys.single, (index, key) => + @searchFilter[key] = this._builderSelectValue(key) + $.each @searchMeta.filter_keys.multi, (index, key) => + @searchFilter[key] = this._builderSelectMultiValue(key) + @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + + renderResultsHeader: () => + @screen.find('#'+@searchType+'-search-filter-description').html(@searchResults.description) + if @searchResults.is_blank_filter + @screen.find('#btn-'+@searchType+'-search-reset').hide() + else + @screen.find('#btn-'+@searchType+'-search-reset').show() + + renderResultsPage: () => + + _formatLocation: (band) -> + if band.city and band.state + band.city + ', ' + band.state + else if band.city + band.city + else if band.regionname + band.regionname + else + 'Location Unavailable' + + friendRequestCallback: (user_id)=> + # TODO: + + paginate: () => + if @pageNumber < @searchResults.page_count && this.willSearch(false) + @screen.find('.paginate-wait').show() + @pageNumber += 1 + @rest.postBandSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + return true + false + + registerResultsPagination: () => + _resultsListContainer = @resultsListContainer + _headerHeight = @screen.find('#'+@searchType+'-search-filter-results-header').height() + _paginator = this.paginate + + @screen.find('.content-body-scroller').scroll -> + if _resultsListContainer.is(':visible') + jthis = $(this) + wintop = jthis.scrollTop() + winheight = jthis.innerHeight() + docheight = jthis[0].scrollHeight - _headerHeight + scrollTrigger = 0.98; + if ((wintop / (docheight - winheight)) >= scrollTrigger) + _paginator() diff --git a/web/app/assets/javascripts/musician_search_filter.js.coffee b/web/app/assets/javascripts/musician_search_filter.js.coffee index 4187d6acd..3aaa44440 100644 --- a/web/app/assets/javascripts/musician_search_filter.js.coffee +++ b/web/app/assets/javascripts/musician_search_filter.js.coffee @@ -2,54 +2,26 @@ $ = jQuery context = window context.JK ||= {}; -context.JK.MusicianSearchFilter = class MusicianSearchFilter +context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchFilter constructor: () -> - @rest = context.JK.Rest() - @logger = context.JK.logger - @searchFilter = null - @profileUtils = context.JK.ProfileUtils - @helpBubble = context.JK.HelpBubbleHelper - @searchResults = null - @isSearching = false - @pageNumber = 1 - @instrument_logo_map = context.JK.getInstrumentIconMap24() + super() + @searchType = 'musician' + @searchTypeS = @searchTypeS+'s' + @restGet = @rest.getMusicianSearchFilter + @restPost = @rest.postMusicianSearchFilter + @searchMeta = gon.musician_search_meta init: (app) => - @app = app - @screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide } - @app.bindScreen('musicians', @screenBindings) - - @screen = $('#musicians-screen') - @resultsListContainer = @screen.find('#musician-search-filter-results-list') - @spinner = @screen.find('.paginate-wait') - - this.registerResultsPagination() - - @screen.find('#btn-musician-search-builder').on 'click', => - this.showBuilder() - - @screen.find('#btn-musician-search-reset').on 'click', => - this.resetFilter() - - afterShow: () => - @screen.find('#musician-search-filter-results').show() - @screen.find('#musician-search-filter-builder').hide() - this.getUserFilterResults() - - showBuilder: () => - @screen.find('#musician-search-filter-results').hide() - @screen.find('#musician-search-filter-builder').show() - @resultsListContainer.empty() - - afterHide: () => - @resultsListContainer.empty() + super(app) renderSearchFilter: () => $.when(this.rest.getMusicianSearchFilter()).done (sFilter) => this.loadSearchFilter(sFilter) loadSearchFilter: (sFilter) => + super(sFilter) + @searchFilter = JSON.parse(sFilter) args = interests: @searchFilter.data_blob.interests @@ -77,31 +49,6 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter this._populateInstruments() this._populateSortOrder() - - - _populateSelectWithKeys: (struct, selection, keys, element) => - element.children().remove() - $.each keys, (idx, value) => - label = struct[value] - blankOption = $ '' - blankOption.text label - blankOption.attr 'value', value - blankOption.attr 'selected', '' if value == selection - element.append(blankOption) - context.JK.dropdown(element) - - _populateSelectIdentifier: (identifier) => - elem = $ '#musician-search-filter-builder select[name='+identifier+']' - struct = gon.musician_search_meta[identifier]['map'] - keys = gon.musician_search_meta[identifier]['keys'] - this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) - - _populateSelectWithInt: (sourceStruct, selection, element) => - struct = - '-1': 'Any' - $.extend(struct, sourceStruct) - this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element) - _populateSortOrder: () => this._populateSelectIdentifier('sort_order') @@ -122,8 +69,8 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter _populateAges: () => @screen.find('#search-filter-ages').empty() - ages_map = gon.musician_search_meta['ages']['map'] - $.each gon.musician_search_meta['ages']['keys'], (index, key) => + ages_map = @searchMeta['ages']['map'] + $.each @searchMeta['ages']['keys'], (index, key) => ageTemplate = @screen.find('#template-search-filter-setup-ages').html() selected = '' ageLabel = ages_map[key] @@ -139,112 +86,34 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter @screen.find('#search-filter-ages').append ageHtml _populateGenres: () => - @screen.find('#search-filter-genres').empty() - @rest.getGenres().done (genres) => - genreTemplate = @screen.find('#template-search-filter-setup-genres').html() - selected = '' - $.each genres, (index, genre) => - if 0 < @searchFilter.data_blob.genres.length - genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) -> - n == genre.id) - else - genreMatch = [] - selected = 'checked' if genreMatch.length > 0 - genreHtml = context.JK.fillTemplate(genreTemplate, - id: genre.id - description: genre.description - checked: selected) - @screen.find('#search-filter-genres').append genreHtml + super() _populateInstruments: () => - @screen.find('#search-filter-instruments').empty() - @rest.getInstruments().done (instruments) => - $.each instruments, (index, instrument) => - instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html() - selected = '' - proficiency = '1' - if 0 < @searchFilter.data_blob.instruments.length - instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) -> - yn = inst.instrument_id == instrument.id - proficiency = inst.proficiency_level if yn - yn) - selected = 'checked' if instMatch.length > 0 - instrumentHtml = context.JK.fillTemplate(instrumentTemplate, - id: instrument.id - description: instrument.description - checked: selected) - @screen.find('#search-filter-instruments').append instrumentHtml - profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select' - jprofsel = @screen.find(profsel) - jprofsel.val(proficiency) - context.JK.dropdown(jprofsel) - return true - - _builderSelectValue: (identifier) => - elem = $ '#musician-search-filter-builder select[name='+identifier+']' - elem.val() - - _builderSelectMultiValue: (identifier) => - vals = [] - elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked' - if 'instruments' == identifier - elem.each (idx) -> - row = $(this).parent().parent() - instrument = - instrument_id: row.data('instrument-id') - proficiency_level: row.find('select').val() - vals.push instrument - else - elem.each (idx) -> - vals.push $(this).val() - vals + super() willSearch: (reload) => - return false if @isSearching - @isSearching = true - if reload - @pageNumber = 1 - @screen.find('#musician-search-filter-spinner').show() - @resultsListContainer.empty() - @screen.find('#musician-search-filter-builder').hide() - @screen.find('#musician-search-filter-results').show() - true + super(reload) didSearch: (response) => - this.loadSearchFilter(response.filter_json) - @searchResults = response - @screen.find('#musician-search-filter-spinner').hide() - this.renderMusicians() - @screen.find('.paginate-wait').hide() - @isSearching = false + super(response) resetFilter: () => - if this.willSearch(true) - @rest.postMusicianSearchFilter({ filter: 'reset' }).done(this.didSearch) + super() cancelFilter: () => - this.resetFilter() + super() getUserFilterResults: () => - if this.willSearch(true) - @rest.getMusicianSearchFilter('results=true').done(this.didSearch) + super() performSearch: () => - if this.willSearch(true) - $.each gon.musician_search_meta.filter_keys.single, (index, key) => - @searchFilter[key] = this._builderSelectValue(key) - $.each gon.musician_search_meta.filter_keys.multi, (index, key) => - @searchFilter[key] = this._builderSelectMultiValue(key) - @rest.postMusicianSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + super() renderResultsHeader: () => - @screen.find('#musician-search-filter-description').html(@searchResults.description) - if @searchResults.is_blank_filter - @screen.find('#btn-musician-search-reset').hide() - else - @screen.find('#btn-musician-search-reset').show() + super() - renderMusicians: () => + renderResultsPage: () => + super() this.renderResultsHeader() if @pageNumber == 1 musicians = @searchResults.musicians len = musicians.length @@ -394,24 +263,7 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter # TODO: paginate: () => - if @pageNumber < @searchResults.page_count && this.willSearch(false) - @screen.find('.paginate-wait').show() - @pageNumber += 1 - @rest.postMusicianSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) - return true - false + super() registerResultsPagination: () => - _resultsListContainer = @resultsListContainer - _headerHeight = @screen.find('#musician-search-filter-results-header').height() - _paginator = this.paginate - - @screen.find('.content-body-scroller').scroll -> - if _resultsListContainer.is(':visible') - jthis = $(this) - wintop = jthis.scrollTop() - winheight = jthis.innerHeight() - docheight = jthis[0].scrollHeight - _headerHeight - scrollTrigger = 0.98; - if ((wintop / (docheight - winheight)) >= scrollTrigger) - _paginator() + super() From 6a23477c4e27d2d5ba6397d5f15d6bd6b2176d7a Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 17:11:24 +0000 Subject: [PATCH 05/66] VRFS-3036 more refactoring --- ruby/lib/jam_ruby.rb | 1 + ruby/lib/jam_ruby/models/band_search.rb | 10 +- .../javascripts/base_search_filter.js.coffee | 3 +- .../musician_search_filter.js.coffee | 230 +++++++++++++++++- 4 files changed, 235 insertions(+), 9 deletions(-) diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index e3af96834..8779d123c 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -221,6 +221,7 @@ require "jam_ruby/models/online_presence" require "jam_ruby/models/json_store" require "jam_ruby/models/base_search" require "jam_ruby/models/musician_search" +require "jam_ruby/models/band_search" include Jampb diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 927049d5b..ced7ea732 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -1,5 +1,5 @@ module JamRuby - class MusicianSearch < BaseSearch + class BandSearch < BaseSearch attr_accessor :user_counters @@ -16,7 +16,7 @@ module JamRuby SORT_VALS = %W{ distance latency } SORT_ORDERS = { - SORT_VALS[0] => 'Distance to Me' + SORT_VALS[0] => 'Distance to Me', SORT_VALS[1] => 'Latency to Me', } @@ -25,9 +25,9 @@ module JamRuby GenrePlayer::TRADITIONAL_BAND, ] BAND_TYPES = { - INTEREST_VALS[0] => 'Any', - INTEREST_VALS[1] => 'Virtual Band', - INTEREST_VALS[2] => 'Traditional Band', + BAND_TYPE_VALS[0] => 'Any', + BAND_TYPE_VALS[1] => 'Virtual Band', + BAND_TYPE_VALS[2] => 'Traditional Band', } PLAY_COMMIT_VALS = [ANY_VAL_STR, diff --git a/web/app/assets/javascripts/base_search_filter.js.coffee b/web/app/assets/javascripts/base_search_filter.js.coffee index efc876b77..788a61233 100644 --- a/web/app/assets/javascripts/base_search_filter.js.coffee +++ b/web/app/assets/javascripts/base_search_filter.js.coffee @@ -51,10 +51,11 @@ context.JK.BaseSearchFilter = class BaseSearchFilter @resultsListContainer.empty() renderSearchFilter: () => + $.when(@restGet()).done (sFilter) => + this.loadSearchFilter(sFilter) loadSearchFilter: (sFilter) => - _populateSelectWithKeys: (struct, selection, keys, element) => element.children().remove() $.each keys, (idx, value) => diff --git a/web/app/assets/javascripts/musician_search_filter.js.coffee b/web/app/assets/javascripts/musician_search_filter.js.coffee index 3aaa44440..25d08edbc 100644 --- a/web/app/assets/javascripts/musician_search_filter.js.coffee +++ b/web/app/assets/javascripts/musician_search_filter.js.coffee @@ -2,12 +2,237 @@ $ = jQuery context = window context.JK ||= {}; +context.JK.BaseSearchFilter = class BaseSearchFilter + + constructor: () -> + @rest = context.JK.Rest() + @logger = context.JK.logger + @searchFilter = null + @profileUtils = context.JK.ProfileUtils + @helpBubble = context.JK.HelpBubbleHelper + @searchResults = null + @isSearching = false + @pageNumber = 1 + @instrument_logo_map = context.JK.getInstrumentIconMap24() + @searchType = '' + @searchTypeS = '' + @restGet = null + @restPost = null + @searchMeta = null + + init: (app) => + @app = app + @screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide } + @app.bindScreen(@searchTypeS, @screenBindings) + + @screen = $('#'+@searchTypeS+'-screen') + @resultsListContainer = @screen.find('#'+@searchType+'-search-filter-results-list') + @spinner = @screen.find('.paginate-wait') + + this.registerResultsPagination() + + @screen.find('#btn-'+@searchType+'-search-builder').on 'click', => + this.showBuilder() + + @screen.find('#btn-'+@searchType+'-search-reset').on 'click', => + this.resetFilter() + + afterShow: () => + @screen.find('#'+@searchType+'-search-filter-results').show() + @screen.find('#'+@searchType+'-search-filter-builder').hide() + this.getUserFilterResults() + + showBuilder: () => + @screen.find('#'+@searchType+'-search-filter-results').hide() + @screen.find('#'+@searchType+'-search-filter-builder').show() + @resultsListContainer.empty() + + afterHide: () => + @resultsListContainer.empty() + + renderSearchFilter: () => + $.when(@restGet()).done (sFilter) => + this.loadSearchFilter(sFilter) + + loadSearchFilter: (sFilter) => + + _populateSelectWithKeys: (struct, selection, keys, element) => + element.children().remove() + $.each keys, (idx, value) => + label = struct[value] + blankOption = $ '' + blankOption.text label + blankOption.attr 'value', value + blankOption.attr 'selected', '' if value == selection + element.append(blankOption) + context.JK.dropdown(element) + + _populateSelectIdentifier: (identifier) => + elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' + struct = @searchMeta[identifier]['map'] + keys = @searchMeta[identifier]['keys'] + this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) + + _populateSelectWithInt: (sourceStruct, selection, element) => + struct = + '-1': 'Any' + $.extend(struct, sourceStruct) + this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element) + + _populateSortOrder: () => + this._populateSelectIdentifier('sort_order') + + _populateGenres: () => + @screen.find('#search-filter-genres').empty() + @rest.getGenres().done (genres) => + genreTemplate = @screen.find('#template-search-filter-setup-genres').html() + selected = '' + $.each genres, (index, genre) => + if 0 < @searchFilter.data_blob.genres.length + genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) -> + n == genre.id) + else + genreMatch = [] + selected = 'checked' if genreMatch.length > 0 + genreHtml = context.JK.fillTemplate(genreTemplate, + id: genre.id + description: genre.description + checked: selected) + @screen.find('#search-filter-genres').append genreHtml + + _populateInstruments: () => + @screen.find('#search-filter-instruments').empty() + @rest.getInstruments().done (instruments) => + $.each instruments, (index, instrument) => + instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html() + selected = '' + proficiency = '1' + if 0 < @searchFilter.data_blob.instruments.length + instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) -> + yn = inst.instrument_id == instrument.id + proficiency = inst.proficiency_level if yn + yn) + selected = 'checked' if instMatch.length > 0 + instrumentHtml = context.JK.fillTemplate(instrumentTemplate, + id: instrument.id + description: instrument.description + checked: selected) + @screen.find('#search-filter-instruments').append instrumentHtml + profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select' + jprofsel = @screen.find(profsel) + jprofsel.val(proficiency) + context.JK.dropdown(jprofsel) + return true + + _builderSelectValue: (identifier) => + elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' + elem.val() + + _builderSelectMultiValue: (identifier) => + vals = [] + elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked' + if 'instruments' == identifier + elem.each (idx) -> + row = $(this).parent().parent() + instrument = + instrument_id: row.data('instrument-id') + proficiency_level: row.find('select').val() + vals.push instrument + else + elem.each (idx) -> + vals.push $(this).val() + vals + + willSearch: (reload) => + return false if @isSearching + @isSearching = true + if reload + @pageNumber = 1 + @screen.find('#'+@searchType+'-search-filter-spinner').show() + @resultsListContainer.empty() + @screen.find('#'+@searchType+'-search-filter-builder').hide() + @screen.find('#'+@searchType+'-search-filter-results').show() + true + + didSearch: (response) => + this.loadSearchFilter(response.filter_json) + @searchResults = response + @screen.find('#'+@searchType+'-search-filter-spinner').hide() + this.renderResultsPage() + @screen.find('.paginate-wait').hide() + @isSearching = false + + resetFilter: () => + if this.willSearch(true) + @restPost({ filter: 'reset' }).done(this.didSearch) + + cancelFilter: () => + this.resetFilter() + + getUserFilterResults: () => + if this.willSearch(true) + @restGet('results=true').done(this.didSearch) + + performSearch: () => + if this.willSearch(true) + $.each @searchMeta.filter_keys.single, (index, key) => + @searchFilter[key] = this._builderSelectValue(key) + $.each @searchMeta.filter_keys.multi, (index, key) => + @searchFilter[key] = this._builderSelectMultiValue(key) + @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + + renderResultsHeader: () => + @screen.find('#'+@searchType+'-search-filter-description').html(@searchResults.description) + if @searchResults.is_blank_filter + @screen.find('#btn-'+@searchType+'-search-reset').hide() + else + @screen.find('#btn-'+@searchType+'-search-reset').show() + + renderResultsPage: () => + + _formatLocation: (band) -> + if band.city and band.state + band.city + ', ' + band.state + else if band.city + band.city + else if band.regionname + band.regionname + else + 'Location Unavailable' + + friendRequestCallback: (user_id)=> + # TODO: + + paginate: () => + if @pageNumber < @searchResults.page_count && this.willSearch(false) + @screen.find('.paginate-wait').show() + @pageNumber += 1 + @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + return true + false + + registerResultsPagination: () => + _resultsListContainer = @resultsListContainer + _headerHeight = @screen.find('#'+@searchType+'-search-filter-results-header').height() + _paginator = this.paginate + + @screen.find('.content-body-scroller').scroll -> + if _resultsListContainer.is(':visible') + jthis = $(this) + wintop = jthis.scrollTop() + winheight = jthis.innerHeight() + docheight = jthis[0].scrollHeight - _headerHeight + scrollTrigger = 0.98; + if ((wintop / (docheight - winheight)) >= scrollTrigger) + _paginator() + + context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchFilter constructor: () -> super() @searchType = 'musician' - @searchTypeS = @searchTypeS+'s' + @searchTypeS = @searchType+'s' @restGet = @rest.getMusicianSearchFilter @restPost = @rest.postMusicianSearchFilter @searchMeta = gon.musician_search_meta @@ -16,8 +241,7 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF super(app) renderSearchFilter: () => - $.when(this.rest.getMusicianSearchFilter()).done (sFilter) => - this.loadSearchFilter(sFilter) + super() loadSearchFilter: (sFilter) => super(sFilter) From 5a6049c935340e61ed645060dbc9d24927c98d1e Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 18:08:36 +0000 Subject: [PATCH 06/66] VRFS-3036 more refactoring --- ruby/lib/jam_ruby/models/base_search.rb | 10 +- .../javascripts/base_search_filter.js.coffee | 227 ------------------ 2 files changed, 5 insertions(+), 232 deletions(-) delete mode 100644 web/app/assets/javascripts/base_search_filter.js.coffee diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 950dab57b..bcd645c22 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -124,8 +124,8 @@ module JamRuby end def _sort_order(rel) - val = json[KEY_SORT_ORDER] - if SORT_VALS[1] == val + val = json[self.class::KEY_SORT_ORDER] + if self.class::SORT_VALS[1] == val locidispid = self.user.last_jam_locidispid || 0 my_locid = locidispid / 1000000 rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") @@ -160,7 +160,7 @@ module JamRuby rel = do_search(filter) @page_number = [page.to_i, 1].max - rel = rel.paginate(:page => @page_number, :per_page => PER_PAGE) + rel = rel.paginate(:page => @page_number, :per_page => self.class::PER_PAGE) rel = self.search_includes(rel) @page_count = rel.total_pages @@ -169,7 +169,7 @@ module JamRuby end def reset_filter - self.data_blob = JSON_SCHEMA + self.data_blob = self.class::JSON_SCHEMA self.save end @@ -183,7 +183,7 @@ module JamRuby end def is_blank? - self.data_blob == JSON_SCHEMA + self.data_blob == self.class::JSON_SCHEMA end def description diff --git a/web/app/assets/javascripts/base_search_filter.js.coffee b/web/app/assets/javascripts/base_search_filter.js.coffee deleted file mode 100644 index 788a61233..000000000 --- a/web/app/assets/javascripts/base_search_filter.js.coffee +++ /dev/null @@ -1,227 +0,0 @@ -$ = jQuery -context = window -context.JK ||= {}; - -context.JK.BaseSearchFilter = class BaseSearchFilter - - constructor: () -> - @rest = context.JK.Rest() - @logger = context.JK.logger - @searchFilter = null - @profileUtils = context.JK.ProfileUtils - @helpBubble = context.JK.HelpBubbleHelper - @searchResults = null - @isSearching = false - @pageNumber = 1 - @instrument_logo_map = context.JK.getInstrumentIconMap24() - @searchType = '' - @searchTypeS = '' - @restGet = null - @restPost = null - @searchMeta = null - - init: (app) => - @app = app - @screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide } - @app.bindScreen(@searchTypeS, @screenBindings) - - @screen = $('#'+@searchTypeS+'-screen') - @resultsListContainer = @screen.find('#'+@searchType+'-search-filter-results-list') - @spinner = @screen.find('.paginate-wait') - - this.registerResultsPagination() - - @screen.find('#btn-'+@searchType+'-search-builder').on 'click', => - this.showBuilder() - - @screen.find('#btn-'+@searchType+'-search-reset').on 'click', => - this.resetFilter() - - afterShow: () => - @screen.find('#'+@searchType+'-search-filter-results').show() - @screen.find('#'+@searchType+'-search-filter-builder').hide() - this.getUserFilterResults() - - showBuilder: () => - @screen.find('#'+@searchType+'-search-filter-results').hide() - @screen.find('#'+@searchType+'-search-filter-builder').show() - @resultsListContainer.empty() - - afterHide: () => - @resultsListContainer.empty() - - renderSearchFilter: () => - $.when(@restGet()).done (sFilter) => - this.loadSearchFilter(sFilter) - - loadSearchFilter: (sFilter) => - - _populateSelectWithKeys: (struct, selection, keys, element) => - element.children().remove() - $.each keys, (idx, value) => - label = struct[value] - blankOption = $ '' - blankOption.text label - blankOption.attr 'value', value - blankOption.attr 'selected', '' if value == selection - element.append(blankOption) - context.JK.dropdown(element) - - _populateSelectIdentifier: (identifier) => - elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' - struct = gon.band_search_meta[identifier]['map'] - keys = gon.band_search_meta[identifier]['keys'] - this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) - - _populateSelectWithInt: (sourceStruct, selection, element) => - struct = - '-1': 'Any' - $.extend(struct, sourceStruct) - this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element) - - _populateSortOrder: () => - this._populateSelectIdentifier('sort_order') - - _populateGenres: () => - @screen.find('#search-filter-genres').empty() - @rest.getGenres().done (genres) => - genreTemplate = @screen.find('#template-search-filter-setup-genres').html() - selected = '' - $.each genres, (index, genre) => - if 0 < @searchFilter.data_blob.genres.length - genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) -> - n == genre.id) - else - genreMatch = [] - selected = 'checked' if genreMatch.length > 0 - genreHtml = context.JK.fillTemplate(genreTemplate, - id: genre.id - description: genre.description - checked: selected) - @screen.find('#search-filter-genres').append genreHtml - - _populateInstruments: () => - @screen.find('#search-filter-instruments').empty() - @rest.getInstruments().done (instruments) => - $.each instruments, (index, instrument) => - instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html() - selected = '' - proficiency = '1' - if 0 < @searchFilter.data_blob.instruments.length - instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) -> - yn = inst.instrument_id == instrument.id - proficiency = inst.proficiency_level if yn - yn) - selected = 'checked' if instMatch.length > 0 - instrumentHtml = context.JK.fillTemplate(instrumentTemplate, - id: instrument.id - description: instrument.description - checked: selected) - @screen.find('#search-filter-instruments').append instrumentHtml - profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select' - jprofsel = @screen.find(profsel) - jprofsel.val(proficiency) - context.JK.dropdown(jprofsel) - return true - - _builderSelectValue: (identifier) => - elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' - elem.val() - - _builderSelectMultiValue: (identifier) => - vals = [] - elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked' - if 'instruments' == identifier - elem.each (idx) -> - row = $(this).parent().parent() - instrument = - instrument_id: row.data('instrument-id') - proficiency_level: row.find('select').val() - vals.push instrument - else - elem.each (idx) -> - vals.push $(this).val() - vals - - willSearch: (reload) => - return false if @isSearching - @isSearching = true - if reload - @pageNumber = 1 - @screen.find('#'+@searchType+'-search-filter-spinner').show() - @resultsListContainer.empty() - @screen.find('#'+@searchType+'-search-filter-builder').hide() - @screen.find('#'+@searchType+'-search-filter-results').show() - true - - didSearch: (response) => - this.loadSearchFilter(response.filter_json) - @searchResults = response - @screen.find('#'+@searchType+'-search-filter-spinner').hide() - this.renderResultsPage() - @screen.find('.paginate-wait').hide() - @isSearching = false - - resetFilter: () => - if this.willSearch(true) - @restPost({ filter: 'reset' }).done(this.didSearch) - - cancelFilter: () => - this.resetFilter() - - getUserFilterResults: () => - if this.willSearch(true) - @restGet('results=true').done(this.didSearch) - - performSearch: () => - if this.willSearch(true) - $.each @searchMeta.filter_keys.single, (index, key) => - @searchFilter[key] = this._builderSelectValue(key) - $.each @searchMeta.filter_keys.multi, (index, key) => - @searchFilter[key] = this._builderSelectMultiValue(key) - @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) - - renderResultsHeader: () => - @screen.find('#'+@searchType+'-search-filter-description').html(@searchResults.description) - if @searchResults.is_blank_filter - @screen.find('#btn-'+@searchType+'-search-reset').hide() - else - @screen.find('#btn-'+@searchType+'-search-reset').show() - - renderResultsPage: () => - - _formatLocation: (band) -> - if band.city and band.state - band.city + ', ' + band.state - else if band.city - band.city - else if band.regionname - band.regionname - else - 'Location Unavailable' - - friendRequestCallback: (user_id)=> - # TODO: - - paginate: () => - if @pageNumber < @searchResults.page_count && this.willSearch(false) - @screen.find('.paginate-wait').show() - @pageNumber += 1 - @rest.postBandSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) - return true - false - - registerResultsPagination: () => - _resultsListContainer = @resultsListContainer - _headerHeight = @screen.find('#'+@searchType+'-search-filter-results-header').height() - _paginator = this.paginate - - @screen.find('.content-body-scroller').scroll -> - if _resultsListContainer.is(':visible') - jthis = $(this) - wintop = jthis.scrollTop() - winheight = jthis.innerHeight() - docheight = jthis[0].scrollHeight - _headerHeight - scrollTrigger = 0.98; - if ((wintop / (docheight - winheight)) >= scrollTrigger) - _paginator() From 7e2e5241bf4fa18fcec5316a31d2075aff08b072 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 12:55:13 +0000 Subject: [PATCH 07/66] VRFS-3036 refactoring musician_search into base_search for band_search --- ruby/lib/jam_ruby.rb | 1 + ruby/lib/jam_ruby/models/base_search.rb | 183 ++++++++++++++++++++ ruby/lib/jam_ruby/models/musician_search.rb | 136 ++------------- 3 files changed, 195 insertions(+), 125 deletions(-) create mode 100644 ruby/lib/jam_ruby/models/base_search.rb diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index 9cc932084..de1b006a8 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -220,6 +220,7 @@ require "jam_ruby/jmep_manager" require "jam_ruby/models/performance_sample" require "jam_ruby/models/online_presence" require "jam_ruby/models/json_store" +require "jam_ruby/models/base_search" require "jam_ruby/models/musician_search" include Jampb diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb new file mode 100644 index 000000000..84b5c9833 --- /dev/null +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -0,0 +1,183 @@ +module JamRuby + class BaseSearch < JsonStore + + attr_accessor :page_count, :results, :page_number + + ANY_VAL_STR = 'any' + ANY_VAL_INT = -1 + + PER_PAGE = 10 + PG_SMALLINT_MAX = 32767 + + KEY_SKILL = 'skill_level' + KEY_GENRES = 'genres' + KEY_INSTRUMENTS = 'instruments' + KEY_GIGS = 'concert_gigs' + KEY_SORT_ORDER = 'sort_order' + + SORT_VALS = %W{ latency distance } + SORT_ORDERS = { + SORT_VALS[0] => 'Latency to Me', + SORT_VALS[1] => 'Distance to Me' + } + + SKILL_VALS = [ANY_VAL_INT, 1, 2] + SKILL_LEVELS = { + SKILL_VALS[0] => 'Any', + SKILL_VALS[1] => 'Amateur', + SKILL_VALS[2] => 'Pro', + } + + GIG_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4] + GIG_LABELS = { + GIG_COUNTS[0] => 'Any', + GIG_COUNTS[1] => 'under 10', + GIG_COUNTS[2] => '10 to 50', + GIG_COUNTS[3] => '50 to 100', + GIG_COUNTS[4] => 'over 100' + } + + INSTRUMENT_PROFICIENCY = { + 1 => 'Beginner', + 2 => 'Intermediate', + 3 => 'Expert', + } + + JSON_SCHEMA = { + KEY_SORT_ORDER => SORT_VALS[0], + KEY_INSTRUMENTS => [], + KEY_GENRES => [], + KEY_SKILL => SKILL_VALS[0].to_s, + KEY_GIGS => GIG_COUNTS[0].to_s, + } + JSON_SCHEMA_KEYS = JSON_SCHEMA.keys + MULTI_VALUE_KEYS = JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact + SINGLE_VALUE_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS + + SEARCH_FILTER_META = { + per_page: PER_PAGE, + filter_keys: { + keys: JSON_SCHEMA_KEYS, + multi: MULTI_VALUE_KEYS, + single: SINGLE_VALUE_KEYS, + }, + sort_order: { keys: SORT_VALS, map: SORT_ORDERS }, + } + + def self.user_search_filter(user) + unless ss = user.send(self.name.demodulize.tableize.singularize) + ss = self.create_search(user) + end + ss + end + + def self.search_filter_json(user) + self.user_search_filter(user).json + end + + def self.create_search(user) + ms = self.new + ms.user = user + ms.data_blob = self::JSON_SCHEMA + ms.save! + ms + end + + def self.search_target_class + end + + def _genres(rel) + gids = json[KEY_GENRES] + unless gids.blank? + gidsql = gids.join("','") + gpsql = "SELECT player_id FROM genre_players WHERE (player_type = '#{self.class.search_target_class.name}' AND genre_id IN ('#{gidsql}'))" + rel = rel.where("#{self.class.search_target_class.table_name}.id IN (#{gpsql})") + end + rel + end + + def _instruments(rel) + rel + end + + def _gigs(rel) + gg = json[KEY_GIGS].to_i + rel = rel.where('concert_count = ?',gg) if 0 <= gg + rel + end + + def _skills(rel) + if 0 < (val = json[KEY_SKILL].to_i) + rel = rel.where(['skill_level = ?', val]) + end + rel + end + + def _sort_order(rel) + val = json[KEY_SORT_ORDER] + if SORT_VALS[1] == val + locidispid = self.user.last_jam_locidispid || 0 + my_locid = locidispid / 1000000 + rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") + rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid") + rel = rel.group("users.id, my_geo.geog, other_geo.geog") + rel = rel.order('st_distance(my_geo.geog, other_geo.geog)') + else + rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{self.user.id}'") + rel = rel.order('current_scores.full_score ASC') + end + rel + end + + def do_search(params={}) + end + + def process_results_page(objs) + end + + def search_includes(rel) + rel + end + + def search_results_page(filter=nil, page=1) + if filter + self.data_blob = filter + self.save + else + filter = self.data_blob + end + + rel = do_search(filter) + + @page_number = [page.to_i, 1].max + rel = rel.paginate(:page => @page_number, :per_page => PER_PAGE) + + rel = self.search_includes(rel) + @page_count = rel.total_pages + + process_results_page(rel.all) + end + + def reset_filter + self.data_blob = JSON_SCHEMA + self.save + end + + def reset_search_results + reset_filter + search_results_page + end + + def search_type + self.class.to_s + end + + def is_blank? + self.data_blob == JSON_SCHEMA + end + + def description + end + + end +end diff --git a/ruby/lib/jam_ruby/models/musician_search.rb b/ruby/lib/jam_ruby/models/musician_search.rb index 22d3d6221..e8284ebfc 100644 --- a/ruby/lib/jam_ruby/models/musician_search.rb +++ b/ruby/lib/jam_ruby/models/musician_search.rb @@ -1,22 +1,11 @@ module JamRuby - class MusicianSearch < JsonStore + class MusicianSearch < BaseSearch - attr_accessor :page_count, :results, :user_counters, :page_number + attr_accessor :user_counters - ANY_VAL_STR = 'any' - ANY_VAL_INT = -1 - - PER_PAGE = 10 - PG_SMALLINT_MAX = 32767 - - KEY_GIGS = 'concert_gigs' KEY_STUDIOS = 'studio_sessions' KEY_AGES = 'ages' - KEY_SKILL = 'skill_level' - KEY_GENRES = 'genres' - KEY_INSTRUMENTS = 'instruments' KEY_INTERESTS = 'interests' - KEY_SORT_ORDER = 'sort_order' SORT_VALS = %W{ latency distance } SORT_ORDERS = { @@ -24,22 +13,6 @@ module JamRuby SORT_VALS[1] => 'Distance to Me' } - SKILL_VALS = [ANY_VAL_INT, 1, 2] - SKILL_LEVELS = { - SKILL_VALS[0] => 'Any', - SKILL_VALS[1] => 'Amateur', - SKILL_VALS[2] => 'Pro', - } - - GIG_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4] - GIG_LABELS = { - GIG_COUNTS[0] => 'Any', - GIG_COUNTS[1] => 'under 10', - GIG_COUNTS[2] => '10 to 50', - GIG_COUNTS[3] => '50 to 100', - GIG_COUNTS[4] => 'over 100' - } - STUDIO_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4] STUDIOS_LABELS = { STUDIO_COUNTS[0] => 'Any', @@ -74,65 +47,19 @@ module JamRuby INTEREST_VALS[5] => 'Co-Writing' } - INSTRUMENT_PROFICIENCY = { - 1 => 'Beginner', - 2 => 'Intermediate', - 3 => 'Expert', - } - - JSON_SCHEMA = { - KEY_SORT_ORDER => SORT_VALS[0], - KEY_INSTRUMENTS => [], + JSON_SCHEMA = BaseSearch::JSON_SCHEMA.merge({ KEY_INTERESTS => INTEREST_VALS[0], - KEY_GENRES => [], - KEY_GIGS => GIG_COUNTS[0].to_s, KEY_STUDIOS => STUDIO_COUNTS[0].to_s, - KEY_SKILL => SKILL_VALS[0].to_s, KEY_AGES => [] - } - JSON_SCHEMA_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS = JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact - SINGLE_VALUE_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS + }) - SEARCH_FILTER_META = { - per_page: PER_PAGE, - filter_keys: { - keys: JSON_SCHEMA_KEYS, - multi: MULTI_VALUE_KEYS, - single: SINGLE_VALUE_KEYS, - }, - sort_order: { keys: SORT_VALS, map: SORT_ORDERS }, + SEARCH_FILTER_META = BaseSearch::SEARCH_FILTER_META.merge({ interests: { keys: INTEREST_VALS, map: INTERESTS }, ages: { keys: AGE_COUNTS, map: AGES } - } + }) - def self.user_search_filter(user) - unless ms = user.musician_search - ms = self.create_search(user) - end - ms - end - - def self.search_filter_json(user) - self.user_search_filter(user).json - end - - def self.create_search(user) - ms = self.new - ms.user = user - ms.data_blob = JSON_SCHEMA - ms.save! - ms - end - - def _genres(rel) - gids = json[KEY_GENRES] - unless gids.blank? - gidsql = gids.join("','") - gpsql = "SELECT player_id FROM genre_players WHERE (player_type = 'JamRuby::User' AND genre_id IN ('#{gidsql}'))" - rel = rel.where("users.id IN (#{gpsql})") - end - rel + def self.search_target_class + User end def _instruments(rel) @@ -204,22 +131,6 @@ module JamRuby rel end - def _sort_order(rel) - val = json[KEY_SORT_ORDER] - if SORT_VALS[1] == val - locidispid = self.user.last_jam_locidispid || 0 - my_locid = locidispid / 1000000 - rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") - rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid") - rel = rel.group("users.id, my_geo.geog, other_geo.geog") - rel = rel.order('st_distance(my_geo.geog, other_geo.geog)') - else - rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{self.user.id}'") - rel = rel.order('current_scores.full_score ASC') - end - rel - end - def do_search(params={}) rel = User.musicians.where('users.id <> ?', self.user.id) rel = self._genres(rel) @@ -233,33 +144,8 @@ module JamRuby rel end - def search_results_page(filter=nil, page=1) - if filter - self.data_blob = filter - self.save - else - filter = self.data_blob - end - - rel = do_search(filter) - - @page_number = [page.to_i, 1].max - rel = rel.paginate(:page => @page_number, :per_page => PER_PAGE) - - rel = rel.includes([:instruments, :followings, :friends]) - @page_count = rel.total_pages - - musician_results(rel.all) - end - - def reset_filter - self.data_blob = JSON_SCHEMA - self.save - end - - def reset_search_results - reset_filter - search_results_page + def search_includes(rel) + rel.includes([:instruments, :followings, :friends]) end RESULT_FOLLOW = :follows @@ -271,7 +157,7 @@ module JamRuby COUNT_SESSION = :count_session COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] - def musician_results(_results) + def process_results_page(_results) @results = _results @user_counters = {} and return self unless user From 674d1de2d36a74ded5da89ea6085594aceeb454a Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 13:21:53 +0000 Subject: [PATCH 08/66] VRFS-3036 refactoring band search --- ruby/lib/jam_ruby/models/base_search.rb | 9 +++++++++ ruby/lib/jam_ruby/models/musician_search.rb | 9 --------- web/app/helpers/client_helper.rb | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 84b5c9833..d6244b355 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -64,6 +64,15 @@ module JamRuby sort_order: { keys: SORT_VALS, map: SORT_ORDERS }, } + RESULT_FOLLOW = :follows + RESULT_FRIEND = :friends + + COUNT_FRIEND = :count_friend + COUNT_FOLLOW = :count_follow + COUNT_RECORD = :count_record + COUNT_SESSION = :count_session + COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] + def self.user_search_filter(user) unless ss = user.send(self.name.demodulize.tableize.singularize) ss = self.create_search(user) diff --git a/ruby/lib/jam_ruby/models/musician_search.rb b/ruby/lib/jam_ruby/models/musician_search.rb index e8284ebfc..cb6f789a9 100644 --- a/ruby/lib/jam_ruby/models/musician_search.rb +++ b/ruby/lib/jam_ruby/models/musician_search.rb @@ -148,15 +148,6 @@ module JamRuby rel.includes([:instruments, :followings, :friends]) end - RESULT_FOLLOW = :follows - RESULT_FRIEND = :friends - - COUNT_FRIEND = :count_friend - COUNT_FOLLOW = :count_follow - COUNT_RECORD = :count_record - COUNT_SESSION = :count_session - COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] - def process_results_page(_results) @results = _results @user_counters = {} and return self unless user diff --git a/web/app/helpers/client_helper.rb b/web/app/helpers/client_helper.rb index c4977e130..c3942e798 100644 --- a/web/app/helpers/client_helper.rb +++ b/web/app/helpers/client_helper.rb @@ -68,6 +68,7 @@ module ClientHelper gon.ftue_network_test_max_clients = Rails.application.config.ftue_network_test_max_clients gon.ftue_maximum_gear_latency = Rails.application.config.ftue_maximum_gear_latency gon.musician_search_meta = MusicianSearch::SEARCH_FILTER_META + gon.band_search_meta = BandSearch::SEARCH_FILTER_META # is this the native client or browser? @nativeClient = is_native_client? From 0b64986766bbd1240a8f75ec6ba5e9bcdd8769c8 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 14:41:27 +0000 Subject: [PATCH 09/66] VRFS-3036 refactoring musician_search into base_search for band_search --- ruby/lib/jam_ruby/models/band_search.rb | 172 ++++++++++++++++++++++++ ruby/lib/jam_ruby/models/base_search.rb | 23 ++-- 2 files changed, 184 insertions(+), 11 deletions(-) create mode 100644 ruby/lib/jam_ruby/models/band_search.rb diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb new file mode 100644 index 000000000..927049d5b --- /dev/null +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -0,0 +1,172 @@ +module JamRuby + class MusicianSearch < BaseSearch + + attr_accessor :user_counters + + KEY_BAND_SEARCH_TYPE = 'band_search_type' + KEY_BAND_TYPE = 'band_type' + KEY_PLAY_COMMIT = 'play_commit' + KEY_TOUR_OPTION = 'tour_option' + + BAND_SEARCH_TYPE_VALS = %W{ to_join to_hire } + BAND_SEARCH_TYPES = { + BAND_SEARCH_TYPE_VALS[0] => 'search bands', + BAND_SEARCH_TYPE_VALS[1] => 'search bands to hire', + } + + SORT_VALS = %W{ distance latency } + SORT_ORDERS = { + SORT_VALS[0] => 'Distance to Me' + SORT_VALS[1] => 'Latency to Me', + } + + BAND_TYPE_VALS = [ANY_VAL_STR, + GenrePlayer::VIRTUAL_BAND, + GenrePlayer::TRADITIONAL_BAND, + ] + BAND_TYPES = { + INTEREST_VALS[0] => 'Any', + INTEREST_VALS[1] => 'Virtual Band', + INTEREST_VALS[2] => 'Traditional Band', + } + + PLAY_COMMIT_VALS = [ANY_VAL_STR, + '0', + '1', + '2', + ] + PLAY_COMMITS = { + PLAY_COMMIT_VALS[0] => 'Any', + PLAY_COMMIT_VALS[1] => 'Infrequent', + PLAY_COMMIT_VALS[2] => 'Once a week', + PLAY_COMMIT_VALS[3] => 'More than once a week', + } + + TOUR_OPTION_VALS = [ANY_VAL_STR, + 'yes', + 'no', + ] + TOUR_OPTIONS = { + TOUR_OPTION_VALS[0] => 'Any', + TOUR_OPTION_VALS[1] => 'Yes', + TOUR_OPTION_VALS[1] => 'No', + } + + JSON_SCHEMA = BaseSearch::JSON_SCHEMA.merge({ + KEY_BAND_SEARCH_TYPE => BAND_SEARCH_TYPES[0], + KEY_BAND_TYPE => BAND_TYPE_VALS[0], + KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0], + KEY_TOUR_OPTION => TOUR_OPTION_VALS[0], + }) + + SEARCH_FILTER_META = BaseSearch::SEARCH_FILTER_META.merge({ + sort_order: { keys: self::SORT_VALS, map: self::SORT_ORDERS }, + band_type: { keys: BAND_TYPE_VALS, map: BAND_TYPES }, + play_commit: { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS }, + tour_option: { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS } + }) + + def self.search_target_class + User + end + + def do_search(params={}) + rel = User.musicians.where('users.id <> ?', self.user.id) + rel = self._sort_order(rel) + rel + end + + def search_includes(rel) + rel.includes([:instruments, :followings, :friends]) + end + + def process_results_page(_results) + @results = _results + if user + @user_counters = @results.inject({}) { |hh,val| hh[val.id] = []; hh } + mids = "'#{@results.map(&:id).join("','")}'" + + # this gets counts for each search result + @results.each do |bb| + counters = { } + counters[COUNT_FOLLOW] = Follow.where(:followable_id => bb.id).count + counters[COUNT_RECORD] = Recording.where(:band_id => bb.id).count + counters[COUNT_SESSION] = MusicSession.where(:band_id => bb.id).count + @user_counters[bb.id] << counters + end + + # this section determines follow/like/friend status for each search result + # so that action links can be activated or not + + rel = Band.select("bands.id AS bid") + rel = rel.joins("LEFT JOIN follows ON follows.user_id = '#{user.id}'") + rel = rel.where(["bands.id IN (#{mids}) AND follows.followable_id = bands.id"]) + rel.all.each { |val| @user_counters[val.bid] << RESULT_FOLLOW } + + else + @user_counters = {} + end + self + end + + private + + def _count(musician, key) + if mm = @user_counters[musician.id] + return mm.detect { |ii| ii.is_a?(Hash) }[key] + end if @user_counters + 0 + end + + public + + def follow_count(musician) + _count(musician, COUNT_FOLLOW) + end + + def friend_count(musician) + _count(musician, COUNT_FRIEND) + end + + def record_count(musician) + _count(musician, COUNT_RECORD) + end + + def session_count(musician) + _count(musician, COUNT_SESSION) + end + + def is_friend?(musician) + if mm = @user_counters[musician.id] + return mm.include?(RESULT_FRIEND) + end if @user_counters + false + end + + def is_follower?(musician) + if mm = @user_counters[musician.id] + return mm.include?(RESULT_FOLLOW) + end if @user_counters + false + end + + def search_type + self.class.to_s + end + + def is_blank? + self.data_blob == JSON_SCHEMA + end + + def description + if self.is_blank? + return 'Click search button to look for musicians with similar interests, skill levels, etc.' + end + jj = self.json + str = 'Current Search: ' + str += "Sort = #{SORT_ORDERS[json_value(BandSearch::KEY_SORT_ORDER)]}" + str + end + + end +end diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index d6244b355..950dab57b 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -44,24 +44,25 @@ module JamRuby } JSON_SCHEMA = { - KEY_SORT_ORDER => SORT_VALS[0], + KEY_SORT_ORDER => self::SORT_VALS[0], KEY_INSTRUMENTS => [], KEY_GENRES => [], - KEY_SKILL => SKILL_VALS[0].to_s, - KEY_GIGS => GIG_COUNTS[0].to_s, + KEY_SKILL => self::SKILL_VALS[0].to_s, + KEY_GIGS => self::GIG_COUNTS[0].to_s, } - JSON_SCHEMA_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS = JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact - SINGLE_VALUE_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS + + JSON_SCHEMA_KEYS = self::JSON_SCHEMA.keys + MULTI_VALUE_KEYS = self::JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact + SINGLE_VALUE_KEYS = self::JSON_SCHEMA.keys - self::MULTI_VALUE_KEYS SEARCH_FILTER_META = { - per_page: PER_PAGE, + per_page: self::PER_PAGE, filter_keys: { - keys: JSON_SCHEMA_KEYS, - multi: MULTI_VALUE_KEYS, - single: SINGLE_VALUE_KEYS, + keys: self::JSON_SCHEMA_KEYS, + multi: self::MULTI_VALUE_KEYS, + single: self::SINGLE_VALUE_KEYS, }, - sort_order: { keys: SORT_VALS, map: SORT_ORDERS }, + sort_order: { keys: self::SORT_VALS, map: self::SORT_ORDERS }, } RESULT_FOLLOW = :follows From 33cdb33f372b0054d54d76758a6e8509903a25ed Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 15:21:39 +0000 Subject: [PATCH 10/66] VRFS-3036 refactoring musician_search into base_search --- .../javascripts/base_search_filter.js.coffee | 226 ++++++++++++++++++ .../musician_search_filter.js.coffee | 198 ++------------- 2 files changed, 251 insertions(+), 173 deletions(-) create mode 100644 web/app/assets/javascripts/base_search_filter.js.coffee diff --git a/web/app/assets/javascripts/base_search_filter.js.coffee b/web/app/assets/javascripts/base_search_filter.js.coffee new file mode 100644 index 000000000..efc876b77 --- /dev/null +++ b/web/app/assets/javascripts/base_search_filter.js.coffee @@ -0,0 +1,226 @@ +$ = jQuery +context = window +context.JK ||= {}; + +context.JK.BaseSearchFilter = class BaseSearchFilter + + constructor: () -> + @rest = context.JK.Rest() + @logger = context.JK.logger + @searchFilter = null + @profileUtils = context.JK.ProfileUtils + @helpBubble = context.JK.HelpBubbleHelper + @searchResults = null + @isSearching = false + @pageNumber = 1 + @instrument_logo_map = context.JK.getInstrumentIconMap24() + @searchType = '' + @searchTypeS = '' + @restGet = null + @restPost = null + @searchMeta = null + + init: (app) => + @app = app + @screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide } + @app.bindScreen(@searchTypeS, @screenBindings) + + @screen = $('#'+@searchTypeS+'-screen') + @resultsListContainer = @screen.find('#'+@searchType+'-search-filter-results-list') + @spinner = @screen.find('.paginate-wait') + + this.registerResultsPagination() + + @screen.find('#btn-'+@searchType+'-search-builder').on 'click', => + this.showBuilder() + + @screen.find('#btn-'+@searchType+'-search-reset').on 'click', => + this.resetFilter() + + afterShow: () => + @screen.find('#'+@searchType+'-search-filter-results').show() + @screen.find('#'+@searchType+'-search-filter-builder').hide() + this.getUserFilterResults() + + showBuilder: () => + @screen.find('#'+@searchType+'-search-filter-results').hide() + @screen.find('#'+@searchType+'-search-filter-builder').show() + @resultsListContainer.empty() + + afterHide: () => + @resultsListContainer.empty() + + renderSearchFilter: () => + + loadSearchFilter: (sFilter) => + + + _populateSelectWithKeys: (struct, selection, keys, element) => + element.children().remove() + $.each keys, (idx, value) => + label = struct[value] + blankOption = $ '' + blankOption.text label + blankOption.attr 'value', value + blankOption.attr 'selected', '' if value == selection + element.append(blankOption) + context.JK.dropdown(element) + + _populateSelectIdentifier: (identifier) => + elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' + struct = gon.band_search_meta[identifier]['map'] + keys = gon.band_search_meta[identifier]['keys'] + this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) + + _populateSelectWithInt: (sourceStruct, selection, element) => + struct = + '-1': 'Any' + $.extend(struct, sourceStruct) + this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element) + + _populateSortOrder: () => + this._populateSelectIdentifier('sort_order') + + _populateGenres: () => + @screen.find('#search-filter-genres').empty() + @rest.getGenres().done (genres) => + genreTemplate = @screen.find('#template-search-filter-setup-genres').html() + selected = '' + $.each genres, (index, genre) => + if 0 < @searchFilter.data_blob.genres.length + genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) -> + n == genre.id) + else + genreMatch = [] + selected = 'checked' if genreMatch.length > 0 + genreHtml = context.JK.fillTemplate(genreTemplate, + id: genre.id + description: genre.description + checked: selected) + @screen.find('#search-filter-genres').append genreHtml + + _populateInstruments: () => + @screen.find('#search-filter-instruments').empty() + @rest.getInstruments().done (instruments) => + $.each instruments, (index, instrument) => + instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html() + selected = '' + proficiency = '1' + if 0 < @searchFilter.data_blob.instruments.length + instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) -> + yn = inst.instrument_id == instrument.id + proficiency = inst.proficiency_level if yn + yn) + selected = 'checked' if instMatch.length > 0 + instrumentHtml = context.JK.fillTemplate(instrumentTemplate, + id: instrument.id + description: instrument.description + checked: selected) + @screen.find('#search-filter-instruments').append instrumentHtml + profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select' + jprofsel = @screen.find(profsel) + jprofsel.val(proficiency) + context.JK.dropdown(jprofsel) + return true + + _builderSelectValue: (identifier) => + elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' + elem.val() + + _builderSelectMultiValue: (identifier) => + vals = [] + elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked' + if 'instruments' == identifier + elem.each (idx) -> + row = $(this).parent().parent() + instrument = + instrument_id: row.data('instrument-id') + proficiency_level: row.find('select').val() + vals.push instrument + else + elem.each (idx) -> + vals.push $(this).val() + vals + + willSearch: (reload) => + return false if @isSearching + @isSearching = true + if reload + @pageNumber = 1 + @screen.find('#'+@searchType+'-search-filter-spinner').show() + @resultsListContainer.empty() + @screen.find('#'+@searchType+'-search-filter-builder').hide() + @screen.find('#'+@searchType+'-search-filter-results').show() + true + + didSearch: (response) => + this.loadSearchFilter(response.filter_json) + @searchResults = response + @screen.find('#'+@searchType+'-search-filter-spinner').hide() + this.renderResultsPage() + @screen.find('.paginate-wait').hide() + @isSearching = false + + resetFilter: () => + if this.willSearch(true) + @restPost({ filter: 'reset' }).done(this.didSearch) + + cancelFilter: () => + this.resetFilter() + + getUserFilterResults: () => + if this.willSearch(true) + @restGet('results=true').done(this.didSearch) + + performSearch: () => + if this.willSearch(true) + $.each @searchMeta.filter_keys.single, (index, key) => + @searchFilter[key] = this._builderSelectValue(key) + $.each @searchMeta.filter_keys.multi, (index, key) => + @searchFilter[key] = this._builderSelectMultiValue(key) + @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + + renderResultsHeader: () => + @screen.find('#'+@searchType+'-search-filter-description').html(@searchResults.description) + if @searchResults.is_blank_filter + @screen.find('#btn-'+@searchType+'-search-reset').hide() + else + @screen.find('#btn-'+@searchType+'-search-reset').show() + + renderResultsPage: () => + + _formatLocation: (band) -> + if band.city and band.state + band.city + ', ' + band.state + else if band.city + band.city + else if band.regionname + band.regionname + else + 'Location Unavailable' + + friendRequestCallback: (user_id)=> + # TODO: + + paginate: () => + if @pageNumber < @searchResults.page_count && this.willSearch(false) + @screen.find('.paginate-wait').show() + @pageNumber += 1 + @rest.postBandSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + return true + false + + registerResultsPagination: () => + _resultsListContainer = @resultsListContainer + _headerHeight = @screen.find('#'+@searchType+'-search-filter-results-header').height() + _paginator = this.paginate + + @screen.find('.content-body-scroller').scroll -> + if _resultsListContainer.is(':visible') + jthis = $(this) + wintop = jthis.scrollTop() + winheight = jthis.innerHeight() + docheight = jthis[0].scrollHeight - _headerHeight + scrollTrigger = 0.98; + if ((wintop / (docheight - winheight)) >= scrollTrigger) + _paginator() diff --git a/web/app/assets/javascripts/musician_search_filter.js.coffee b/web/app/assets/javascripts/musician_search_filter.js.coffee index 4187d6acd..3aaa44440 100644 --- a/web/app/assets/javascripts/musician_search_filter.js.coffee +++ b/web/app/assets/javascripts/musician_search_filter.js.coffee @@ -2,54 +2,26 @@ $ = jQuery context = window context.JK ||= {}; -context.JK.MusicianSearchFilter = class MusicianSearchFilter +context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchFilter constructor: () -> - @rest = context.JK.Rest() - @logger = context.JK.logger - @searchFilter = null - @profileUtils = context.JK.ProfileUtils - @helpBubble = context.JK.HelpBubbleHelper - @searchResults = null - @isSearching = false - @pageNumber = 1 - @instrument_logo_map = context.JK.getInstrumentIconMap24() + super() + @searchType = 'musician' + @searchTypeS = @searchTypeS+'s' + @restGet = @rest.getMusicianSearchFilter + @restPost = @rest.postMusicianSearchFilter + @searchMeta = gon.musician_search_meta init: (app) => - @app = app - @screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide } - @app.bindScreen('musicians', @screenBindings) - - @screen = $('#musicians-screen') - @resultsListContainer = @screen.find('#musician-search-filter-results-list') - @spinner = @screen.find('.paginate-wait') - - this.registerResultsPagination() - - @screen.find('#btn-musician-search-builder').on 'click', => - this.showBuilder() - - @screen.find('#btn-musician-search-reset').on 'click', => - this.resetFilter() - - afterShow: () => - @screen.find('#musician-search-filter-results').show() - @screen.find('#musician-search-filter-builder').hide() - this.getUserFilterResults() - - showBuilder: () => - @screen.find('#musician-search-filter-results').hide() - @screen.find('#musician-search-filter-builder').show() - @resultsListContainer.empty() - - afterHide: () => - @resultsListContainer.empty() + super(app) renderSearchFilter: () => $.when(this.rest.getMusicianSearchFilter()).done (sFilter) => this.loadSearchFilter(sFilter) loadSearchFilter: (sFilter) => + super(sFilter) + @searchFilter = JSON.parse(sFilter) args = interests: @searchFilter.data_blob.interests @@ -77,31 +49,6 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter this._populateInstruments() this._populateSortOrder() - - - _populateSelectWithKeys: (struct, selection, keys, element) => - element.children().remove() - $.each keys, (idx, value) => - label = struct[value] - blankOption = $ '' - blankOption.text label - blankOption.attr 'value', value - blankOption.attr 'selected', '' if value == selection - element.append(blankOption) - context.JK.dropdown(element) - - _populateSelectIdentifier: (identifier) => - elem = $ '#musician-search-filter-builder select[name='+identifier+']' - struct = gon.musician_search_meta[identifier]['map'] - keys = gon.musician_search_meta[identifier]['keys'] - this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) - - _populateSelectWithInt: (sourceStruct, selection, element) => - struct = - '-1': 'Any' - $.extend(struct, sourceStruct) - this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element) - _populateSortOrder: () => this._populateSelectIdentifier('sort_order') @@ -122,8 +69,8 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter _populateAges: () => @screen.find('#search-filter-ages').empty() - ages_map = gon.musician_search_meta['ages']['map'] - $.each gon.musician_search_meta['ages']['keys'], (index, key) => + ages_map = @searchMeta['ages']['map'] + $.each @searchMeta['ages']['keys'], (index, key) => ageTemplate = @screen.find('#template-search-filter-setup-ages').html() selected = '' ageLabel = ages_map[key] @@ -139,112 +86,34 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter @screen.find('#search-filter-ages').append ageHtml _populateGenres: () => - @screen.find('#search-filter-genres').empty() - @rest.getGenres().done (genres) => - genreTemplate = @screen.find('#template-search-filter-setup-genres').html() - selected = '' - $.each genres, (index, genre) => - if 0 < @searchFilter.data_blob.genres.length - genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) -> - n == genre.id) - else - genreMatch = [] - selected = 'checked' if genreMatch.length > 0 - genreHtml = context.JK.fillTemplate(genreTemplate, - id: genre.id - description: genre.description - checked: selected) - @screen.find('#search-filter-genres').append genreHtml + super() _populateInstruments: () => - @screen.find('#search-filter-instruments').empty() - @rest.getInstruments().done (instruments) => - $.each instruments, (index, instrument) => - instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html() - selected = '' - proficiency = '1' - if 0 < @searchFilter.data_blob.instruments.length - instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) -> - yn = inst.instrument_id == instrument.id - proficiency = inst.proficiency_level if yn - yn) - selected = 'checked' if instMatch.length > 0 - instrumentHtml = context.JK.fillTemplate(instrumentTemplate, - id: instrument.id - description: instrument.description - checked: selected) - @screen.find('#search-filter-instruments').append instrumentHtml - profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select' - jprofsel = @screen.find(profsel) - jprofsel.val(proficiency) - context.JK.dropdown(jprofsel) - return true - - _builderSelectValue: (identifier) => - elem = $ '#musician-search-filter-builder select[name='+identifier+']' - elem.val() - - _builderSelectMultiValue: (identifier) => - vals = [] - elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked' - if 'instruments' == identifier - elem.each (idx) -> - row = $(this).parent().parent() - instrument = - instrument_id: row.data('instrument-id') - proficiency_level: row.find('select').val() - vals.push instrument - else - elem.each (idx) -> - vals.push $(this).val() - vals + super() willSearch: (reload) => - return false if @isSearching - @isSearching = true - if reload - @pageNumber = 1 - @screen.find('#musician-search-filter-spinner').show() - @resultsListContainer.empty() - @screen.find('#musician-search-filter-builder').hide() - @screen.find('#musician-search-filter-results').show() - true + super(reload) didSearch: (response) => - this.loadSearchFilter(response.filter_json) - @searchResults = response - @screen.find('#musician-search-filter-spinner').hide() - this.renderMusicians() - @screen.find('.paginate-wait').hide() - @isSearching = false + super(response) resetFilter: () => - if this.willSearch(true) - @rest.postMusicianSearchFilter({ filter: 'reset' }).done(this.didSearch) + super() cancelFilter: () => - this.resetFilter() + super() getUserFilterResults: () => - if this.willSearch(true) - @rest.getMusicianSearchFilter('results=true').done(this.didSearch) + super() performSearch: () => - if this.willSearch(true) - $.each gon.musician_search_meta.filter_keys.single, (index, key) => - @searchFilter[key] = this._builderSelectValue(key) - $.each gon.musician_search_meta.filter_keys.multi, (index, key) => - @searchFilter[key] = this._builderSelectMultiValue(key) - @rest.postMusicianSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + super() renderResultsHeader: () => - @screen.find('#musician-search-filter-description').html(@searchResults.description) - if @searchResults.is_blank_filter - @screen.find('#btn-musician-search-reset').hide() - else - @screen.find('#btn-musician-search-reset').show() + super() - renderMusicians: () => + renderResultsPage: () => + super() this.renderResultsHeader() if @pageNumber == 1 musicians = @searchResults.musicians len = musicians.length @@ -394,24 +263,7 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter # TODO: paginate: () => - if @pageNumber < @searchResults.page_count && this.willSearch(false) - @screen.find('.paginate-wait').show() - @pageNumber += 1 - @rest.postMusicianSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) - return true - false + super() registerResultsPagination: () => - _resultsListContainer = @resultsListContainer - _headerHeight = @screen.find('#musician-search-filter-results-header').height() - _paginator = this.paginate - - @screen.find('.content-body-scroller').scroll -> - if _resultsListContainer.is(':visible') - jthis = $(this) - wintop = jthis.scrollTop() - winheight = jthis.innerHeight() - docheight = jthis[0].scrollHeight - _headerHeight - scrollTrigger = 0.98; - if ((wintop / (docheight - winheight)) >= scrollTrigger) - _paginator() + super() From 13c1c5311effd6cd0020d2756df6fcb060972538 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 17:11:24 +0000 Subject: [PATCH 11/66] VRFS-3036 more refactoring --- ruby/lib/jam_ruby.rb | 1 + ruby/lib/jam_ruby/models/band_search.rb | 10 +- .../javascripts/base_search_filter.js.coffee | 3 +- .../musician_search_filter.js.coffee | 230 +++++++++++++++++- 4 files changed, 235 insertions(+), 9 deletions(-) diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index de1b006a8..f8670a820 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -222,6 +222,7 @@ require "jam_ruby/models/online_presence" require "jam_ruby/models/json_store" require "jam_ruby/models/base_search" require "jam_ruby/models/musician_search" +require "jam_ruby/models/band_search" include Jampb diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 927049d5b..ced7ea732 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -1,5 +1,5 @@ module JamRuby - class MusicianSearch < BaseSearch + class BandSearch < BaseSearch attr_accessor :user_counters @@ -16,7 +16,7 @@ module JamRuby SORT_VALS = %W{ distance latency } SORT_ORDERS = { - SORT_VALS[0] => 'Distance to Me' + SORT_VALS[0] => 'Distance to Me', SORT_VALS[1] => 'Latency to Me', } @@ -25,9 +25,9 @@ module JamRuby GenrePlayer::TRADITIONAL_BAND, ] BAND_TYPES = { - INTEREST_VALS[0] => 'Any', - INTEREST_VALS[1] => 'Virtual Band', - INTEREST_VALS[2] => 'Traditional Band', + BAND_TYPE_VALS[0] => 'Any', + BAND_TYPE_VALS[1] => 'Virtual Band', + BAND_TYPE_VALS[2] => 'Traditional Band', } PLAY_COMMIT_VALS = [ANY_VAL_STR, diff --git a/web/app/assets/javascripts/base_search_filter.js.coffee b/web/app/assets/javascripts/base_search_filter.js.coffee index efc876b77..788a61233 100644 --- a/web/app/assets/javascripts/base_search_filter.js.coffee +++ b/web/app/assets/javascripts/base_search_filter.js.coffee @@ -51,10 +51,11 @@ context.JK.BaseSearchFilter = class BaseSearchFilter @resultsListContainer.empty() renderSearchFilter: () => + $.when(@restGet()).done (sFilter) => + this.loadSearchFilter(sFilter) loadSearchFilter: (sFilter) => - _populateSelectWithKeys: (struct, selection, keys, element) => element.children().remove() $.each keys, (idx, value) => diff --git a/web/app/assets/javascripts/musician_search_filter.js.coffee b/web/app/assets/javascripts/musician_search_filter.js.coffee index 3aaa44440..25d08edbc 100644 --- a/web/app/assets/javascripts/musician_search_filter.js.coffee +++ b/web/app/assets/javascripts/musician_search_filter.js.coffee @@ -2,12 +2,237 @@ $ = jQuery context = window context.JK ||= {}; +context.JK.BaseSearchFilter = class BaseSearchFilter + + constructor: () -> + @rest = context.JK.Rest() + @logger = context.JK.logger + @searchFilter = null + @profileUtils = context.JK.ProfileUtils + @helpBubble = context.JK.HelpBubbleHelper + @searchResults = null + @isSearching = false + @pageNumber = 1 + @instrument_logo_map = context.JK.getInstrumentIconMap24() + @searchType = '' + @searchTypeS = '' + @restGet = null + @restPost = null + @searchMeta = null + + init: (app) => + @app = app + @screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide } + @app.bindScreen(@searchTypeS, @screenBindings) + + @screen = $('#'+@searchTypeS+'-screen') + @resultsListContainer = @screen.find('#'+@searchType+'-search-filter-results-list') + @spinner = @screen.find('.paginate-wait') + + this.registerResultsPagination() + + @screen.find('#btn-'+@searchType+'-search-builder').on 'click', => + this.showBuilder() + + @screen.find('#btn-'+@searchType+'-search-reset').on 'click', => + this.resetFilter() + + afterShow: () => + @screen.find('#'+@searchType+'-search-filter-results').show() + @screen.find('#'+@searchType+'-search-filter-builder').hide() + this.getUserFilterResults() + + showBuilder: () => + @screen.find('#'+@searchType+'-search-filter-results').hide() + @screen.find('#'+@searchType+'-search-filter-builder').show() + @resultsListContainer.empty() + + afterHide: () => + @resultsListContainer.empty() + + renderSearchFilter: () => + $.when(@restGet()).done (sFilter) => + this.loadSearchFilter(sFilter) + + loadSearchFilter: (sFilter) => + + _populateSelectWithKeys: (struct, selection, keys, element) => + element.children().remove() + $.each keys, (idx, value) => + label = struct[value] + blankOption = $ '' + blankOption.text label + blankOption.attr 'value', value + blankOption.attr 'selected', '' if value == selection + element.append(blankOption) + context.JK.dropdown(element) + + _populateSelectIdentifier: (identifier) => + elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' + struct = @searchMeta[identifier]['map'] + keys = @searchMeta[identifier]['keys'] + this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) + + _populateSelectWithInt: (sourceStruct, selection, element) => + struct = + '-1': 'Any' + $.extend(struct, sourceStruct) + this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element) + + _populateSortOrder: () => + this._populateSelectIdentifier('sort_order') + + _populateGenres: () => + @screen.find('#search-filter-genres').empty() + @rest.getGenres().done (genres) => + genreTemplate = @screen.find('#template-search-filter-setup-genres').html() + selected = '' + $.each genres, (index, genre) => + if 0 < @searchFilter.data_blob.genres.length + genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) -> + n == genre.id) + else + genreMatch = [] + selected = 'checked' if genreMatch.length > 0 + genreHtml = context.JK.fillTemplate(genreTemplate, + id: genre.id + description: genre.description + checked: selected) + @screen.find('#search-filter-genres').append genreHtml + + _populateInstruments: () => + @screen.find('#search-filter-instruments').empty() + @rest.getInstruments().done (instruments) => + $.each instruments, (index, instrument) => + instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html() + selected = '' + proficiency = '1' + if 0 < @searchFilter.data_blob.instruments.length + instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) -> + yn = inst.instrument_id == instrument.id + proficiency = inst.proficiency_level if yn + yn) + selected = 'checked' if instMatch.length > 0 + instrumentHtml = context.JK.fillTemplate(instrumentTemplate, + id: instrument.id + description: instrument.description + checked: selected) + @screen.find('#search-filter-instruments').append instrumentHtml + profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select' + jprofsel = @screen.find(profsel) + jprofsel.val(proficiency) + context.JK.dropdown(jprofsel) + return true + + _builderSelectValue: (identifier) => + elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' + elem.val() + + _builderSelectMultiValue: (identifier) => + vals = [] + elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked' + if 'instruments' == identifier + elem.each (idx) -> + row = $(this).parent().parent() + instrument = + instrument_id: row.data('instrument-id') + proficiency_level: row.find('select').val() + vals.push instrument + else + elem.each (idx) -> + vals.push $(this).val() + vals + + willSearch: (reload) => + return false if @isSearching + @isSearching = true + if reload + @pageNumber = 1 + @screen.find('#'+@searchType+'-search-filter-spinner').show() + @resultsListContainer.empty() + @screen.find('#'+@searchType+'-search-filter-builder').hide() + @screen.find('#'+@searchType+'-search-filter-results').show() + true + + didSearch: (response) => + this.loadSearchFilter(response.filter_json) + @searchResults = response + @screen.find('#'+@searchType+'-search-filter-spinner').hide() + this.renderResultsPage() + @screen.find('.paginate-wait').hide() + @isSearching = false + + resetFilter: () => + if this.willSearch(true) + @restPost({ filter: 'reset' }).done(this.didSearch) + + cancelFilter: () => + this.resetFilter() + + getUserFilterResults: () => + if this.willSearch(true) + @restGet('results=true').done(this.didSearch) + + performSearch: () => + if this.willSearch(true) + $.each @searchMeta.filter_keys.single, (index, key) => + @searchFilter[key] = this._builderSelectValue(key) + $.each @searchMeta.filter_keys.multi, (index, key) => + @searchFilter[key] = this._builderSelectMultiValue(key) + @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + + renderResultsHeader: () => + @screen.find('#'+@searchType+'-search-filter-description').html(@searchResults.description) + if @searchResults.is_blank_filter + @screen.find('#btn-'+@searchType+'-search-reset').hide() + else + @screen.find('#btn-'+@searchType+'-search-reset').show() + + renderResultsPage: () => + + _formatLocation: (band) -> + if band.city and band.state + band.city + ', ' + band.state + else if band.city + band.city + else if band.regionname + band.regionname + else + 'Location Unavailable' + + friendRequestCallback: (user_id)=> + # TODO: + + paginate: () => + if @pageNumber < @searchResults.page_count && this.willSearch(false) + @screen.find('.paginate-wait').show() + @pageNumber += 1 + @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + return true + false + + registerResultsPagination: () => + _resultsListContainer = @resultsListContainer + _headerHeight = @screen.find('#'+@searchType+'-search-filter-results-header').height() + _paginator = this.paginate + + @screen.find('.content-body-scroller').scroll -> + if _resultsListContainer.is(':visible') + jthis = $(this) + wintop = jthis.scrollTop() + winheight = jthis.innerHeight() + docheight = jthis[0].scrollHeight - _headerHeight + scrollTrigger = 0.98; + if ((wintop / (docheight - winheight)) >= scrollTrigger) + _paginator() + + context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchFilter constructor: () -> super() @searchType = 'musician' - @searchTypeS = @searchTypeS+'s' + @searchTypeS = @searchType+'s' @restGet = @rest.getMusicianSearchFilter @restPost = @rest.postMusicianSearchFilter @searchMeta = gon.musician_search_meta @@ -16,8 +241,7 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF super(app) renderSearchFilter: () => - $.when(this.rest.getMusicianSearchFilter()).done (sFilter) => - this.loadSearchFilter(sFilter) + super() loadSearchFilter: (sFilter) => super(sFilter) From 6fb07d8a311c2b64f9c8446e117c83b35fe1b84f Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 7 May 2015 18:08:36 +0000 Subject: [PATCH 12/66] VRFS-3036 more refactoring --- ruby/lib/jam_ruby/models/base_search.rb | 10 +- .../javascripts/base_search_filter.js.coffee | 227 ------------------ 2 files changed, 5 insertions(+), 232 deletions(-) delete mode 100644 web/app/assets/javascripts/base_search_filter.js.coffee diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 950dab57b..bcd645c22 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -124,8 +124,8 @@ module JamRuby end def _sort_order(rel) - val = json[KEY_SORT_ORDER] - if SORT_VALS[1] == val + val = json[self.class::KEY_SORT_ORDER] + if self.class::SORT_VALS[1] == val locidispid = self.user.last_jam_locidispid || 0 my_locid = locidispid / 1000000 rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") @@ -160,7 +160,7 @@ module JamRuby rel = do_search(filter) @page_number = [page.to_i, 1].max - rel = rel.paginate(:page => @page_number, :per_page => PER_PAGE) + rel = rel.paginate(:page => @page_number, :per_page => self.class::PER_PAGE) rel = self.search_includes(rel) @page_count = rel.total_pages @@ -169,7 +169,7 @@ module JamRuby end def reset_filter - self.data_blob = JSON_SCHEMA + self.data_blob = self.class::JSON_SCHEMA self.save end @@ -183,7 +183,7 @@ module JamRuby end def is_blank? - self.data_blob == JSON_SCHEMA + self.data_blob == self.class::JSON_SCHEMA end def description diff --git a/web/app/assets/javascripts/base_search_filter.js.coffee b/web/app/assets/javascripts/base_search_filter.js.coffee deleted file mode 100644 index 788a61233..000000000 --- a/web/app/assets/javascripts/base_search_filter.js.coffee +++ /dev/null @@ -1,227 +0,0 @@ -$ = jQuery -context = window -context.JK ||= {}; - -context.JK.BaseSearchFilter = class BaseSearchFilter - - constructor: () -> - @rest = context.JK.Rest() - @logger = context.JK.logger - @searchFilter = null - @profileUtils = context.JK.ProfileUtils - @helpBubble = context.JK.HelpBubbleHelper - @searchResults = null - @isSearching = false - @pageNumber = 1 - @instrument_logo_map = context.JK.getInstrumentIconMap24() - @searchType = '' - @searchTypeS = '' - @restGet = null - @restPost = null - @searchMeta = null - - init: (app) => - @app = app - @screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide } - @app.bindScreen(@searchTypeS, @screenBindings) - - @screen = $('#'+@searchTypeS+'-screen') - @resultsListContainer = @screen.find('#'+@searchType+'-search-filter-results-list') - @spinner = @screen.find('.paginate-wait') - - this.registerResultsPagination() - - @screen.find('#btn-'+@searchType+'-search-builder').on 'click', => - this.showBuilder() - - @screen.find('#btn-'+@searchType+'-search-reset').on 'click', => - this.resetFilter() - - afterShow: () => - @screen.find('#'+@searchType+'-search-filter-results').show() - @screen.find('#'+@searchType+'-search-filter-builder').hide() - this.getUserFilterResults() - - showBuilder: () => - @screen.find('#'+@searchType+'-search-filter-results').hide() - @screen.find('#'+@searchType+'-search-filter-builder').show() - @resultsListContainer.empty() - - afterHide: () => - @resultsListContainer.empty() - - renderSearchFilter: () => - $.when(@restGet()).done (sFilter) => - this.loadSearchFilter(sFilter) - - loadSearchFilter: (sFilter) => - - _populateSelectWithKeys: (struct, selection, keys, element) => - element.children().remove() - $.each keys, (idx, value) => - label = struct[value] - blankOption = $ '' - blankOption.text label - blankOption.attr 'value', value - blankOption.attr 'selected', '' if value == selection - element.append(blankOption) - context.JK.dropdown(element) - - _populateSelectIdentifier: (identifier) => - elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' - struct = gon.band_search_meta[identifier]['map'] - keys = gon.band_search_meta[identifier]['keys'] - this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) - - _populateSelectWithInt: (sourceStruct, selection, element) => - struct = - '-1': 'Any' - $.extend(struct, sourceStruct) - this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element) - - _populateSortOrder: () => - this._populateSelectIdentifier('sort_order') - - _populateGenres: () => - @screen.find('#search-filter-genres').empty() - @rest.getGenres().done (genres) => - genreTemplate = @screen.find('#template-search-filter-setup-genres').html() - selected = '' - $.each genres, (index, genre) => - if 0 < @searchFilter.data_blob.genres.length - genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) -> - n == genre.id) - else - genreMatch = [] - selected = 'checked' if genreMatch.length > 0 - genreHtml = context.JK.fillTemplate(genreTemplate, - id: genre.id - description: genre.description - checked: selected) - @screen.find('#search-filter-genres').append genreHtml - - _populateInstruments: () => - @screen.find('#search-filter-instruments').empty() - @rest.getInstruments().done (instruments) => - $.each instruments, (index, instrument) => - instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html() - selected = '' - proficiency = '1' - if 0 < @searchFilter.data_blob.instruments.length - instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) -> - yn = inst.instrument_id == instrument.id - proficiency = inst.proficiency_level if yn - yn) - selected = 'checked' if instMatch.length > 0 - instrumentHtml = context.JK.fillTemplate(instrumentTemplate, - id: instrument.id - description: instrument.description - checked: selected) - @screen.find('#search-filter-instruments').append instrumentHtml - profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select' - jprofsel = @screen.find(profsel) - jprofsel.val(proficiency) - context.JK.dropdown(jprofsel) - return true - - _builderSelectValue: (identifier) => - elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' - elem.val() - - _builderSelectMultiValue: (identifier) => - vals = [] - elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked' - if 'instruments' == identifier - elem.each (idx) -> - row = $(this).parent().parent() - instrument = - instrument_id: row.data('instrument-id') - proficiency_level: row.find('select').val() - vals.push instrument - else - elem.each (idx) -> - vals.push $(this).val() - vals - - willSearch: (reload) => - return false if @isSearching - @isSearching = true - if reload - @pageNumber = 1 - @screen.find('#'+@searchType+'-search-filter-spinner').show() - @resultsListContainer.empty() - @screen.find('#'+@searchType+'-search-filter-builder').hide() - @screen.find('#'+@searchType+'-search-filter-results').show() - true - - didSearch: (response) => - this.loadSearchFilter(response.filter_json) - @searchResults = response - @screen.find('#'+@searchType+'-search-filter-spinner').hide() - this.renderResultsPage() - @screen.find('.paginate-wait').hide() - @isSearching = false - - resetFilter: () => - if this.willSearch(true) - @restPost({ filter: 'reset' }).done(this.didSearch) - - cancelFilter: () => - this.resetFilter() - - getUserFilterResults: () => - if this.willSearch(true) - @restGet('results=true').done(this.didSearch) - - performSearch: () => - if this.willSearch(true) - $.each @searchMeta.filter_keys.single, (index, key) => - @searchFilter[key] = this._builderSelectValue(key) - $.each @searchMeta.filter_keys.multi, (index, key) => - @searchFilter[key] = this._builderSelectMultiValue(key) - @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) - - renderResultsHeader: () => - @screen.find('#'+@searchType+'-search-filter-description').html(@searchResults.description) - if @searchResults.is_blank_filter - @screen.find('#btn-'+@searchType+'-search-reset').hide() - else - @screen.find('#btn-'+@searchType+'-search-reset').show() - - renderResultsPage: () => - - _formatLocation: (band) -> - if band.city and band.state - band.city + ', ' + band.state - else if band.city - band.city - else if band.regionname - band.regionname - else - 'Location Unavailable' - - friendRequestCallback: (user_id)=> - # TODO: - - paginate: () => - if @pageNumber < @searchResults.page_count && this.willSearch(false) - @screen.find('.paginate-wait').show() - @pageNumber += 1 - @rest.postBandSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) - return true - false - - registerResultsPagination: () => - _resultsListContainer = @resultsListContainer - _headerHeight = @screen.find('#'+@searchType+'-search-filter-results-header').height() - _paginator = this.paginate - - @screen.find('.content-body-scroller').scroll -> - if _resultsListContainer.is(':visible') - jthis = $(this) - wintop = jthis.scrollTop() - winheight = jthis.innerHeight() - docheight = jthis[0].scrollHeight - _headerHeight - scrollTrigger = 0.98; - if ((wintop / (docheight - winheight)) >= scrollTrigger) - _paginator() From 737367b016546fb4f229027ed2e106eb6a757431 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 18 May 2015 04:00:12 +0000 Subject: [PATCH 13/66] VRFS-3036 building out band search filter features, refactoring musician search filter --- ruby/lib/jam_ruby/models/band_search.rb | 89 +++++- ruby/lib/jam_ruby/models/base_search.rb | 50 ++-- ruby/lib/jam_ruby/models/musician_search.rb | 27 +- ruby/lib/jam_ruby/models/user.rb | 1 + web/app/assets/javascripts/findBand.js | 257 ------------------ web/app/assets/javascripts/jam_rest.js | 17 +- ....coffee => member_search_filter.js.coffee} | 178 +++++++++++- .../assets/stylesheets/client/band.css.scss | 32 +++ web/app/controllers/api_search_controller.rb | 30 +- web/app/controllers/spikes_controller.rb | 7 +- web/app/helpers/client_helper.rb | 4 +- web/app/views/api_search/index.rabl | 34 +++ .../clients/_band_search_filter.html.slim | 94 +++++++ web/app/views/clients/_bands.html.erb | 86 ------ web/app/views/clients/_bands.html.slim | 140 ++++++++++ web/app/views/clients/index.html.erb | 6 +- .../views/spikes/band_search_filter.html.slim | 15 + web/config/routes.rb | 2 + web/lib/tasks/sample_data.rake | 2 +- 19 files changed, 658 insertions(+), 413 deletions(-) delete mode 100644 web/app/assets/javascripts/findBand.js rename web/app/assets/javascripts/{musician_search_filter.js.coffee => member_search_filter.js.coffee} (79%) create mode 100644 web/app/views/clients/_band_search_filter.html.slim delete mode 100644 web/app/views/clients/_bands.html.erb create mode 100644 web/app/views/clients/_bands.html.slim create mode 100644 web/app/views/spikes/band_search_filter.html.slim diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index ced7ea732..0dae6a088 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -1,12 +1,16 @@ module JamRuby class BandSearch < BaseSearch + cattr_accessor :jschema, :search_meta attr_accessor :user_counters KEY_BAND_SEARCH_TYPE = 'band_search_type' KEY_BAND_TYPE = 'band_type' KEY_PLAY_COMMIT = 'play_commit' KEY_TOUR_OPTION = 'tour_option' + KEY_PERF_SAMPLES = 'perform_samples' + KEY_HIRE_MAX_COST = 'max_cost' + KEY_HIRE_FREE = 'free_gigs' BAND_SEARCH_TYPE_VALS = %W{ to_join to_hire } BAND_SEARCH_TYPES = { @@ -20,6 +24,13 @@ module JamRuby SORT_VALS[1] => 'Latency to Me', } + HIRE_SORT_VALS = %W{ distance price_asc price_desc } + HIRE_SORT_ORDERS = { + HIRE_SORT_VALS[0] => 'Distance to Me', + HIRE_SORT_VALS[1] => 'Gig Minimum Price (Low to High)', + HIRE_SORT_VALS[2] => 'Gig Minimum Price (High to Low)', + } + BAND_TYPE_VALS = [ANY_VAL_STR, GenrePlayer::VIRTUAL_BAND, GenrePlayer::TRADITIONAL_BAND, @@ -52,19 +63,37 @@ module JamRuby TOUR_OPTION_VALS[1] => 'No', } - JSON_SCHEMA = BaseSearch::JSON_SCHEMA.merge({ - KEY_BAND_SEARCH_TYPE => BAND_SEARCH_TYPES[0], - KEY_BAND_TYPE => BAND_TYPE_VALS[0], - KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0], - KEY_TOUR_OPTION => TOUR_OPTION_VALS[0], - }) + PERF_SAMPLES_VALS = TOUR_OPTION_VALS.clone + PERF_SAMPLES = TOUR_OPTIONS.clone - SEARCH_FILTER_META = BaseSearch::SEARCH_FILTER_META.merge({ - sort_order: { keys: self::SORT_VALS, map: self::SORT_ORDERS }, - band_type: { keys: BAND_TYPE_VALS, map: BAND_TYPES }, - play_commit: { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS }, - tour_option: { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS } - }) + def self.json_schema + return @@jschema if @@jschema + @@jschema = { + BAND_SEARCH_TYPE_VALS[0] => BaseSearch.json_schema.merge({ + KEY_BAND_TYPE => BAND_TYPE_VALS[0], + KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0], + KEY_TOUR_OPTION => TOUR_OPTION_VALS[0], + }), + BAND_SEARCH_TYPE_VALS[1] => { + KEY_SORT_ORDER => self::HIRE_SORT_VALS[0], + KEY_GENRES => [], + KEY_SKILL => self::SKILL_VALS[0].to_s, + KEY_GIGS => self::GIG_COUNTS[0].to_s, + KEY_PERF_SAMPLES => self::PERF_SAMPLES[0].to_s, + KEY_HIRE_MAX_COST => 0, + KEY_HIRE_FREE => 0, + }, + } + end + + def self.search_filter_meta + return @@search_meta if @@search_meta + @@search_meta = { + BAND_SEARCH_TYPE_VALS[0] => super(self.json_schema[BAND_SEARCH_TYPE_VALS[0]]), + BAND_SEARCH_TYPE_VALS[1] => super(self.json_schema[BAND_SEARCH_TYPE_VALS[1]], + { keys: HIRE_SORT_VALS, map: HIRE_SORT_ORDERS }), + } + end def self.search_target_class User @@ -155,7 +184,7 @@ module JamRuby end def is_blank? - self.data_blob == JSON_SCHEMA + self.data_blob == self.class.json_schema end def description @@ -168,5 +197,39 @@ module JamRuby str end + def reset_filter(subtype, data=nil) + data ||= self.class.json_schema[subtype] + dblob = self.data_blob + dblob[subtype] = data + self.data_blob = dblob + self.save + end + + def reset_search_results(subtype=BAND_SEARCH_TYPE_VALS[0]) + reset_filter(subtype) + search_results_page(subtype) + end + + def self.search_filter_json(user, subtype=BAND_SEARCH_TYPE_VALS[0]) + self.user_search_filter(user).json[subtype] + end + + def search_results_page(subtype=BAND_SEARCH_TYPE_VALS[0], filter=nil, page=1) + if filter + reset_filter(subtype, filter) + else + filter = self.data_blob[subtype] + end + rel = do_search(filter) + + @page_number = [page.to_i, 1].max + rel = rel.paginate(:page => @page_number, :per_page => self.class::PER_PAGE) + + rel = self.search_includes(rel) + @page_count = rel.total_pages + + process_results_page(rel.all) + end + end end diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index bcd645c22..8a1672084 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -43,27 +43,31 @@ module JamRuby 3 => 'Expert', } - JSON_SCHEMA = { - KEY_SORT_ORDER => self::SORT_VALS[0], - KEY_INSTRUMENTS => [], - KEY_GENRES => [], - KEY_SKILL => self::SKILL_VALS[0].to_s, - KEY_GIGS => self::GIG_COUNTS[0].to_s, - } + def self.json_schema + { + KEY_SORT_ORDER => self::SORT_VALS[0], + KEY_INSTRUMENTS => [], + KEY_GENRES => [], + KEY_SKILL => self::SKILL_VALS[0].to_s, + KEY_GIGS => self::GIG_COUNTS[0].to_s, + } + end - JSON_SCHEMA_KEYS = self::JSON_SCHEMA.keys - MULTI_VALUE_KEYS = self::JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact - SINGLE_VALUE_KEYS = self::JSON_SCHEMA.keys - self::MULTI_VALUE_KEYS - - SEARCH_FILTER_META = { - per_page: self::PER_PAGE, - filter_keys: { - keys: self::JSON_SCHEMA_KEYS, - multi: self::MULTI_VALUE_KEYS, - single: self::SINGLE_VALUE_KEYS, - }, - sort_order: { keys: self::SORT_VALS, map: self::SORT_ORDERS }, - } + def self.search_filter_meta(jschema=nil, sort_order=nil) + jschema ||= self.json_schema + schema_keys = jschema.keys + sort_order ||= { keys: self::SORT_VALS, map: self::SORT_ORDERS } + multi_keys = jschema.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact + { + per_page: self::PER_PAGE, + filter_keys: { + keys: schema_keys, + multi: multi_keys, + single: schema_keys - multi_keys, + }, + sort_order: sort_order + } + end RESULT_FOLLOW = :follows RESULT_FRIEND = :friends @@ -88,7 +92,7 @@ module JamRuby def self.create_search(user) ms = self.new ms.user = user - ms.data_blob = self::JSON_SCHEMA + ms.data_blob = self.json_schema ms.save! ms end @@ -169,7 +173,7 @@ module JamRuby end def reset_filter - self.data_blob = self.class::JSON_SCHEMA + self.data_blob = self.class.json_schema self.save end @@ -183,7 +187,7 @@ module JamRuby end def is_blank? - self.data_blob == self.class::JSON_SCHEMA + self.data_blob == self.class.json_schema end def description diff --git a/ruby/lib/jam_ruby/models/musician_search.rb b/ruby/lib/jam_ruby/models/musician_search.rb index cb6f789a9..8f97d8a43 100644 --- a/ruby/lib/jam_ruby/models/musician_search.rb +++ b/ruby/lib/jam_ruby/models/musician_search.rb @@ -1,6 +1,7 @@ module JamRuby class MusicianSearch < BaseSearch + cattr_accessor :jschema, :search_meta attr_accessor :user_counters KEY_STUDIOS = 'studio_sessions' @@ -47,16 +48,22 @@ module JamRuby INTEREST_VALS[5] => 'Co-Writing' } - JSON_SCHEMA = BaseSearch::JSON_SCHEMA.merge({ - KEY_INTERESTS => INTEREST_VALS[0], - KEY_STUDIOS => STUDIO_COUNTS[0].to_s, - KEY_AGES => [] - }) + def self.json_schema + return @@jschema if @@jschema + @@jschema = BaseSearch.json_schema.merge({ + KEY_INTERESTS => INTEREST_VALS[0], + KEY_STUDIOS => STUDIO_COUNTS[0].to_s, + KEY_AGES => [] + }) + end - SEARCH_FILTER_META = BaseSearch::SEARCH_FILTER_META.merge({ - interests: { keys: INTEREST_VALS, map: INTERESTS }, - ages: { keys: AGE_COUNTS, map: AGES } - }) + def self.search_filter_meta + return @@search_meta if @@search_meta + @@search_meta = super.merge({ + interests: { keys: INTEREST_VALS, map: INTERESTS }, + ages: { keys: AGE_COUNTS, map: AGES } + }) + end def self.search_target_class User @@ -226,7 +233,7 @@ module JamRuby end def is_blank? - self.data_blob == JSON_SCHEMA + self.data_blob == self.class.json_schema end def description diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 8987a9db8..b116aaffb 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -169,6 +169,7 @@ module JamRuby has_many :performance_samples, :class_name => "JamRuby::PerformanceSample", :foreign_key=> 'player_id' has_one :musician_search, :class_name => 'JamRuby::MusicianSearch' + has_one :band_search, :class_name => 'JamRuby::BandSearch' before_save :create_remember_token, :if => :should_validate_password? before_save :stringify_avatar_info , :if => :updating_avatar diff --git a/web/app/assets/javascripts/findBand.js b/web/app/assets/javascripts/findBand.js deleted file mode 100644 index e7c30f315..000000000 --- a/web/app/assets/javascripts/findBand.js +++ /dev/null @@ -1,257 +0,0 @@ -(function(context,$) { - "use strict"; - - context.JK = context.JK || {}; - context.JK.FindBandScreen = function(app) { - - var logger = context.JK.logger; - var bands = {}; - var bandList; - var instrument_logo_map = context.JK.getInstrumentIconMap24(); - var did_show_band_page = false; - var page_num=1, page_count=0; - var helpBubble = context.JK.HelpBubbleHelper; - var $screen = $('#bands-screen'); - var $results = $screen.find('#band-filter-results'); - - function loadBands(queryString) { - // squelch nulls and undefines - queryString = !!queryString ? queryString : ""; - - $.ajax({ - type: "GET", - url: "/api/search.json?" + queryString, - success: afterLoadBands, - error: app.ajaxError - }); - } - - function search() { - did_show_band_page = true; - var queryString = 'srch_b=1&page='+page_num+'&'; - - // order by - var orderby = $('#band_order_by').val(); - if (typeof orderby != 'undefined' && orderby.length > 0) { - queryString += "orderby=" + orderby + '&'; - } - // genre filter - var genre = $('#band_genre').val(); - if (typeof genre != 'undefined' && !(genre === '')) { - queryString += "genre=" + genre + '&'; - } - // distance filter - var query_param = $('#band_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]; - queryString += "distance=" + distance + '&'; - } - } - loadBands(queryString); - } - - function refreshDisplay() { - clearResults(); - search(); - } - - function afterLoadBands(mList) { - // display the 'no bands' banner if appropriate - var $noBandsFound = $('#bands-none-found'); - bandList = mList; - - if(bandList.length == 0) { - $noBandsFound.show(); - bands = []; - } - else { - $noBandsFound.hide(); - bands = bandList['bands']; - if (!(typeof bands === 'undefined')) { - $('#band-filter-city').text(bandList['city']); - if (0 == page_count) { - page_count = bandList['page_count']; - } - renderBands(); - } - } - } - - function renderBands() { - var ii, len; - var mTemplate = $('#template-find-band-row').html(); - var pTemplate = $('#template-band-player-info').html(); - var aTemplate = $('#template-band-action-btns').html(); - var eTemplate = $('#template-band-edit-btns').html(); - var bVals, bb, renderings=''; - var instr_logos, instr; - var players, playerVals, aPlayer, isMember; - - for (ii=0, len=bands.length; ii < len; ii++) { - bb = bands[ii]; - instr_logos = ''; - players = ''; - playerVals = {}; - isMember = false; - for (var jj=0, ilen=bb['players'].length; jj'; - } - if (!isMember) { - isMember = aPlayer.user_id == context.JK.currentUserId; - } - playerVals = { - user_id: aPlayer.user_id, - player_name: aPlayer.name, - profile_url: '/client#/profile/' + aPlayer.user_id, - avatar_url: context.JK.resolveAvatarUrl(aPlayer.photo_url), - player_instruments: player_instrs - }; - - players += context.JK.fillTemplate(pTemplate, playerVals); - } - - var actionVals, band_actions; - if (isMember) { - actionVals = { - profile_url: "/client#/bandProfile/" + bb.id, - band_edit_url: "/client#/band/setup/" + bb.id + '/step1', - band_member_url: "/client#/band/setup/" + bb.id + '/step2' - }; - band_actions = context.JK.fillTemplate(eTemplate, actionVals); - } else { - actionVals = { - profile_url: "/client#/bandProfile/" + bb.id, - button_follow: bb['is_following'] ? '' : 'button-orange', - button_message: 'button-orange' - }; - band_actions = context.JK.fillTemplate(aTemplate, actionVals); - } - - var bgenres = ''; - for (jj=0, ilen=bb['genres'].length; jj'; - } - - bgenres += '
'; - - bVals = { - avatar_url: context.JK.resolveBandAvatarUrl(bb.photo_url), - profile_url: "/client#/bandProfile/" + bb.id, - band_name: bb.name, - band_location: bb.city + ', ' + bb.state, - genres: bgenres, - instruments: instr_logos, - biography: bb['biography'], - follow_count: bb['follow_count'], - recording_count: bb['recording_count'], - session_count: bb['session_count'], - band_id: bb['id'], - band_player_template: players, - band_action_template: band_actions - }; - - var $rendering = $(context.JK.fillTemplate(mTemplate, bVals)) - - var $offsetParent = $results.closest('.content'); - var data = {entity_type: 'band'}; - - var options = {positions: ['top', 'bottom', 'right', 'left'], offsetParent: $offsetParent}; - context.JK.helpBubble($('.follower-count', $rendering), 'follower-count', data, options); - context.JK.helpBubble($('.recording-count', $rendering), 'recording-count', data, options); - context.JK.helpBubble($('.session-count', $rendering), 'session-count', data, options); - - $results.append($rendering); - } - - $('.search-m-follow').on('click', followBand); - context.JK.bindHoverEvents(); - } - - function beforeShow(data) { - } - - function afterShow(data) { - if (!did_show_band_page) { - refreshDisplay(); - } - } - - function clearResults() { - bands = {}; - $('#band-filter-results').empty(); - page_num = 1; - page_count = 0; - } - - function followBand(evt) { - // if the band is already followed, remove the button-orange class, and prevent - // the link from working - if (0 == $(this).closest('.button-orange').size()) return false; - $(this).click(function(ee) {ee.preventDefault();}); - - evt.stopPropagation(); - var newFollowing = {}; - newFollowing.band_id = $(this).parent().data('band-id'); - var url = "/api/users/" + context.JK.currentUserId + "/followings"; - $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: url, - data: JSON.stringify(newFollowing), - processData: false, - success: function(response) { - // remove the orange look to indicate it's not selectable - // @FIXME -- this will need to be tweaked when we allow unfollowing - $('div[data-band-id='+newFollowing.band_id+'] .search-m-follow').removeClass('button-orange').addClass('button-grey'); - }, - error: app.ajaxError(arguments) - }); - } - - function events() { - $('#band_query_distance').change(refreshDisplay); - $('#band_genre').change(refreshDisplay); - $('#band_order_by').change(refreshDisplay); - - $('#band-filter-results').closest('.content-body-scroller').bind('scroll', function() { - if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { - if (page_num < page_count) { - page_num += 1; - search(); - } - } - }); - } - - function initialize() { - var screenBindings = { - 'beforeShow': beforeShow, - 'afterShow': afterShow - }; - app.bindScreen('bands', screenBindings); - - events(); - } - - this.initialize = initialize; - this.renderBands = renderBands; - this.afterShow = afterShow; - this.clearResults = clearResults; - - return this; - } -})(window,jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 6c3cce4f0..901b875b0 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -1639,6 +1639,19 @@ }); } + function getBandSearchFilter(query) { + var qarg = query === undefined ? '' : query; + return $.get("/api/search/bands.json?"+qarg); + } + + function postBandSearchFilter(query) { + return $.ajax({ + type: "POST", + url: "/api/search/bands.json", + data: query + }); + } + function getMount(options) { var id = getId(options); return $.ajax({ @@ -1852,6 +1865,8 @@ this.addRecordingTimeline = addRecordingTimeline; this.getMusicianSearchFilter = getMusicianSearchFilter; this.postMusicianSearchFilter = postMusicianSearchFilter; + this.getBandSearchFilter = getBandSearchFilter; + this.postBandSearchFilter = postBandSearchFilter; this.playJamTrack = playJamTrack; this.createSignupHint = createSignupHint; this.createAlert = createAlert; @@ -1860,4 +1875,4 @@ }; -})(window,jQuery); \ No newline at end of file +})(window,jQuery); diff --git a/web/app/assets/javascripts/musician_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee similarity index 79% rename from web/app/assets/javascripts/musician_search_filter.js.coffee rename to web/app/assets/javascripts/member_search_filter.js.coffee index 25d08edbc..4df9e8557 100644 --- a/web/app/assets/javascripts/musician_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -31,12 +31,6 @@ context.JK.BaseSearchFilter = class BaseSearchFilter this.registerResultsPagination() - @screen.find('#btn-'+@searchType+'-search-builder').on 'click', => - this.showBuilder() - - @screen.find('#btn-'+@searchType+'-search-reset').on 'click', => - this.resetFilter() - afterShow: () => @screen.find('#'+@searchType+'-search-filter-results').show() @screen.find('#'+@searchType+'-search-filter-builder').hide() @@ -50,6 +44,9 @@ context.JK.BaseSearchFilter = class BaseSearchFilter afterHide: () => @resultsListContainer.empty() + searchMetaData: () => + @searchMeta + renderSearchFilter: () => $.when(@restGet()).done (sFilter) => this.loadSearchFilter(sFilter) @@ -69,8 +66,8 @@ context.JK.BaseSearchFilter = class BaseSearchFilter _populateSelectIdentifier: (identifier) => elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' - struct = @searchMeta[identifier]['map'] - keys = @searchMeta[identifier]['keys'] + struct = this.searchMetaData()[identifier]['map'] + keys = this.searchMetaData()[identifier]['keys'] this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) _populateSelectWithInt: (sourceStruct, selection, element) => @@ -171,13 +168,19 @@ context.JK.BaseSearchFilter = class BaseSearchFilter getUserFilterResults: () => if this.willSearch(true) - @restGet('results=true').done(this.didSearch) + this.doRestGet() + + doRestGet: (query) => + query2 = 'results=true&' + unless (typeof query == "undefined") + query2 += query + @restGet(query2).done(this.didSearch) performSearch: () => if this.willSearch(true) - $.each @searchMeta.filter_keys.single, (index, key) => + $.each this.searchMetaData().filter_keys.single, (index, key) => @searchFilter[key] = this._builderSelectValue(key) - $.each @searchMeta.filter_keys.multi, (index, key) => + $.each this.searchMetaData().filter_keys.multi, (index, key) => @searchFilter[key] = this._builderSelectMultiValue(key) @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) @@ -239,6 +242,10 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF init: (app) => super(app) + @screen.find('#btn-'+@searchType+'-search-builder').on 'click', => + this.showBuilder() + @screen.find('#btn-'+@searchType+'-search-reset').on 'click', => + this.resetFilter() renderSearchFilter: () => super() @@ -293,8 +300,8 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF _populateAges: () => @screen.find('#search-filter-ages').empty() - ages_map = @searchMeta['ages']['map'] - $.each @searchMeta['ages']['keys'], (index, key) => + ages_map = this.searchMetaData()['ages']['map'] + $.each this.searchMetaData()['ages']['keys'], (index, key) => ageTemplate = @screen.find('#template-search-filter-setup-ages').html() selected = '' ageLabel = ages_map[key] @@ -491,3 +498,148 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF registerResultsPagination: () => super() + + +context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter + + constructor: () -> + super() + @searchType = 'band' + @searchTypeS = @searchType+'s' + @restGet = @rest.getBandSearchFilter + @restPost = @rest.postBandSearchFilter + @searchMeta = gon.band_search_meta + @searchSubType = 'to_join' + + init: (app) => + super(app) + + @screen.find('#btn-'+@searchType+'-search-builder-to_join').on 'click', => + this.showBuilderToJoin() + @screen.find('#btn-'+@searchType+'-search-builder-to_hire').on 'click', => + this.showBuilderToHire() + + showBuilderToJoin: () => + @searchSubType = 'to_join' + this.showBuilder() + + showBuilderToHire: () => + @searchSubType = 'to_hire' + this.showBuilder() + + searchMetaData: () => + @searchMeta[@searchSubType] + + renderSearchFilter: () => + super() + + _searchFilterArgsToJoin: () => + args = + tour_option: @searchFilter.data_blob.tour_option + skill_level: @searchFilter.data_blob.skill_level + play_commit: @searchFilter.data_blob.play_commit + band_type: @searchFilter.data_blob.band_type + concert_gigs: @searchFilter.data_blob.concert_gigs + + _searchFilterArgsToHire: () => + args = + skill_level: @searchFilter.data_blob.skill_level + concert_gigs: @searchFilter.data_blob.concert_gigs + perform_samples: @searchFilter.data_blob.perform_samples + max_cost: @searchFilter.data_blob.max_cost + free_gigs: @searchFilter.data_blob.free_gigs + + _populateSearchFilterToJoin: () => + this._populateInstruments() + this._populateSkill() + this._populateGigs() + this._populateBandType() + this._populatePlayCommit() + this._populateTourOption() + + _populateSearchFilterToHire: () => + + loadSearchFilter: (sFilter) => + super(sFilter) + + @searchFilter = JSON.parse(sFilter) + switch @searchSubType + when 'to_join' then args = _searchFilterArgsToJoin() + when 'to_hire' then args = _searchFilterArgsToHire() + + template = context.JK.fillTemplate(@screen.find('#template-band-search-filter-'+@searchSubType).html(), args) + + content_root = @screen.find('#band-search-filter-builder') + content_root.html template + + @screen.find('#btn-perform-band-search').on 'click', => + this.performSearch() + + @screen.find('#btn-band-search-cancel').on 'click', => + this.cancelFilter() + + this._populateGenres() + this._populateSortOrder() + + switch @searchSubType + when 'to_join' then _populateSearchFilterToJoin() + when 'to_hire' then _populateSearchFilterToHire() + + _populateSortOrder: () => + this._populateSelectIdentifier('sort_order') + + _populateGenres: () => + super() + + _populateInstruments: () => + super() + + willSearch: (reload) => + super(reload) + + didSearch: (response) => + super(response) + + resetFilter: () => + super() + + cancelFilter: () => + super() + + doRestGet: (query) => + super('subtype='+@searchSubType) + + performSearch: () => + super() + + renderResultsHeader: () => + super() + + renderResultsPage: () => + super() + this.renderResultsHeader() if @pageNumber == 1 + bands = @searchResults.bands + len = bands.length + if 0 == len + @screen.find('#band-search-filter-results-list-blank').show() + @screen.find('#band-search-filter-results-list-blank').html('No results found') + return + else + @screen.find('#band-search-filter-results-list-blank').hide() + + _bindMessageBand: () => + + _bindFriendBand: () => + + _bindFollowBand: () => + + _formatLocation: (band) -> + + friendRequestCallback: (user_id)=> + # TODO: + + paginate: () => + super() + + registerResultsPagination: () => + super() diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index 4a9ff616d..72f431151 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -350,4 +350,36 @@ label { margin-bottom:2px; } +} + +#musicians-screen { + + .builder-section { + padding: 10px; + margin-bottom: 20px; + } + + #bands-filter-to-join { + + .builder-section { + padding: 10px; + margin-bottom: 20px; + } + + .col-left { + float: left; + width: 50%; + margin-left: auto; + margin-right: auto; + } + + .col-right { + float: right; + width: 50%; + margin-left: auto; + margin-right: auto; + } + + } + } \ No newline at end of file diff --git a/web/app/controllers/api_search_controller.rb b/web/app/controllers/api_search_controller.rb index 0663265ff..be15b0074 100644 --- a/web/app/controllers/api_search_controller.rb +++ b/web/app/controllers/api_search_controller.rb @@ -7,7 +7,7 @@ class ApiSearchController < ApiController def index if 1 == params[Search::PARAM_MUSICIAN].to_i || 1 == params[Search::PARAM_BAND].to_i - query = params.clone + query = parasobj.clone query[:remote_ip] = request.remote_ip if 1 == query[Search::PARAM_MUSICIAN].to_i @search = Search.musician_filter(query, current_user) @@ -32,13 +32,35 @@ class ApiSearchController < ApiController end elsif request.post? - ms = MusicianSearch.user_search_filter(current_user) + sobj = MusicianSearch.user_search_filter(current_user) filter = params[:filter] if filter == 'reset' - @search = ms.reset_search_results + @search = sobj.reset_search_results else json = JSON.parse(filter, :create_additions => false) - @search = ms.search_results_page(json, [params[:page].to_i, 1].max) + @search = sobj.search_results_page(json, [params[:page].to_i, 1].max) + end + respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index' + end + end + + def bands + if request.get? + if params[:results] + @search = BandSearch.user_search_filter(current_user).search_results_page(params[:subtype]) + respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index' + else + render :json => BandSearch.search_filter_json(current_user, params[:subtype]), :status => 200 + end + + elsif request.post? + sobj = BandSearch.user_search_filter(current_user) + filter = params[:filter] + if filter == 'reset' + @search = sobj.reset_search_results(params[:subtype]) + else + json = JSON.parse(filter, :create_additions => false) + @search = sobj.search_results_page(json, [params[:page].to_i, 1].max) end respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index' end diff --git a/web/app/controllers/spikes_controller.rb b/web/app/controllers/spikes_controller.rb index 0edce85ce..069a2d757 100644 --- a/web/app/controllers/spikes_controller.rb +++ b/web/app/controllers/spikes_controller.rb @@ -69,7 +69,12 @@ class SpikesController < ApplicationController end def musician_search_filter - # gon.musician_search_meta = MusicianSearch::SEARCH_FILTER_META + # gon.musician_search_meta = MusicianSearch.search_filter_meta + render :layout => 'web' + end + + def band_search_filter + gon.band_search_meta = BandSearch.search_filter_meta render :layout => 'web' end diff --git a/web/app/helpers/client_helper.rb b/web/app/helpers/client_helper.rb index c3942e798..f6febfb1d 100644 --- a/web/app/helpers/client_helper.rb +++ b/web/app/helpers/client_helper.rb @@ -67,8 +67,8 @@ module ClientHelper gon.ftue_network_test_duration = Rails.application.config.ftue_network_test_duration gon.ftue_network_test_max_clients = Rails.application.config.ftue_network_test_max_clients gon.ftue_maximum_gear_latency = Rails.application.config.ftue_maximum_gear_latency - gon.musician_search_meta = MusicianSearch::SEARCH_FILTER_META - gon.band_search_meta = BandSearch::SEARCH_FILTER_META + gon.musician_search_meta = MusicianSearch.search_filter_meta + gon.band_search_meta = BandSearch.search_filter_meta # is this the native client or browser? @nativeClient = is_native_client? diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index ea256bf52..14a00b499 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -58,6 +58,40 @@ if @search.is_a?(MusicianSearch) last_jam_audio_latency(musician) end } + +elsif @search.is_a?(BandSearch) + + node :page_count do |foo| + @search.page_count + end + + child(:results => :bands) { + attributes :id, :name, :city, :state, :country, :photo_url, :biography, :logo_url, :website + + node :is_following do |band| + @search.is_follower?(band) + end + + node :biography do |band| + band.biography.nil? ? "" : band.biography + end + + child :genres => :genres do + attributes :genre_id, :description + end + + child :users => :players do |pl| + node :user_id do |uu| uu.id end + node :photo_url do |uu| uu.photo_url end + node :name do |uu| uu.name end + node :instruments do |uu| uu.instruments.map(&:id).join(',') end + end + + node :follow_count do |band| @search.follow_count(band) end + node :recording_count do |band| @search.record_count(band) end + node :session_count do |band| @search.session_count(band) end + } + else if @search.session_invite_search? diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim new file mode 100644 index 000000000..a80cd9f1d --- /dev/null +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -0,0 +1,94 @@ +.content-body-scroller + div#band-search-filter-builder.content-wrapper + + div#band-search-filter-results.content-wrapper + div#band-search-filter-results-header + a#btn-band-search-builder-to_join.button-orange href="#" SEARCH FOR BAND TO JOIN + a#btn-band-search-reset-to_hire.button-grey href="#" SEARCH FOR BAND TO HIRE + div#band-search-filter-description + div.clearall + div#band-search-filter-spinner.spinner-large + + div#band-search-filter-results-wrapper + div#band-search-filter-results-list-blank + div#band-search-filter-results-list.content-wrapper + div.paginate-wait + Fetching more results... + div.spinner-small + +script#template-band-search-filter-to_join type="text/template" + #bands-filter-to_join + #band-search-filter-builder-top.builder-section + .col-left + h2 search bands + .col-right.builder-sort-order + .text-label Sort Results By: + select.easydropdown name="sort_order" + option selected="selected" value="{sort_order}" {sort_order} + .clearall + + #band-search-filter-builder-middle1.builder-section + .col-left + .field + label for="search-filter-genres" Genres: + .search-filter-setup-genres.band-setup-genres + table#search-filter-genres cellpadding="10" cellspacing="6" width="100%" + + .col-right + .field + label for="search-filter-instruments" + | Instruments & Skill Level: + .search-filter-setup-instruments.band-setup-genres.builder-instruments + table#search-filter-instruments cellpadding="10" cellspacing="6" width="100%" + .clearall + + #band-search-filter-builder-middle2.builder-section + .col-left + .field.builder-selector + label Type: + select.easydropdown name="band_type" + option selected="selected" value="{band_type}" {band_type} + + .field.builder-selector + label Play Commitment: + select.easydropdown name="play_commit" + option selected="selected" value="{play_commit}" {play_commit} + + .col-right + .field.builder-selector + label Status: + select.easydropdown name="skill_level" + option selected="selected" value="{skill_level}" {skill_level} + + .field.builder-selector + label Concert Gigs Played: + select.easydropdown name="concert_gigs" + option selected="selected" value="{concert_gigs}" {concert_gigs} + + .field.builder-selector + label Touring Option: + select.easydropdown name="tour_option" + option selected="selected" value="{tour_option}" {tour_option} + .clearall + + .clearall + #band-search-filter-builder-bottom.builder-section.builder-action-buttons + .col-right + a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH + a#btn-band-search-cancel.builder-button.button-grey href="#" CANCEL + +script#template-search-filter-setup-instrument type="text/template" + tr data-instrument-id="{id}" + td {description} + td align="right" width="50%" + select.proficiency_selector name="proficiency" + option value="1" Beginner + option value="2" Intermediate + option value="3" Expert + +script#template-search-filter-setup-genres type="text/template" + tr + td {description} + +/! Session Row Template +script#template-search-band-row type="text/template" diff --git a/web/app/views/clients/_bands.html.erb b/web/app/views/clients/_bands.html.erb deleted file mode 100644 index ae7bdbf5c..000000000 --- a/web/app/views/clients/_bands.html.erb +++ /dev/null @@ -1,86 +0,0 @@ - -<%= content_tag(:div, :layout => 'screen', 'layout-id' => 'bands', :class => "screen secondary", :id => "bands-screen") do -%> - <%= content_tag(:div, :class => :content) do -%> - <%= content_tag(:div, :class => 'content-head') do -%> - <%= content_tag(:div, image_tag("content/icon_bands.png", {:height => 19, :width => 19}), :class => 'content-icon') %> - <%= content_tag(:h1, 'bands') %> - <%= render "screen_navigation" %> - <% end -%> - <%= content_tag(:div, :class => 'content-body') do -%> - <%= form_tag('', {:id => 'find-band-form', :class => 'inner-content'}) do -%> - <%= render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_BAND}) %> - <%= content_tag(:div, :class => 'filter-body') do %> - <%= content_tag(:div, :class => 'content-body-scroller') do -%> - <%= content_tag(:div, content_tag(:div, '', :id => 'band-filter-results', :class => 'filter-results'), :class => 'content-wrapper') %> - <% end -%> - <% end -%> - <% end -%> - <% end -%> - <% end -%> -<% end -%> - - - - - - - - - - diff --git a/web/app/views/clients/_bands.html.slim b/web/app/views/clients/_bands.html.slim new file mode 100644 index 000000000..c472fbe39 --- /dev/null +++ b/web/app/views/clients/_bands.html.slim @@ -0,0 +1,140 @@ +#bands-screen.screen.secondary layout="screen" layout-id="bands" + .content + .content-head + .content-icon + img alt="Icon_bands" height="19" src="/assets/content/icon_bands.png" width="19" / + h1 bands + = render "screen_navigation" + .content-body + = render "clients/band_search_filter" + +script#template-band-search-filter-to_join type="text/template" + #bands-filter-to_join + #band-search-filter-builder-top.builder-section + .col-left + h2 search bands + .col-right.builder-sort-order + .text-label Sort Results By: + select.easydropdown name="sort_order" + option selected="selected" value="{sort_order}" {sort_order} + .clearall + + #band-search-filter-builder-middle1.builder-section + .col-left + .field + label for="search-filter-genres" Genres: + .search-filter-setup-genres.band-setup-genres + table#search-filter-genres cellpadding="10" cellspacing="6" width="100%" + + .col-right + .field + label for="search-filter-instruments" + | Instruments & Skill Level: + .search-filter-setup-instruments.band-setup-genres.builder-instruments + table#search-filter-instruments cellpadding="10" cellspacing="6" width="100%" + .clearall + + #band-search-filter-builder-middle2.builder-section + .col-left + .field.builder-selector + label Type: + select.easydropdown name="band_type" + option selected="selected" value="{band_type}" {band_type} + + .field.builder-selector + label Play Commitment: + select.easydropdown name="play_commit" + option selected="selected" value="{play_commit}" {play_commit} + + .col-right + .field.builder-selector + label Status: + select.easydropdown name="skill_level" + option selected="selected" value="{skill_level}" {skill_level} + + .field.builder-selector + label Concert Gigs Played: + select.easydropdown name="concert_gigs" + option selected="selected" value="{concert_gigs}" {concert_gigs} + + .field.builder-selector + label Touring Option: + select.easydropdown name="tour_option" + option selected="selected" value="{tour_option}" {tour_option} + + .clearall + + .clearall + #band-search-filter-builder-bottom.builder-section.builder-action-buttons + .col-right + a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH + a#btn-band-search-cancel.builder-button.button-grey href="#" CANCEL + +/! Session Row Template +script#template-search-band-row type="text/template" + .profile-band-list-result.band-list-result + .f11 + .left style="width:63px;margin-top:-12px;" + /! avatar + .avatar-small + img src="{avatar_url}" / + .right.mband-players style="width:265px; margin-top:-4px;" + table.musicians cellpadding="0" cellspacing="5" + | {band_player_template} + div style="margin-left: 63px; margin-right: 275px;margin-top: 12px;" + .first-row data-hint="top-row" + .lcol.left + /! name and location + .result-name + | {band_name} + .result-location + | {band_location} + br / + #result_genres.nowrap.mt10 + | {genres} + .whitespace + .biography + | {biography} + .clearleft + .button-row + .lcol.stats.left + span.follower-count + | {follow_count} + img src="../assets/content/icon_followers.png" width="22" height="12" align="absmiddle" style="margin-right:4px;" / + span.recording-count + | {recording_count} + img src="../assets/content/icon_recordings.png" width="12" height="13" align="absmiddle" style="margin-right:4px;" / + span.session-count + | {session_count} + img src="../assets/content/icon_session_tiny.png" width="12" height="12" align="absmiddle" / + .clearall + .result-list-button-wrapper data-band-id="{band_id}" + | {band_action_template} + .clearall + +script#template-search-band-action-btns type="text/template" + a.button-orange smallbutton href="{profile_url}" + PROFILE + a class="{button_follow} smallbutton search-m-follow" href="#" + FOLLOW + +script#template-search-band-edit-btns type="text/template" + a href="{profile_url}" class="button-orange smallbutton" + PROFILE + a href="{band_edit_url}" class="button-orange smallbutton" + EDIT BAND + a href="{band_member_url}" class="button-orange smallbutton" + INVITE + +script#template-search-band-player-info type="text/template" + tr + td + a.avatar-tiny href="{profile_url}" user-id="{user_id}" hoveraction="musician" + img src="{avatar_url}" / + td style="padding: 0 4px;width:88px" + a user-id="{user_id}" hoveraction="musician" href="{profile_url}" + strong + | {player_name} + td.instruments + | {player_instruments} + diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index 5654778b9..f894825f9 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -296,8 +296,10 @@ // var findMusicianScreen = new JK.FindMusicianScreen(JK.app); //findMusicianScreen.initialize(JK.TextMessageDialogInstance); - var findBandScreen = new JK.FindBandScreen(JK.app); - findBandScreen.initialize(); + var findBandScreen = new JK.BandSearchFilter(); + findBandScreen.init(JK.app); + // var findBandScreen = new JK.FindBandScreen(JK.app); + // findBandScreen.initialize(); var sessionScreen = new JK.SessionScreen(JK.app); sessionScreen.initialize(localRecordingsDialog, recordingFinishedDialog, JK.FriendSelectorDialogInstance); diff --git a/web/app/views/spikes/band_search_filter.html.slim b/web/app/views/spikes/band_search_filter.html.slim new file mode 100644 index 000000000..9dff2e51e --- /dev/null +++ b/web/app/views/spikes/band_search_filter.html.slim @@ -0,0 +1,15 @@ += javascript_include_tag "profile_utils" += javascript_include_tag "member_search_filter" += stylesheet_link_tag "client/band" +#band_search_spike += render "clients/band_search_filter" + +javascript: + var initialized = false; + $(document).on('JAMKAZAM_READY', function(e, data) { + setTimeout(function() { + window.band_search_filter = new JK.BandSearchFilter(); + band_search_filter.init(); + band_search_filter.afterShow(); + }, 1) + }); diff --git a/web/config/routes.rb b/web/config/routes.rb index bb3aadf10..2cd392338 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -111,6 +111,7 @@ SampleApp::Application.routes.draw do match '/site_validate', to: 'spikes#site_validate' match '/recording_source', to: 'spikes#recording_source' match '/musician_search_filter', to: 'spikes#musician_search_filter' + match '/band_search_filter', to: 'spikes#band_search_filter' # junk pages match '/help', to: 'static_pages#help' @@ -451,6 +452,7 @@ SampleApp::Application.routes.draw do # search match '/search' => 'api_search#index', :via => :get match '/search/musicians' => 'api_search#musicians', :via => [:get, :post] + match '/search/bands' => 'api_search#bands', :via => [:get, :post] # join requests match '/join_requests/:id' => 'api_join_requests#show', :via => :get, :as => 'api_join_request_detail' diff --git a/web/lib/tasks/sample_data.rake b/web/lib/tasks/sample_data.rake index 88c496ddf..0da3673f7 100644 --- a/web/lib/tasks/sample_data.rake +++ b/web/lib/tasks/sample_data.rake @@ -128,7 +128,7 @@ end def make_band_members Band.find_each do |bb| User.order('RANDOM()').limit(4).each do |uu| - BandMusician.create!({:user_id => uu.id, :band_id => bb.id}) + BandMusician.create({:user_id => uu.id, :band_id => bb.id}) end end end From d76f54b40e2604b5257b73070b2639fc3dfec442 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 19 May 2015 00:52:35 +0000 Subject: [PATCH 14/66] VRFS-3036 fixed broken merge --- ruby/lib/jam_ruby/models/base_search.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 007f2aecd..8a1672084 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -92,11 +92,7 @@ module JamRuby def self.create_search(user) ms = self.new ms.user = user -<<<<<<< HEAD ms.data_blob = self.json_schema -======= - ms.data_blob = self::JSON_SCHEMA ->>>>>>> 5a6049c935340e61ed645060dbc9d24927c98d1e ms.save! ms end @@ -177,11 +173,7 @@ module JamRuby end def reset_filter -<<<<<<< HEAD self.data_blob = self.class.json_schema -======= - self.data_blob = self.class::JSON_SCHEMA ->>>>>>> 5a6049c935340e61ed645060dbc9d24927c98d1e self.save end @@ -195,11 +187,7 @@ module JamRuby end def is_blank? -<<<<<<< HEAD self.data_blob == self.class.json_schema -======= - self.data_blob == self.class::JSON_SCHEMA ->>>>>>> 5a6049c935340e61ed645060dbc9d24927c98d1e end def description From e794ccc7af875c028b6accbbcd66fd939a9cb35b Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 19 May 2015 05:48:29 +0000 Subject: [PATCH 15/66] VRFS-3036 bands to_join builder controls --- ruby/lib/jam_ruby/models/band_search.rb | 8 +- web/Gemfile | 2 +- .../member_search_filter.js.coffee | 92 +++++++++++-------- web/app/views/api_search/index.rabl | 25 ++--- .../views/spikes/band_search_filter.html.slim | 6 +- 5 files changed, 71 insertions(+), 62 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 0dae6a088..c7a6c64dd 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -88,8 +88,14 @@ module JamRuby def self.search_filter_meta return @@search_meta if @@search_meta + toJoinMeta = super(self.json_schema[BAND_SEARCH_TYPE_VALS[0]]) + toJoinMeta.merge!({ + KEY_BAND_TYPE => { keys: BAND_TYPE_VALS, map: BAND_TYPES }, + KEY_PLAY_COMMIT => { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS }, + KEY_TOUR_OPTION => { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS } + }) @@search_meta = { - BAND_SEARCH_TYPE_VALS[0] => super(self.json_schema[BAND_SEARCH_TYPE_VALS[0]]), + BAND_SEARCH_TYPE_VALS[0] => toJoinMeta, BAND_SEARCH_TYPE_VALS[1] => super(self.json_schema[BAND_SEARCH_TYPE_VALS[1]], { keys: HIRE_SORT_VALS, map: HIRE_SORT_ORDERS }), } diff --git a/web/Gemfile b/web/Gemfile index c06ceac7d..d0c2911fe 100644 --- a/web/Gemfile +++ b/web/Gemfile @@ -102,7 +102,7 @@ group :development, :test do # gem 'teaspoon' # gem 'teaspoon-jasmine' - # gem 'puma' + gem 'puma' end group :unix do gem 'therubyracer' #, '0.11.0beta8' diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index e8c82727e..06199b524 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -47,6 +47,9 @@ context.JK.BaseSearchFilter = class BaseSearchFilter searchMetaData: () => @searchMeta + filterData: () => + @searchFilter.data_blob + renderSearchFilter: () => $.when(@restGet()).done (sFilter) => this.loadSearchFilter(sFilter) @@ -68,7 +71,7 @@ context.JK.BaseSearchFilter = class BaseSearchFilter elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']' struct = this.searchMetaData()[identifier]['map'] keys = this.searchMetaData()[identifier]['keys'] - this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem) + this._populateSelectWithKeys(struct, this.filterData()[identifier], keys, elem) _populateSelectWithInt: (sourceStruct, selection, element) => struct = @@ -79,14 +82,22 @@ context.JK.BaseSearchFilter = class BaseSearchFilter _populateSortOrder: () => this._populateSelectIdentifier('sort_order') + _populateSkill: () => + elem = $ '#musician-search-filter-builder select[name=skill_level]' + this._populateSelectWithInt(@profileUtils.skillLevelMap, this.filterData().skill_level.toString(), elem) + + _populateGigs: () => + elem = $ '#musician-search-filter-builder select[name=concert_gigs]' + this._populateSelectWithInt(@profileUtils.gigMap, this.filterData().concert_gigs.toString(), elem) + _populateGenres: () => @screen.find('#search-filter-genres').empty() @rest.getGenres().done (genres) => genreTemplate = @screen.find('#template-search-filter-setup-genres').html() selected = '' $.each genres, (index, genre) => - if 0 < @searchFilter.data_blob.genres.length - genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) -> + if 0 < this.filterData().genres.length + genreMatch = $.grep(this.filterData().genres, (n, i) -> n == genre.id) else genreMatch = [] @@ -104,8 +115,8 @@ context.JK.BaseSearchFilter = class BaseSearchFilter instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html() selected = '' proficiency = '1' - if 0 < @searchFilter.data_blob.instruments.length - instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) -> + if 0 < this.filterData().instruments.length + instMatch = $.grep(this.filterData().instruments, (inst, i) -> yn = inst.instrument_id == instrument.id proficiency = inst.proficiency_level if yn yn) @@ -179,10 +190,10 @@ context.JK.BaseSearchFilter = class BaseSearchFilter performSearch: () => if this.willSearch(true) $.each this.searchMetaData().filter_keys.single, (index, key) => - @searchFilter[key] = this._builderSelectValue(key) + this.filterData()[key] = this._builderSelectValue(key) $.each this.searchMetaData().filter_keys.multi, (index, key) => - @searchFilter[key] = this._builderSelectMultiValue(key) - @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + this.filterData()[key] = this._builderSelectMultiValue(key) + @restPost({ filter: JSON.stringify(this.filterData()), page: @pageNumber }).done(this.didSearch) renderResultsHeader: () => @screen.find('#'+@searchType+'-search-filter-description').html(@searchResults.description) @@ -210,7 +221,7 @@ context.JK.BaseSearchFilter = class BaseSearchFilter if @pageNumber < @searchResults.page_count && this.willSearch(false) @screen.find('.paginate-wait').show() @pageNumber += 1 - @restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch) + @restPost({ filter: JSON.stringify(this.filterData()), page: @pageNumber }).done(this.didSearch) return true false @@ -255,10 +266,10 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF @searchFilter = JSON.parse(sFilter) args = - interests: @searchFilter.data_blob.interests - skill_level: @searchFilter.data_blob.skill_level - studio_sessions: @searchFilter.data_blob.studio_sessions - concert_gigs: @searchFilter.data_blob.concert_gigs + interests: this.filterData().interests + skill_level: this.filterData().skill_level + studio_sessions: this.filterData().studio_sessions + concert_gigs: this.filterData().concert_gigs template = context.JK.fillTemplate(@screen.find('#template-musician-search-filter').html(), args) @@ -288,15 +299,7 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF _populateStudio: () => elem = $ '#musician-search-filter-builder select[name=studio_sessions]' - this._populateSelectWithInt(@profileUtils.studioMap, @searchFilter.data_blob.studio_sessions.toString(), elem) - - _populateGigs: () => - elem = $ '#musician-search-filter-builder select[name=concert_gigs]' - this._populateSelectWithInt(@profileUtils.gigMap, @searchFilter.data_blob.concert_gigs.toString(), elem) - - _populateSkill: () => - elem = $ '#musician-search-filter-builder select[name=skill_level]' - this._populateSelectWithInt(@profileUtils.skillLevelMap, @searchFilter.data_blob.skill_level.toString(), elem) + this._populateSelectWithInt(@profileUtils.studioMap, this.filterData().studio_sessions.toString(), elem) _populateAges: () => @screen.find('#search-filter-ages').empty() @@ -305,9 +308,9 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF ageTemplate = @screen.find('#template-search-filter-setup-ages').html() selected = '' ageLabel = ages_map[key] - if 0 < @searchFilter.data_blob.ages.length + if 0 < this.filterData().ages.length key_val = key.toString() - ageMatch = $.grep(@searchFilter.data_blob.ages, (n, i) -> + ageMatch = $.grep(this.filterData().ages, (n, i) -> n == key_val) selected = 'checked' if ageMatch.length > 0 ageHtml = context.JK.fillTemplate(ageTemplate, @@ -534,19 +537,19 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter _searchFilterArgsToJoin: () => args = - tour_option: @searchFilter.data_blob.tour_option - skill_level: @searchFilter.data_blob.skill_level - play_commit: @searchFilter.data_blob.play_commit - band_type: @searchFilter.data_blob.band_type - concert_gigs: @searchFilter.data_blob.concert_gigs + tour_option: this.filterData().tour_option + skill_level: this.filterData().skill_level + play_commit: this.filterData().play_commit + band_type: this.filterData().band_type + concert_gigs: this.filterData().concert_gigs _searchFilterArgsToHire: () => args = - skill_level: @searchFilter.data_blob.skill_level - concert_gigs: @searchFilter.data_blob.concert_gigs - perform_samples: @searchFilter.data_blob.perform_samples - max_cost: @searchFilter.data_blob.max_cost - free_gigs: @searchFilter.data_blob.free_gigs + skill_level: this.filterData().skill_level + concert_gigs: this.filterData().concert_gigs + perform_samples: this.filterData().perform_samples + max_cost: this.filterData().max_cost + free_gigs: this.filterData().free_gigs _populateSearchFilterToJoin: () => this._populateInstruments() @@ -563,8 +566,8 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter @searchFilter = JSON.parse(sFilter) switch @searchSubType - when 'to_join' then args = _searchFilterArgsToJoin() - when 'to_hire' then args = _searchFilterArgsToHire() + when 'to_join' then args = this._searchFilterArgsToJoin() + when 'to_hire' then args = this._searchFilterArgsToHire() template = context.JK.fillTemplate(@screen.find('#template-band-search-filter-'+@searchSubType).html(), args) @@ -581,8 +584,17 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter this._populateSortOrder() switch @searchSubType - when 'to_join' then _populateSearchFilterToJoin() - when 'to_hire' then _populateSearchFilterToHire() + when 'to_join' then this._populateSearchFilterToJoin() + when 'to_hire' then this._populateSearchFilterToHire() + + _populateBandType: () => + this._populateSelectIdentifier('band_type') + + _populatePlayCommit: () => + this._populateSelectIdentifier('play_commit') + + _populateTourOption: () => + this._populateSelectIdentifier('tour_option') _populateSortOrder: () => this._populateSelectIdentifier('sort_order') @@ -642,3 +654,7 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter registerResultsPagination: () => super() + + filterData: () => + super()[@searchSubType] + diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index 14a00b499..d35bfcb3b 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -1,8 +1,6 @@ object @search -node :search_type do |ss| ss.search_type end - -if @search.is_a?(MusicianSearch) +if @search.is_a?(BaseSearch) node :page_count do |foo| @search.page_count @@ -19,7 +17,8 @@ if @search.is_a?(MusicianSearch) node :filter_json do |foo| @search.to_json end - + + if @search.is_a? MusicianSearch child(:results => :musicians) { attributes :id, :first_name, :last_name, :name, :city, :state, :country, :online, :musician, :photo_url, :biography, :regionname, :score, :full_score @@ -61,10 +60,6 @@ if @search.is_a?(MusicianSearch) elsif @search.is_a?(BandSearch) - node :page_count do |foo| - @search.page_count - end - child(:results => :bands) { attributes :id, :name, :city, :state, :country, :photo_url, :biography, :logo_url, :website @@ -79,21 +74,13 @@ elsif @search.is_a?(BandSearch) child :genres => :genres do attributes :genre_id, :description end - - child :users => :players do |pl| - node :user_id do |uu| uu.id end - node :photo_url do |uu| uu.photo_url end - node :name do |uu| uu.name end - node :instruments do |uu| uu.instruments.map(&:id).join(',') end - end - - node :follow_count do |band| @search.follow_count(band) end - node :recording_count do |band| @search.record_count(band) end - node :session_count do |band| @search.session_count(band) end } +end else +node :search_type do |ss| ss.search_type end + if @search.session_invite_search? child(:results => :suggestions) { node :value do |uu| uu.name end diff --git a/web/app/views/spikes/band_search_filter.html.slim b/web/app/views/spikes/band_search_filter.html.slim index 9dff2e51e..a98478205 100644 --- a/web/app/views/spikes/band_search_filter.html.slim +++ b/web/app/views/spikes/band_search_filter.html.slim @@ -1,15 +1,15 @@ = javascript_include_tag "profile_utils" = javascript_include_tag "member_search_filter" = stylesheet_link_tag "client/band" -#band_search_spike -= render "clients/band_search_filter" +#bands-screen + = render "clients/band_search_filter" javascript: var initialized = false; $(document).on('JAMKAZAM_READY', function(e, data) { setTimeout(function() { window.band_search_filter = new JK.BandSearchFilter(); - band_search_filter.init(); + band_search_filter.init(data.app); band_search_filter.afterShow(); }, 1) }); From 1a91704532fdad7f4d7162328b0e552286e00b6d Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 20 May 2015 06:25:22 +0000 Subject: [PATCH 16/66] VRFS-3036 band search filters --- ruby/lib/jam_ruby/models/band_search.rb | 2 +- .../member_search_filter.js.coffee | 14 ++++-- .../clients/_band_search_filter.html.slim | 48 ++++++++++++++++--- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index c7a6c64dd..87c0a335a 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -60,7 +60,7 @@ module JamRuby TOUR_OPTIONS = { TOUR_OPTION_VALS[0] => 'Any', TOUR_OPTION_VALS[1] => 'Yes', - TOUR_OPTION_VALS[1] => 'No', + TOUR_OPTION_VALS[2] => 'No', } PERF_SAMPLES_VALS = TOUR_OPTION_VALS.clone diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 06199b524..50d202289 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -83,11 +83,11 @@ context.JK.BaseSearchFilter = class BaseSearchFilter this._populateSelectIdentifier('sort_order') _populateSkill: () => - elem = $ '#musician-search-filter-builder select[name=skill_level]' + elem = $ '#'+@searchType+'-search-filter-builder select[name=skill_level]' this._populateSelectWithInt(@profileUtils.skillLevelMap, this.filterData().skill_level.toString(), elem) _populateGigs: () => - elem = $ '#musician-search-filter-builder select[name=concert_gigs]' + elem = $ '#'+@searchType+'-search-filter-builder select[name=concert_gigs]' this._populateSelectWithInt(@profileUtils.gigMap, this.filterData().concert_gigs.toString(), elem) _populateGenres: () => @@ -522,12 +522,18 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter this.showBuilderToHire() showBuilderToJoin: () => + @screen.find('.band-search-filter-builder-top-to_join').show() + @screen.find('.band-search-filter-builder-top-to_hire').hide() @searchSubType = 'to_join' this.showBuilder() + this._loadSearchFilter() if @searchFilter showBuilderToHire: () => + @screen.find('.band-search-filter-builder-top-to_join').hide() + @screen.find('.band-search-filter-builder-top-to_hire').show() @searchSubType = 'to_hire' this.showBuilder() + this._loadSearchFilter() if @searchFilter searchMetaData: () => @searchMeta[@searchSubType] @@ -563,8 +569,10 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter loadSearchFilter: (sFilter) => super(sFilter) - @searchFilter = JSON.parse(sFilter) + this._loadSearchFilter() + + _loadSearchFilter: () => switch @searchSubType when 'to_join' then args = this._searchFilterArgsToJoin() when 'to_hire' then args = this._searchFilterArgsToHire() diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index a80cd9f1d..31caf974b 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -4,7 +4,7 @@ div#band-search-filter-results.content-wrapper div#band-search-filter-results-header a#btn-band-search-builder-to_join.button-orange href="#" SEARCH FOR BAND TO JOIN - a#btn-band-search-reset-to_hire.button-grey href="#" SEARCH FOR BAND TO HIRE + a#btn-band-search-builder-to_hire.button-orange href="#" SEARCH FOR BAND TO HIRE div#band-search-filter-description div.clearall div#band-search-filter-spinner.spinner-large @@ -18,7 +18,7 @@ script#template-band-search-filter-to_join type="text/template" #bands-filter-to_join - #band-search-filter-builder-top.builder-section + .band-search-filter-builder-top.builder-section .col-left h2 search bands .col-right.builder-sort-order @@ -27,7 +27,7 @@ script#template-band-search-filter-to_join type="text/template" option selected="selected" value="{sort_order}" {sort_order} .clearall - #band-search-filter-builder-middle1.builder-section + .band-search-filter-builder-middle1.builder-section .col-left .field label for="search-filter-genres" Genres: @@ -37,12 +37,13 @@ script#template-band-search-filter-to_join type="text/template" .col-right .field label for="search-filter-instruments" - | Instruments & Skill Level: + | Looking for New Members with These Skills: .search-filter-setup-instruments.band-setup-genres.builder-instruments table#search-filter-instruments cellpadding="10" cellspacing="6" width="100%" + .clearall - #band-search-filter-builder-middle2.builder-section + .band-search-filter-builder-middle2.builder-section .col-left .field.builder-selector label Type: @@ -72,7 +73,42 @@ script#template-band-search-filter-to_join type="text/template" .clearall .clearall - #band-search-filter-builder-bottom.builder-section.builder-action-buttons + .band-search-filter-builder-bottom.builder-section.builder-action-buttons + .col-right + a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH + a#btn-band-search-cancel.builder-button.button-grey href="#" CANCEL + +script#template-band-search-filter-to_hire type="text/template" + #bands-filter-to_hire + .band-search-filter-builder-top-to_hire.builder-section + .col-left + h2 search bands + .col-right.builder-sort-order + .text-label Sort Results By: + select.easydropdown name="sort_order" + option selected="selected" value="{sort_order}" {sort_order} + .clearall + + .band-search-filter-builder-middle1.builder-section + .col-left + .field + label for="search-filter-genres" Genres: + .search-filter-setup-genres.band-setup-genres + table#search-filter-genres cellpadding="10" cellspacing="6" width="100%" + + .col-right + .field + label for="search-filter-instruments" + | Instruments & Skill Level: + .search-filter-setup-instruments.band-setup-genres.builder-instruments + table#search-filter-instruments cellpadding="10" cellspacing="6" width="100%" + .clearall + + .band-search-filter-builder-middle2.builder-section + .clearall + + .clearall + .band-search-filter-builder-bottom.builder-section.builder-action-buttons .col-right a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH a#btn-band-search-cancel.builder-button.button-grey href="#" CANCEL From 8d3247e084828a191552c9cd2a4222066168a058 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 20 May 2015 09:24:53 +0000 Subject: [PATCH 17/66] VRFS-3036 to hire builder --- ruby/lib/jam_ruby/models/band_search.rb | 6 ++-- .../member_search_filter.js.coffee | 6 ++++ .../clients/_band_search_filter.html.slim | 29 +++++++++++++++---- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 87c0a335a..bed8a2c26 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -94,10 +94,12 @@ module JamRuby KEY_PLAY_COMMIT => { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS }, KEY_TOUR_OPTION => { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS } }) + toHireMeta = super(self.json_schema[BAND_SEARCH_TYPE_VALS[1]], + { keys: HIRE_SORT_VALS, map: HIRE_SORT_ORDERS }) + toHireMeta.merge!({}) @@search_meta = { BAND_SEARCH_TYPE_VALS[0] => toJoinMeta, - BAND_SEARCH_TYPE_VALS[1] => super(self.json_schema[BAND_SEARCH_TYPE_VALS[1]], - { keys: HIRE_SORT_VALS, map: HIRE_SORT_ORDERS }), + BAND_SEARCH_TYPE_VALS[1] => toHireMeta, } end diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 50d202289..cd7f99325 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -566,6 +566,9 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter this._populateTourOption() _populateSearchFilterToHire: () => + this._populateSkill() + this._populateGigs() + this._populatePerformSamples() loadSearchFilter: (sFilter) => super(sFilter) @@ -607,6 +610,9 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter _populateSortOrder: () => this._populateSelectIdentifier('sort_order') + _populatePerformSamples: () => + this._populateSelectIdentifier('perform_samples') + _populateGenres: () => super() diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index 31caf974b..ab45177a6 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -97,11 +97,30 @@ script#template-band-search-filter-to_hire type="text/template" table#search-filter-genres cellpadding="10" cellspacing="6" width="100%" .col-right - .field - label for="search-filter-instruments" - | Instruments & Skill Level: - .search-filter-setup-instruments.band-setup-genres.builder-instruments - table#search-filter-instruments cellpadding="10" cellspacing="6" width="100%" + .field.builder-selector + label Status: + select.easydropdown name="skill_level" + option selected="selected" value="{skill_level}" {skill_level} + + .field.builder-selector + label Concert Gigs Played: + select.easydropdown name="concert_gigs" + option selected="selected" value="{concert_gigs}" {concert_gigs} + + .field.builder-selector + label Performance Sample Available: + select.easydropdown name="perform_samples" + option selected="selected" value="{perform_samples}" {perform_samples} + + .field.builder-selector + input type="checkbox" id="max_cost" name="{max_cost}" + | Find bands to play a paid gig at a cost not to exceed + input type="text" id="max_cost_amount" name="{max_cost}" + + .field.builder-selector + input type="checkbox" id="free_gigs" name="{free_gigs}" + | Find bands that will play free gigs + .clearall .band-search-filter-builder-middle2.builder-section From 3af55a3c149ef700aa2cd8cbd7f2a8c102eaa46b Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 21 May 2015 05:47:14 +0000 Subject: [PATCH 18/66] VRFS-3036 tohire builder --- ruby/lib/jam_ruby/models/band_search.rb | 6 ++++-- .../javascripts/member_search_filter.js.coffee | 12 +++++++++++- web/app/views/clients/_band_search_filter.html.slim | 8 +++----- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index bed8a2c26..272198c6f 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -81,7 +81,7 @@ module JamRuby KEY_GIGS => self::GIG_COUNTS[0].to_s, KEY_PERF_SAMPLES => self::PERF_SAMPLES[0].to_s, KEY_HIRE_MAX_COST => 0, - KEY_HIRE_FREE => 0, + KEY_HIRE_FREE => 1, }, } end @@ -96,7 +96,9 @@ module JamRuby }) toHireMeta = super(self.json_schema[BAND_SEARCH_TYPE_VALS[1]], { keys: HIRE_SORT_VALS, map: HIRE_SORT_ORDERS }) - toHireMeta.merge!({}) + toHireMeta.merge!({ + KEY_PERF_SAMPLES => { keys: PERF_SAMPLES_VALS, map: PERF_SAMPLES }, + }) @@search_meta = { BAND_SEARCH_TYPE_VALS[0] => toJoinMeta, BAND_SEARCH_TYPE_VALS[1] => toHireMeta, diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index cd7f99325..5dec03b88 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -550,12 +550,22 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter concert_gigs: this.filterData().concert_gigs _searchFilterArgsToHire: () => + if 0 < this.filterData().max_cost + has_max_cost = 'checked' + else + has_max_cost = '' + if 1==this.filterData().free_gigs + has_free_gigs = 'checked' + else + has_free_gigs = '' + args = skill_level: this.filterData().skill_level concert_gigs: this.filterData().concert_gigs perform_samples: this.filterData().perform_samples + has_max_cost: has_max_cost max_cost: this.filterData().max_cost - free_gigs: this.filterData().free_gigs + has_free_gigs: has_free_gigs _populateSearchFilterToJoin: () => this._populateInstruments() diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index ab45177a6..053cbe55d 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -113,13 +113,11 @@ script#template-band-search-filter-to_hire type="text/template" option selected="selected" value="{perform_samples}" {perform_samples} .field.builder-selector - input type="checkbox" id="max_cost" name="{max_cost}" - | Find bands to play a paid gig at a cost not to exceed - input type="text" id="max_cost_amount" name="{max_cost}" + Find bands to play a paid gig at a cost not to exceed + input type="text" id="max_cost_amount" name="max_cost" value="{max_cost}" .field.builder-selector - input type="checkbox" id="free_gigs" name="{free_gigs}" - | Find bands that will play free gigs + Find bands that will play free gigs .clearall From 777d4a39cbb5125afdca4850bea17c0135702c9a Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 21 May 2015 06:42:27 +0000 Subject: [PATCH 19/66] VRFS-3036 tohire builder --- web/Gemfile | 1 + .../javascripts/member_search_filter.js.coffee | 17 ++++++++++++++++- web/app/controllers/api_search_controller.rb | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/web/Gemfile b/web/Gemfile index d0c2911fe..308aee8d5 100644 --- a/web/Gemfile +++ b/web/Gemfile @@ -103,6 +103,7 @@ group :development, :test do # gem 'teaspoon' # gem 'teaspoon-jasmine' gem 'puma' + gem 'byebug' end group :unix do gem 'therubyracer' #, '0.11.0beta8' diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 5dec03b88..8bdbb8407 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -521,6 +521,9 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter @screen.find('#btn-'+@searchType+'-search-builder-to_hire').on 'click', => this.showBuilderToHire() + isToHire: () => + 'to_hire' == @searchSubType + showBuilderToJoin: () => @screen.find('.band-search-filter-builder-top-to_join').show() @screen.find('.band-search-filter-builder-top-to_hire').hide() @@ -645,7 +648,19 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter super('subtype='+@searchSubType) performSearch: () => - super() + if this.willSearch(true) + filterPost = this.filterData() + $.each this.searchMetaData().filter_keys.single, (index, key) => + filterPost[key] = this._builderSelectValue(key) + $.each this.searchMetaData().filter_keys.multi, (index, key) => + filterPost[key] = this._builderSelectMultiValue(key) + + if this.isToHire() + filterPost['max_cost'] = parseInt($('#max_cost_amount').val()) + filterPost['free_gigs'] = if $('#free_gigs').prop('checked') then 1 else 0 + + postData = { subtype: @searchSubType, filter: JSON.stringify(filterPost), page: @pageNumber } + @restPost(postData).done(this.didSearch) renderResultsHeader: () => super() diff --git a/web/app/controllers/api_search_controller.rb b/web/app/controllers/api_search_controller.rb index be15b0074..54e3ab5b0 100644 --- a/web/app/controllers/api_search_controller.rb +++ b/web/app/controllers/api_search_controller.rb @@ -60,7 +60,7 @@ class ApiSearchController < ApiController @search = sobj.reset_search_results(params[:subtype]) else json = JSON.parse(filter, :create_additions => false) - @search = sobj.search_results_page(json, [params[:page].to_i, 1].max) + @search = sobj.search_results_page(params[:subtype], json, [params[:page].to_i, 1].max) end respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index' end From 14bce171c80a7f50456c8526fb615fa3ff7b6456 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Fri, 22 May 2015 07:48:05 +0000 Subject: [PATCH 20/66] VRFS-3036 fixed nits --- .../assets/javascripts/member_search_filter.js.coffee | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 8bdbb8407..8bd429fbd 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -94,14 +94,16 @@ context.JK.BaseSearchFilter = class BaseSearchFilter @screen.find('#search-filter-genres').empty() @rest.getGenres().done (genres) => genreTemplate = @screen.find('#template-search-filter-setup-genres').html() - selected = '' $.each genres, (index, genre) => if 0 < this.filterData().genres.length genreMatch = $.grep(this.filterData().genres, (n, i) -> n == genre.id) else - genreMatch = [] - selected = 'checked' if genreMatch.length > 0 + genreMatch = [] + if genreMatch.length > 0 + selected = 'checked' + else + selected = '' genreHtml = context.JK.fillTemplate(genreTemplate, id: genre.id description: genre.description @@ -148,7 +150,8 @@ context.JK.BaseSearchFilter = class BaseSearchFilter vals.push instrument else elem.each (idx) -> - vals.push $(this).val() + if $(this).prop('checked') + vals.push $(this).val() vals willSearch: (reload) => From b5f46329b337323ea28b079c2c08a69bf08b0bc2 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Fri, 22 May 2015 08:09:52 +0000 Subject: [PATCH 21/66] VRFS-3036 tightening code --- .../assets/javascripts/member_search_filter.js.coffee | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 8bd429fbd..c5cacb8a6 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -94,16 +94,14 @@ context.JK.BaseSearchFilter = class BaseSearchFilter @screen.find('#search-filter-genres').empty() @rest.getGenres().done (genres) => genreTemplate = @screen.find('#template-search-filter-setup-genres').html() + filterGenres = this.filterData().genres $.each genres, (index, genre) => - if 0 < this.filterData().genres.length - genreMatch = $.grep(this.filterData().genres, (n, i) -> + if 0 < filterGenres.length + genreMatch = $.grep(filterGenres, (n, i) -> n == genre.id) else genreMatch = [] - if genreMatch.length > 0 - selected = 'checked' - else - selected = '' + if genreMatch.length > 0 then selected = 'checked' else selected = '' genreHtml = context.JK.fillTemplate(genreTemplate, id: genre.id description: genre.description From cb7b48b4ec1ab08d037a02176c1dd18bea968330 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Fri, 22 May 2015 12:09:14 +0000 Subject: [PATCH 22/66] VRFS-3036 band search querying --- ruby/lib/jam_ruby/models/band_search.rb | 69 +++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 272198c6f..afbf5657a 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -106,12 +106,73 @@ module JamRuby end def self.search_target_class - User + Band end - def do_search(params={}) - rel = User.musicians.where('users.id <> ?', self.user.id) - rel = self._sort_order(rel) + def _sort_order(rel, filter) + rel + end + + def _genres(rel, filter) + super(rel, filter) + end + + def _instruments(rel, filter) + rel + end + + def _concert_gigs(rel, filter) + rel + end + + def _band_type(rel, filter) + case filter[KEY_BAND_TYPE] + when GenrePlayer::VIRTUAL_BAND: rel.where(band_type: GenrePlayer::VIRTUAL_BAND) + when GenrePlayer::TRADITIONAL_BAND: rel.where(band_type: GenrePlayer::TRADITIONAL_BAND) + default: rel + end + end + + def _play_commit(rel, filter) + rel + end + + def _tour_option(rel, filter) + case filter[KEY_TOUR_OPTION] + when 'yes': rel.where(touring_option: true) + when 'no': rel.where(touring_option: false) + default: rel + end + end + + def _perform_samples(rel, filter) + rel + end + + def _max_cost(rel, filter) + rel + end + + def _free_gigs(rel, filter) + case filter[KEY_FREE_GIGS] + when 'yes': rel.where(free_gigs: true) + when 'no': rel.where(free_gigs: false) + default: rel + end + end + + def _skill_level(rel, filter) + rel + end + + def do_search(filter) + rel = Band.unscoped + filter.keys.each do |fkey| + mname = "_#{fkey}" + if self.responds_to?(mname) + rel = self.send(mname.to_sym, rel, filter) + end + end rel end From 2f28d3a342bcdccc15425854bd70f67ef5f9eb2c Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 26 May 2015 06:39:43 +0000 Subject: [PATCH 23/66] VRFS-3036 band query --- ruby/lib/jam_ruby/models/band_search.rb | 51 +++++++++++++++------ ruby/lib/jam_ruby/models/base_search.rb | 8 ++++ ruby/lib/jam_ruby/models/musician_search.rb | 12 ----- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index afbf5657a..ef1ce930b 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -42,9 +42,9 @@ module JamRuby } PLAY_COMMIT_VALS = [ANY_VAL_STR, - '0', '1', '2', + '3', ] PLAY_COMMITS = { PLAY_COMMIT_VALS[0] => 'Any', @@ -117,31 +117,38 @@ module JamRuby super(rel, filter) end - def _instruments(rel, filter) - rel - end - def _concert_gigs(rel, filter) + gg = filter[KEY_GIGS].to_i + rel = rel.where(concert_count: gg) if 0 <= gg rel end def _band_type(rel, filter) case filter[KEY_BAND_TYPE] - when GenrePlayer::VIRTUAL_BAND: rel.where(band_type: GenrePlayer::VIRTUAL_BAND) - when GenrePlayer::TRADITIONAL_BAND: rel.where(band_type: GenrePlayer::TRADITIONAL_BAND) - default: rel + when GenrePlayer::VIRTUAL_BAND + rel.where(band_type: GenrePlayer::VIRTUAL_BAND) + when GenrePlayer::TRADITIONAL_BAND + rel.where(band_type: GenrePlayer::TRADITIONAL_BAND) + else + rel end end def _play_commit(rel, filter) + unless ANY_VAL_STR == filter[KEY_PLAY_COMMIT] + rel = rel.where(play_commitment: filter[KEY_PLAY_COMMIT].to_i) + end rel end def _tour_option(rel, filter) case filter[KEY_TOUR_OPTION] - when 'yes': rel.where(touring_option: true) - when 'no': rel.where(touring_option: false) - default: rel + when 'yes' + rel.where(touring_option: true) + when 'no' + rel.where(touring_option: false) + else + rel end end @@ -150,19 +157,33 @@ module JamRuby end def _max_cost(rel, filter) + if 0 < (max_cost = filter[KEY_HIRE_MAX_COST].to_i) + col = Band.arel_table[:gig_minimum] + rel = rel.where(col.lteq(max_cost)) + end rel end def _free_gigs(rel, filter) case filter[KEY_FREE_GIGS] - when 'yes': rel.where(free_gigs: true) - when 'no': rel.where(free_gigs: false) - default: rel + when 'yes' + rel.where(free_gigs: true) + when 'no' + rel.where(free_gigs: false) + else + rel end end def _skill_level(rel, filter) - rel + case filter[KEY_SKILL_LEVEL].to_i + when SKILL_VALS[1] + rel.where(free_gigs: true) + when SKILL_VALS[2] + rel.where(paid_gigs: true) + else + rel + end end def do_search(filter) diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 8a1672084..46f244c93 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -111,6 +111,14 @@ module JamRuby end def _instruments(rel) + unless (instruments = json[KEY_INSTRUMENTS]).blank? + instsql = "SELECT player_id FROM musicians_instruments WHERE ((" + instsql += instruments.collect do |inst| + "instrument_id = '#{inst['instrument_id']}' AND proficiency_level = #{inst['proficiency_level']}" + end.join(") OR (") + instsql += "))" + rel = rel.where("#{self.class.search_target_class.table_name}users.id IN (#{instsql})") + end rel end diff --git a/ruby/lib/jam_ruby/models/musician_search.rb b/ruby/lib/jam_ruby/models/musician_search.rb index 8f97d8a43..8d1713fa6 100644 --- a/ruby/lib/jam_ruby/models/musician_search.rb +++ b/ruby/lib/jam_ruby/models/musician_search.rb @@ -69,18 +69,6 @@ module JamRuby User end - def _instruments(rel) - unless (instruments = json['instruments']).blank? - instsql = "SELECT player_id FROM musicians_instruments WHERE ((" - instsql += instruments.collect do |inst| - "instrument_id = '#{inst['instrument_id']}' AND proficiency_level = #{inst['proficiency_level']}" - end.join(") OR (") - instsql += "))" - rel = rel.where("users.id IN (#{instsql})") - end - rel - end - def _ages(rel) unless (vals = json[KEY_AGES]).blank? return rel if vals.detect { |vv| ANY_VAL_INT == vv } From 7edee8d4941928f9e7df5277c9712b889c00ebe8 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 26 May 2015 08:43:11 +0000 Subject: [PATCH 24/66] VRFS-3036 first pass testing --- ruby/lib/jam_ruby/models/band_search.rb | 53 ++-- ruby/lib/jam_ruby/models/base_search.rb | 8 +- .../models/band_filter_search_spec.rb | 232 +++--------------- 3 files changed, 61 insertions(+), 232 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index ef1ce930b..afab8d770 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -4,6 +4,8 @@ module JamRuby cattr_accessor :jschema, :search_meta attr_accessor :user_counters + serialize :data_blob, JSON + KEY_BAND_SEARCH_TYPE = 'band_search_type' KEY_BAND_TYPE = 'band_type' KEY_PLAY_COMMIT = 'play_commit' @@ -12,10 +14,13 @@ module JamRuby KEY_HIRE_MAX_COST = 'max_cost' KEY_HIRE_FREE = 'free_gigs' - BAND_SEARCH_TYPE_VALS = %W{ to_join to_hire } + TO_JOIN = 'to_join' + TO_HIRE = 'to_hire' + + BAND_SEARCH_TYPE_VALS = [TO_JOIN, TO_HIRE] BAND_SEARCH_TYPES = { - BAND_SEARCH_TYPE_VALS[0] => 'search bands', - BAND_SEARCH_TYPE_VALS[1] => 'search bands to hire', + TO_JOIN => 'search bands', + TO_HIRE => 'search bands to hire', } SORT_VALS = %W{ distance latency } @@ -69,12 +74,12 @@ module JamRuby def self.json_schema return @@jschema if @@jschema @@jschema = { - BAND_SEARCH_TYPE_VALS[0] => BaseSearch.json_schema.merge({ + TO_JOIN => BaseSearch.json_schema.merge({ KEY_BAND_TYPE => BAND_TYPE_VALS[0], KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0], KEY_TOUR_OPTION => TOUR_OPTION_VALS[0], }), - BAND_SEARCH_TYPE_VALS[1] => { + TO_HIRE => { KEY_SORT_ORDER => self::HIRE_SORT_VALS[0], KEY_GENRES => [], KEY_SKILL => self::SKILL_VALS[0].to_s, @@ -88,20 +93,20 @@ module JamRuby def self.search_filter_meta return @@search_meta if @@search_meta - toJoinMeta = super(self.json_schema[BAND_SEARCH_TYPE_VALS[0]]) + toJoinMeta = super(self.json_schema[TO_JOIN]) toJoinMeta.merge!({ KEY_BAND_TYPE => { keys: BAND_TYPE_VALS, map: BAND_TYPES }, KEY_PLAY_COMMIT => { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS }, KEY_TOUR_OPTION => { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS } }) - toHireMeta = super(self.json_schema[BAND_SEARCH_TYPE_VALS[1]], + toHireMeta = super(self.json_schema[TO_HIRE], { keys: HIRE_SORT_VALS, map: HIRE_SORT_ORDERS }) toHireMeta.merge!({ KEY_PERF_SAMPLES => { keys: PERF_SAMPLES_VALS, map: PERF_SAMPLES }, }) @@search_meta = { - BAND_SEARCH_TYPE_VALS[0] => toJoinMeta, - BAND_SEARCH_TYPE_VALS[1] => toHireMeta, + TO_JOIN => toJoinMeta, + TO_HIRE => toHireMeta, } end @@ -176,7 +181,7 @@ module JamRuby end def _skill_level(rel, filter) - case filter[KEY_SKILL_LEVEL].to_i + case filter[KEY_SKILL].to_i when SKILL_VALS[1] rel.where(free_gigs: true) when SKILL_VALS[2] @@ -190,7 +195,7 @@ module JamRuby rel = Band.unscoped filter.keys.each do |fkey| mname = "_#{fkey}" - if self.responds_to?(mname) + if self.respond_to?(mname) rel = self.send(mname.to_sym, rel, filter) end end @@ -198,7 +203,7 @@ module JamRuby end def search_includes(rel) - rel.includes([:instruments, :followings, :friends]) + rel.includes([:instruments]) end def process_results_page(_results) @@ -210,20 +215,8 @@ module JamRuby # this gets counts for each search result @results.each do |bb| counters = { } - counters[COUNT_FOLLOW] = Follow.where(:followable_id => bb.id).count - counters[COUNT_RECORD] = Recording.where(:band_id => bb.id).count - counters[COUNT_SESSION] = MusicSession.where(:band_id => bb.id).count @user_counters[bb.id] << counters end - - # this section determines follow/like/friend status for each search result - # so that action links can be activated or not - - rel = Band.select("bands.id AS bid") - rel = rel.joins("LEFT JOIN follows ON follows.user_id = '#{user.id}'") - rel = rel.where(["bands.id IN (#{mids}) AND follows.followable_id = bands.id"]) - rel.all.each { |val| @user_counters[val.bid] << RESULT_FOLLOW } - else @user_counters = {} end @@ -297,20 +290,24 @@ module JamRuby self.save end - def reset_search_results(subtype=BAND_SEARCH_TYPE_VALS[0]) + def reset_search_results(subtype=TO_JOIN) reset_filter(subtype) search_results_page(subtype) end - def self.search_filter_json(user, subtype=BAND_SEARCH_TYPE_VALS[0]) + def self.search_filter_json(user, subtype=TO_JOIN) self.user_search_filter(user).json[subtype] end - def search_results_page(subtype=BAND_SEARCH_TYPE_VALS[0], filter=nil, page=1) + def search_filter_for_subtype(subtype) + self.data_blob[subtype] + end + + def search_results_page(subtype=TO_JOIN, filter=nil, page=1) if filter reset_filter(subtype, filter) else - filter = self.data_blob[subtype] + filter = self.search_filter_for_subtype(subtype) end rel = do_search(filter) diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 46f244c93..b1bf0a090 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -100,8 +100,8 @@ module JamRuby def self.search_target_class end - def _genres(rel) - gids = json[KEY_GENRES] + def _genres(rel, query_data=json) + gids = query_data[KEY_GENRES] unless gids.blank? gidsql = gids.join("','") gpsql = "SELECT player_id FROM genre_players WHERE (player_type = '#{self.class.search_target_class.name}' AND genre_id IN ('#{gidsql}'))" @@ -110,8 +110,8 @@ module JamRuby rel end - def _instruments(rel) - unless (instruments = json[KEY_INSTRUMENTS]).blank? + def _instruments(rel, query_data=json) + unless (instruments = query_data[KEY_INSTRUMENTS]).blank? instsql = "SELECT player_id FROM musicians_instruments WHERE ((" instsql += instruments.collect do |inst| "instrument_id = '#{inst['instrument_id']}' AND proficiency_level = #{inst['proficiency_level']}" diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index d2114f13c..1d7f47553 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -1,6 +1,19 @@ require 'spec_helper' -describe 'Band search' do +describe 'Band Search Model' do + + let!(:searcher) { FactoryGirl.create(:austin_user) } + let!(:search) { BandSearch.user_search_filter(searcher) } + + let!(:austin_user) { FactoryGirl.create(:austin_user) } + let!(:dallas_user) { FactoryGirl.create(:dallas_user) } + let!(:miami_user) { FactoryGirl.create(:miami_user) } + let!(:seattle_user) { FactoryGirl.create(:seattle_user) } + + let!(:user_types) { [:austin_user, :dallas_user, :miami_user, :seattle_user] } + + let!(:to_join) { search.search_filter_for_subtype(BandSearch::TO_JOIN) } + let!(:to_hire) { search.search_filter_for_subtype(BandSearch::TO_HIRE) } before(:each) do Band.delete_all @@ -16,215 +29,34 @@ describe 'Band search' do FactoryGirl.create(:band_musician, :band => bb, :user => FactoryGirl.create(:user)) end end - end - context 'default filter settings' do + describe "creates search obj" do - it "finds all bands" do - # expects all the bands - num = Band.count - results = Search.band_filter({ :per_page => num }) - expect(results.results.count).to eq(num) + before(:all) do + User.delete_all + end + + it "associates to user" do + expect(search.user).to eq(searcher) + searcher.reload + expect(searcher.band_search).to eq(search) end - it "finds bands with proper ordering" do - # the ordering should be create_at since no followers exist - expect(Follow.count).to eq(0) - results = Search.band_filter({ :per_page => Band.count }) - - rbands = @bands.reverse - results.results.each_with_index do |uu, idx| - expect(uu.id).to eq(@bands.reverse[idx].id) - end - end - - it "sorts bands by followers" do - users = [] - 4.downto(1) { |nn| users << FactoryGirl.create(:user) } - - users.each_with_index do |u, index| - if index != 0 - f1 = Follow.new - f1.user = u - f1.followable = @band4 - f1.save - end - end - - users.each_with_index do |u, index| - if index != 0 - f1 = Follow.new - f1.user = u - f1.followable = @band3 - f1.save - end - end - - f1 = Follow.new - f1.user = users.first - f1.followable = @band2 - f1.save - - # establish sorting order - # @band4.followers.concat(users[1..-1]) - # @band3.followers.concat(users[1..3]) - # @band2.followers.concat(users[0]) - @bands.map(&:reload) - - expect(@band4.followers.count).to be 3 - expect(Follow.count).to be 7 - - # refresh the order to ensure it works right - users.each_with_index do |u, index| - if index != 0 - f1 = Follow.new - f1.user = u - f1.followable = @band2 - f1.save - end - end - - # @band2.followers.concat(users[1..-1]) - results = Search.band_filter({ :per_page => @bands.size }, users[0]) - expect(results.results[0].id).to eq(@band2.id) - - # check the follower count for given entry - expect(results.results[0].search_follow_count.to_i).not_to eq(0) - # check the follow relationship between current_user and result - expect(results.is_follower?(@band2)).to be true - end - - it 'paginates properly' do - # make sure pagination works right - params = { :per_page => 2, :page => 1 } - results = Search.band_filter(params) - expect(results.results.count).to be 2 + it "sets json" do + expect(search.search_filter_for_subtype(BandSearch::TO_JOIN)).to eq(BandSearch.json_schema[BandSearch::TO_JOIN]) + expect(search.search_filter_for_subtype(BandSearch::TO_HIRE)).to eq(BandSearch.json_schema[BandSearch::TO_HIRE]) end end - def make_session(band) - usr = band.users[0] - session = FactoryGirl.create(:active_music_session, :creator => usr, :description => "Session", :band => band) - FactoryGirl.create(:connection, :user => usr, :music_session => session) - user = FactoryGirl.create(:user) - session - end - - context 'band stat counters' do - - it "follow stat shows follower count" do - users = [] - 2.downto(1) { |nn| users << FactoryGirl.create(:user) } - - users.each do |u| - f1 = Follow.new - f1.user = u - f1.followable = @band1 - f1.save - end - - # establish sorting order - # @band1.followers.concat(users) - results = Search.band_filter({},@band1) - uu = results.results.detect { |mm| mm.id == @band1.id } - expect(uu).to_not be_nil - expect(results.follow_count(uu)).to eq(users.count) + describe "filtering by keys" do + it "filters by genre" do + filter = to_join + filter[BandSearch::KEY_GENRES] = [Band.first.genres.first.id] + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to be >= 1 end - - it "session stat shows session count" do - make_session(@band1) - @band1.reload - results = Search.band_filter({},@band1) - uu = results.results.detect { |mm| mm.id == @band1.id } - expect(uu).to_not be_nil - expect(results.session_count(uu)).to be 1 - end - - end - - context 'band sorting' do - - it "by plays" do - make_session(@band2) - make_session(@band2) - make_session(@band2) - make_session(@band1) - # order results by num recordings - results = Search.band_filter({ :orderby => 'plays' }) - expect(results.results[0].id).to eq(@band2.id) - expect(results.results[1].id).to eq(@band1.id) - end - - it "by now playing" do - # should get 1 result with 1 active session - session = make_session(@band3) - #FactoryGirl.create(:active_music_session, :music_session => session) - - results = Search.band_filter({ :orderby => 'playing' }) - expect(results.results.count).to be 1 - expect(results.results.first.id).to eq(@band3.id) - - # should get 2 results with 2 active sessions - # sort order should be created_at DESC - session = make_session(@band4) - #FactoryGirl.create(:active_music_session, :music_session => session) - results = Search.band_filter({ :orderby => 'playing' }) - expect(results.results.count).to be 2 - expect(results.results[0].id).to eq(@band4.id) - expect(results.results[1].id).to eq(@band3.id) - end - - end - - - context 'filter settings' do - it "searches bands for a genre" do - genre = FactoryGirl.create(:genre) - @band1.genres << genre - @band1.reload - ggg = @band1.genres.detect { |gg| gg.id == genre.id } - expect(ggg).to_not be_nil - results = Search.band_filter({ :genre => ggg.id }) - results.results.each do |rr| - expect(rr.genres.detect { |gg| gg.id==ggg.id }.id).to eq(genre.id) - end - expect(results.results.count).to be 1 - end - - it "finds bands within a given distance of given location" do - pending 'distance search changes' - num = Band.count - expect(@band1.lat).to_not be_nil - # short distance - results = Search.band_filter({ :per_page => num, - :distance => 10, - :city => 'Apex' }, @band1) - expect(results.results.count).to be num - # long distance - results = Search.band_filter({ :per_page => num, - :distance => 1000, - :city => 'Miami', - :state => 'FL' }, @band1) - expect(results.results.count).to be num - end - - it "finds bands within a given distance of bands location" do - pending 'distance search changes' - expect(@band1.lat).to_not be_nil - # uses the location of @band1 - results = Search.band_filter({ :distance => 10, :per_page => Band.count }, @band1) - expect(results.results.count).to be Band.count - end - - it "finds no bands within a given distance of location" do - pending 'distance search changes' - expect(@band1.lat).to_not be_nil - results = Search.band_filter({ :distance => 10, :city => 'San Francisco' }, @band1) - expect(results.results.count).to be 0 - end - end end From 38881216fc74714459022492b0a0e939ede45ab7 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 27 May 2015 02:14:39 +0000 Subject: [PATCH 25/66] VRFS-3036 genre filter spec --- ruby/spec/jam_ruby/models/band_filter_search_spec.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index 1d7f47553..a615b6ec4 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -53,9 +53,13 @@ describe 'Band Search Model' do describe "filtering by keys" do it "filters by genre" do filter = to_join - filter[BandSearch::KEY_GENRES] = [Band.first.genres.first.id] + band_id = Band.first.genres.first.id + filter[BandSearch::KEY_GENRES] = [band_id] search.search_results_page(BandSearch::TO_JOIN, filter) - expect(search.results.count).to be >= 1 + expect(search.results.count).to eq(Band.all.map(&:genres).flatten.select { |bb| bb.id == band_id }.count) + end + + it "" do end end From 9757712977ffd97e00bfa27559a47f0217b8bece Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 27 May 2015 02:58:04 +0000 Subject: [PATCH 26/66] VRFS-3036 testing filter by key --- ruby/lib/jam_ruby/models/band_search.rb | 30 ++++++++-------- ruby/lib/jam_ruby/models/base_search.rb | 3 ++ .../models/band_filter_search_spec.rb | 35 +++++++++++++++++-- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index afab8d770..1615d8a3f 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -8,7 +8,7 @@ module JamRuby KEY_BAND_SEARCH_TYPE = 'band_search_type' KEY_BAND_TYPE = 'band_type' - KEY_PLAY_COMMIT = 'play_commit' + KEY_PLAY_COMMIT = 'play_commitment' KEY_TOUR_OPTION = 'tour_option' KEY_PERF_SAMPLES = 'perform_samples' KEY_HIRE_MAX_COST = 'max_cost' @@ -50,22 +50,24 @@ module JamRuby '1', '2', '3', + '4', ] PLAY_COMMITS = { PLAY_COMMIT_VALS[0] => 'Any', PLAY_COMMIT_VALS[1] => 'Infrequent', - PLAY_COMMIT_VALS[2] => 'Once a week', - PLAY_COMMIT_VALS[3] => 'More than once a week', + PLAY_COMMIT_VALS[2] => 'Once a Week', + PLAY_COMMIT_VALS[3] => '2-3 Times Per Week', + PLAY_COMMIT_VALS[4] => '4+ Times Per Week', } TOUR_OPTION_VALS = [ANY_VAL_STR, - 'yes', - 'no', + VAL_YES, + VAL_NO, ] TOUR_OPTIONS = { TOUR_OPTION_VALS[0] => 'Any', - TOUR_OPTION_VALS[1] => 'Yes', - TOUR_OPTION_VALS[2] => 'No', + TOUR_OPTION_VALS[1] => VAL_YES, + TOUR_OPTION_VALS[2] => VAL_NO, } PERF_SAMPLES_VALS = TOUR_OPTION_VALS.clone @@ -139,7 +141,7 @@ module JamRuby end end - def _play_commit(rel, filter) + def _play_commitment(rel, filter) unless ANY_VAL_STR == filter[KEY_PLAY_COMMIT] rel = rel.where(play_commitment: filter[KEY_PLAY_COMMIT].to_i) end @@ -148,9 +150,9 @@ module JamRuby def _tour_option(rel, filter) case filter[KEY_TOUR_OPTION] - when 'yes' + when VAL_YES rel.where(touring_option: true) - when 'no' + when VAL_NO rel.where(touring_option: false) else rel @@ -164,16 +166,16 @@ module JamRuby def _max_cost(rel, filter) if 0 < (max_cost = filter[KEY_HIRE_MAX_COST].to_i) col = Band.arel_table[:gig_minimum] - rel = rel.where(col.lteq(max_cost)) + rel = rel.where(col.lteq(max_cost)).where(col.gt(0)) end rel end def _free_gigs(rel, filter) - case filter[KEY_FREE_GIGS] - when 'yes' + case filter[KEY_HIRE_FREE] + when VAL_YES rel.where(free_gigs: true) - when 'no' + when VAL_NO rel.where(free_gigs: false) else rel diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index b1bf0a090..714c7bbb3 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -6,6 +6,9 @@ module JamRuby ANY_VAL_STR = 'any' ANY_VAL_INT = -1 + VAL_YES = 'yes' + VAL_NO = 'no' + PER_PAGE = 10 PG_SMALLINT_MAX = 32767 diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index a615b6ec4..e473e1554 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -51,16 +51,47 @@ describe 'Band Search Model' do end describe "filtering by keys" do + + let!(:band) { Band.first } + it "filters by genre" do filter = to_join - band_id = Band.first.genres.first.id + band_id = band.id filter[BandSearch::KEY_GENRES] = [band_id] search.search_results_page(BandSearch::TO_JOIN, filter) expect(search.results.count).to eq(Band.all.map(&:genres).flatten.select { |bb| bb.id == band_id }.count) end - it "" do + it "filters by free gigs" do + filter = to_join + band.update_attribute(BandSearch::KEY_HIRE_FREE, true) + filter[BandSearch::KEY_HIRE_FREE] = BandSearch::VAL_YES + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + expect(search.results[0].id).to eq(band.id) end + + it "filters by max cost" do + filter = to_join + band.update_attribute(:gig_minimum, 10) + filter[BandSearch::KEY_HIRE_MAX_COST] = 5 + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(0) + + filter[BandSearch::KEY_HIRE_MAX_COST] = 15 + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + end + + it "filters by play commitment" do + filter = to_join + band.update_attribute(BandSearch::KEY_PLAY_COMMIT, BandSearch::PLAY_COMMIT_VALS[1].to_i) + filter[BandSearch::KEY_PLAY_COMMIT] = BandSearch::PLAY_COMMIT_VALS[1] + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + expect(search.results[0].id).to eq(band.id) + end + end end From f66cf79cf2786aac9b072fc2ffb1f22c0724edc2 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 27 May 2015 04:10:05 +0000 Subject: [PATCH 27/66] VRFS-3036 band search filter tests --- ruby/lib/jam_ruby/models/band_search.rb | 43 +++---- ruby/lib/jam_ruby/models/base_search.rb | 2 +- ruby/lib/jam_ruby/models/musician_search.rb | 2 +- .../models/band_filter_search_spec.rb | 111 +++++++++++++----- 4 files changed, 106 insertions(+), 52 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 1615d8a3f..54e2384eb 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -7,9 +7,9 @@ module JamRuby serialize :data_blob, JSON KEY_BAND_SEARCH_TYPE = 'band_search_type' - KEY_BAND_TYPE = 'band_type' + KEY_BAND_STATUS = 'band_status' KEY_PLAY_COMMIT = 'play_commitment' - KEY_TOUR_OPTION = 'tour_option' + KEY_TOUR_OPTION = 'touring_option' KEY_PERF_SAMPLES = 'perform_samples' KEY_HIRE_MAX_COST = 'max_cost' KEY_HIRE_FREE = 'free_gigs' @@ -23,6 +23,8 @@ module JamRuby TO_HIRE => 'search bands to hire', } + SKILL_VAL_STRS = [ANY_VAL_STR, 'amateur', 'professional'] + SORT_VALS = %W{ distance latency } SORT_ORDERS = { SORT_VALS[0] => 'Distance to Me', @@ -36,14 +38,14 @@ module JamRuby HIRE_SORT_VALS[2] => 'Gig Minimum Price (High to Low)', } - BAND_TYPE_VALS = [ANY_VAL_STR, + BAND_STATUS_VALS = [ANY_VAL_STR, GenrePlayer::VIRTUAL_BAND, GenrePlayer::TRADITIONAL_BAND, ] - BAND_TYPES = { - BAND_TYPE_VALS[0] => 'Any', - BAND_TYPE_VALS[1] => 'Virtual Band', - BAND_TYPE_VALS[2] => 'Traditional Band', + BAND_STATUSS = { + BAND_STATUS_VALS[0] => 'Any', + BAND_STATUS_VALS[1] => 'Virtual Band', + BAND_STATUS_VALS[2] => 'Traditional Band', } PLAY_COMMIT_VALS = [ANY_VAL_STR, @@ -77,14 +79,15 @@ module JamRuby return @@jschema if @@jschema @@jschema = { TO_JOIN => BaseSearch.json_schema.merge({ - KEY_BAND_TYPE => BAND_TYPE_VALS[0], + KEY_SKILL => self::SKILL_VAL_STRS[0].to_s, + KEY_BAND_STATUS => BAND_STATUS_VALS[0], KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0], KEY_TOUR_OPTION => TOUR_OPTION_VALS[0], }), TO_HIRE => { KEY_SORT_ORDER => self::HIRE_SORT_VALS[0], KEY_GENRES => [], - KEY_SKILL => self::SKILL_VALS[0].to_s, + KEY_SKILL => self::SKILL_VAL_STRS[0].to_s, KEY_GIGS => self::GIG_COUNTS[0].to_s, KEY_PERF_SAMPLES => self::PERF_SAMPLES[0].to_s, KEY_HIRE_MAX_COST => 0, @@ -97,7 +100,7 @@ module JamRuby return @@search_meta if @@search_meta toJoinMeta = super(self.json_schema[TO_JOIN]) toJoinMeta.merge!({ - KEY_BAND_TYPE => { keys: BAND_TYPE_VALS, map: BAND_TYPES }, + KEY_BAND_STATUS => { keys: BAND_STATUS_VALS, map: BAND_STATUSS }, KEY_PLAY_COMMIT => { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS }, KEY_TOUR_OPTION => { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS } }) @@ -130,12 +133,12 @@ module JamRuby rel end - def _band_type(rel, filter) - case filter[KEY_BAND_TYPE] + def _band_status(rel, filter) + case filter[KEY_BAND_STATUS] when GenrePlayer::VIRTUAL_BAND - rel.where(band_type: GenrePlayer::VIRTUAL_BAND) + rel.where(band_status: GenrePlayer::VIRTUAL_BAND.sub('_band','')) when GenrePlayer::TRADITIONAL_BAND - rel.where(band_type: GenrePlayer::TRADITIONAL_BAND) + rel.where(band_status: GenrePlayer::TRADITIONAL_BAND.sub('_band','')) else rel end @@ -148,7 +151,7 @@ module JamRuby rel end - def _tour_option(rel, filter) + def _touring_option(rel, filter) case filter[KEY_TOUR_OPTION] when VAL_YES rel.where(touring_option: true) @@ -183,11 +186,11 @@ module JamRuby end def _skill_level(rel, filter) - case filter[KEY_SKILL].to_i - when SKILL_VALS[1] - rel.where(free_gigs: true) - when SKILL_VALS[2] - rel.where(paid_gigs: true) + case filter[KEY_SKILL] + when SKILL_VAL_STRS[1] + rel.where(band_type: SKILL_VAL_STRS[1]) + when SKILL_VAL_STRS[2] + rel.where(band_type: SKILL_VAL_STRS[2]) else rel end diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 714c7bbb3..7cac827e1 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -120,7 +120,7 @@ module JamRuby "instrument_id = '#{inst['instrument_id']}' AND proficiency_level = #{inst['proficiency_level']}" end.join(") OR (") instsql += "))" - rel = rel.where("#{self.class.search_target_class.table_name}users.id IN (#{instsql})") + rel = rel.where("#{self.class.search_target_class.table_name}.id IN (#{instsql})") end rel end diff --git a/ruby/lib/jam_ruby/models/musician_search.rb b/ruby/lib/jam_ruby/models/musician_search.rb index 8d1713fa6..695ca5236 100644 --- a/ruby/lib/jam_ruby/models/musician_search.rb +++ b/ruby/lib/jam_ruby/models/musician_search.rb @@ -113,7 +113,7 @@ module JamRuby def _skills(rel) if 0 < (val = json[KEY_SKILL].to_i) - rel = rel.where(['skill_level = ?', val]) + rel = rel.where(skill_level: val) end rel end diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index e473e1554..ea9e51daa 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -54,42 +54,93 @@ describe 'Band Search Model' do let!(:band) { Band.first } - it "filters by genre" do - filter = to_join - band_id = band.id - filter[BandSearch::KEY_GENRES] = [band_id] - search.search_results_page(BandSearch::TO_JOIN, filter) - expect(search.results.count).to eq(Band.all.map(&:genres).flatten.select { |bb| bb.id == band_id }.count) + context 'all search keys' do + it "filters by gigs" do + filter = to_join + band.update_attribute(:concert_count, BandSearch::GIG_COUNTS[2]) + filter[BandSearch::KEY_GIGS] = BandSearch::GIG_COUNTS[2] + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + expect(search.results[0].id).to eq(band.id) + end + it "filters by genre" do + filter = to_join + band_id = band.id + filter[BandSearch::KEY_GENRES] = [band_id] + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(Band.all.map(&:genres).flatten.select { |bb| bb.id == band_id }.count) + end + + it "filters by skill level" do + filter = to_join + band.update_attribute(:band_type, BandSearch::SKILL_VAL_STRS[1]) + filter[BandSearch::KEY_SKILL] = BandSearch::SKILL_VAL_STRS[1] + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + expect(search.results[0].id).to eq(band.id) + end + + it "filters by instruments" do + filter = to_join + minst = FactoryGirl.create(:musician_instrument) + band.musician_instruments << minst + band.save + filter[BandSearch::KEY_INSTRUMENTS] = [{'instrument_id' => minst.instrument_id, + 'proficiency_level' => minst.proficiency_level + }] + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + expect(search.results[0].id).to eq(band.id) + end + end - it "filters by free gigs" do - filter = to_join - band.update_attribute(BandSearch::KEY_HIRE_FREE, true) - filter[BandSearch::KEY_HIRE_FREE] = BandSearch::VAL_YES - search.search_results_page(BandSearch::TO_JOIN, filter) - expect(search.results.count).to eq(1) - expect(search.results[0].id).to eq(band.id) + context 'to_join' do + + let!(:filter) { to_join } + + it "filters by play commitment" do + band.update_attribute(BandSearch::KEY_PLAY_COMMIT, BandSearch::PLAY_COMMIT_VALS[1].to_i) + filter[BandSearch::KEY_PLAY_COMMIT] = BandSearch::PLAY_COMMIT_VALS[1] + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + expect(search.results[0].id).to eq(band.id) + end + + it "filters by tour option" do + band.update_attribute(BandSearch::KEY_TOUR_OPTION, true) + filter[BandSearch::KEY_TOUR_OPTION] = BandSearch::VAL_YES + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + expect(search.results[0].id).to eq(band.id) + end + end - it "filters by max cost" do - filter = to_join - band.update_attribute(:gig_minimum, 10) - filter[BandSearch::KEY_HIRE_MAX_COST] = 5 - search.search_results_page(BandSearch::TO_JOIN, filter) - expect(search.results.count).to eq(0) - filter[BandSearch::KEY_HIRE_MAX_COST] = 15 - search.search_results_page(BandSearch::TO_JOIN, filter) - expect(search.results.count).to eq(1) - end + context 'to_hire' do + + let!(:filter) { to_hire } + + it "filters by free gigs" do + band.update_attribute(BandSearch::KEY_HIRE_FREE, true) + filter[BandSearch::KEY_HIRE_FREE] = BandSearch::VAL_YES + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + expect(search.results[0].id).to eq(band.id) + end + + it "filters by max cost" do + band.update_attribute(:gig_minimum, 10) + filter[BandSearch::KEY_HIRE_MAX_COST] = 5 + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(0) + + filter[BandSearch::KEY_HIRE_MAX_COST] = 15 + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(1) + end - it "filters by play commitment" do - filter = to_join - band.update_attribute(BandSearch::KEY_PLAY_COMMIT, BandSearch::PLAY_COMMIT_VALS[1].to_i) - filter[BandSearch::KEY_PLAY_COMMIT] = BandSearch::PLAY_COMMIT_VALS[1] - search.search_results_page(BandSearch::TO_JOIN, filter) - expect(search.results.count).to eq(1) - expect(search.results[0].id).to eq(band.id) end end From 8480f582ad0749cf7c8de8b02b19491b0fc59347 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 27 May 2015 05:08:56 +0000 Subject: [PATCH 28/66] VRFS-3036 tuning band search filter spec --- ruby/lib/jam_ruby/models/band_search.rb | 13 ++++++++--- .../models/band_filter_search_spec.rb | 22 +++++++++++++------ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 54e2384eb..5a2d2646e 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -10,7 +10,7 @@ module JamRuby KEY_BAND_STATUS = 'band_status' KEY_PLAY_COMMIT = 'play_commitment' KEY_TOUR_OPTION = 'touring_option' - KEY_PERF_SAMPLES = 'perform_samples' + KEY_PERF_SAMPLES = 'performance_samples' KEY_HIRE_MAX_COST = 'max_cost' KEY_HIRE_FREE = 'free_gigs' @@ -162,8 +162,15 @@ module JamRuby end end - def _perform_samples(rel, filter) - rel + def _performance_samples(rel, filter) + case filter[KEY_PERF_SAMPLES] + when VAL_YES + rel.joins("LEFT OUTER JOIN performance_samples AS ps ON ps.player_id = bands.id AND player_type = '#{self.class.name}'").where(["ps.id IS NOT NULL"]) + when VAL_NO + rel.joins("LEFT OUTER JOIN performance_samples AS ps ON ps.player_id = bands.id AND player_type = '#{self.class.name}'").where(["ps.id IS NULL"]) + else + rel + end end def _max_cost(rel, filter) diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index ea9e51daa..8c923d7be 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -55,8 +55,10 @@ describe 'Band Search Model' do let!(:band) { Band.first } context 'all search keys' do + + let!(:filter) { to_join } + it "filters by gigs" do - filter = to_join band.update_attribute(:concert_count, BandSearch::GIG_COUNTS[2]) filter[BandSearch::KEY_GIGS] = BandSearch::GIG_COUNTS[2] search.search_results_page(BandSearch::TO_JOIN, filter) @@ -64,7 +66,6 @@ describe 'Band Search Model' do expect(search.results[0].id).to eq(band.id) end it "filters by genre" do - filter = to_join band_id = band.id filter[BandSearch::KEY_GENRES] = [band_id] search.search_results_page(BandSearch::TO_JOIN, filter) @@ -72,7 +73,6 @@ describe 'Band Search Model' do end it "filters by skill level" do - filter = to_join band.update_attribute(:band_type, BandSearch::SKILL_VAL_STRS[1]) filter[BandSearch::KEY_SKILL] = BandSearch::SKILL_VAL_STRS[1] search.search_results_page(BandSearch::TO_JOIN, filter) @@ -81,7 +81,6 @@ describe 'Band Search Model' do end it "filters by instruments" do - filter = to_join minst = FactoryGirl.create(:musician_instrument) band.musician_instruments << minst band.save @@ -125,7 +124,7 @@ describe 'Band Search Model' do it "filters by free gigs" do band.update_attribute(BandSearch::KEY_HIRE_FREE, true) filter[BandSearch::KEY_HIRE_FREE] = BandSearch::VAL_YES - search.search_results_page(BandSearch::TO_JOIN, filter) + search.search_results_page(BandSearch::TO_HIRE, filter) expect(search.results.count).to eq(1) expect(search.results[0].id).to eq(band.id) end @@ -133,14 +132,23 @@ describe 'Band Search Model' do it "filters by max cost" do band.update_attribute(:gig_minimum, 10) filter[BandSearch::KEY_HIRE_MAX_COST] = 5 - search.search_results_page(BandSearch::TO_JOIN, filter) + search.search_results_page(BandSearch::TO_HIRE, filter) expect(search.results.count).to eq(0) filter[BandSearch::KEY_HIRE_MAX_COST] = 15 - search.search_results_page(BandSearch::TO_JOIN, filter) + search.search_results_page(BandSearch::TO_HIRE, filter) expect(search.results.count).to eq(1) end + it "filters by perform samples" do + pending + PerformanceSample.create(searcher, {player: band, service_type: 'youtube', service_id: 'abc123'}) + filter[BandSearch::KEY_PERF_SAMPLES] = BandSearch::VAL_YES + search.search_results_page(BandSearch::TO_HIRE, filter) + expect(search.results.count).to eq(1) + expect(search.results[0].id).to eq(band.id) + end + end end From 1bd1794318549988a5d30ba8120de6e0797ce135 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 27 May 2015 08:20:46 +0000 Subject: [PATCH 29/66] VRFS-3036 band web search args --- ruby/lib/jam_ruby/models/band_search.rb | 113 +++++++++++++++--- ruby/lib/jam_ruby/models/base_search.rb | 14 --- ruby/lib/jam_ruby/models/musician_search.rb | 19 ++- .../models/band_filter_search_spec.rb | 10 +- .../member_search_filter.js.coffee | 6 +- 5 files changed, 128 insertions(+), 34 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 5a2d2646e..416a55ccf 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -7,6 +7,7 @@ module JamRuby serialize :data_blob, JSON KEY_BAND_SEARCH_TYPE = 'band_search_type' + KEY_BAND_TYPE = 'band_type' KEY_BAND_STATUS = 'band_status' KEY_PLAY_COMMIT = 'play_commitment' KEY_TOUR_OPTION = 'touring_option' @@ -23,7 +24,8 @@ module JamRuby TO_HIRE => 'search bands to hire', } - SKILL_VAL_STRS = [ANY_VAL_STR, 'amateur', 'professional'] + BAND_TYPE_VAL_STRS = [ANY_VAL_STR, 'amateur', 'professional'] + BAND_TYPES = BAND_TYPE_VAL_STRS.map(&:camelcase) SORT_VALS = %W{ distance latency } SORT_ORDERS = { @@ -42,7 +44,7 @@ module JamRuby GenrePlayer::VIRTUAL_BAND, GenrePlayer::TRADITIONAL_BAND, ] - BAND_STATUSS = { + BAND_STATUS = { BAND_STATUS_VALS[0] => 'Any', BAND_STATUS_VALS[1] => 'Virtual Band', BAND_STATUS_VALS[2] => 'Traditional Band', @@ -79,7 +81,7 @@ module JamRuby return @@jschema if @@jschema @@jschema = { TO_JOIN => BaseSearch.json_schema.merge({ - KEY_SKILL => self::SKILL_VAL_STRS[0].to_s, + KEY_BAND_TYPE => self::BAND_TYPE_VAL_STRS[0].to_s, KEY_BAND_STATUS => BAND_STATUS_VALS[0], KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0], KEY_TOUR_OPTION => TOUR_OPTION_VALS[0], @@ -87,8 +89,8 @@ module JamRuby TO_HIRE => { KEY_SORT_ORDER => self::HIRE_SORT_VALS[0], KEY_GENRES => [], - KEY_SKILL => self::SKILL_VAL_STRS[0].to_s, KEY_GIGS => self::GIG_COUNTS[0].to_s, + KEY_BAND_STATUS => BAND_STATUS_VALS[0], KEY_PERF_SAMPLES => self::PERF_SAMPLES[0].to_s, KEY_HIRE_MAX_COST => 0, KEY_HIRE_FREE => 1, @@ -100,7 +102,8 @@ module JamRuby return @@search_meta if @@search_meta toJoinMeta = super(self.json_schema[TO_JOIN]) toJoinMeta.merge!({ - KEY_BAND_STATUS => { keys: BAND_STATUS_VALS, map: BAND_STATUSS }, + KEY_BAND_TYPE => { keys: BAND_TYPE_VAL_STRS, map: BAND_TYPES }, + KEY_BAND_STATUS => { keys: BAND_STATUS_VALS, map: BAND_STATUS }, KEY_PLAY_COMMIT => { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS }, KEY_TOUR_OPTION => { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS } }) @@ -119,10 +122,6 @@ module JamRuby Band end - def _sort_order(rel, filter) - rel - end - def _genres(rel, filter) super(rel, filter) end @@ -192,17 +191,41 @@ module JamRuby end end - def _skill_level(rel, filter) - case filter[KEY_SKILL] - when SKILL_VAL_STRS[1] - rel.where(band_type: SKILL_VAL_STRS[1]) - when SKILL_VAL_STRS[2] + def _band_type(rel, filter) + case filter[KEY_BAND_TYPE] + when BAND_TYPE_VAL_STRS[1] + rel.where(band_type: BAND_TYPE_VAL_STRS[1]) + when BAND_TYPE_VAL_STRS[2] rel.where(band_type: SKILL_VAL_STRS[2]) else rel end end + def _sort_order(rel, filter) + val = filter[KEY_SORT_ORDER] + if 'distance' == val + # locidispid = self.user.last_jam_locidispid || 0 + # my_locid = locidispid / 1000000 + # rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") + # rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid") + # rel = rel.group("users.id, my_geo.geog, other_geo.geog") + # rel = rel.order('st_distance(my_geo.geog, other_geo.geog)') + + elsif 'latency' == val + # rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{self.user.id}'") + # rel = rel.order('current_scores.full_score ASC') + + elsif 'price_asc' == val + rel = rel.order('gig_minimum ASC') + + elsif 'price_desc' == val + rel = rel.order('gig_minimum DESC') + end + + rel + end + def do_search(filter) rel = Band.unscoped filter.keys.each do |fkey| @@ -332,5 +355,67 @@ module JamRuby process_results_page(rel.all) end + def description(filter) + return '' if self.is_blank? + + str = 'Current Search: ' + + str += 'Sort = ' + case sort = filter[KEY_SORT_ORDER] + when 'distance' + str += SORT_ORDERS[sort] + when 'latency' + str += SORT_ORDERS[sort] + when 'price_asc' + str += HIRE_SORT_ORDERS[sort] + when 'price_desc' + str += HIRE_SORT_ORDERS[sort] + end + + if (val = filter[KEY_BAND_TYPE].to_i) != ANY_VAL_INT + str += "; Band type = #{SKILL_LEVELS[val]}" + end + if (val = filter[KEY_BAND_STATUS]) != ANY_VAL_STR + str += "; Band status = #{BAND_STATUS[val]}" + end + if (val = filter[KEY_PLAY_COMMIT]) != ANY_VAL_STR + str += "; Play Commitment = #{PLAY_COMMITS[val]}" + end + if (val = filter[KEY_TOUR_OPTION]) != ANY_VAL_STR + str += "; Touring Options = #{TOUR_OPTIONS[val]}" + end + if (val = filter[KEY_PERF_SAMPLES]) != ANY_VAL_STR + str += "; Performance Samples = #{PERF_SAMPLES[val]}" + end + if (val = filter[KEY_HIRE_MAX_COST].to_i) > 0 + str += "; Maximum gig cost = $#{val}" + end + if filter[KEY_HIRE_FREE] + str += "; Bands playing free gigs" + end + if (val = filter[KEY_GIGS].to_i) != GIG_COUNTS[0] + str += "; Concert Gigs = #{GIG_LABELS[val]}" + end + if 0 < (val = filter[KEY_GENRES]).length + str += "; Genres = " + genres = Genre.where(["id IN (?)", val]).order('description').pluck(:description) + genres.each_with_index do |gg, idx| + str += "#{gg}" + str += ', ' unless idx==(genres.length-1) + end + end + if 0 < (val = filter[KEY_INSTRUMENTS]).length + str += "; Instruments = " + instr_ids = val.collect { |vv| vv['instrument_id'] } + instrs = Instrument.where(["id IN (?)", instr_ids]).order(:description) + instrs.each_with_index do |ii, idx| + proficiency = val.detect { |vv| vv['instrument_id'] == ii.id }['proficiency_level'] + str += "#{ii.description} (#{INSTRUMENT_PROFICIENCY[proficiency.to_i]})" + str += ', ' unless idx==(instrs.length-1) + end + end + str + end + end end diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 7cac827e1..462372796 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -51,7 +51,6 @@ module JamRuby KEY_SORT_ORDER => self::SORT_VALS[0], KEY_INSTRUMENTS => [], KEY_GENRES => [], - KEY_SKILL => self::SKILL_VALS[0].to_s, KEY_GIGS => self::GIG_COUNTS[0].to_s, } end @@ -139,19 +138,6 @@ module JamRuby end def _sort_order(rel) - val = json[self.class::KEY_SORT_ORDER] - if self.class::SORT_VALS[1] == val - locidispid = self.user.last_jam_locidispid || 0 - my_locid = locidispid / 1000000 - rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") - rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid") - rel = rel.group("users.id, my_geo.geog, other_geo.geog") - rel = rel.order('st_distance(my_geo.geog, other_geo.geog)') - else - rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{self.user.id}'") - rel = rel.order('current_scores.full_score ASC') - end - rel end def do_search(params={}) diff --git a/ruby/lib/jam_ruby/models/musician_search.rb b/ruby/lib/jam_ruby/models/musician_search.rb index 695ca5236..a5a2cd270 100644 --- a/ruby/lib/jam_ruby/models/musician_search.rb +++ b/ruby/lib/jam_ruby/models/musician_search.rb @@ -53,7 +53,8 @@ module JamRuby @@jschema = BaseSearch.json_schema.merge({ KEY_INTERESTS => INTEREST_VALS[0], KEY_STUDIOS => STUDIO_COUNTS[0].to_s, - KEY_AGES => [] + KEY_AGES => [], + KEY_SKILL => self::SKILL_VALS[0].to_s, }) end @@ -126,6 +127,22 @@ module JamRuby rel end + def _sort_order(rel) + val = json[self.class::KEY_SORT_ORDER] + if self.class::SORT_VALS[1] == val + locidispid = self.user.last_jam_locidispid || 0 + my_locid = locidispid / 1000000 + rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") + rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid") + rel = rel.group("users.id, my_geo.geog, other_geo.geog") + rel = rel.order('st_distance(my_geo.geog, other_geo.geog)') + else + rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{self.user.id}'") + rel = rel.order('current_scores.full_score ASC') + end + rel + end + def do_search(params={}) rel = User.musicians.where('users.id <> ?', self.user.id) rel = self._genres(rel) diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index 8c923d7be..5b9043866 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -72,9 +72,9 @@ describe 'Band Search Model' do expect(search.results.count).to eq(Band.all.map(&:genres).flatten.select { |bb| bb.id == band_id }.count) end - it "filters by skill level" do + it "filters by band_type" do band.update_attribute(:band_type, BandSearch::SKILL_VAL_STRS[1]) - filter[BandSearch::KEY_SKILL] = BandSearch::SKILL_VAL_STRS[1] + filter[BandSearch::KEY_BAND_TYPE] = BandSearch::SKILL_VAL_STRS[1] search.search_results_page(BandSearch::TO_JOIN, filter) expect(search.results.count).to eq(1) expect(search.results[0].id).to eq(band.id) @@ -90,6 +90,12 @@ describe 'Band Search Model' do search.search_results_page(BandSearch::TO_JOIN, filter) expect(search.results.count).to eq(1) expect(search.results[0].id).to eq(band.id) + + filter[BandSearch::KEY_INSTRUMENTS] = [{'instrument_id' => minst.instrument_id, + 'proficiency_level' => minst.proficiency_level + 1 + }] + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(0) end end diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index c5cacb8a6..3b802566a 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -616,16 +616,16 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter this._populateSelectIdentifier('band_type') _populatePlayCommit: () => - this._populateSelectIdentifier('play_commit') + this._populateSelectIdentifier('play_commitment') _populateTourOption: () => - this._populateSelectIdentifier('tour_option') + this._populateSelectIdentifier('touring_option') _populateSortOrder: () => this._populateSelectIdentifier('sort_order') _populatePerformSamples: () => - this._populateSelectIdentifier('perform_samples') + this._populateSelectIdentifier('performance_samples') _populateGenres: () => super() From e50dc6e20d32cf3f407db012ce10cac2fd917cf5 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 27 May 2015 12:17:42 +0000 Subject: [PATCH 30/66] VRFS-3036 band search results --- .../models/band_filter_search_spec.rb | 5 + .../member_search_filter.js.coffee | 112 ++++++++++++++++++ web/app/views/api_search/index.rabl | 11 ++ .../clients/_band_search_filter.html.slim | 68 ++++++++++- 4 files changed, 193 insertions(+), 3 deletions(-) diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index 5b9043866..80d998643 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -48,6 +48,11 @@ describe 'Band Search Model' do expect(search.search_filter_for_subtype(BandSearch::TO_HIRE)).to eq(BandSearch.json_schema[BandSearch::TO_HIRE]) end + it "loads all bands by default" do + search.search_results_page + expect(search.results.count).to eq(Band.count) + end + end describe "filtering by keys" do diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 3b802566a..fc40a05af 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -522,6 +522,8 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter @screen.find('#btn-'+@searchType+'-search-builder-to_hire').on 'click', => this.showBuilderToHire() + @resultsList = @screen.find('#band-search-filter-results-list') + isToHire: () => 'to_hire' == @searchSubType @@ -672,12 +674,122 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter bands = @searchResults.bands len = bands.length if 0 == len + @screen.find('#band-search-filter-results-list').hide() @screen.find('#band-search-filter-results-list-blank').show() @screen.find('#band-search-filter-results-list-blank').html('No results found') return else @screen.find('#band-search-filter-results-list-blank').hide() + @screen.find('#band-search-filter-results-list').show() + this.renderBands(bands) + renderBands: (bands) => + toolTip = undefined + ii = undefined + len = undefined + mTemplate = $('#template-find-band-row').html() + pTemplate = $('#template-band-player-info').html() + aTemplate = $('#template-band-action-btns').html() + eTemplate = $('#template-band-edit-btns').html() + bVals = undefined + bb = undefined + renderings = '' + instr_logos = undefined + instr = undefined + players = undefined + playerVals = undefined + aPlayer = undefined + isMember = undefined + ii = 0 + len = bands.length + while ii < len + bb = bands[ii] + instr_logos = '' + players = '' + playerVals = {} + isMember = false + jj = 0 + ilen = bb['players'].length + while jj < ilen + toolTip = '' + aPlayer = bb['players'][jj] + player_instrs = '' + iter_pinstruments = aPlayer['instruments'].split(',') + kk = 0 + klen = iter_pinstruments.length + while kk < klen + pinstr = iter_pinstruments[kk] + toolTip = '' + if pinstr of @instrument_logo_map + instr = @instrument_logo_map[pinstr].asset + toolTip = pinstr + player_instrs += '' + kk++ + if !isMember + isMember = aPlayer.user_id == context.JK.currentUserId + playerVals = + user_id: aPlayer.user_id + player_name: aPlayer.name + profile_url: '/client#/profile/' + aPlayer.user_id + avatar_url: context.JK.resolveAvatarUrl(aPlayer.photo_url) + player_instruments: player_instrs + players += context.JK.fillTemplate(pTemplate, playerVals) + jj++ + actionVals = undefined + band_actions = undefined + if isMember + actionVals = + profile_url: '/client#/bandProfile/' + bb.id + band_edit_url: '/client#/band/setup/' + bb.id + '/step1' + band_member_url: '/client#/band/setup/' + bb.id + '/step2' + band_actions = context.JK.fillTemplate(eTemplate, actionVals) + else + actionVals = + profile_url: '/client#/bandProfile/' + bb.id + button_follow: if bb['is_following'] then '' else 'button-orange' + button_message: 'button-orange' + band_actions = context.JK.fillTemplate(aTemplate, actionVals) + bgenres = '' + jj = 0 + ilen = bb['genres'].length + while jj < ilen + bgenres += bb['genres'][jj]['description'] + '
' + jj++ + bgenres += '
' + bVals = + avatar_url: context.JK.resolveBandAvatarUrl(bb.photo_url) + profile_url: '/client#/bandProfile/' + bb.id + band_name: bb.name + band_location: bb.city + ', ' + bb.state + genres: bgenres + instruments: instr_logos + biography: bb['biography'] + follow_count: bb['follow_count'] + recording_count: bb['recording_count'] + session_count: bb['session_count'] + band_id: bb['id'] + band_player_template: players + band_action_template: band_actions + $rendering = $(context.JK.fillTemplate(mTemplate, bVals)) + $offsetParent = @resultsList.closest('.content') + data = entity_type: 'band' + options = + positions: [ + 'top' + 'bottom' + 'right' + 'left' + ] + offsetParent: $offsetParent + context.JK.helpBubble $('.follower-count', $rendering), 'follower-count', data, options + context.JK.helpBubble $('.recording-count', $rendering), 'recording-count', data, options + context.JK.helpBubble $('.session-count', $rendering), 'session-count', data, options + @resultsList.append $rendering + ii++ + $('.search-m-follow').on 'click', this._bindFollowBand + context.JK.bindHoverEvents() + return + _bindMessageBand: () => _bindFriendBand: () => diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index d35bfcb3b..b2b043c61 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -74,6 +74,17 @@ elsif @search.is_a?(BandSearch) child :genres => :genres do attributes :genre_id, :description end + + child :users => :players do |pl| + node :user_id do |uu| uu.id end + node :photo_url do |uu| uu.photo_url end + node :name do |uu| uu.name end + node :instruments do |uu| uu.instruments.map(&:id).join(',') end + end + + node :follow_count do |band| @search.follow_count(band) end + node :recording_count do |band| @search.record_count(band) end + node :session_count do |band| @search.session_count(band) end } end diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index 053cbe55d..0ca5e8be0 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -11,7 +11,7 @@ div#band-search-filter-results-wrapper div#band-search-filter-results-list-blank - div#band-search-filter-results-list.content-wrapper + div.content-wrapper#band-search-filter-results-list div.paginate-wait Fetching more results... div.spinner-small @@ -143,5 +143,67 @@ script#template-search-filter-setup-genres type="text/template" tr td {description} -/! Session Row Template -script#template-search-band-row type="text/template" +script#template-find-band-row type="text/template" + .profile-band-list-result.band-list-result + .f11 + .left style="width:63px;margin-top:-12px;" + .avatar-small + img src="{avatar_url}" / + .right.mband-players style="width:265px; margin-top:-4px;" + table.musicians cellpadding="0" cellspacing="5" + | {band_player_template} + div style="margin-left: 63px; margin-right: 275px;margin-top: 12px;" + .first-row data-hint="top-row" + .lcol.left + .result-name + | {band_name} + .result-location + | {band_location} + br + #result_genres.nowrap.mt10 + | {genres} + .whitespace + .biography + | {biography} + .clearleft + .button-row + .lcol.stats.left + span.follower-count + | {follow_count} + img src="../assets/content/icon_followers.png" width="22" height="12" align="absmiddle" style="margin-right:4px;" + span.recording-count + | {recording_count} + img src="../assets/content/icon_recordings.png" width="12" height="13" align="absmiddle" style="margin-right:4px;" + span.session-count + | {session_count} + img src="../assets/content/icon_session_tiny.png" width="12" height="12" align="absmiddle" + .clearall + .result-list-button-wrapper data-band-id="{band_id}" + | {band_action_template} + .clearall + +script#template-band-action-btns type="text/template" + a.button-orange.smallbutton href="{profile_url}" + PROFILE + a.smallbutton.search-m-follow href="#" class="{button_follow}" + FOLLOW + +script#template-band-edit-btns type="text/template" + a.button-orange.smallbutton href="{profile_url}" + PROFILE + a.button-orange.smallbutton href="{band_edit_url}" + EDIT BAND + a.button-orange.smallbutton href="{band_member_url}" + INVITE + +script#template-band-player-info type="text/template" + tr + td + a.avatar-tiny href="{profile_url}" user-id="{user_id}" hoveraction="musician" + img src="{avatar_url}" + td style="padding: 0 4px;width:88px;" + a user-id="{user_id}" hoveraction="musician" href="{profile_url}" + strong + | {player_name} + td.instruments + | {player_instruments} From 4f5a39db181c3f662b6fdbe59f4bcd18b94e6e7c Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 27 May 2015 15:08:04 +0000 Subject: [PATCH 31/66] VRFS-3036 band results display --- ruby/lib/jam_ruby/models/band.rb | 1 + ruby/lib/jam_ruby/models/band_search.rb | 32 ++++++++----------- .../models/band_filter_search_spec.rb | 6 ++++ .../member_search_filter.js.coffee | 28 +++++++++++++--- web/app/views/api_search/index.rabl | 1 - .../clients/_band_search_filter.html.slim | 15 +++------ 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index a0c3a5033..2d656dba0 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -69,6 +69,7 @@ module JamRuby end def follower_count + # FIXME: this could be a lot of followers; calling size loads all the data into memory self.followers.size end diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 416a55ccf..327e40574 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -77,6 +77,10 @@ module JamRuby PERF_SAMPLES_VALS = TOUR_OPTION_VALS.clone PERF_SAMPLES = TOUR_OPTIONS.clone + COUNT_FOLLOW = :count_follow + COUNT_RECORD = :count_record + COUNT_SESSION = :count_session + def self.json_schema return @@jschema if @@jschema @@jschema = { @@ -241,16 +245,19 @@ module JamRuby rel.includes([:instruments]) end - def process_results_page(_results) + def _process_results_page(_results) @results = _results if user - @user_counters = @results.inject({}) { |hh,val| hh[val.id] = []; hh } - mids = "'#{@results.map(&:id).join("','")}'" + @user_counters = @results.inject({}) { |hh,val| hh[val.id] = {}; hh } # this gets counts for each search result @results.each do |bb| - counters = { } - @user_counters[bb.id] << counters + counters = { + COUNT_FOLLOW => Follow.where(:followable_id => bb.id).count, + COUNT_RECORD => Recording.where(:band_id => bb.id).count, + COUNT_SESSION => MusicSession.where(:band_id => bb.id).count + } + @user_counters[bb.id] = counters end else @user_counters = {} @@ -262,7 +269,7 @@ module JamRuby def _count(musician, key) if mm = @user_counters[musician.id] - return mm.detect { |ii| ii.is_a?(Hash) }[key] + return mm[key] end if @user_counters 0 end @@ -273,10 +280,6 @@ module JamRuby _count(musician, COUNT_FOLLOW) end - def friend_count(musician) - _count(musician, COUNT_FRIEND) - end - def record_count(musician) _count(musician, COUNT_RECORD) end @@ -285,13 +288,6 @@ module JamRuby _count(musician, COUNT_SESSION) end - def is_friend?(musician) - if mm = @user_counters[musician.id] - return mm.include?(RESULT_FRIEND) - end if @user_counters - false - end - def is_follower?(musician) if mm = @user_counters[musician.id] return mm.include?(RESULT_FOLLOW) @@ -352,7 +348,7 @@ module JamRuby rel = self.search_includes(rel) @page_count = rel.total_pages - process_results_page(rel.all) + _process_results_page(rel.all) end def description(filter) diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index 80d998643..f773ba0f6 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -53,6 +53,12 @@ describe 'Band Search Model' do expect(search.results.count).to eq(Band.count) end + it "has follower counts" do + Follow.create(user_id: searcher.id, followable: Band.first) + search.search_results_page + expect(search.user_counters[Band.first.id][BandSearch::COUNT_FOLLOW]).to eq(1) + end + end describe "filtering by keys" do diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index fc40a05af..ec3a050c6 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -790,12 +790,30 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter context.JK.bindHoverEvents() return - _bindMessageBand: () => - - _bindFriendBand: () => - _bindFollowBand: () => - + objThis = this + if 0 == $(this).closest('.button-orange').size() + return false + $(this).click (ee) -> + ee.preventDefault() + return + evt.stopPropagation() + newFollowing = {} + newFollowing.band_id = $(this).parent().data('band-id') + url = '/api/users/' + context.JK.currentUserId + '/followings' + $.ajax + type: 'POST' + dataType: 'json' + contentType: 'application/json' + url: url + data: JSON.stringify(newFollowing) + processData: false + success: (response) -> + $('div[data-band-id=' + newFollowing.band_id + '] .search-m-follow').removeClass('button-orange').addClass 'button-grey' + return + error: app.ajaxError(arguments) + return + _formatLocation: (band) -> friendRequestCallback: (user_id)=> diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index b2b043c61..812bf4f3d 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -49,7 +49,6 @@ if @search.is_a?(BaseSearch) end node :follow_count do |musician| @search.follow_count(musician) end - node :friend_count do |musician| @search.friend_count(musician) end node :recording_count do |musician| @search.record_count(musician) end node :session_count do |musician| @search.session_count(musician) end diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index 0ca5e8be0..958c5b66c 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -183,18 +183,13 @@ script#template-find-band-row type="text/template" .clearall script#template-band-action-btns type="text/template" - a.button-orange.smallbutton href="{profile_url}" - PROFILE - a.smallbutton.search-m-follow href="#" class="{button_follow}" - FOLLOW + a.button-orange.smallbutton href="{profile_url}" PROFILE + a.smallbutton.search-m-follow href="#" class="{button_follow}" FOLLOW script#template-band-edit-btns type="text/template" - a.button-orange.smallbutton href="{profile_url}" - PROFILE - a.button-orange.smallbutton href="{band_edit_url}" - EDIT BAND - a.button-orange.smallbutton href="{band_member_url}" - INVITE + a.button-orange.smallbutton href="{profile_url}" PROFILE + a.button-orange.smallbutton href="{band_edit_url}" EDIT BAND + a.button-orange.smallbutton href="{band_member_url}" INVITE script#template-band-player-info type="text/template" tr From dde84587b95a54a3b904ba37092befa2e81ceaa5 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 3 Jun 2015 06:41:21 +0000 Subject: [PATCH 32/66] VRFS-3036 syncing ui/json --- ruby/lib/jam_ruby/models/band_search.rb | 21 ++++++------ .../models/band_filter_search_spec.rb | 2 +- .../member_search_filter.js.coffee | 33 +++++++++++-------- .../clients/_band_search_filter.html.slim | 20 +++++------ 4 files changed, 41 insertions(+), 35 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 327e40574..d38291d54 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -114,6 +114,7 @@ module JamRuby toHireMeta = super(self.json_schema[TO_HIRE], { keys: HIRE_SORT_VALS, map: HIRE_SORT_ORDERS }) toHireMeta.merge!({ + KEY_BAND_STATUS => { keys: BAND_STATUS_VALS, map: BAND_STATUS }, KEY_PERF_SAMPLES => { keys: PERF_SAMPLES_VALS, map: PERF_SAMPLES }, }) @@search_meta = { @@ -267,8 +268,8 @@ module JamRuby private - def _count(musician, key) - if mm = @user_counters[musician.id] + def _count(band, key) + if mm = @user_counters[band.id] return mm[key] end if @user_counters 0 @@ -276,20 +277,20 @@ module JamRuby public - def follow_count(musician) - _count(musician, COUNT_FOLLOW) + def follow_count(band) + _count(band, COUNT_FOLLOW) end - def record_count(musician) - _count(musician, COUNT_RECORD) + def record_count(band) + _count(band, COUNT_RECORD) end - def session_count(musician) - _count(musician, COUNT_SESSION) + def session_count(band) + _count(band, COUNT_SESSION) end - def is_follower?(musician) - if mm = @user_counters[musician.id] + def is_follower?(band) + if mm = @user_counters[band.id] return mm.include?(RESULT_FOLLOW) end if @user_counters false diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index f773ba0f6..bab3b6e7f 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -56,7 +56,7 @@ describe 'Band Search Model' do it "has follower counts" do Follow.create(user_id: searcher.id, followable: Band.first) search.search_results_page - expect(search.user_counters[Band.first.id][BandSearch::COUNT_FOLLOW]).to eq(1) + expect(search.follow_count(Band.first)).to eq(1) end end diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index ec3a050c6..cd38bfebe 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -82,10 +82,6 @@ context.JK.BaseSearchFilter = class BaseSearchFilter _populateSortOrder: () => this._populateSelectIdentifier('sort_order') - _populateSkill: () => - elem = $ '#'+@searchType+'-search-filter-builder select[name=skill_level]' - this._populateSelectWithInt(@profileUtils.skillLevelMap, this.filterData().skill_level.toString(), elem) - _populateGigs: () => elem = $ '#'+@searchType+'-search-filter-builder select[name=concert_gigs]' this._populateSelectWithInt(@profileUtils.gigMap, this.filterData().concert_gigs.toString(), elem) @@ -323,6 +319,10 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF _populateGenres: () => super() + _populateSkill: () => + elem = $ '#'+@searchType+'-search-filter-builder select[name=skill_level]' + this._populateSelectWithInt(@profileUtils.skillLevelMap, this.filterData().skill_level.toString(), elem) + _populateInstruments: () => super() @@ -549,9 +549,9 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter _searchFilterArgsToJoin: () => args = - tour_option: this.filterData().tour_option - skill_level: this.filterData().skill_level - play_commit: this.filterData().play_commit + touring_option: this.filterData().touring_option + band_status: this.filterData().band_status + play_commitment: this.filterData().play_commitment band_type: this.filterData().band_type concert_gigs: this.filterData().concert_gigs @@ -566,9 +566,9 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter has_free_gigs = '' args = - skill_level: this.filterData().skill_level + band_status: this.filterData().band_status concert_gigs: this.filterData().concert_gigs - perform_samples: this.filterData().perform_samples + performance_samples: this.filterData().performance_samples has_max_cost: has_max_cost max_cost: this.filterData().max_cost has_free_gigs: has_free_gigs @@ -577,12 +577,12 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter this._populateInstruments() this._populateSkill() this._populateGigs() - this._populateBandType() this._populatePlayCommit() this._populateTourOption() + this._populateBandStatus() _populateSearchFilterToHire: () => - this._populateSkill() + this._populateBandStatus() this._populateGigs() this._populatePerformSamples() @@ -614,8 +614,12 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter when 'to_join' then this._populateSearchFilterToJoin() when 'to_hire' then this._populateSearchFilterToHire() - _populateBandType: () => - this._populateSelectIdentifier('band_type') + _populateSkill: () => + elem = $ '#'+@searchType+'-search-filter-builder select[name=band_type]' + this._populateSelectWithInt(@profileUtils.skillLevelMap, this.filterData().band_type.toString(), elem) + + _populateBandStatus: () => + this._populateSelectIdentifier('band_status') _populatePlayCommit: () => this._populateSelectIdentifier('play_commitment') @@ -642,7 +646,8 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter super(response) resetFilter: () => - super() + if this.willSearch(true) + @restPost({ filter: 'reset', subtype: @searchSubType }).done(this.didSearch) cancelFilter: () => super() diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index 958c5b66c..c7209f816 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -52,14 +52,14 @@ script#template-band-search-filter-to_join type="text/template" .field.builder-selector label Play Commitment: - select.easydropdown name="play_commit" - option selected="selected" value="{play_commit}" {play_commit} + select.easydropdown name="play_commitment" + option selected="selected" value="{play_commitment}" {play_commitment} .col-right .field.builder-selector label Status: - select.easydropdown name="skill_level" - option selected="selected" value="{skill_level}" {skill_level} + select.easydropdown name="band_status" + option selected="selected" value="{band_status}" {band_status} .field.builder-selector label Concert Gigs Played: @@ -68,8 +68,8 @@ script#template-band-search-filter-to_join type="text/template" .field.builder-selector label Touring Option: - select.easydropdown name="tour_option" - option selected="selected" value="{tour_option}" {tour_option} + select.easydropdown name="touring_option" + option selected="selected" value="{touring_option}" {touring_option} .clearall .clearall @@ -99,8 +99,8 @@ script#template-band-search-filter-to_hire type="text/template" .col-right .field.builder-selector label Status: - select.easydropdown name="skill_level" - option selected="selected" value="{skill_level}" {skill_level} + select.easydropdown name="band_status" + option selected="selected" value="{band_status}" {band_status} .field.builder-selector label Concert Gigs Played: @@ -109,8 +109,8 @@ script#template-band-search-filter-to_hire type="text/template" .field.builder-selector label Performance Sample Available: - select.easydropdown name="perform_samples" - option selected="selected" value="{perform_samples}" {perform_samples} + select.easydropdown name="performance_samples" + option selected="selected" value="{performance_samples}" {performance_samples} .field.builder-selector Find bands to play a paid gig at a cost not to exceed From 56af10afb3d5d3a646284fc981eae5143f5e18cf Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 4 Jun 2015 05:54:02 +0000 Subject: [PATCH 33/66] VRFS-3036 results / builder page swpping --- ruby/lib/jam_ruby/models/band_search.rb | 26 +++++----------- .../models/band_filter_search_spec.rb | 8 +++++ .../member_search_filter.js.coffee | 30 ++++++++++++++----- web/app/views/api_search/index.rabl | 6 +++- .../clients/_band_search_filter.html.slim | 10 +++++-- 5 files changed, 50 insertions(+), 30 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index d38291d54..1f5bd57e1 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -300,18 +300,8 @@ module JamRuby self.class.to_s end - def is_blank? - self.data_blob == self.class.json_schema - end - - def description - if self.is_blank? - return 'Click search button to look for musicians with similar interests, skill levels, etc.' - end - jj = self.json - str = 'Current Search: ' - str += "Sort = #{SORT_ORDERS[json_value(BandSearch::KEY_SORT_ORDER)]}" - str + def is_blank?(subtype=TO_JOIN) + self.search_filter_for_subtype(subtype) == self.class.json_schema[subtype] end def reset_filter(subtype, data=nil) @@ -352,9 +342,10 @@ module JamRuby _process_results_page(rel.all) end - def description(filter) - return '' if self.is_blank? + def description(subtype=TO_JOIN) + return '' if self.is_blank?(subtype) + filter = search_filter_for_subtype(subtype) str = 'Current Search: ' str += 'Sort = ' @@ -396,12 +387,9 @@ module JamRuby if 0 < (val = filter[KEY_GENRES]).length str += "; Genres = " genres = Genre.where(["id IN (?)", val]).order('description').pluck(:description) - genres.each_with_index do |gg, idx| - str += "#{gg}" - str += ', ' unless idx==(genres.length-1) - end + str += genres.join(', ') end - if 0 < (val = filter[KEY_INSTRUMENTS]).length + if 0 < ((val = filter[KEY_INSTRUMENTS]) || '').length str += "; Instruments = " instr_ids = val.collect { |vv| vv['instrument_id'] } instrs = Instrument.where(["id IN (?)", instr_ids]).order(:description) diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index bab3b6e7f..3a3b9cba3 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -59,6 +59,14 @@ describe 'Band Search Model' do expect(search.follow_count(Band.first)).to eq(1) end + it "render description" do + filter = to_join + filter[BandSearch::KEY_TOUR_OPTION] = BandSearch::VAL_YES + search.search_results_page(BandSearch::TO_JOIN, filter) + search.search_results_page + expect(search.description).to_not eq('') + end + end describe "filtering by keys" do diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index cd38bfebe..1e4584dfa 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -193,11 +193,6 @@ context.JK.BaseSearchFilter = class BaseSearchFilter @restPost({ filter: JSON.stringify(this.filterData()), page: @pageNumber }).done(this.didSearch) renderResultsHeader: () => - @screen.find('#'+@searchType+'-search-filter-description').html(@searchResults.description) - if @searchResults.is_blank_filter - @screen.find('#btn-'+@searchType+'-search-reset').hide() - else - @screen.find('#btn-'+@searchType+'-search-reset').show() renderResultsPage: () => @@ -345,7 +340,11 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF super() renderResultsHeader: () => - super() + @screen.find('#'+@searchType+'-search-filter-description').html(@searchResults.description) + if @searchResults.is_blank_filter + @screen.find('#btn-'+@searchType+'-search-reset').hide() + else + @screen.find('#btn-'+@searchType+'-search-reset').show() renderResultsPage: () => super() @@ -503,6 +502,7 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF registerResultsPagination: () => super() + context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter constructor: () -> @@ -521,12 +521,22 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter this.showBuilderToJoin() @screen.find('#btn-'+@searchType+'-search-builder-to_hire').on 'click', => this.showBuilderToHire() + @screen.find('#btn-'+@searchType+'-search-builder').on 'click', => + this.showBuilderActive() + @screen.find('#btn-'+@searchType+'-search-reset').on 'click', => + this.resetFilter() @resultsList = @screen.find('#band-search-filter-results-list') isToHire: () => 'to_hire' == @searchSubType + showBuilderActive: () => + if this.isToHire() + this.showBuilderToHire() + else + this.showBuilderToJoin() + showBuilderToJoin: () => @screen.find('.band-search-filter-builder-top-to_join').show() @screen.find('.band-search-filter-builder-top-to_hire').hide() @@ -671,7 +681,13 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter @restPost(postData).done(this.didSearch) renderResultsHeader: () => - super() + if @searchResults.is_blank_filter + @screen.find('#band-search-filter-results-blank').show() + @screen.find('#band-search-filter-results-filtered').hide() + else + @screen.find('#band-search-filter-results-blank').hide() + @screen.find('#band-search-filter-results-filtered').show() + @screen.find('#band-search-filter-description').html(@searchResults.description) renderResultsPage: () => super() diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index 812bf4f3d..9941f867e 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -11,13 +11,17 @@ if @search.is_a?(BaseSearch) end node :is_blank_filter do |foo| - @search.is_blank? + @search.is_blank?(params[:subtype]) end node :filter_json do |foo| @search.to_json end + node :description do |foo| + @search.description(params[:subtype]) + end + if @search.is_a? MusicianSearch child(:results => :musicians) { attributes :id, :first_name, :last_name, :name, :city, :state, :country, :online, :musician, :photo_url, :biography, :regionname, :score, :full_score diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index c7209f816..0e976c208 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -3,9 +3,13 @@ div#band-search-filter-results.content-wrapper div#band-search-filter-results-header - a#btn-band-search-builder-to_join.button-orange href="#" SEARCH FOR BAND TO JOIN - a#btn-band-search-builder-to_hire.button-orange href="#" SEARCH FOR BAND TO HIRE - div#band-search-filter-description + #band-search-filter-results-blank + a.button-orange#btn-band-search-builder-to_join href="#" SEARCH FOR BAND TO JOIN + a.button-orange#btn-band-search-builder-to_hire href="#" SEARCH FOR BAND TO HIRE + #band-search-filter-results-filtered + a.button-orange#btn-band-search-builder href="#" SEARCH + a.button-grey#btn-band-search-reset href="#" RESET + div#band-search-filter-description div.clearall div#band-search-filter-spinner.spinner-large From 965ee2e0bcd7e5599d83eb7958f0ade307ab1859 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 4 Jun 2015 07:38:16 +0000 Subject: [PATCH 34/66] VRFS-3036 tests for description --- ruby/lib/jam_ruby/models/band_search.rb | 48 ++++++----- .../models/band_filter_search_spec.rb | 79 ++++++++++++++++++- .../member_search_filter.js.coffee | 14 ++-- 3 files changed, 115 insertions(+), 26 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 1f5bd57e1..a81323769 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -25,7 +25,10 @@ module JamRuby } BAND_TYPE_VAL_STRS = [ANY_VAL_STR, 'amateur', 'professional'] - BAND_TYPES = BAND_TYPE_VAL_STRS.map(&:camelcase) + BAND_TYPES = { + BAND_TYPE_VAL_STRS[0] => BAND_TYPE_VAL_STRS[0].camelcase, + BAND_TYPE_VAL_STRS[1] => BAND_TYPE_VAL_STRS[1].camelcase, + } SORT_VALS = %W{ distance latency } SORT_ORDERS = { @@ -95,7 +98,7 @@ module JamRuby KEY_GENRES => [], KEY_GIGS => self::GIG_COUNTS[0].to_s, KEY_BAND_STATUS => BAND_STATUS_VALS[0], - KEY_PERF_SAMPLES => self::PERF_SAMPLES[0].to_s, + KEY_PERF_SAMPLES => self::PERF_SAMPLES_VALS[0], KEY_HIRE_MAX_COST => 0, KEY_HIRE_FREE => 1, }, @@ -358,37 +361,46 @@ module JamRuby str += HIRE_SORT_ORDERS[sort] when 'price_desc' str += HIRE_SORT_ORDERS[sort] - end + end if filter.has_key?(KEY_SORT_ORDER) + + if (val = filter[KEY_BAND_TYPE]) != ANY_VAL_STR + str += "; Band type = #{BAND_TYPES[val]}" + end if filter.has_key?(KEY_BAND_TYPE) - if (val = filter[KEY_BAND_TYPE].to_i) != ANY_VAL_INT - str += "; Band type = #{SKILL_LEVELS[val]}" - end if (val = filter[KEY_BAND_STATUS]) != ANY_VAL_STR str += "; Band status = #{BAND_STATUS[val]}" - end + end if filter.has_key?(KEY_BAND_STATUS) + if (val = filter[KEY_PLAY_COMMIT]) != ANY_VAL_STR - str += "; Play Commitment = #{PLAY_COMMITS[val]}" - end + str += "; Play commitment = #{PLAY_COMMITS[val]}" + end if filter.has_key?(KEY_PLAY_COMMIT) + if (val = filter[KEY_TOUR_OPTION]) != ANY_VAL_STR - str += "; Touring Options = #{TOUR_OPTIONS[val]}" - end + str += "; Touring options = #{TOUR_OPTIONS[val]}" + end if filter.has_key?(KEY_TOUR_OPTION) + if (val = filter[KEY_PERF_SAMPLES]) != ANY_VAL_STR - str += "; Performance Samples = #{PERF_SAMPLES[val]}" - end + str += "; Performance samples = #{PERF_SAMPLES[val]}" + end if filter.has_key?(KEY_PERF_SAMPLES) + if (val = filter[KEY_HIRE_MAX_COST].to_i) > 0 str += "; Maximum gig cost = $#{val}" - end + end if filter.has_key?(KEY_HIRE_MAX_COST) + if filter[KEY_HIRE_FREE] str += "; Bands playing free gigs" - end + end if filter.has_key?(KEY_HIRE_FREE) + if (val = filter[KEY_GIGS].to_i) != GIG_COUNTS[0] str += "; Concert Gigs = #{GIG_LABELS[val]}" - end + end if filter.has_key?(KEY_GIGS) + if 0 < (val = filter[KEY_GENRES]).length str += "; Genres = " genres = Genre.where(["id IN (?)", val]).order('description').pluck(:description) str += genres.join(', ') - end + end if filter.has_key?(KEY_GENRES) + if 0 < ((val = filter[KEY_INSTRUMENTS]) || '').length str += "; Instruments = " instr_ids = val.collect { |vv| vv['instrument_id'] } @@ -398,7 +410,7 @@ module JamRuby str += "#{ii.description} (#{INSTRUMENT_PROFICIENCY[proficiency.to_i]})" str += ', ' unless idx==(instrs.length-1) end - end + end if filter.has_key?(KEY_INSTRUMENTS) str end diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index 3a3b9cba3..dcb0051e1 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -59,14 +59,87 @@ describe 'Band Search Model' do expect(search.follow_count(Band.first)).to eq(1) end - it "render description" do - filter = to_join + end + + describe "generates description" do + let!(:filter) { to_join } + + def check_description(_filter, subtype, key, value, lookup, label) + _filter[key] = value + search.search_results_page(subtype, _filter) + expect(search.description).to match(/Current Search: Sort = .*; #{label} = #{lookup[value]}$/) + end + + it "renders no description for blank" do + search.search_results_page + expect(search.description).to eq('') + end + + it "renders description for sort order" do filter[BandSearch::KEY_TOUR_OPTION] = BandSearch::VAL_YES search.search_results_page(BandSearch::TO_JOIN, filter) search.search_results_page - expect(search.description).to_not eq('') + expect(search.description).to match(/Sort =/) end + it "renders description for band type" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_BAND_TYPE, + BandSearch::BAND_TYPE_VAL_STRS[1], + BandSearch::BAND_TYPES, + 'Band type') + end + + it "renders description for band status" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_BAND_STATUS, + BandSearch::SKILL_VALS[1], + BandSearch::BAND_STATUS, + 'Band status') + end + + it "renders description for play commitment" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_PLAY_COMMIT, + BandSearch::PLAY_COMMIT_VALS[1], + BandSearch::PLAY_COMMITS, + 'Play commitment') + end + + it "renders description for tour option" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_TOUR_OPTION, + BandSearch::VAL_YES, + BandSearch::TOUR_OPTIONS, + 'Touring options') + end + + it "renders description for performance samples" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_PERF_SAMPLES, + BandSearch::PERF_SAMPLES_VALS[1], + BandSearch::PERF_SAMPLES, + 'Performance samples') + end + + it "renders description for genres" do + to_join[BandSearch::KEY_GENRES] = [Genre.first.id] + search.search_results_page(BandSearch::TO_JOIN, to_join) + expect(search.description).to match(/Current Search: Sort = .*; Genres = #{Genre.first.description}$/) + end + + it "renders description for instruments" do + to_join[BandSearch::KEY_INSTRUMENTS] = [{ 'instrument_id' => Instrument.first.id, 'proficiency_level' => 1 }] + search.search_results_page(BandSearch::TO_JOIN, to_join) + expect(search.description).to match(/Current Search: Sort = .*; Instruments = #{Instrument.first.description} \(#{BandSearch::INSTRUMENT_PROFICIENCY[1]}\)$/) + end + + end describe "filtering by keys" do diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 1e4584dfa..822b00f80 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -527,6 +527,7 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter this.resetFilter() @resultsList = @screen.find('#band-search-filter-results-list') + @screen.find('#band-search-filter-results-filtered').hide() isToHire: () => 'to_hire' == @searchSubType @@ -657,6 +658,9 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter resetFilter: () => if this.willSearch(true) + @screen.find('#band-search-filter-results-blank').show() + @screen.find('#band-search-filter-results-filtered').hide() + @screen.find('#band-search-filter-description').html('') @restPost({ filter: 'reset', subtype: @searchSubType }).done(this.didSearch) cancelFilter: () => @@ -682,12 +686,12 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter renderResultsHeader: () => if @searchResults.is_blank_filter - @screen.find('#band-search-filter-results-blank').show() - @screen.find('#band-search-filter-results-filtered').hide() + @screen.find('#band-search-filter-results-blank').show() + @screen.find('#band-search-filter-results-filtered').hide() else - @screen.find('#band-search-filter-results-blank').hide() - @screen.find('#band-search-filter-results-filtered').show() - @screen.find('#band-search-filter-description').html(@searchResults.description) + @screen.find('#band-search-filter-results-blank').hide() + @screen.find('#band-search-filter-results-filtered').show() + @screen.find('#band-search-filter-description').html(@searchResults.description) renderResultsPage: () => super() From 0691e079af23a8d49fd2ce829b463479335e9b95 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 4 Jun 2015 08:11:41 +0000 Subject: [PATCH 35/66] VRFS-3036 description testing --- ruby/lib/jam_ruby/models/band_search.rb | 6 +- .../models/band_filter_search_spec.rb | 156 ++++++++++++------ 2 files changed, 106 insertions(+), 56 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index a81323769..2508bb543 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -100,7 +100,7 @@ module JamRuby KEY_BAND_STATUS => BAND_STATUS_VALS[0], KEY_PERF_SAMPLES => self::PERF_SAMPLES_VALS[0], KEY_HIRE_MAX_COST => 0, - KEY_HIRE_FREE => 1, + KEY_HIRE_FREE => 0, }, } end @@ -387,12 +387,12 @@ module JamRuby str += "; Maximum gig cost = $#{val}" end if filter.has_key?(KEY_HIRE_MAX_COST) - if filter[KEY_HIRE_FREE] + if 0 < filter[KEY_HIRE_FREE] str += "; Bands playing free gigs" end if filter.has_key?(KEY_HIRE_FREE) if (val = filter[KEY_GIGS].to_i) != GIG_COUNTS[0] - str += "; Concert Gigs = #{GIG_LABELS[val]}" + str += "; Concert gigs = #{GIG_LABELS[val]}" end if filter.has_key?(KEY_GIGS) if 0 < (val = filter[KEY_GENRES]).length diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index dcb0051e1..1d1933cb7 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -62,12 +62,11 @@ describe 'Band Search Model' do end describe "generates description" do - let!(:filter) { to_join } def check_description(_filter, subtype, key, value, lookup, label) _filter[key] = value search.search_results_page(subtype, _filter) - expect(search.description).to match(/Current Search: Sort = .*; #{label} = #{lookup[value]}$/) + expect(search.description(subtype)).to match(/Current Search: Sort = .*; #{label} = #{lookup[value]}$/) end it "renders no description for blank" do @@ -76,69 +75,120 @@ describe 'Band Search Model' do end it "renders description for sort order" do - filter[BandSearch::KEY_TOUR_OPTION] = BandSearch::VAL_YES - search.search_results_page(BandSearch::TO_JOIN, filter) + to_join[BandSearch::KEY_TOUR_OPTION] = BandSearch::VAL_YES + search.search_results_page(BandSearch::TO_JOIN, to_join) search.search_results_page expect(search.description).to match(/Sort =/) end - it "renders description for band type" do - check_description(to_join, - BandSearch::TO_JOIN, - BandSearch::KEY_BAND_TYPE, - BandSearch::BAND_TYPE_VAL_STRS[1], - BandSearch::BAND_TYPES, - 'Band type') + context "to_join" do + + it "renders description for band type" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_BAND_TYPE, + BandSearch::BAND_TYPE_VAL_STRS[1], + BandSearch::BAND_TYPES, + 'Band type') + end + + it "renders description for band status" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_BAND_STATUS, + BandSearch::SKILL_VALS[1], + BandSearch::BAND_STATUS, + 'Band status') + end + + it "renders description for concert gigs" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_GIGS, + BandSearch::GIG_COUNTS[1], + BandSearch::GIG_LABELS, + 'Concert gigs') + end + + it "renders description for play commitment" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_PLAY_COMMIT, + BandSearch::PLAY_COMMIT_VALS[1], + BandSearch::PLAY_COMMITS, + 'Play commitment') + end + + it "renders description for tour option" do + check_description(to_join, + BandSearch::TO_JOIN, + BandSearch::KEY_TOUR_OPTION, + BandSearch::VAL_YES, + BandSearch::TOUR_OPTIONS, + 'Touring options') + end + + it "renders description for genres" do + to_join[BandSearch::KEY_GENRES] = [Genre.first.id] + search.search_results_page(BandSearch::TO_JOIN, to_join) + expect(search.description).to match(/Current Search: Sort = .*; Genres = #{Genre.first.description}$/) + end + + it "renders description for instruments" do + to_join[BandSearch::KEY_INSTRUMENTS] = [{ 'instrument_id' => Instrument.first.id, 'proficiency_level' => 1 }] + search.search_results_page(BandSearch::TO_JOIN, to_join) + expect(search.description).to match(/Current Search: Sort = .*; Instruments = #{Instrument.first.description} \(#{BandSearch::INSTRUMENT_PROFICIENCY[1]}\)$/) + end + end - it "renders description for band status" do - check_description(to_join, - BandSearch::TO_JOIN, - BandSearch::KEY_BAND_STATUS, - BandSearch::SKILL_VALS[1], - BandSearch::BAND_STATUS, - 'Band status') - end + context "to_hire" do + it "renders description for genres" do + to_hire[BandSearch::KEY_GENRES] = [Genre.first.id] + search.search_results_page(BandSearch::TO_HIRE, to_hire) + expect(search.description(BandSearch::TO_HIRE)).to match(/Current Search: Sort = .*; Genres = #{Genre.first.description}$/) + end - it "renders description for play commitment" do - check_description(to_join, - BandSearch::TO_JOIN, - BandSearch::KEY_PLAY_COMMIT, - BandSearch::PLAY_COMMIT_VALS[1], - BandSearch::PLAY_COMMITS, - 'Play commitment') - end + it "renders description for band status" do + check_description(to_hire, + BandSearch::TO_HIRE, + BandSearch::KEY_BAND_STATUS, + BandSearch::BAND_STATUS_VALS[1], + BandSearch::BAND_STATUS, + 'Band status') + end - it "renders description for tour option" do - check_description(to_join, - BandSearch::TO_JOIN, - BandSearch::KEY_TOUR_OPTION, - BandSearch::VAL_YES, - BandSearch::TOUR_OPTIONS, - 'Touring options') - end + it "renders description for concert gigs" do + check_description(to_hire, + BandSearch::TO_HIRE, + BandSearch::KEY_GIGS, + BandSearch::GIG_COUNTS[1], + BandSearch::GIG_LABELS, + 'Concert gigs') + end - it "renders description for performance samples" do - check_description(to_join, - BandSearch::TO_JOIN, - BandSearch::KEY_PERF_SAMPLES, - BandSearch::PERF_SAMPLES_VALS[1], - BandSearch::PERF_SAMPLES, - 'Performance samples') - end + it "renders description for performance samples" do + check_description(to_hire, + BandSearch::TO_HIRE, + BandSearch::KEY_PERF_SAMPLES, + BandSearch::PERF_SAMPLES_VALS[1], + BandSearch::PERF_SAMPLES, + 'Performance samples') + end - it "renders description for genres" do - to_join[BandSearch::KEY_GENRES] = [Genre.first.id] - search.search_results_page(BandSearch::TO_JOIN, to_join) - expect(search.description).to match(/Current Search: Sort = .*; Genres = #{Genre.first.description}$/) - end + it "renders description max cost" do + to_hire[BandSearch::KEY_HIRE_MAX_COST] = 100 + search.search_results_page(BandSearch::TO_HIRE, to_hire) + expect(search.description(BandSearch::TO_HIRE)).to match(/Current Search: Sort = .*; Maximum gig cost = \$100$/) + end - it "renders description for instruments" do - to_join[BandSearch::KEY_INSTRUMENTS] = [{ 'instrument_id' => Instrument.first.id, 'proficiency_level' => 1 }] - search.search_results_page(BandSearch::TO_JOIN, to_join) - expect(search.description).to match(/Current Search: Sort = .*; Instruments = #{Instrument.first.description} \(#{BandSearch::INSTRUMENT_PROFICIENCY[1]}\)$/) - end + it "renders description free gigs" do + to_hire[BandSearch::KEY_HIRE_FREE] = 1 + search.search_results_page(BandSearch::TO_HIRE, to_hire) + expect(search.description(BandSearch::TO_HIRE)).to match(/Current Search: Sort = .*; Bands playing free gigs$/) + end + end end From d099ca039d74698b904863e0d23293521e8a2a55 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Thu, 4 Jun 2015 08:17:46 +0000 Subject: [PATCH 36/66] VRFS-3036 description testing --- ruby/spec/jam_ruby/models/band_filter_search_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index 1d1933cb7..b60b4db81 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -215,8 +215,8 @@ describe 'Band Search Model' do end it "filters by band_type" do - band.update_attribute(:band_type, BandSearch::SKILL_VAL_STRS[1]) - filter[BandSearch::KEY_BAND_TYPE] = BandSearch::SKILL_VAL_STRS[1] + band.update_attribute(:band_type, BandSearch::BAND_TYPE_VAL_STRS[1]) + filter[BandSearch::KEY_BAND_TYPE] = BandSearch::BAND_TYPE_VAL_STRS[1] search.search_results_page(BandSearch::TO_JOIN, filter) expect(search.results.count).to eq(1) expect(search.results[0].id).to eq(band.id) From 0be7146e4f49e4a09c073e74cc4c47f9e86bbce4 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 8 Jun 2015 06:11:55 +0000 Subject: [PATCH 37/66] VRFS-3036 CSS tuning --- .../member_search_filter.js.coffee | 2 + .../assets/stylesheets/client/band.css.scss | 81 +++++++++++++++---- web/app/views/api_search/index.rabl | 24 ++++-- .../clients/_band_search_filter.html.slim | 21 ++--- 4 files changed, 94 insertions(+), 34 deletions(-) diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 822b00f80..e45e5fb4f 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -544,6 +544,7 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter @searchSubType = 'to_join' this.showBuilder() this._loadSearchFilter() if @searchFilter + @screen.find('.band-search-filter-builder-top-to_join h2').html('search bands') showBuilderToHire: () => @screen.find('.band-search-filter-builder-top-to_join').hide() @@ -551,6 +552,7 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter @searchSubType = 'to_hire' this.showBuilder() this._loadSearchFilter() if @searchFilter + @screen.find('.band-search-filter-builder-top-to_hire h2').html('search bands to hire') searchMetaData: () => @searchMeta[@searchSubType] diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index d5246e6a4..1c40d16b6 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -1,6 +1,6 @@ @import "client/common.css.scss"; -#band-setup, #band-profile { +#band-setup, #band-profile, #bands-filter-to_hire, #bands-filter-to_join { font-family: Raleway, Arial, Helvetica, verdana, arial, sans-serif; .band-field { input[type="text"], select, textarea { @@ -433,33 +433,82 @@ } } -#band-screen { +#bands-screen { + + .col-left { + float: left; + width: 50%; + margin-left: auto; + margin-right: auto; + } + + .col-right { + float: right; + width: 50%; + margin-left: auto; + margin-right: auto; + } .builder-section { padding: 10px; margin-bottom: 20px; } + #bands-filter-to_hire { + + } - #bands-filter-to-join { + #bands-filter-to_join { + .builder-sort-order { + .text-label { + float: right; + margin-right: 10px; + padding-top: 5px; + } + .sort-order-selector { + float: right; + .easydropdown-wrapper { + width: 140px; + } + } + } + .col-left { + float: left; + width: 30%; + margin-left: auto; + margin-right: auto; + padding-right: 20px; + + .easydropdown-wrapper { + width: 100%; + } + + } + + .col-right { + float: right; + width: 66%; + margin-left: auto; + margin-right: auto; + + .easydropdown-wrapper { + width: 40%; + } + } + + .search-filter-setup-genres { + } + .search-filter-setup-instruments { + } + .band-search-filter-builder-bottom { + text-align: right; + width: 80%; + } .builder-section { padding: 10px; margin-bottom: 20px; } - .col-left { - float: left; - width: 50%; - margin-left: auto; - margin-right: auto; - } - - .col-right { - float: right; - width: 50%; - margin-left: auto; - margin-right: auto; - } } } \ No newline at end of file diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index 9941f867e..155f9e365 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -10,19 +10,19 @@ if @search.is_a?(BaseSearch) current_user.last_jam_audio_latency.round if current_user.last_jam_audio_latency end - node :is_blank_filter do |foo| - @search.is_blank?(params[:subtype]) - end - node :filter_json do |foo| @search.to_json end - node :description do |foo| - @search.description(params[:subtype]) - end - if @search.is_a? MusicianSearch + node :description do |foo| + @search.description + end + + node :is_blank_filter do |foo| + @search.is_blank? + end + child(:results => :musicians) { attributes :id, :first_name, :last_name, :name, :city, :state, :country, :online, :musician, :photo_url, :biography, :regionname, :score, :full_score @@ -63,6 +63,14 @@ if @search.is_a?(BaseSearch) elsif @search.is_a?(BandSearch) + node :is_blank_filter do |foo| + @search.is_blank?(params[:subtype]) + end + + node :description do |foo| + @search.description(params[:subtype]) + end + child(:results => :bands) { attributes :id, :name, :city, :state, :country, :photo_url, :biography, :logo_url, :website diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index 0e976c208..ed08f39c3 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -26,9 +26,10 @@ script#template-band-search-filter-to_join type="text/template" .col-left h2 search bands .col-right.builder-sort-order - .text-label Sort Results By: + .sort-order-selector select.easydropdown name="sort_order" option selected="selected" value="{sort_order}" {sort_order} + .text-label Sort Results By: .clearall .band-search-filter-builder-middle1.builder-section @@ -79,8 +80,8 @@ script#template-band-search-filter-to_join type="text/template" .clearall .band-search-filter-builder-bottom.builder-section.builder-action-buttons .col-right - a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH a#btn-band-search-cancel.builder-button.button-grey href="#" CANCEL + a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH script#template-band-search-filter-to_hire type="text/template" #bands-filter-to_hire @@ -116,23 +117,23 @@ script#template-band-search-filter-to_hire type="text/template" select.easydropdown name="performance_samples" option selected="selected" value="{performance_samples}" {performance_samples} - .field.builder-selector - Find bands to play a paid gig at a cost not to exceed - input type="text" id="max_cost_amount" name="max_cost" value="{max_cost}" - - .field.builder-selector - Find bands that will play free gigs - .clearall .band-search-filter-builder-middle2.builder-section + .field.builder-selector + Find bands to play a paid gig at a cost not to exceed + input type="text" id="max_cost_amount" name="max_cost" value="{max_cost}" + + .field.builder-selector + Find bands that will play free gigs + .clearall .clearall .band-search-filter-builder-bottom.builder-section.builder-action-buttons .col-right - a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH a#btn-band-search-cancel.builder-button.button-grey href="#" CANCEL + a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH script#template-search-filter-setup-instrument type="text/template" tr data-instrument-id="{id}" From 119b4fcb129ccc21b8615739e341fb05f07cb4e1 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 8 Jun 2015 06:30:30 +0000 Subject: [PATCH 38/66] VRFS-3036 CSS tuning --- .../assets/stylesheets/client/band.css.scss | 27 ++++++++++++++++--- .../clients/_band_search_filter.html.slim | 23 +++++++++------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index 1c40d16b6..39ff17acc 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -458,6 +458,25 @@ } #bands-filter-to_join { + width: 75%; + + .builder-selector { + margin-top: 10px; + } + .lhs { + float: left; + width: 40%; + .easydropdown-wrapper { + width: 100%; + } + } + .rhs { + float: right; + width: 40%; + .easydropdown-wrapper { + width: 100%; + } + } .builder-sort-order { .text-label { float: right; @@ -490,9 +509,6 @@ margin-left: auto; margin-right: auto; - .easydropdown-wrapper { - width: 40%; - } } .search-filter-setup-genres { @@ -501,7 +517,10 @@ } .band-search-filter-builder-bottom { text-align: right; - width: 80%; + #btn-perform-band-search { + width: 120px; + margin-left: 20px; + } } .builder-section { diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index ed08f39c3..350b8b312 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -62,19 +62,24 @@ script#template-band-search-filter-to_join type="text/template" .col-right .field.builder-selector - label Status: - select.easydropdown name="band_status" - option selected="selected" value="{band_status}" {band_status} + .lhs + label Status: + select.easydropdown name="band_status" + option selected="selected" value="{band_status}" {band_status} .field.builder-selector - label Concert Gigs Played: - select.easydropdown name="concert_gigs" - option selected="selected" value="{concert_gigs}" {concert_gigs} + .rhs + label Concert Gigs Played: + select.easydropdown name="concert_gigs" + option selected="selected" value="{concert_gigs}" {concert_gigs} + + .clearall .field.builder-selector - label Touring Option: - select.easydropdown name="touring_option" - option selected="selected" value="{touring_option}" {touring_option} + .lhs + label Touring Option: + select.easydropdown name="touring_option" + option selected="selected" value="{touring_option}" {touring_option} .clearall .clearall From 11374201757e298828290b811efa1d43da5f5ca8 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 8 Jun 2015 06:48:41 +0000 Subject: [PATCH 39/66] VRFS-3036 CSS tuning --- .../assets/stylesheets/client/band.css.scss | 129 +++++++++--------- 1 file changed, 64 insertions(+), 65 deletions(-) diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index 39ff17acc..dfdec79a6 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -458,76 +458,75 @@ } #bands-filter-to_join { - width: 75%; - - .builder-selector { - margin-top: 10px; - } - .lhs { - float: left; - width: 40%; - .easydropdown-wrapper { - width: 100%; + width: 75%; + + .builder-selector { + margin-top: 10px; } - } - .rhs { - float: right; - width: 40%; - .easydropdown-wrapper { - width: 100%; - } - } - .builder-sort-order { - .text-label { - float: right; - margin-right: 10px; - padding-top: 5px; - } - .sort-order-selector { - float: right; + .lhs { + float: left; + width: 40%; .easydropdown-wrapper { - width: 140px; + width: 100%; } } - } - .col-left { - float: left; - width: 30%; - margin-left: auto; - margin-right: auto; - padding-right: 20px; - - .easydropdown-wrapper { - width: 100%; - } - - } - - .col-right { - float: right; - width: 66%; - margin-left: auto; - margin-right: auto; - - } - - .search-filter-setup-genres { - } - .search-filter-setup-instruments { - } - .band-search-filter-builder-bottom { - text-align: right; - #btn-perform-band-search { - width: 120px; - margin-left: 20px; + .rhs { + float: right; + width: 40%; + .easydropdown-wrapper { + width: 100%; } } - - .builder-section { - padding: 10px; - margin-bottom: 20px; + .builder-sort-order { + .text-label { + float: right; + margin-right: 10px; + padding-top: 5px; + } + .sort-order-selector { + float: right; + .easydropdown-wrapper { + width: 140px; + } + } + } + .col-left { + float: left; + width: 30%; + margin-left: auto; + margin-right: auto; + padding-right: 20px; + + .easydropdown-wrapper { + width: 100%; + } + + } + + .col-right { + float: right; + width: 66%; + margin-left: auto; + margin-right: auto; + + } + + .search-filter-setup-genres { + } + .search-filter-setup-instruments { + } + .band-search-filter-builder-bottom { + text-align: right; + #btn-perform-band-search { + width: 120px; + margin-left: 20px; + } + } + + .builder-section { + padding: 10px; + margin-bottom: 20px; + } + } - - } - } \ No newline at end of file From b49b44f7243be43fc0ac97fb3511f7b13d890222 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 9 Jun 2015 04:56:14 +0000 Subject: [PATCH 40/66] VRFS-3036 CSS tuning --- .../member_search_filter.js.coffee | 4 +- .../assets/stylesheets/client/band.css.scss | 72 +++++++++++++------ .../clients/_band_search_filter.html.slim | 7 +- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index e45e5fb4f..1fc4423d4 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -544,7 +544,7 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter @searchSubType = 'to_join' this.showBuilder() this._loadSearchFilter() if @searchFilter - @screen.find('.band-search-filter-builder-top-to_join h2').html('search bands') + # @screen.find('.band-search-filter-builder-top-to_join h2').html('search bands') showBuilderToHire: () => @screen.find('.band-search-filter-builder-top-to_join').hide() @@ -552,7 +552,7 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter @searchSubType = 'to_hire' this.showBuilder() this._loadSearchFilter() if @searchFilter - @screen.find('.band-search-filter-builder-top-to_hire h2').html('search bands to hire') + # @screen.find('.band-search-filter-builder-top-to_hire h2').html('search bands to hire') searchMetaData: () => @searchMeta[@searchSubType] diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index dfdec79a6..e3dfc2bf6 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -453,8 +453,59 @@ padding: 10px; margin-bottom: 20px; } + + .builder-sort-order { + .text-label { + float: right; + margin-right: 10px; + padding-top: 5px; + } + .sort-order-selector { + float: right; + .easydropdown-wrapper { + width: 140px; + } + } + } + + .band-search-filter-builder-bottom { + text-align: right; + #btn-perform-band-search { + width: 120px; + margin-left: 20px; + } + } + #bands-filter-to_hire { + width: 60%; + + .builder-selector { + margin-top: 10px; + } + + #max_cost_amount { + width: 60px; + } + .col-left { + float: left; + width: 45%; + margin-left: auto; + margin-right: auto; + padding-right: 20px; + + } + + .col-right { + float: right; + width: 40%; + margin-left: auto; + margin-right: auto; + + .easydropdown-wrapper { + width: 100%; + } + } } #bands-filter-to_join { @@ -477,19 +528,6 @@ width: 100%; } } - .builder-sort-order { - .text-label { - float: right; - margin-right: 10px; - padding-top: 5px; - } - .sort-order-selector { - float: right; - .easydropdown-wrapper { - width: 140px; - } - } - } .col-left { float: left; width: 30%; @@ -515,14 +553,6 @@ } .search-filter-setup-instruments { } - .band-search-filter-builder-bottom { - text-align: right; - #btn-perform-band-search { - width: 120px; - margin-left: 20px; - } - } - .builder-section { padding: 10px; margin-bottom: 20px; diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index 350b8b312..5f33509f6 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -92,11 +92,12 @@ script#template-band-search-filter-to_hire type="text/template" #bands-filter-to_hire .band-search-filter-builder-top-to_hire.builder-section .col-left - h2 search bands + h2 search bands to hire .col-right.builder-sort-order - .text-label Sort Results By: + .sort-order-selector select.easydropdown name="sort_order" option selected="selected" value="{sort_order}" {sort_order} + .text-label Sort Results By: .clearall .band-search-filter-builder-middle1.builder-section @@ -126,7 +127,7 @@ script#template-band-search-filter-to_hire type="text/template" .band-search-filter-builder-middle2.builder-section .field.builder-selector - Find bands to play a paid gig at a cost not to exceed + Find bands to play a paid gig at a cost not to exceed  $ input type="text" id="max_cost_amount" name="max_cost" value="{max_cost}" .field.builder-selector From c40d7c5f622a839ac882d6c2e838de41a6e0b64b Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 9 Jun 2015 05:39:03 +0000 Subject: [PATCH 41/66] VRFS-3036 CSS tuning --- web/app/assets/stylesheets/client/band.css.scss | 9 +++++++++ web/app/views/clients/_band_search_filter.html.slim | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index e3dfc2bf6..f69a571d1 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -468,6 +468,11 @@ } } + #band-search-filter-builder { + margin-left: 20px; + padding-top: 20px; + } + .band-search-filter-builder-bottom { text-align: right; #btn-perform-band-search { @@ -476,6 +481,10 @@ } } + tr:nth-child(even) td { + padding-bottom: 0; + } + #bands-filter-to_hire { width: 60%; diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index 5f33509f6..4b2af665d 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -127,11 +127,11 @@ script#template-band-search-filter-to_hire type="text/template" .band-search-filter-builder-middle2.builder-section .field.builder-selector - Find bands to play a paid gig at a cost not to exceed  $ +  Find bands to play a paid gig at a cost not to exceed  $ input type="text" id="max_cost_amount" name="max_cost" value="{max_cost}" .field.builder-selector - Find bands that will play free gigs +  Find bands that will play free gigs .clearall From 745c448e6b13f7dfdcd8be794638b3201fe43ee5 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 9 Jun 2015 06:46:34 +0000 Subject: [PATCH 42/66] VRFS-3036 CSS tuning and integration testing --- ruby/lib/jam_ruby/models/band_search.rb | 1 + .../member_search_filter.js.coffee | 3 +- .../assets/stylesheets/client/band.css.scss | 42 ++++++++++++++++--- .../clients/_band_search_filter.html.slim | 1 + 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 2508bb543..0aa8ad5cc 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -28,6 +28,7 @@ module JamRuby BAND_TYPES = { BAND_TYPE_VAL_STRS[0] => BAND_TYPE_VAL_STRS[0].camelcase, BAND_TYPE_VAL_STRS[1] => BAND_TYPE_VAL_STRS[1].camelcase, + BAND_TYPE_VAL_STRS[2] => BAND_TYPE_VAL_STRS[2].camelcase, } SORT_VALS = %W{ distance latency } diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 1fc4423d4..808828be9 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -628,8 +628,7 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter when 'to_hire' then this._populateSearchFilterToHire() _populateSkill: () => - elem = $ '#'+@searchType+'-search-filter-builder select[name=band_type]' - this._populateSelectWithInt(@profileUtils.skillLevelMap, this.filterData().band_type.toString(), elem) + this._populateSelectIdentifier('band_type') _populateBandStatus: () => this._populateSelectIdentifier('band_status') diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index f69a571d1..6316fefe9 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -449,6 +449,12 @@ margin-right: auto; } + .band-search-filter-results-list { + .profile-band-list-result { + padding-top: 5px; + } + } + .builder-section { padding: 10px; margin-bottom: 20px; @@ -469,8 +475,7 @@ } #band-search-filter-builder { - margin-left: 20px; - padding-top: 20px; + margin-left: 5px; } .band-search-filter-builder-bottom { @@ -485,8 +490,29 @@ padding-bottom: 0; } + #band-search-filter-results-header { + padding: 10px 10px 10px 10px; + } + + #band-search-filter-description { + padding: 5px 5px 5px 5px; + display: inline; + margin-left: auto; + margin-right: auto; + } + + #btn-band-search-builder { + float: left; + margin-right: 20px; + } + + #btn-band-search-reset { + float: right; + margin-left: 20px; + } + #bands-filter-to_hire { - width: 60%; + width: 100%; .builder-selector { margin-top: 10px; @@ -507,7 +533,7 @@ .col-right { float: right; - width: 40%; + width: 45%; margin-left: auto; margin-right: auto; @@ -518,7 +544,7 @@ } #bands-filter-to_join { - width: 75%; + width: 100%; .builder-selector { margin-top: 10px; @@ -560,7 +586,11 @@ .search-filter-setup-genres { } - .search-filter-setup-instruments { + + .band-setup-genres { + .easydropdown-wrapper { + width: 100%; + } } .builder-section { padding: 10px; diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index 4b2af665d..dc64fbb52 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -5,6 +5,7 @@ div#band-search-filter-results-header #band-search-filter-results-blank a.button-orange#btn-band-search-builder-to_join href="#" SEARCH FOR BAND TO JOIN + | - or -  a.button-orange#btn-band-search-builder-to_hire href="#" SEARCH FOR BAND TO HIRE #band-search-filter-results-filtered a.button-orange#btn-band-search-builder href="#" SEARCH From 405350c64999108e2d68a24e8094baf3c3b2548b Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 9 Jun 2015 07:09:05 +0000 Subject: [PATCH 43/66] VRFS-3036 CSS tuning and integration testing --- .../member_search_filter.js.coffee | 44 ++++++++++--------- .../assets/stylesheets/client/band.css.scss | 9 +++- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index 808828be9..e2a227e11 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -812,33 +812,35 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter context.JK.helpBubble $('.session-count', $rendering), 'session-count', data, options @resultsList.append $rendering ii++ - $('.search-m-follow').on 'click', this._bindFollowBand + + this._bindFollowBand() + context.JK.bindHoverEvents() return _bindFollowBand: () => objThis = this - if 0 == $(this).closest('.button-orange').size() - return false - $(this).click (ee) -> - ee.preventDefault() - return - evt.stopPropagation() - newFollowing = {} - newFollowing.band_id = $(this).parent().data('band-id') - url = '/api/users/' + context.JK.currentUserId + '/followings' - $.ajax - type: 'POST' - dataType: 'json' - contentType: 'application/json' - url: url - data: JSON.stringify(newFollowing) - processData: false - success: (response) -> - $('div[data-band-id=' + newFollowing.band_id + '] .search-m-follow').removeClass('button-orange').addClass 'button-grey' + @screen.find('.search-m-follow').on 'click', (evt) -> + if 0 == $(this).closest('.button-orange').size() + return false + $(this).click (ee) -> + ee.preventDefault() return - error: app.ajaxError(arguments) - return + evt.stopPropagation() + newFollowing = {} + newFollowing.band_id = $(this).parent().data('band-id') + url = '/api/users/' + context.JK.currentUserId + '/followings' + $.ajax + type: 'POST' + dataType: 'json' + contentType: 'application/json' + url: url + data: JSON.stringify(newFollowing) + processData: false + success: (response) -> + $('div[data-band-id=' + newFollowing.band_id + '] .search-m-follow').removeClass('button-orange').addClass 'button-grey' + return + error: objThis.app.ajaxError(arguments) _formatLocation: (band) -> diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index 6316fefe9..59c8c330f 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -449,7 +449,14 @@ margin-right: auto; } - .band-search-filter-results-list { + #band-search-filter-spinner { + display: block; + margin-left: auto; + margin-right: auto; + margin-top: 40px; + } + + #band-search-filter-results-list { .profile-band-list-result { padding-top: 5px; } From 1ad3f6a79fe6f076b1573f97b8ec370fde9e2f52 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 10 Jun 2015 16:07:49 +0000 Subject: [PATCH 44/66] VRFS-3036 css tuning --- .../stylesheets/client/musician.css.scss | 28 +++++++++++++++++-- .../clients/_musician_search_filter.html.slim | 6 ++-- .../spikes/musician_search_filter.html.slim | 8 +++--- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/web/app/assets/stylesheets/client/musician.css.scss b/web/app/assets/stylesheets/client/musician.css.scss index e075a212e..7cb998fd5 100644 --- a/web/app/assets/stylesheets/client/musician.css.scss +++ b/web/app/assets/stylesheets/client/musician.css.scss @@ -176,14 +176,15 @@ .col-left { float: left; - width: 50%; + width: 45%; margin-left: auto; margin-right: auto; + padding-right: 20px; } .col-right { float: right; - width: 50%; + width: 45%; margin-left: auto; margin-right: auto; } @@ -218,6 +219,14 @@ } .builder-ages { width: 100%; + height: 100%; + background-color:#c5c5c5; + border:none; + -webkit-box-shadow: inset 2px 2px 3px 0px #888; + box-shadow: inset 2px 2px 3px 0px #888; + color:#000; + overflow:auto; + font-size:12px; } .builder-instruments { width: 100%; @@ -230,6 +239,21 @@ margin-top: 20px; } + .musician-setup-genres { + width:100%; + height:200px; + background-color:#c5c5c5; + border:none; + -webkit-box-shadow: inset 2px 2px 3px 0px #888; + box-shadow: inset 2px 2px 3px 0px #888; + color:#000; + overflow:auto; + font-size:12px; + .easydropdown-wrapper { + width: 100%; + } + } + } .filter-element { diff --git a/web/app/views/clients/_musician_search_filter.html.slim b/web/app/views/clients/_musician_search_filter.html.slim index f9f87697d..b454bee83 100644 --- a/web/app/views/clients/_musician_search_filter.html.slim +++ b/web/app/views/clients/_musician_search_filter.html.slim @@ -30,7 +30,7 @@ script#template-musician-search-filter type="text/template" .col-left .field label for="search-filter-genres" Genres: - .search-filter-setup-genres.band-setup-genres + .search-filter-setup-genres.musician-setup-genres table#search-filter-genres cellpadding="10" cellspacing="6" width="100%" .field.builder-selector @@ -47,7 +47,7 @@ script#template-musician-search-filter type="text/template" .field label for="search-filter-instruments" | Instruments & Skill Level: - .search-filter-setup-instruments.band-setup-genres.builder-instruments + .search-filter-setup-instruments.musician-setup-genres.builder-instruments table#search-filter-instruments cellpadding="10" cellspacing="6" width="100%" .col-left @@ -64,7 +64,7 @@ script#template-musician-search-filter type="text/template" .col-right .field.builder-selector label for="search-filter-ages" Ages: - .search-filter-setup-ages.band-setup-genres.builder-ages + .search-filter-setup-ages.builder-ages table#search-filter-ages cellpadding="10" cellspacing="6" width="100%" .clearall diff --git a/web/app/views/spikes/musician_search_filter.html.slim b/web/app/views/spikes/musician_search_filter.html.slim index 777cf2636..d6ae1f1da 100644 --- a/web/app/views/spikes/musician_search_filter.html.slim +++ b/web/app/views/spikes/musician_search_filter.html.slim @@ -1,15 +1,15 @@ = javascript_include_tag "profile_utils" -= javascript_include_tag "musician_search_filter" += javascript_include_tag "member_search_filter" = stylesheet_link_tag "client/musician" -#musician_search_spike -= render "clients/musician_search_filter" +#musicians-screen + = render "clients/musician_search_filter" javascript: var initialized = false; $(document).on('JAMKAZAM_READY', function(e, data) { setTimeout(function() { window.musician_search_filter = new JK.MusicianSearchFilter(); - musician_search_filter.init(); + musician_search_filter.init(data.app); musician_search_filter.afterShow(); }, 1) }); From ebe620a3b321518ced2ab5898f514d10674a0bdd Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 10 Jun 2015 16:35:39 +0000 Subject: [PATCH 45/66] VRFS-3036 fixed performance sample query and test --- ruby/lib/jam_ruby/models/band_search.rb | 10 +++++----- ruby/spec/jam_ruby/models/band_filter_search_spec.rb | 12 ++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 0aa8ad5cc..7f529cc66 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -173,9 +173,9 @@ module JamRuby def _performance_samples(rel, filter) case filter[KEY_PERF_SAMPLES] when VAL_YES - rel.joins("LEFT OUTER JOIN performance_samples AS ps ON ps.player_id = bands.id AND player_type = '#{self.class.name}'").where(["ps.id IS NOT NULL"]) + rel.joins("LEFT OUTER JOIN performance_samples AS ps ON ps.player_id = bands.id AND player_type = '#{Band.name}'").where(["ps.id IS NOT NULL"]) when VAL_NO - rel.joins("LEFT OUTER JOIN performance_samples AS ps ON ps.player_id = bands.id AND player_type = '#{self.class.name}'").where(["ps.id IS NULL"]) + rel.joins("LEFT OUTER JOIN performance_samples AS ps ON ps.player_id = bands.id AND player_type = '#{Band.name}'").where(["ps.id IS NULL"]) else rel end @@ -246,8 +246,8 @@ module JamRuby rel end - def search_includes(rel) - rel.includes([:instruments]) + def search_includes(rel, subtype=TO_JOIN) + TO_JOIN == subtype ? rel.includes([:instruments]) : rel end def _process_results_page(_results) @@ -340,7 +340,7 @@ module JamRuby @page_number = [page.to_i, 1].max rel = rel.paginate(:page => @page_number, :per_page => self.class::PER_PAGE) - rel = self.search_includes(rel) + rel = self.search_includes(rel, subtype) @page_count = rel.total_pages _process_results_page(rel.all) diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index b60b4db81..cbf435618 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -289,8 +289,16 @@ describe 'Band Search Model' do end it "filters by perform samples" do - pending - PerformanceSample.create(searcher, {player: band, service_type: 'youtube', service_id: 'abc123'}) + filter[BandSearch::KEY_PERF_SAMPLES] = BandSearch::VAL_YES + search.search_results_page(BandSearch::TO_HIRE, filter) + expect(search.results.count).to eq(0) + + ps = PerformanceSample.new + ps.player = band + ps.service_type = 'youtube' + ps.service_id = 'abc123' + ps.save + # PerformanceSample.create(player: band, service_type: 'youtube', service_id: 'abc123') filter[BandSearch::KEY_PERF_SAMPLES] = BandSearch::VAL_YES search.search_results_page(BandSearch::TO_HIRE, filter) expect(search.results.count).to eq(1) From 5d8ba22172dcfc7f563031b9567ce6e9bd4f2953 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 10 Jun 2015 16:36:58 +0000 Subject: [PATCH 46/66] VRFS-3036 added performance sample test case --- ruby/spec/jam_ruby/models/band_filter_search_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index cbf435618..95b15e88b 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -293,6 +293,10 @@ describe 'Band Search Model' do search.search_results_page(BandSearch::TO_HIRE, filter) expect(search.results.count).to eq(0) + filter[BandSearch::KEY_PERF_SAMPLES] = BandSearch::VAL_NO + search.search_results_page(BandSearch::TO_HIRE, filter) + expect(search.results.count).to eq(Band.count) + ps = PerformanceSample.new ps.player = band ps.service_type = 'youtube' From 4f897fc6aabb8ec87b57a4dc7d89d9d1017ef5a5 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Sun, 28 Jun 2015 04:00:44 +0000 Subject: [PATCH 47/66] VRFS-3036 fixed typo referencing old constant SKILL_VAL_STRS --- ruby/lib/jam_ruby/models/band_search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 7f529cc66..40933476c 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -205,7 +205,7 @@ module JamRuby when BAND_TYPE_VAL_STRS[1] rel.where(band_type: BAND_TYPE_VAL_STRS[1]) when BAND_TYPE_VAL_STRS[2] - rel.where(band_type: SKILL_VAL_STRS[2]) + rel.where(band_type: BAND_TYPE_VAL_STRS[2]) else rel end From 4f2f37f7a9f9a4dfc4a778b8c97e9bd949dd9de9 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Sun, 28 Jun 2015 19:49:02 +0000 Subject: [PATCH 48/66] removed latency as search; fixed regressions --- ruby/lib/jam_ruby/models/band_search.rb | 91 ++++++++++--------- .../models/band_filter_search_spec.rb | 24 +++++ .../member_search_filter.js.coffee | 2 +- web/app/views/api_search/index.rabl | 1 + .../clients/_band_search_filter.html.slim | 10 +- 5 files changed, 81 insertions(+), 47 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band_search.rb b/ruby/lib/jam_ruby/models/band_search.rb index 40933476c..976250935 100644 --- a/ruby/lib/jam_ruby/models/band_search.rb +++ b/ruby/lib/jam_ruby/models/band_search.rb @@ -31,11 +31,15 @@ module JamRuby BAND_TYPE_VAL_STRS[2] => BAND_TYPE_VAL_STRS[2].camelcase, } - SORT_VALS = %W{ distance latency } + SORT_VALS = %W{ distance } SORT_ORDERS = { - SORT_VALS[0] => 'Distance to Me', - SORT_VALS[1] => 'Latency to Me', + SORT_VALS[0] => 'Distance to Me' } + # SORT_VALS = %W{ distance latency } + # SORT_ORDERS = { + # SORT_VALS[0] => 'Distance to Me' + # SORT_VALS[1] => 'Latency to Me', + # } HIRE_SORT_VALS = %W{ distance price_asc price_desc } HIRE_SORT_ORDERS = { @@ -89,6 +93,7 @@ module JamRuby return @@jschema if @@jschema @@jschema = { TO_JOIN => BaseSearch.json_schema.merge({ + KEY_SORT_ORDER => self::SORT_VALS[0], KEY_BAND_TYPE => self::BAND_TYPE_VAL_STRS[0].to_s, KEY_BAND_STATUS => BAND_STATUS_VALS[0], KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0], @@ -213,17 +218,13 @@ module JamRuby def _sort_order(rel, filter) val = filter[KEY_SORT_ORDER] - if 'distance' == val - # locidispid = self.user.last_jam_locidispid || 0 - # my_locid = locidispid / 1000000 - # rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") - # rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid") - # rel = rel.group("users.id, my_geo.geog, other_geo.geog") - # rel = rel.order('st_distance(my_geo.geog, other_geo.geog)') - - elsif 'latency' == val - # rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{self.user.id}'") - # rel = rel.order('current_scores.full_score ASC') + if 'distance' == val || val.blank? + locidispid = self.user.last_jam_locidispid || 0 + my_locid = locidispid / 1000000 + rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}") + rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON other_geo.latitude = bands.lat AND other_geo.longitude = bands.lng") + rel = rel.group("bands.id, my_geo.geog, other_geo.geog") + rel = rel.order('st_distance(my_geo.geog, other_geo.geog)') elsif 'price_asc' == val rel = rel.order('gig_minimum ASC') @@ -231,7 +232,6 @@ module JamRuby elsif 'price_desc' == val rel = rel.order('gig_minimum DESC') end - rel end @@ -345,73 +345,82 @@ module JamRuby _process_results_page(rel.all) end + + def _add_description(descrip, add) + descrip += "; " if 0 < descrip.length + descrip + add + end def description(subtype=TO_JOIN) return '' if self.is_blank?(subtype) filter = search_filter_for_subtype(subtype) - str = 'Current Search: ' - - str += 'Sort = ' - case sort = filter[KEY_SORT_ORDER] - when 'distance' - str += SORT_ORDERS[sort] - when 'latency' - str += SORT_ORDERS[sort] - when 'price_asc' - str += HIRE_SORT_ORDERS[sort] - when 'price_desc' - str += HIRE_SORT_ORDERS[sort] - end if filter.has_key?(KEY_SORT_ORDER) + str = '' + if filter.has_key?(KEY_SORT_ORDER) + str += 'Sort = ' + case sort = filter[KEY_SORT_ORDER] + when 'distance' + str += SORT_ORDERS[sort] + when 'latency' + str += SORT_ORDERS[sort] + when 'price_asc' + str += HIRE_SORT_ORDERS[sort] + when 'price_desc' + str += HIRE_SORT_ORDERS[sort] + end + end if (val = filter[KEY_BAND_TYPE]) != ANY_VAL_STR - str += "; Band type = #{BAND_TYPES[val]}" + str = _add_description(str, "Band type = #{BAND_TYPES[val]}") end if filter.has_key?(KEY_BAND_TYPE) if (val = filter[KEY_BAND_STATUS]) != ANY_VAL_STR - str += "; Band status = #{BAND_STATUS[val]}" + str = _add_description(str, "Band status = #{BAND_STATUS[val]}") end if filter.has_key?(KEY_BAND_STATUS) if (val = filter[KEY_PLAY_COMMIT]) != ANY_VAL_STR - str += "; Play commitment = #{PLAY_COMMITS[val]}" + str = _add_description(str, "Play commitment = #{PLAY_COMMITS[val]}") end if filter.has_key?(KEY_PLAY_COMMIT) if (val = filter[KEY_TOUR_OPTION]) != ANY_VAL_STR - str += "; Touring options = #{TOUR_OPTIONS[val]}" + str = _add_description(str, "Touring options = #{TOUR_OPTIONS[val]}") end if filter.has_key?(KEY_TOUR_OPTION) if (val = filter[KEY_PERF_SAMPLES]) != ANY_VAL_STR - str += "; Performance samples = #{PERF_SAMPLES[val]}" + str = _add_description(str, "Performance samples = #{PERF_SAMPLES[val]}") end if filter.has_key?(KEY_PERF_SAMPLES) if (val = filter[KEY_HIRE_MAX_COST].to_i) > 0 - str += "; Maximum gig cost = $#{val}" + str = _add_description(str, "Maximum gig cost = $#{val}") end if filter.has_key?(KEY_HIRE_MAX_COST) if 0 < filter[KEY_HIRE_FREE] - str += "; Bands playing free gigs" + str = _add_description(str, "Bands playing free gigs") end if filter.has_key?(KEY_HIRE_FREE) if (val = filter[KEY_GIGS].to_i) != GIG_COUNTS[0] - str += "; Concert gigs = #{GIG_LABELS[val]}" + str = _add_description(str, "Concert gigs = #{GIG_LABELS[val]}") end if filter.has_key?(KEY_GIGS) if 0 < (val = filter[KEY_GENRES]).length - str += "; Genres = " + gstr = "Genres = " genres = Genre.where(["id IN (?)", val]).order('description').pluck(:description) - str += genres.join(', ') + gstr += genres.join(', ') + str = _add_description(str, gstr) end if filter.has_key?(KEY_GENRES) if 0 < ((val = filter[KEY_INSTRUMENTS]) || '').length - str += "; Instruments = " + istr = "Instruments = " instr_ids = val.collect { |vv| vv['instrument_id'] } instrs = Instrument.where(["id IN (?)", instr_ids]).order(:description) instrs.each_with_index do |ii, idx| proficiency = val.detect { |vv| vv['instrument_id'] == ii.id }['proficiency_level'] - str += "#{ii.description} (#{INSTRUMENT_PROFICIENCY[proficiency.to_i]})" - str += ', ' unless idx==(instrs.length-1) + istr += "#{ii.description} (#{INSTRUMENT_PROFICIENCY[proficiency.to_i]})" + istr += ', ' unless idx==(instrs.length-1) end + str = _add_description(str, istr) end if filter.has_key?(KEY_INSTRUMENTS) + str = "Current Search: #{str}" str end diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index 95b15e88b..ebcb92d2d 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -246,6 +246,30 @@ describe 'Band Search Model' do let!(:filter) { to_join } + it "sorts by distance" do + bands = Band.all.reverse + bb = bands.first + bb.lat, bb.lng = austin_geoip[:geoiplocation].latitude, austin_geoip[:geoiplocation].longitude + bb.save! + bb = bands.second + bb.lat, bb.lng = dallas_geoip[:geoiplocation].latitude, dallas_geoip[:geoiplocation].longitude + bb.save! + bb = bands.third + bb.lat, bb.lng = miami_geoip[:geoiplocation].latitude, miami_geoip[:geoiplocation].longitude + bb.save! + bb = bands.fourth + bb.lat, bb.lng = seattle_geoip[:geoiplocation].latitude, seattle_geoip[:geoiplocation].longitude + bb.save! + + filter[BandSearch::KEY_SORT_ORDER] = BandSearch::SORT_VALS[0] + search.search_results_page(BandSearch::TO_JOIN, filter) + expect(search.results.count).to eq(Band.count) + expect(search.results.first.id).to eq(bands.first.id) + expect(search.results.second.id).to eq(bands.second.id) + expect(search.results.third.id).to eq(bands.third.id) + expect(search.results.fourth.id).to eq(bands.fourth.id) + end + it "filters by play commitment" do band.update_attribute(BandSearch::KEY_PLAY_COMMIT, BandSearch::PLAY_COMMIT_VALS[1].to_i) filter[BandSearch::KEY_PLAY_COMMIT] = BandSearch::PLAY_COMMIT_VALS[1] diff --git a/web/app/assets/javascripts/member_search_filter.js.coffee b/web/app/assets/javascripts/member_search_filter.js.coffee index e2a227e11..357806ebc 100644 --- a/web/app/assets/javascripts/member_search_filter.js.coffee +++ b/web/app/assets/javascripts/member_search_filter.js.coffee @@ -621,7 +621,7 @@ context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter this.cancelFilter() this._populateGenres() - this._populateSortOrder() + this._populateSortOrder() if this.isToHire() switch @searchSubType when 'to_join' then this._populateSearchFilterToJoin() diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index 155f9e365..12e7fbf53 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -52,6 +52,7 @@ if @search.is_a?(BaseSearch) node :name do |uu| uu.name end end + node :friend_count do |musician| @search.friend_count(musician) end node :follow_count do |musician| @search.follow_count(musician) end node :recording_count do |musician| @search.record_count(musician) end node :session_count do |musician| @search.session_count(musician) end diff --git a/web/app/views/clients/_band_search_filter.html.slim b/web/app/views/clients/_band_search_filter.html.slim index dc64fbb52..58340e5d1 100644 --- a/web/app/views/clients/_band_search_filter.html.slim +++ b/web/app/views/clients/_band_search_filter.html.slim @@ -26,11 +26,11 @@ script#template-band-search-filter-to_join type="text/template" .band-search-filter-builder-top.builder-section .col-left h2 search bands - .col-right.builder-sort-order - .sort-order-selector - select.easydropdown name="sort_order" - option selected="selected" value="{sort_order}" {sort_order} - .text-label Sort Results By: + / .col-right.builder-sort-order + / .sort-order-selector + / select.easydropdown name="sort_order" + / option selected="selected" value="{sort_order}" {sort_order} + / .text-label Sort Results By: .clearall .band-search-filter-builder-middle1.builder-section From 0c58a0c1d384dbcaebe43f132f6a4e9aef7f9d24 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 27 Jul 2015 15:35:21 -0500 Subject: [PATCH 49/66] * VRFS-3364 - show metronome while jamtrack is open --- .../react-components/SessionMediaTracks.js.jsx.coffee | 7 +++---- .../react-components/SessionMetronome.js.jsx.coffee | 1 + .../client/react-components/SessionTrack.css.scss | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee index f72068f29..d4d50a8ae 100644 --- a/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee @@ -263,10 +263,9 @@ ChannelGroupIds = context.JK.ChannelGroupIds # All the JamTracks mediaTracks.push(``) - # this is not ready yet until VRFS-3363 is done - #if @state.metronome? - # @state.metronome.mode = MIX_MODES.PERSONAL - # mediaTracks.push(``) + if @state.metronome? + @state.metronome.mode = MIX_MODES.PERSONAL + mediaTracks.push(``) for jamTrack in @state.jamTracks jamTrack.mode = MIX_MODES.PERSONAL diff --git a/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee index d1231642d..aa7654c7e 100644 --- a/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee @@ -33,6 +33,7 @@ MIX_MODES = context.JK.MIX_MODES "session-track" : true "metronome" : true "no-mixer" : @props.mode == MIX_MODES.MASTER # show it as disabled if in master mode + "in-jam-track" : @props.location == 'jam-track' }) pan = if mixers.mixer? then mixers.mixer?.pan else 0 diff --git a/web/app/assets/stylesheets/client/react-components/SessionTrack.css.scss b/web/app/assets/stylesheets/client/react-components/SessionTrack.css.scss index 49529aed6..57c2bbe03 100644 --- a/web/app/assets/stylesheets/client/react-components/SessionTrack.css.scss +++ b/web/app/assets/stylesheets/client/react-components/SessionTrack.css.scss @@ -175,6 +175,15 @@ .track-controls { margin-left:0; } + &.in-jam-track { + min-height:56px; + .track-buttons { + margin-top:2px; + } + table.vu { + margin-top: 10px; + } + } } &.recorded-track, &.jam-track, &.recorded-category, &.jam-track-category { From 55ccf89e647d334e38c1e99b9e78200f9ed2399b Mon Sep 17 00:00:00 2001 From: Seth Call Date: Tue, 28 Jul 2015 14:11:28 -0500 Subject: [PATCH 50/66] * VRFS-3396 took out carmen gem; database in production/staging has display names in db --- web/lib/max_mind_manager.rb | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/web/lib/max_mind_manager.rb b/web/lib/max_mind_manager.rb index fceef6353..db630195c 100644 --- a/web/lib/max_mind_manager.rb +++ b/web/lib/max_mind_manager.rb @@ -5,24 +5,11 @@ class MaxMindManager < BaseManager end def self.countries - Country.get_all.map do |c| - country = Carmen::Country.coded(c.countrycode) - { - countrycode: c.countrycode, - countryname: country.name - } - end + Country.get_all.map { |c| {countrycode: c.countrycode, countryname: c.countryname} } end def self.regions(country) - Region.get_all(country).map do |r| - country = Carmen::Country.coded(r.countrycode) - region = country.subregions.coded(r.region) - { - region: r.region, - name: region.name - } - end + Region.get_all(country).map { |r| { region: r.region, name: r.regionname } } end def self.cities(country, region) From 6a806a05cb331358bacc177d120f4b678687f187 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 4 Aug 2015 14:10:02 +0000 Subject: [PATCH 51/66] VRFS-3393 merging musician-search2 into develop --- .../clients/_musician_search_filter.html.slim | 39 +++++++------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/web/app/views/clients/_musician_search_filter.html.slim b/web/app/views/clients/_musician_search_filter.html.slim index b4f7e26f6..b454bee83 100644 --- a/web/app/views/clients/_musician_search_filter.html.slim +++ b/web/app/views/clients/_musician_search_filter.html.slim @@ -4,7 +4,6 @@ div#musician-search-filter-results.content-wrapper div#musician-search-filter-results-header a#btn-musician-search-builder.button-orange href="#" SEARCH - span.musician-search-text Click search button to look for musicians with similar interests, skill levels, etc. a#btn-musician-search-reset.button-grey href="#" RESET div#musician-search-filter-description div.clearall @@ -22,9 +21,9 @@ script#template-musician-search-filter type="text/template" .col-left h2 search musicians .col-right.builder-sort-order - .text-label Sort Results By: - select.easydropdown name="sort_order" - option selected="selected" value="{sort_order}" {sort_order} + .text-label Sort Results By: + select.easydropdown name="sort_order" + option selected="selected" value="{sort_order}" {sort_order} .clearall #musician-search-filter-builder-middle.builder-section @@ -35,12 +34,12 @@ script#template-musician-search-filter type="text/template" table#search-filter-genres cellpadding="10" cellspacing="6" width="100%" .field.builder-selector - label Interests + label Interests: select.easydropdown name="interests" option selected="selected" value="{interests}" {interests} .field.builder-selector - label Studio Sessions Played + label Studio Sessions Played: select.easydropdown name="studio_sessions" option selected="selected" value="{studio_sessions}" {studio_sessions} @@ -53,12 +52,12 @@ script#template-musician-search-filter type="text/template" .col-left .field.builder-selector - label Status + label Status: select.easydropdown name="skill_level" option selected="selected" value="{skill_level}" {skill_label} .field.builder-selector - label Concert Gigs Played + label Concert Gigs Played: select.easydropdown name="concert_gigs" option selected="selected" value="{concert_gigs}" {concert_gigs} @@ -85,25 +84,13 @@ script#template-search-filter-setup-instrument type="text/template" option value="2" Intermediate option value="3" Expert -script#template-search-filter-setup-genres type="text/template" - .genre-option - | {% if(data.checked) { %} - input value="{{data.id}}" checked="checked" type="checkbox" - | {% } else { %} - input value="{{data.id}}" type="checkbox" - | {% } %} - label - | {{data.description}} +script#template-search-filter-setup-genres type="text/template" + tr + td {description} -script#template-search-filter-setup-ages type="text/template" - .age-option - | {% if(data.checked) { %} - input value="{{data.id}}" checked="checked" type="checkbox" - | {% } else { %} - input value="{{data.id}}" type="checkbox" - | {% } %} - label - | {{data.description}} +script#template-search-filter-setup-ages type="text/template" + tr + td {description} /! Session Row Template script#template-search-musician-row type="text/template" From c11cc5eb9ed703a09c875b86a0df954ac7a998cf Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 4 Aug 2015 14:11:46 +0000 Subject: [PATCH 52/66] added fixmes for sql injection vulnerabilities --- ruby/lib/jam_ruby/models/base_search.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruby/lib/jam_ruby/models/base_search.rb b/ruby/lib/jam_ruby/models/base_search.rb index 462372796..f08c46a7d 100644 --- a/ruby/lib/jam_ruby/models/base_search.rb +++ b/ruby/lib/jam_ruby/models/base_search.rb @@ -102,6 +102,7 @@ module JamRuby def self.search_target_class end + # FIXME: SQL INJECTION def _genres(rel, query_data=json) gids = query_data[KEY_GENRES] unless gids.blank? @@ -112,6 +113,7 @@ module JamRuby rel end + # FIXME: SQL INJECTION def _instruments(rel, query_data=json) unless (instruments = query_data[KEY_INSTRUMENTS]).blank? instsql = "SELECT player_id FROM musicians_instruments WHERE ((" From 557e19e5e7097a9672ee720f419d39ad2886d074 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 9 Aug 2015 13:37:43 -0500 Subject: [PATCH 53/66] * allow better onboarding of JamTracks including audio from Tency Music (VRFS-3296, VRFS-3386) --- admin/config/initializers/jam_tracks.rb | 1 - db/manifest | 1 + db/up/jam_track_onboarding_enhancements.sql | 65 ++ ruby/lib/jam_ruby.rb | 3 + .../lib/jam_ruby/import/tency_stem_mapping.rb | 360 ++++++ ruby/lib/jam_ruby/jam_track_importer.rb | 1036 +++++++++++++++-- ruby/lib/jam_ruby/models/genre.rb | 3 +- ruby/lib/jam_ruby/models/genre_jam_track.rb | 8 + ruby/lib/jam_ruby/models/jam_track.rb | 114 +- ruby/lib/jam_ruby/models/jam_track_file.rb | 78 ++ ruby/lib/jam_ruby/models/jam_track_track.rb | 136 ++- ruby/spec/factories.rb | 2 +- ruby/spec/jam_ruby/jam_track_importer_spec.rb | 102 +- ruby/spec/jam_ruby/models/jam_track_spec.rb | 106 +- .../jam_ruby/models/jam_track_track_spec.rb | 1 + .../SessionMediaTracks.js.jsx.coffee | 2 + .../SessionMetronome.js.jsx.coffee | 1 + .../react-components/SessionTrack.css.scss | 2 + .../api_music_sessions_controller.rb | 4 +- .../controllers/api_recordings_controller.rb | 4 +- web/app/controllers/api_users_controller.rb | 2 +- web/app/views/api_jam_tracks/show.rabl | 2 +- .../views/api_jam_tracks/show_for_client.rabl | 6 +- web/lib/tasks/jam_tracks.rake | 58 +- .../api_jam_tracks_controller_spec.rb | 1 + web/spec/factories.rb | 2 +- web/spec/features/jamtrack_shopping_spec.rb | 4 +- 27 files changed, 1914 insertions(+), 190 deletions(-) create mode 100644 db/up/jam_track_onboarding_enhancements.sql create mode 100644 ruby/lib/jam_ruby/import/tency_stem_mapping.rb create mode 100644 ruby/lib/jam_ruby/models/genre_jam_track.rb create mode 100644 ruby/lib/jam_ruby/models/jam_track_file.rb diff --git a/admin/config/initializers/jam_tracks.rb b/admin/config/initializers/jam_tracks.rb index cd02eccee..33efd995c 100644 --- a/admin/config/initializers/jam_tracks.rb +++ b/admin/config/initializers/jam_tracks.rb @@ -16,7 +16,6 @@ class JamRuby::JamTrack end def jmep_json_generate - self.genre_id = nil if self.genre_id == '' self.licensor_id = nil if self.licensor_id == '' self.jmep_json = nil if self.jmep_json == '' self.time_signature = nil if self.time_signature == '' diff --git a/db/manifest b/db/manifest index 691ae0001..81df91ca8 100755 --- a/db/manifest +++ b/db/manifest @@ -298,3 +298,4 @@ musician_search.sql enhance_band_profile.sql alter_band_profile_rate_defaults.sql repair_band_profile.sql +jam_track_onboarding_enhancements.sql diff --git a/db/up/jam_track_onboarding_enhancements.sql b/db/up/jam_track_onboarding_enhancements.sql new file mode 100644 index 000000000..1336ecdf4 --- /dev/null +++ b/db/up/jam_track_onboarding_enhancements.sql @@ -0,0 +1,65 @@ +UPDATE instruments SET id = 'double bass', description = 'Double Bass' WHERE id = 'upright bass'; +INSERT INTO instruments (id, description, popularity) VALUES ('steel guitar', 'Steel Guitar', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('orchestra', 'Orchestra', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('glockenspiel', 'Glockenspiel', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('dobro', 'Dobro', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('harp', 'Harp', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('vocoder', 'Vocoder', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('flugelhorn', 'Flugelhorn', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('timpani', 'Timpani', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('bassoon', 'Bassoon', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('charango', 'Charango', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('theremin', 'Theremin', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('sitar', 'Sitar', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('piccolo', 'Piccolo', 1); +INSERT INTO instruments (id, description, popularity) VALUES ('bagpipes', 'Bagpipes', 1); +ALTER TABLE jam_tracks ADD COLUMN onboarding_exceptions JSON; +ALTER TABLE jam_track_tracks ADD COLUMN original_filename VARCHAR; +ALTER TABLE jam_tracks ADD COLUMN additional_info VARCHAR; +ALTER TABLE jam_tracks ADD COLUMN language VARCHAR NOT NULL DEFAULT 'eng'; +ALTER TABLE jam_tracks ADD COLUMN year INTEGER; +ALTER TABLE jam_tracks ADD COLUMN vendor_id VARCHAR; + +INSERT INTO jam_track_licensors (name, description) VALUES ('Tency Music', 'Tency Music is a music production company specialized in re-recordings.'); + +CREATE TABLE genres_jam_tracks ( + id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), + jam_track_id VARCHAR(64) NOT NULL REFERENCES jam_tracks(id) ON DELETE CASCADE, + genre_id VARCHAR(64) NOT NULL REFERENCES genres(id) ON DELETE CASCADE, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +INSERT INTO genres_jam_tracks (jam_track_id, genre_id) ((SELECT jam_tracks.id, jam_tracks.genre_id FROM jam_tracks)); +ALTER TABLE jam_tracks DROP COLUMN genre_id; + +-- holds precount, click.wav, click.txt +CREATE TABLE jam_track_files ( + id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), + jam_track_id VARCHAR(64) REFERENCES jam_tracks(id) ON DELETE CASCADE, + file_type VARCHAR NOT NULL, + original_filename VARCHAR NOT NULL, + precount_num INTEGER, + url VARCHAR, + md5 VARCHAR, + length bigint, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +INSERT INTO genres (id, description) VALUES ('soft rock', 'Soft Rock'); +INSERT INTO genres (id, description) VALUES ('rap', 'Rap'); +INSERT INTO genres (id, description) VALUES ('tv & movie soundtrack', 'TV & Movie Soundtrack'); +INSERT INTO genres (id, description) VALUES ('holiday', 'Holiday'); +INSERT INTO genres (id, description) VALUES ('kids', 'Kids'); +INSERT INTO genres (id, description) VALUES ('disco', 'Disco'); +INSERT INTO genres (id, description) VALUES ('soul', 'Soul'); +INSERT INTO genres (id, description) VALUES ('hard rock', 'Hard Rock'); +INSERT INTO genres (id, description) VALUES ('funk', 'Funk'); +INSERT INTO genres (id, description) VALUES ('dance', 'Dance'); +INSERT INTO genres (id, description) VALUES ('creole', 'Creole'); +INSERT INTO genres (id, description) VALUES ('traditional', 'Traditional'); +INSERT INTO genres (id, description) VALUES ('oldies', 'Oldies'); +INSERT INTO genres (id, description) VALUES ('world', 'World'); +INSERT INTO genres (id, description) VALUES ('musical', 'Musical'); +INSERT INTO genres (id, description) VALUES ('celtic', 'Celtic'); diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index 82484997e..6b2d70a20 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -206,6 +206,8 @@ require "jam_ruby/models/jam_track" require "jam_ruby/models/jam_track_track" require "jam_ruby/models/jam_track_right" require "jam_ruby/models/jam_track_tap_in" +require "jam_ruby/models/jam_track_file" +require "jam_ruby/models/genre_jam_track" require "jam_ruby/app/mailers/async_mailer" require "jam_ruby/app/mailers/batch_mailer" require "jam_ruby/app/mailers/progress_mailer" @@ -238,6 +240,7 @@ require "jam_ruby/models/performance_sample" require "jam_ruby/models/online_presence" require "jam_ruby/models/json_store" require "jam_ruby/models/musician_search" +require "jam_ruby/import/tency_stem_mapping" include Jampb diff --git a/ruby/lib/jam_ruby/import/tency_stem_mapping.rb b/ruby/lib/jam_ruby/import/tency_stem_mapping.rb new file mode 100644 index 000000000..769496562 --- /dev/null +++ b/ruby/lib/jam_ruby/import/tency_stem_mapping.rb @@ -0,0 +1,360 @@ +module JamRuby + + # this is probably a one-off class used to map Tency-named stems into JamKazam-named stems + class TencyStemMapping + + @@log = Logging.logger[TencyStemMapping] + + def s3_manager + @s3_manager ||= S3Manager.new('jamkazam-tency', APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key) + end + + def initialize + @originals_folder = "/Volumes/sethcall/Dropbox/seth@jamkazam.com/JamTracks - Tency Music - Original Folder for Normalization Map" + @mapping_folder = "/Volumes/sethcall/Dropbox/seth@jamkazam.com/JamTracks - Tency Music" + @original_songs = {} + @mapping_songs = {} + @mappings = {} + end + + def create_map + tency_originals + tency_maps + + dump + end + + def create_mapping_map + tency_maps + + dump_map + end + + def hydrate + @original_songs = YAML.load_file('original_songs.yml') + @mapping_songs = YAML.load_file('mapping_songs.yml') + end + + def parse_sanitized_filename(filename) + instrument = nil + part = nil + + basename = File.basename(filename) + stem = basename.index('Stem') + + if stem + stripped = basename[(stem + 'Stem'.length)..-5] # takes of 'stem' and '.wav' + stripped.strip! + dash = stripped.index('-') + + if dash == 0 + stripped = stripped[1..-1].strip! + # now we should have something like "Vocal - Lead" (instrument - part) + instrument, part = stripped.split('-') + instrument.strip! if instrument + part.strip! if part + else + "no or misplaced dash for #{filename}" + end + + else + raise "no stem for #{filename}" + end + + [instrument, part] + end + + # For all the tracks that I have labeled manually as + # Instrument = Upright Bass and Part = Upright Bass, + # can you please change both the Instrument and Part to Double Bass instead? + # + def check_mappings + missing_instrument = 0 + missing_part = 0 + part_names = [] + + hydrate + @mapping_songs.each do |cache_id, data| + mapped_filename = data[:filename] + @@log.debug("parsing #{mapped_filename}") + instrument, part = parse_sanitized_filename(mapped_filename) + @@log.debug("parsed #{instrument} (#{part})") + missing_instrument = missing_instrument + 1 unless instrument + missing_part = missing_part + 1 unless part + part_names << mapped_filename unless part + end + + @@log.info("SUMMARY") + @@log.info("-------") + @@log.info("missing instruments:#{missing_instrument} missing parts: #{missing_part}") + @@log.info("files with no parts: #{part_names}") + + # files with no parts: + # ["Huey Lewis And The News - Heart And Soul - 31957/Heart And Soul Stem - Synth 2.wav", + # "ZZ Top - Tush - 20852/Tush Stem - Clicktrack.wav", + # "Crosby Stills And Nash - Teach Your Children - 15440/Teach Your Children Stem - Bass Guitar.wav", + # /Brad Paisley - She's Everything - 19886/She's Everything Stem - Clicktrack.wav", + # "Toby Keith - Beer For My Horses - 7221/Beer For My Horses Stem - Lap Steel.wav", + # Toby Keith - Beer For My Horses - 7221/Beer For My Horses Stem - Acoustic Guitar.wav" + + end + + def track_mapping(basename, instr_part) + instrument = instr_part[:instrument] + part = instr_part[:part] + + basename.downcase! + + info = @mappings[basename] + + unless info + info = {matches:[]} + @mappings[basename] = info + end + + info[:matches] << instr_part + end + + def correlate + mapped = 0 + unmapped = 0 + unmapped_details = [] + no_instrument = [] + common_unknown_instruments = {} + + hydrate + @mapping_songs.each do |cache_id, data| + # go through each track hand-mapped, and find it's matching song if any. + + mapped_filename = data[:filename] + found_original = @original_songs[cache_id] + if found_original + # mapping made + + original_filename = found_original[:filename] + original_basename = File.basename(original_filename).downcase + + mapped = mapped + 1 + + instrument, part = parse_sanitized_filename(mapped_filename) + instr_part = JamTrackImporter.determine_instrument(instrument, part) + + instr_part[:instrument] + + if instr_part[:instrument] + + # track the mapping of this one + track_mapping(original_basename, instr_part) + + else + @@log.error("unable to determine instrument for #{File.basename(mapped_filename)}") + no_instrument << ({filename: File.basename(mapped_filename), instrument: instrument, part: part}) + common_unknown_instruments["#{instrument}-(#{part})"] = 1 + end + + else + unmapped = unmapped + 1 + unmapped_details << {filename: mapped_filename} + end + end + + puts("SUMMARY") + puts("-------") + puts("MAPPED:#{mapped} UNMAPPED:#{unmapped}") + unmapped_details.each do |unmapped_detail| + puts "UNMAPPED FILE: #{File.basename(unmapped_detail[:filename])}" + end + puts("UNKNOWN INSTRUMENT: #{no_instrument.length}") + no_instrument.each do |item| + puts("UNKNOWN INSTRUMENT: #{item[:filename]}") + end + common_unknown_instruments.each do |key, value| + puts("#{key}") + end + @mappings.each do |basename, mapping| + matches = mapping[:matches] + counts = matches.each_with_object(Hash.new(0)) { |word,counts| counts[word] += 1 } + ordered_matches = counts.sort_by {|k, v| -v} + output = "" + ordered_matches.each do |match| + detail = match[0] + count = match[1] + output << "#{detail[:instrument]}(#{detail[:part]})/#{count}, " + end + + puts "map detail: #{basename}: #{output}" + + mapping[:ordered] = ordered_matches + mapping[:detail] = output + end + CSV.open("mapping.csv", "wb") do |csv| + @mappings.each do |basename, mapping| + item = mapping[:ordered] + + trust_worthy = item.length == 1 + unless trust_worthy + # if the 1st item is at least 4 'counts' more than the next item, we can consider it trust_worthy + if item[0][1] - 4 > item[1][1] + trust_worthy = true + end + end + csv << [ basename, item[0][0][:instrument], item[0][0][:part], item[0][1], trust_worthy ] + end + end + CSV.open("determinate-single-matches.csv", "wb") do |csv| + @mappings.each do |basename, mapping| + if mapping[:ordered].length == 1 && mapping[:ordered][0][1] == 1 + item = mapping[:ordered] + csv << [ basename, item[0][0][:instrument], item[0][0][:part], item[0][1] ] + end + end + end + CSV.open("determinate-multi-matches.csv", "wb") do |csv| + @mappings.each do |basename, mapping| + if mapping[:ordered].length == 1 && mapping[:ordered][0][1] > 1 + item = mapping[:ordered] + csv << [ basename, item[0][0][:instrument], item[0][0][:part], item[0][1] ] + end + end + end + CSV.open("ambiguous-matches.csv", "wb") do |csv| + @mappings.each do |basename, mapping| + if mapping[:ordered].length > 1 + csv << [ basename, mapping[:detail] ] + end + end + end + end + + def dump + File.open('original_songs.yml', 'w') {|f| f.write(YAML.dump(@original_songs)) } + File.open('mapping_songs.yml', 'w') {|f| f.write(YAML.dump(@mapping_songs)) } + end + def dump_map + File.open('mapping_songs.yml', 'w') {|f| f.write(YAML.dump(@mapping_songs)) } + end + + def md5(filepath) + Digest::MD5.file(filepath).hexdigest + end + + def tency_original_check + songs = Pathname.new(@originals_folder).children.select { |c| c.directory? } + songs.each do |song| + dirs = Pathname.new(song).children.select {|c| c.directory? } + + @@log.debug "SONG #{song}" + dirs.each do |dir| + @@log.debug "#{dir.basename.to_s}" + end + @@log.debug "" + end + end + + def tency_originals + songs = Pathname.new(@originals_folder).children.select { |c| c.directory? } + songs.each do |filename| + id = parse_id(filename.basename.to_s ) + files = Pathname.new(filename).children.select {|c| c.file? } + + # also look into any 1st level folders we might find + + dirs = Pathname.new(filename).children.select {|c| c.directory? } + dirs.each do |dir| + more_tracks = Pathname.new(dir).children.select {|c| c.file? } + files = files + more_tracks + end + + files.each do |file| + @@log.debug("processing original track #{file.to_s}") + md5 = md5(file.to_s) + song = {md5:md5, filename:file.to_s, id:id} + @original_songs[cache_id(id, md5)] = song + end + end + + end + + def tency_maps + songs = Pathname.new(@mapping_folder).children.select { |c| c.directory? } + songs.each do |song_filename| + id = parse_id_mapped(song_filename.basename.to_s ) + @@log.debug "processing song #{song_filename.to_s}" + + tracks = Pathname.new(song_filename).children.select {|c| c.file? } + tracks.each do |track| + if track.to_s.include? "Stem" + @@log.debug("processing mapped track #{track.to_s}") + md5 = md5(track.to_s) + + song = {md5:md5, filename:track.to_s} + @mapping_songs[cache_id(id, md5)] = song + end + end + end + end + + def cache_id(id, md5) + "#{id}-#{md5}" + end + + def parse_id(filename) + #amy-winehouse_you-know-i-m-no-good-feat-ghostface-killah_11767 + + index = filename.rindex('_') + if index + id = filename[(index + 1)..-1] + + if id.end_with?('/') + id = id[0...-1] + end + + id = id.to_i + + if id == 0 + raise "no valid ID in filename: #{filename}" + end + else + raise "no _ in filename: #{filename}" + end + id + end + + def parse_id_mapped(filename) + #Flyleaf - I'm So Sick - 15771 + + index = filename.rindex('-') + if index + id = filename[(index + 1)..-1] + + if id.end_with?('/') + id = id[0...-1] + end + + id.strip! + + id = id.to_i + + if id == 0 + raise "no valid ID in filename: #{filename}" + end + else + raise "no - in filename: #{filename}" + end + id + end + + + + def tency_originals2 + s3_manager.list_directories('mapper').each do |song_folder| + @@log.debug("searching through tency directory. song folder:'#{song_folder}'") + + id = parse_id(song_folder) + @@log.debug("ID #{id}") + + top_folder = s3_manager.list_directories(song_folder) + end + end + end +end \ No newline at end of file diff --git a/ruby/lib/jam_ruby/jam_track_importer.rb b/ruby/lib/jam_ruby/jam_track_importer.rb index 70ef72e6a..502f88f0c 100644 --- a/ruby/lib/jam_ruby/jam_track_importer.rb +++ b/ruby/lib/jam_ruby/jam_track_importer.rb @@ -14,6 +14,7 @@ module JamRuby attr_accessor :name attr_accessor :reason attr_accessor :detail + attr_accessor :storage_format def jamkazam_s3_manager @s3_manager ||= S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key) @@ -23,11 +24,141 @@ module JamRuby @public_s3_manager ||= S3Manager.new(APP_CONFIG.aws_bucket_public, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key) end + def initialize(storage_format = 'default') + @storage_format = storage_format + end + def finish(reason, detail) self.reason = reason self.detail = detail end + + # this method was created due to Tency-sourced data having no master track + # it goes through all audio tracks, and creates a master mix from it. (mix + normalize) + def create_master(metadata, metalocation) + + parsed_metalocation = parse_metalocation(metalocation) + + if parsed_metalocation.nil? + finish("invalid_metalocation", metalocation) + return + end + + original_artist = parsed_metalocation[1] + meta_name = parsed_metalocation[2] + + self.name = metadata[:name] || meta_name + + + audio_path = metalocation[0...-"/meta.yml".length] + + all_files = fetch_important_files(audio_path) + + audio_files = [] + master_found = false + all_files.each do |file| + + parsed_wav = parse_file(file) + if parsed_wav[:master] + master_found = true + elsif parsed_wav[:type] == :track + + audio_files << file + end + end + + if master_found + @@log.debug("master exists... skipping #{self.name} ") + finish('success', nil) + return + else + + tracks = [] + + #tmp_dir = Dir.mktmpdir + #tmp_dir = "/var/folders/05/1jpzfcln1hq9p666whnd7chr0000gn/T/d20150809-9945-1ykr85u" + Dir.mktmpdir do |tmp_dir| + @@log.debug("downloading all audio files in #{tmp_dir}") + audio_files.each do |s3_track| + track = File.join(tmp_dir, File.basename(s3_track)) + tracks << track + JamTrackImporter.song_storage_manager.download(s3_track, track) + end + + # first have to check if all are the same sample rate. If not, we have to make it so + + first_sample_rate = nil + normalize_needed = false + tracks.each do |track| + sample_rate = `soxi -r "#{track}"`.strip + + puts "SAMPLE RATE #{sample_rate}" + if first_sample_rate.nil? + first_sample_rate = sample_rate + else + if first_sample_rate != sample_rate + # we need to normalize all of them + normalize_needed = true + break + end + end + end + + normalized_tracks = [] + if normalize_needed + tracks.each do |track| + normalized_track = File.join(tmp_dir, 'normalized-' + File.basename(track)) + output = `sox "#{track}" "#{normalized_track}" rate #{first_sample_rate}` + @@log.debug("resampling #{normalized_track}; output: #{output}") + normalized_tracks << normalized_track + end + tracks = normalized_tracks + end + + + + temp_file = File.join(tmp_dir, "temp.wav") + output_filename = JamTrackImporter.remove_s3_special_chars("#{self.name} Master Mix.wav") + output_file = File.join(tmp_dir, output_filename) + command = "sox -m " + tracks.each do |track| + command << " \"#{track}\"" + end + command << " \"#{temp_file}\"" + + @@log.debug("mixing with cmd: " + command) + sox_output = `#{command}` + result_code = $?.to_i + + if result_code != 0 + @@log.error("unable to generate master mix") + finish("sox_master_mix_failure", sox_output) + else + + # now normalize the audio + + command = "sox --norm \"#{temp_file}\" \"#{output_file}\"" + @@log.debug("normalizing with cmd: " + command) + sox_output = `#{command}` + result_code = $?.to_i + if result_code != 0 + @@log.error("unable to normalize master mix") + finish("sox_master_mix_failure", sox_output) + else + + # now we need to upload the output back up + s3_target = audio_path + '/' + output_filename + @@log.debug("uploading #{output_file} to #{s3_target}") + JamTrackImporter.song_storage_manager.upload(s3_target, output_file ) + finish('success', nil) + end + + end + end + end + end + def dry_run(metadata, metalocation) metadata ||= {} @@ -38,35 +169,92 @@ module JamRuby original_artist = parsed_metalocation[1] name = parsed_metalocation[2] + JamTrackImporter.summaries[:unique_artists] << original_artist + success = dry_run_metadata(metadata, original_artist, name) return unless success - dry_run_audio(metadata, "audio/#{original_artist}/#{name}") + audio_path = metalocation[0...-"/meta.yml".length] + + + dry_run_audio(metadata, audio_path) finish("success", nil) end + def is_tency_storage? + assert_storage_set + @storage_format == 'Tency' + end + + def assert_storage_set + raise "no storage_format set" if @storage_format.nil? + end + + def parse_metalocation(metalocation) + # metalocation = mapped/4 Non Blondes - What's Up - 6475/meta.yml + if is_tency_storage? - bits = metalocation.split('/') + suffix = '/meta.yml' - if bits.length != 4 - finish("invalid_metalocation", "metalocation not valid #{metalocation}") - return nil + unless metalocation.end_with? suffix + finish("invalid_metalocation", "metalocation not valid #{metalocation}") + return nil + end + + metalocation = metalocation[0...-suffix.length] + + first_path = metalocation.index('/') + if first_path.nil? + finish("invalid_metalocation", "metalocation not valid #{metalocation}") + return nil + end + metalocation = metalocation[(first_path + 1)..-1] + + bits = ['audio'] + # example: Sister Hazel - All For You - 10385 + first_dash = metalocation.index(' - ') + if first_dash + artist = metalocation[0...(first_dash)].strip + bits << artist + else + finish("invalid_metalocation", "metalocation not valid #{metalocation}") + return nil + end + + last_dash = metalocation.rindex('-') + if last_dash + song = metalocation[(first_dash+3)...last_dash].strip + bits << song + else + finish("invalid_metalocation", "metalocation not valid #{metalocation}") + return nil + end + + bits << 'meta.yml' + bits + else + bits = metalocation.split('/') + + if bits.length != 4 + finish("invalid_metalocation", "metalocation not valid #{metalocation}") + return nil + end + + if bits[0] != "audio" + finish("invalid_metalocation", "first bit is not 'audio' #{metalocation}") + return nil + end + + if bits[3] != 'meta.yml' + finish('invalid_metalocation', "last bit is not 'meta.yml' #{metalocation}") + return nil + end + + bits end - - if bits[0] != "audio" - finish("invalid_metalocation", "first bit is not 'audio' #{metalocation}") - return nil - end - - if bits[3] != 'meta.yml' - finish('invalid_metalocation', "last bit is not 'meta.yml' #{metalocation}") - return nil - end - - bits end # if you change this, it will (at least without some work )break development usage of jamtracks @@ -91,6 +279,83 @@ module JamRuby true end + def determine_genres(metadata) + + genres = [] + if metadata[:genres] + metadata[:genres].each do |genre| + if genre == 'hard/metal' + genres << Genre.find('hard rock') + genres << Genre.find('metal') + elsif genre == 'christmas' + genres << Genre.find('holiday') + elsif genre == 'alternative' + genres << Genre.find('alternative rock') + elsif genre == '80s' + # swallow + elsif genre == 'love' + # swallow + elsif genre == 'christian' || genre == 'gospel' + genres << Genre.find('religious') + elsif genre == 'punk/grunge' + genres << Genre.find('punk') + elsif genre == 'electro' + genres << Genre.find('electronic') + elsif genre == 'teen pop' + genres << Genre.find('pop') + elsif genre == "rock 'n roll" + genres << Genre.find('rock') + elsif genre == 'zouk/creole' + genres << Genre.find('creole') + elsif genre == 'world/folk' + genres << Genre.find('world') + genres << Genre.find('folk') + elsif genre == 'french pop' + # swallow + elsif genre == 'schlager' + #swallow + elsif genre == 'humour' + # swallow + elsif genre == 'oriental' + genres << genre.find('asian') + else + found = Genre.find_by_id(genre) + genres << found if found + end + + end + end + + genres + end + + def determine_language(metadata) + + found = ISO_639.find_by_code('eng') + + language = metadata[:language] + + if language + language.downcase! + + if language == 'instrumental' + return 'instrumental' + end + + if language.include? 'spanish' + found = ISO_639.find_by_code('spa') + elsif language.include? 'german' + found = ISO_639.find_by_code('ger') + elsif language.include? 'portuguese' + found = ISO_639.find_by_code('por') + elsif language.include? 'english' + found = ISO_639.find_by_code('eng') + end + end + + found[0] # 3 letter code + end + def synchronize_metadata(jam_track, metadata, metalocation, original_artist, name, options) metadata ||= {} @@ -104,14 +369,24 @@ module JamRuby jam_track.metalocation = metalocation jam_track.original_artist = metadata["original_artist"] || original_artist jam_track.name = self.name - jam_track.genre_id = 'rock' + jam_track.additional_info = metadata[:additional_info] + jam_track.year = metadata[:year] + jam_track.genres = determine_genres(metadata) + jam_track.language = determine_language(metadata) jam_track.plan_code = metadata["plan_code"] || gen_plan_code(jam_track.original_artist, jam_track.name) jam_track.price = 1.99 - jam_track.reproduction_royalty_amount = 0 - jam_track.licensor_royalty_amount = 0 + jam_track.reproduction_royalty_amount = nil + jam_track.reproduction_royalty = true + jam_track.public_performance_royalty = true + jam_track.licensor_royalty_amount = 0.4 jam_track.sales_region = 'Worldwide' jam_track.recording_type = 'Cover' jam_track.description = "This is a JamTrack audio file for use exclusively with the JamKazam service. This JamTrack is a high quality cover of the #{jam_track.original_artist} song \"#{jam_track.name}\"." + + if is_tency_storage? + jam_track.vendor_id = metadata[:id] + jam_track.licensor = JamTrackLicensor.find_by_name('Tency Music') + end else if !options[:resync_audio] #@@log.debug("#{self.name} skipped because it already exists in database") @@ -167,12 +442,18 @@ module JamRuby else instrument = 'electric guitar' end - elsif potential_instrument == 'electric gutiar' || potential_instrument == 'electric guitat' + elsif potential_instrument == 'acoustic' + instrument = 'acoustic guitar' + elsif potential_instrument == 'acoutic guitar' + instrument = 'electric guitar' + elsif potential_instrument == 'electric gutiar' || potential_instrument == 'electric guitat' || potential_instrument == 'electric guitary' instrument = 'electric guitar' elsif potential_instrument == 'keys' instrument = 'keyboard' elsif potential_instrument == 'vocal' || potential_instrument == 'vocals' instrument = 'voice' + elsif potential_instrument == 'upright bass' + instrument = 'double bass' elsif potential_instrument == 'bass' instrument = 'bass guitar' elsif potential_instrument == 'drum' @@ -185,8 +466,9 @@ module JamRuby else part = 'Sound FX' end - - + elsif potential_instrument == 'computer scratches' + instrument = 'computer' + part = 'Scratches' elsif potential_instrument == "sax" instrument = 'saxophone' elsif potential_instrument == "vocal back up" @@ -213,18 +495,43 @@ module JamRuby elsif potential_instrument == 'fretless bass' instrument = 'bass guitar' part = 'Fretless' + elsif potential_instrument == 'lap steel' || potential_instrument == 'pedal steel' + instrument = 'steel guitar' elsif potential_instrument == 'clock percussion' instrument = 'computer' part = 'Clock' - elsif potential_instrument == 'horns' + elsif potential_instrument == 'horns' || potential_instrument == 'horn' instrument = 'other' part = 'Horns' - elsif potential_instrument == 'strings' + elsif potential_instrument == 'english horn' instrument = 'other' + part = 'English Horn' + elsif potential_instrument == 'bass clarinet' + instrument = 'other' + part = 'Bass Clarinet' + elsif potential_instrument == 'recorder' + instrument = 'other' + part = 'Recorder' + elsif potential_instrument == 'marimba' + instrument = 'keyboard' + part = 'Marimba' + elsif potential_instrument == 'strings' + instrument = 'orchestra' part = 'Strings' - elsif potential_instrument == 'orchestration' - instrument = 'computer' - part = 'Orchestration' + elsif potential_instrument == 'celesta' + instrument = 'keyboard' + elsif potential_instrument == 'balalaika' + instrument = 'other' + part = 'Balalaika' + elsif potential_instrument == 'tanpura' + instrument = 'other' + part = 'Tanpura' + elsif potential_instrument == 'quena' + instrument = 'other' + part = 'Quena' + elsif potential_instrument == 'bouzouki' + instrument = 'other' + part = 'Bouzouki' elsif potential_instrument == 'claps' || potential_instrument == 'hand claps' instrument = 'computer' part = 'Claps' @@ -246,20 +553,44 @@ module JamRuby end - def parse_wav(file) + def parse_file(file) bits = file.split('/') filename = bits[bits.length - 1] # remove all but just the filename filename_no_ext = filename[0..-5] comparable_filename = filename_no_ext.downcase # remove .wav + type = nil master = false instrument = nil part = nil + precount_num = nil + no_precount_detail = nil + if comparable_filename == "click" || comparable_filename.include?("clicktrack") + if filename.end_with?('.txt') + type = :clicktxt + else + type = :clickwav + end + elsif comparable_filename.include? "precount" + type = :precount + index = comparable_filename.index('precount') + precount = comparable_filename[(index + 'precount'.length)..-1].strip + if precount.start_with?('_') + precount = precount[1..-1] + end + if precount.to_i == 0 + no_precount_detail = comparable_filename + else + precount_num = precount.to_i + end - if comparable_filename.include?("master mix") || comparable_filename.include?("mastered mix") + + elsif comparable_filename.include?("master mix") || comparable_filename.include?("mastered mix") master = true + type = :master else + type = :track stem_location = comparable_filename.index('stem -') unless stem_location stem_location = comparable_filename.index('stems -') @@ -294,72 +625,171 @@ module JamRuby result = determine_instrument(possible_instrument, possible_part) instrument = result[:instrument] part = result[:part] + else + if is_tency_storage? + # we can check to see if we can find mapping info for this filename + mapping = JamTrackImporter.tency_mapping[filename.downcase] + + if mapping && mapping[:trust] + instrument = mapping[:instrument] + part = mapping[:part] + end + + # tency mapping didn't work; let's retry with our own home-grown mapping + if instrument.nil? && !possible_instrument.nil? + result = determine_instrument(possible_instrument, possible_part) + instrument = result[:instrument] + part = result[:part] + end + end end + end - {filename: filename, master: master, instrument: instrument, part: part} + {filename: filename, master: master, instrument: instrument, part: part, type: type, precount_num: precount_num, no_precount_detail: no_precount_detail} end def dry_run_audio(metadata, s3_path) - all_files = fetch_wav_files(s3_path) + all_files = fetch_important_files(s3_path) all_files.each do |file| - if file.end_with?('.wav') - parsed_wav = parse_wav(file) - if parsed_wav[:master] - @@log.debug("#{self.name} master! filename: #{parsed_wav[:filename]}") - else - if !parsed_wav[:instrument] || !parsed_wav[:part] - @@log.warn("#{self.name} track! instrument: #{parsed_wav[:instrument] ? parsed_wav[:instrument] : 'N/A'}, part: #{parsed_wav[:part] ? parsed_wav[:part] : 'N/A'}, filename: #{parsed_wav[:filename]} ") - else - @@log.debug("#{self.name} track! instrument: #{parsed_wav[:instrument] ? parsed_wav[:instrument] : 'N/A'}, part: #{parsed_wav[:part] ? parsed_wav[:part] : 'N/A'}, filename: #{parsed_wav[:filename]} ") + + # ignore click/precount + parsed_wav = parse_file(file) + if parsed_wav[:master] + @@log.debug("#{self.name} master! filename: #{parsed_wav[:filename]}") + elsif parsed_wav[:type] == :track + + JamTrackImporter.summaries[:total_tracks] += 1 + + if parsed_wav[:instrument].nil? + detail = JamTrackImporter.summaries[:no_instrument_detail] + file_detail = detail[parsed_wav[:filename].downcase] + if file_detail.nil? + detail[parsed_wav[:filename].downcase] = 0 end + detail[parsed_wav[:filename].downcase] += 1 + + JamTrackImporter.summaries[:no_instrument] += 1 + end + + JamTrackImporter.summaries[:no_part] += 1 if parsed_wav[:part].nil? + + if !parsed_wav[:instrument] || !parsed_wav[:part] + @@log.warn("#{self.name} track! instrument: #{parsed_wav[:instrument] ? parsed_wav[:instrument] : 'N/A'}, part: #{parsed_wav[:part] ? parsed_wav[:part] : 'N/A'}, filename: #{parsed_wav[:filename]} ") + else + @@log.debug("#{self.name} track! instrument: #{parsed_wav[:instrument] ? parsed_wav[:instrument] : 'N/A'}, part: #{parsed_wav[:part] ? parsed_wav[:part] : 'N/A'}, filename: #{parsed_wav[:filename]} ") + end + elsif parsed_wav[:type] == :clickwav + + elsif parsed_wav[:type] == :clicktxt + + elsif parsed_wav[:type] == :precount + if parsed_wav[:precount_num].nil? + JamTrackImporter.summaries[:no_precount_num] += 1 + JamTrackImporter.summaries[:no_precount_detail] << parsed_wav[:no_precount_detail] + end + + else + JamTrackImporter.summaries[:unknown_filetype] += 1 + end + end + end + + + def set_custom_weight(track) + + slop = 800 + + instrument_weight = nil + # if there are any persisted tracks, do not sort from scratch; just stick new stuff at the end + + if track.persisted? + instrument_weight = track.position + else + if track.instrument_id == 'voice' + + if track.part && track.part.start_with?('Lead') + instrument_weight = 100 + elsif track.part && track.part.start_with?('Backing') + instrument_weight = 110 + else + instrument_weight = 120 + end + + elsif track.instrument_id == 'drums' + + if track.part && track.part == 'Drums' + instrument_weight = 150 + elsif track.part && track.part == 'Percussion' + instrument_weight = 160 + else + instrument_weight = 170 + end + + elsif track.instrument_id == 'bass guitar' && track.part && track.part == 'Bass' + instrument_weight = 180 + + elsif track.instrument_id == 'piano' && track.part && track.part == 'Piano' + instrument_weight = 250 + + elsif track.instrument_id == 'keyboard' + + if track.part && track.part.start_with?('Synth') + instrument_weight = 260 + elsif track.part && track.part.start_with?('Pads') + instrument_weight = 270 + else + instrument_weight = 280 + end + + elsif track.instrument_id == 'acoustic guitar' + if track.part && track.part.start_with?('Lead') + instrument_weight = 300 + elsif track.part && track.part.start_with?('Rhythm') + instrument_weight = 310 + else + instrument_weight = 320 + end + elsif track.instrument_id == 'electric guitar' + if track.part && track.part.start_with?('Lead') + instrument_weight = 400 + elsif track.part && track.part.start_with?('Solo') + instrument_weight = 410 + elsif track.part && track.part.start_with?('Rhythm') + instrument_weight = 420 + else + instrument_weight = 440 end else - @@log.debug("#{self.name} ignoring non-wav file #{file}") + instrument_weight = slop + end + + if track.track_type == 'Master' + instrument_weight = 1000 end end + + instrument_weight end def sort_tracks(tracks) - def set_custom_weight(track) - weight = 5 - # if there are any persisted tracks, do not sort from scratch; just stick new stuff at the end - - if track.persisted? - weight = track.position - else - case track.instrument_id - when 'electric guitar' - weight = 100 - when 'acoustic guitar' - weight = 200 - when 'drums' - weight = 300 - when 'keys' - weight = 400 - when 'computer' - weight = 600 - else - weight = 500 - end - if track.track_type == 'Master' - weight = 1000 - end - end - - - weight - end - sorted_tracks = tracks.sort do |a, b| a_weight = set_custom_weight(a) b_weight = set_custom_weight(b) - a_weight <=> b_weight + if a_weight != b_weight + a_weight <=> b_weight + elsif a.instrument_id != b.instrument_id + a.instrument_id <=> b.instrument_id + else + a_part = a.part + b_part = b.part + a_part <=> b_part + end end # default to 1, but if there are any persisted tracks, this will get manipulated to be +1 the highest persisted track @@ -387,9 +817,10 @@ module JamRuby attempt_to_match_existing_tracks = true # find all wav files in the JamTracks s3 bucket - wav_files = fetch_wav_files(s3_path) + wav_files = fetch_important_files(s3_path) tracks = [] + addt_files = [] wav_files.each do |wav_file| @@ -419,27 +850,51 @@ module JamRuby @@log.debug("no existing track found; creating a new one") track = JamTrackTrack.new + track.original_filename = wav_file track.original_audio_s3_path = wav_file - parsed_wav = parse_wav(wav_file) + file = JamTrackFile.new + file.original_filename = wav_file + file.original_audio_s3_path = wav_file + parsed_wav = parse_file(wav_file) + + unknowns = 0 if parsed_wav[:master] track.track_type = 'Master' - track.part = 'Master' + track.part = 'Master Mix' + track.instrument_id = 'computer' + tracks << track @@log.debug("#{self.name} master! filename: #{parsed_wav[:filename]}") - else + elsif parsed_wav[:type] == :track + if !parsed_wav[:instrument] || !parsed_wav[:part] @@log.warn("#{self.name} track! instrument: #{parsed_wav[:instrument] ? parsed_wav[:instrument] : 'N/A'}, part: #{parsed_wav[:part] ? parsed_wav[:part] : 'N/A'}, filename: #{parsed_wav[:filename]} ") + unknowns += 1 else @@log.debug("#{self.name} track! instrument: #{parsed_wav[:instrument] ? parsed_wav[:instrument] : 'N/A'}, part: #{parsed_wav[:part] ? parsed_wav[:part] : 'N/A'}, filename: #{parsed_wav[:filename]} ") end + track.instrument_id = parsed_wav[:instrument] || 'other' track.track_type = 'Track' - track.part = parsed_wav[:part] || 'Other' + track.part = parsed_wav[:part] || "Other #{unknowns}" + tracks << track + elsif parsed_wav[:type] == :clicktxt + file.file_type = 'ClickTxt' + addt_files << file + elsif parsed_wav[:type] == :clickwav + file.file_type = 'ClickWav' + addt_files << file + elsif parsed_wav[:type] == :precount + file.file_type = 'Precount' + file.precount_num = parsed_wav[:precount_num] + addt_files << file + else + finish("unknown_file_type", "unknown file type #{wave_file}") + return false end - tracks << track end jam_track.jam_track_tracks.each do |jam_track_track| @@ -450,10 +905,18 @@ module JamRuby end end + jam_track.jam_track_files.each do |jam_track_file| + unless addt_files.include?(jam_track_file) + @@log.info("destroying removed JamTrackFile #{jam_track_file.inspect}") + jam_track_file.destroy # should also delete s3 files associated with this jamtrack + end + end + @@log.info("sorting tracks") tracks = sort_tracks(tracks) jam_track.jam_track_tracks = tracks + jam_track.jam_track_files = addt_files saved = jam_track.save @@ -505,7 +968,7 @@ module JamRuby wav_file = File.join(tmp_dir, basename) # bring the original wav file down from S3 to local file system - JamTrackImporter::s3_manager.download(track.original_audio_s3_path, wav_file) + JamTrackImporter::song_storage_manager.download(track.original_audio_s3_path, wav_file) sample_rate = `soxi -r "#{wav_file}"`.strip @@ -553,7 +1016,10 @@ module JamRuby if !preview_succeeded return false end + elsif track.track_type == 'Track' + synchronize_track_preview(track, tmp_dir, ogg_44100) end + end track.save! @@ -582,6 +1048,68 @@ module JamRuby true end + def synchronize_track_preview(track, tmp_dir, ogg_44100) + + out_wav = File.join(tmp_dir, 'stripped.wav') + + burp_gaps = ['0.3', '0.2', '0.1', '0.05'] + + total_time_command = "soxi -D \"#{ogg_44100}\"" + total_time = `#{total_time_command}`.to_f + + result_code = -20 + stripped_time = total_time # default to the case where we just start the preview at the beginning + + burp_gaps.each do |gap| + command_strip_lead_silence = "sox \"#{ogg_44100}\" \"#{out_wav}\" silence 1 #{gap} 1%" + + @@log.debug("stripping silence: " + command_strip_lead_silence) + + output = `#{command_strip_lead_silence}` + + result_code = $?.to_i + + if result_code == 0 + stripped_time_command = "soxi -D \"#{out_wav}\"" + stripped_time_test = `#{stripped_time_command}`.to_f + + if stripped_time_test < 1 # meaning a very short duration + @@log.warn("could not determine the start of non-silencea. assuming beginning") + stripped_time = total_time # default to the case where we just start the preview at the beginning + else + stripped_time = stripped_time_test # accept the measured time of the stripped file and move on by using break + break + end + else + @@log.warn("unable to determine silence for jam_track #{track.original_filename}, #{output}") + stripped_time = total_time # default to the case where we just start the preview at the beginning + end + + end + + preview_start_time = total_time - stripped_time + + # this is in seconds; convert to integer milliseconds + preview_start_time = (preview_start_time * 1000).to_i + + preview_start_time = nil if preview_start_time < 0 + + track.preview_start_time = preview_start_time + + if track.preview_start_time + @@log.debug("determined track start time to be #{track.preview_start_time}") + else + @@log.debug("determined track start time to be #{track.preview_start_time}") + end + + track.process_preview(ogg_44100, tmp_dir) if track.preview_start_time + + if track.preview_generate_error + @@log.warn(track.preview_generate_error) + end + + end + def synchronize_master_preview(track, tmp_dir, ogg_44100, ogg_digest) begin @@ -639,12 +1167,12 @@ module JamRuby end def fetch_all_files(s3_path) - JamTrackImporter::s3_manager.list_files(s3_path) + JamTrackImporter::song_storage_manager.list_files(s3_path) end - def fetch_wav_files(s3_path) + def fetch_important_files(s3_path) files = fetch_all_files(s3_path) - files.select { |file| file.end_with?('.wav') } + files.select { |file| file.end_with?('.wav') || file.end_with?('.txt') } end def synchronize(jam_track, metadata, metalocation, options) @@ -664,7 +1192,9 @@ module JamRuby return unless success - synchronized_audio = synchronize_audio(jam_track, metadata, "audio/#{original_artist}/#{name}", options[:skip_audio_upload]) + audio_path = metalocation[0...-"/meta.yml".length] + + synchronized_audio = synchronize_audio(jam_track, metadata, audio_path, options[:skip_audio_upload]) return unless synchronized_audio @@ -673,6 +1203,9 @@ module JamRuby finish("success", nil) end + # do a last check on any problems with the jamtrack + jam_track.sync_onboarding_exceptions + end def synchronize_recurly(jam_track) @@ -690,16 +1223,205 @@ module JamRuby class << self + attr_accessor :storage_format + attr_accessor :tency_mapping + attr_accessor :tency_metadata + attr_accessor :summaries + + def report_summaries + @@log.debug("SUMMARIES DUMP") + @@log.debug("--------------") + @summaries.each do |k, v| + + if k == :no_instrument_detail + @@log.debug("#{k}: #{v}") + elsif k == :no_precount_detail + v.each do |precount_detail| + @@log.debug("precount: #{precount_detail}") + end + elsif k == :unique_artists + v.each do |artist| + @@log.debug("artist: #{artist}") + end + else + @@log.debug("#{k}: #{v}") + end + end + end + + def song_storage_manager + if is_tency_storage? + tency_s3_manager + else + s3_manager + end + end + + def summaries + @summaries ||= {unknown_filetype: 0, no_instrument: 0, no_part: 0, total_tracks: 0, no_instrument_detail: {}, no_precount_num: 0, no_precount_detail: [], unique_artists: SortedSet.new} + end + + def tency_s3_manager + @tency_s3_manager ||= S3Manager.new('jamkazam-tency', APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key) + end + def s3_manager @s3_manager ||= S3Manager.new(APP_CONFIG.aws_bucket_jamtracks, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key) end def private_s3_manager - @s3_manager ||= S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key) + @private_s3_manager ||= S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key) end + def extract_tency_song_id(metalocation) + # metalocation = mapped/4 Non Blondes - What's Up - 6475/meta.yml + + first_path = metalocation.index('/') + return nil unless first_path + metalocation = metalocation[(first_path + 1)..-1] + + suffix = '/meta.yml' + metalocation = metalocation[0...-suffix.length] + + last_dash = metalocation.rindex('-') + return nil if last_dash.nil? + + id = metalocation[(last_dash+1)..-1].strip + + return nil if id.to_i == 0 + + id + end + + def is_tency_storage? + assert_storage_set + @storage_format == 'Tency' + end + + def assert_storage_set + raise "no storage_format set" if @storage_format.nil? + end + + def iterate_tency_song_storage(&blk) + count = 0 + song_storage_manager.list_directories('mapped').each do |song| + @@log.debug("searching through song directory '#{song}'") + + metalocation = "#{song}meta.yml" + + metadata = load_metalocation(metalocation) + + blk.call(metadata, metalocation) + + count += 1 + #break if count > 100 + + end + end + + def iterate_default_song_storage(&blk) + song_storage_manager.list_directories('audio').each do |original_artist| + @@log.debug("searching through artist directory '#{original_artist}'") + + songs = song_storage_manager.list_directories(original_artist) + songs.each do |song| + @@log.debug("searching through song directory' #{song}'") + + metalocation = "#{song}meta.yml" + + metadata = load_metalocation(metalocation) + + blk.call(metadata, metalocation) + end + end + end + + def iterate_song_storage(&blk) + if is_tency_storage? + iterate_tency_song_storage do |metadata, metalocation| + blk.call(metadata, metalocation) + end + else + iterate_default_song_storage do |metadata, metalocation| + blk.call(metadata, metalocation) + end + end + end def dry_run + iterate_song_storage do |metadata, metalocation| + jam_track_importer = JamTrackImporter.new(@storage_format) + + jam_track_importer.dry_run(metadata, metalocation) + end + + report_summaries + end + + # figure out which songs are in S3 that do not exist in the 2k spreadsheet (mapping.csv), and which songs are in the 2k spreadsheet that are not in S3 + def tency_delta + in_s3 = {} + in_mapping = {} + + load_tency_mappings + + JamTrackImporter.tency_metadata.each do |song_id, metadata| + in_mapping[song_id] = {artist: metadata[:original_artist], song: metadata[:name]} + end + + iterate_song_storage do |metadata, metalocation| + + importer = JamTrackImporter.new(@storage_format) + song_id = JamTrackImporter.extract_tency_song_id(metalocation) + parsed_metalocation = importer.parse_metalocation(metalocation) + + next if song_id.nil? + next if parsed_metalocation.nil? + + original_artist = parsed_metalocation[1] + meta_name = parsed_metalocation[2] + + in_s3[song_id] = {artist: original_artist, song: meta_name} + end + + in_s3_keys = Set.new(in_s3.keys) + in_mapping_keys = Set.new(in_mapping.keys) + only_in_mapping = in_mapping_keys - in_s3_keys + only_in_s3 = in_s3_keys - in_mapping_keys + + CSV.open("only_in_s3.csv", "wb") do |csv| + only_in_s3.each do |song_id| + csv << [ song_id, in_s3[song_id][:artist], in_s3[song_id][:song] ] + end + end + + CSV.open("only_in_2k_selection.csv", "wb") do |csv| + only_in_mapping.each do |song_id| + csv << [ song_id, in_mapping[song_id][:artist], in_mapping[song_id][:song] ] + end + end + + end + def create_masters + iterate_song_storage do |metadata, metalocation| + next if metadata.nil? + jam_track_importer = JamTrackImporter.new(@storage_format) + + jam_track_importer.create_master(metadata, metalocation) + end + end + + def create_master(path) + metalocation = "#{path}/meta.yml" + + metadata = load_metalocation(metalocation) + + jam_track_importer = JamTrackImporter.new(@storage_format) + + jam_track_importer.create_master(metadata, metalocation) + end + + def dry_run_original s3_manager.list_directories('audio').each do |original_artist| @@log.debug("searching through artist directory '#{original_artist}'") @@ -906,23 +1628,35 @@ module JamRuby end end + def remove_s3_special_chars(filename) + filename.tr('/&@:,$=+?;\^`><{}[]#%~|', '') + end + def onboarding_exceptions + JamTrack.all.each do |jam_track| + jam_track.onboarding_exceptions + end + end def synchronize_all(options) importers = [] - s3_manager.list_directories('audio').each do |original_artist| - @@log.debug("searching through artist directory '#{original_artist}'") + count = 0 + iterate_song_storage do |metadata, metalocation| - songs = s3_manager.list_directories(original_artist) - songs.each do |song| - @@log.debug("searching through song directory' #{song}'") + next if metadata.nil? && is_tency_storage? - metalocation = "#{song}meta.yml" + importer = synchronize_from_meta(metalocation, options) + importers << importer - importer = synchronize_from_meta(metalocation, options) - importers << importer + if importer.reason != 'jam_track_exists' + count+=1 + end + + if count > 100 + break end end + @@log.info("SUMMARY") @@log.info("-------") importers.each do |importer| @@ -956,12 +1690,113 @@ module JamRuby end end + def genre_dump + load_tency_mappings + + genres = {} + @tency_metadata.each do |id, value| + + genre1 = value[:genre1] + genre2 = value[:genre2] + genre3 = value[:genre3] + genre4 = value[:genre4] + genre5 = value[:genre5] + + genres[genre1.downcase.strip] = genre1.downcase.strip if genre1 + genres[genre2.downcase.strip] = genre2.downcase.strip if genre2 + genres[genre3.downcase.strip] = genre3.downcase.strip if genre3 + genres[genre4.downcase.strip] = genre4.downcase.strip if genre4 + genres[genre5.downcase.strip] = genre5.downcase.strip if genre5 + end + + all_genres = Genre.select(:id).all.map(&:id) + + all_genres = Set.new(all_genres) + genres.each do |genre, value| + found = all_genres.include? genre + + puts "#{genre}" unless found + end + end + + def load_tency_mappings + Dir.mktmpdir do |tmp_dir| + mapping_file = File.join(tmp_dir, 'mapping.csv') + metadata_file = File.join(tmp_dir, 'metadata.csv') + + # this is a developer option to skip the download and look in the CWD to grab mapping.csv and metadata.csv + if ENV['TENCY_ALREADY_DOWNLOADED'] == '1' + mapping_file = 'mapping.csv' + metadata_file = 'metadata.csv' + else + tency_s3_manager.download('mapping/mapping.csv', mapping_file) + tency_s3_manager.download('mapping/metadata.csv', metadata_file) + end + + mapping_csv = CSV.read(mapping_file) + metadata_csv = CSV.read(metadata_file, headers: true, return_headers: false) + + @tency_mapping = {} + @tency_metadata = {} + # convert both to hashes + mapping_csv.each do |line| + @tency_mapping[line[0].strip] = {instrument: line[1], part: line[2], count: line[3], trust: line[4]} + end + + metadata_csv.each do |line| + @tency_metadata[line[0].strip] = {id: line[0].strip, original_artist: line[1], name: line[2], additional_info: line[3], year: line[4], language: line[5], isrc: line[10], genre1: line[11], genre2: line[12], genre3: line[13], genre4: line[14], genre5: line[15]} + end + + + @tency_metadata.each do |id, value| + + genres = [] + + genre1 = value[:genre1] + genre2 = value[:genre2] + genre3 = value[:genre3] + genre4 = value[:genre4] + genre5 = value[:genre5] + + genres << genre1.downcase.strip if genre1 + genres << genre2.downcase.strip if genre2 + genres << genre3.downcase.strip if genre3 + genres << genre4.downcase.strip if genre4 + genres << genre5.downcase.strip if genre5 + + value[:genres] = genres + end + + + end + end + def load_metalocation(metalocation) - begin - data = s3_manager.read_all(metalocation) - return YAML.load(data) - rescue AWS::S3::Errors::NoSuchKey - return nil + + if is_tency_storage? + load_tency_mappings if @tency_mapping.nil? + song_id = extract_tency_song_id(metalocation) + + if song_id.nil? + puts "missing_song_id #{metalocation}" + return nil + end + + + tency_data = @tency_metadata[song_id] + + if tency_data.nil? + @@log.warn("missing tency metadata '#{song_id}'") + end + + return tency_data + else + begin + data = s3_manager.read_all(metalocation) + return YAML.load(data) + rescue AWS::S3::Errors::NoSuchKey + return nil + end end end @@ -975,7 +1810,7 @@ module JamRuby end def sync_from_metadata(jam_track, meta, metalocation, options) - jam_track_importer = JamTrackImporter.new + jam_track_importer = JamTrackImporter.new(@storage_format) JamTrack.transaction do #begin @@ -998,6 +1833,9 @@ module JamRuby meta = load_metalocation(metalocation) + if meta.nil? && is_tency_storage? + raise "no tency song matching this metalocation #{metalocation}" + end jam_track_importer = nil if jam_track @@log.debug("jamtrack #{jam_track.name} located by metalocation") diff --git a/ruby/lib/jam_ruby/models/genre.rb b/ruby/lib/jam_ruby/models/genre.rb index 1b0cd9ada..91d80f755 100644 --- a/ruby/lib/jam_ruby/models/genre.rb +++ b/ruby/lib/jam_ruby/models/genre.rb @@ -16,7 +16,8 @@ module JamRuby has_and_belongs_to_many :recordings, :class_name => "JamRuby::Recording", :join_table => "recordings_genres" # jam tracks - has_many :jam_tracks, :class_name => "JamRuby::JamTrack" + has_many :genres_jam_tracks, :class_name => "JamRuby::GenreJamTrack", :foreign_key => "genre_id" + has_many :jam_tracks, :through => :genres_jam_tracks, :class_name => "JamRuby::JamTrack", :source => :genre def to_s description diff --git a/ruby/lib/jam_ruby/models/genre_jam_track.rb b/ruby/lib/jam_ruby/models/genre_jam_track.rb new file mode 100644 index 000000000..aa05e4fd8 --- /dev/null +++ b/ruby/lib/jam_ruby/models/genre_jam_track.rb @@ -0,0 +1,8 @@ +module JamRuby + class GenreJamTrack < ActiveRecord::Base + + self.table_name = 'genres_jam_tracks' + belongs_to :jam_track, class_name: 'JamRuby::JamTrack' + belongs_to :genre, class_name: 'JamRuby::Genre' + end +end diff --git a/ruby/lib/jam_ruby/models/jam_track.rb b/ruby/lib/jam_ruby/models/jam_track.rb index 8ab120c62..3338124be 100644 --- a/ruby/lib/jam_ruby/models/jam_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track.rb @@ -14,7 +14,7 @@ module JamRuby attr_accessor :uploading_preview attr_accessible :name, :description, :bpm, :time_signature, :status, :recording_type, - :original_artist, :songwriter, :publisher, :licensor, :licensor_id, :pro, :genre, :genre_id, :sales_region, :price, + :original_artist, :songwriter, :publisher, :licensor, :licensor_id, :pro, :genres_jam_tracks_attributes, :sales_region, :price, :reproduction_royalty, :public_performance_royalty, :reproduction_royalty_amount, :licensor_royalty_amount, :pro_royalty_amount, :plan_code, :initial_play_silence, :jam_track_tracks_attributes, :jam_track_tap_ins_attributes, :version, :jmep_json, :jmep_text, :pro_ascap, :pro_bmi, :pro_sesac, :duration, as: :admin @@ -39,14 +39,17 @@ module JamRuby validates :public_performance_royalty, inclusion: {in: [nil, true, false]} validates :duration, numericality: {only_integer: true}, :allow_nil => true - validates_format_of :reproduction_royalty_amount, with: /^\d+\.*\d{0,3}$/ - validates_format_of :licensor_royalty_amount, with: /^\d+\.*\d{0,3}$/ + validates_format_of :reproduction_royalty_amount, with: /^\d+\.*\d{0,4}$/, :allow_blank => true + validates_format_of :licensor_royalty_amount, with: /^\d+\.*\d{0,4}$/, :allow_blank => true - belongs_to :genre, class_name: "JamRuby::Genre" belongs_to :licensor , class_name: 'JamRuby::JamTrackLicensor', foreign_key: 'licensor_id' + has_many :genres_jam_tracks, :class_name => "JamRuby::GenreJamTrack", :foreign_key => "jam_track_id" + has_many :genres, :through => :genres_jam_tracks, :class_name => "JamRuby::Genre", :source => :genre + has_many :jam_track_tracks, :class_name => "JamRuby::JamTrackTrack", order: 'track_type ASC, position ASC, part ASC, instrument_id ASC' has_many :jam_track_tap_ins, :class_name => "JamRuby::JamTrackTapIn", order: 'offset_time ASC' + has_many :jam_track_files, :class_name => "JamRuby::JamTrackFile" has_many :jam_track_rights, :class_name => "JamRuby::JamTrackRight" #, inverse_of: 'jam_track', :foreign_key => "jam_track_id" # ' @@ -67,6 +70,82 @@ module JamRuby accepts_nested_attributes_for :jam_track_tracks, allow_destroy: true accepts_nested_attributes_for :jam_track_tap_ins, allow_destroy: true + + # we can make sure a few things stay in sync here. + # 1) the reproduction_royalty_amount has to stay in sync based on duration + # 2) the onboarding_exceptions JSON column + after_save :sync_reproduction_royalty + after_save :sync_onboarding_exceptions + + + def sync_reproduction_royalty + + # reproduction royalty table based on duration + + # The statutory mechanical royalty rate for permanent digital downloads is: + # 9.10¢ per copy for songs 5 minutes or less, or + # 1.75¢ per minute or fraction thereof, per copy for songs over 5 minutes. + # So the base rate is 9.1 cents for anything up to 5 minutes. + # 5.01 to 6 minutes should be 10.5 cents. + # 6.01 to 7 minutes should be 12.25 cents. + # Etc. + + royalty = nil + if self.duration + minutes = (self.duration - 1) / 60 + extra_minutes = minutes - 4 + extra_minutes = 0 if extra_minutes < 0 + royalty = (0.091 + (0.0175 * extra_minutes)).round(5) + end + self.update_column(:reproduction_royalty_amount, royalty) + + true + end + + def sync_onboarding_exceptions + + exceptions = {} + if self.duration.nil? + exceptions[:no_duration] = true + end + + if self.genres.count == 0 + exceptions[:no_genres] = true + end + + if self.year.nil? + exceptions[:no_year] = true + end + + if self.licensor.nil? + exceptions[:no_licensor] = true + end + + if self.missing_instrument_info? + exceptions[:unknown_instrument] = true + end + + if self.master_track.nil? + exceptions[:no_master] = true + end + + if missing_previews? + exceptions[:missing_previews] = true + end + + if duplicate_positions? + exceptions[:duplicate_positions] = true + end + + if exceptions.keys.length == 0 + self.update_column(:onboarding_exceptions, nil) + else + self.update_column(:onboarding_exceptions, exceptions.to_json) + end + + true + end + def duplicate_positions? counter = {} jam_track_tracks.each do |track| @@ -87,6 +166,17 @@ module JamRuby duplicate end + def missing_instrument_info? + missing_instrument_info = false + self.jam_track_tracks.each do |track| + if track.instrument_id == 'other' && (track.part == nil || track.part.start_with?('Other')) + missing_instrument_info = true + break + end + end + missing_instrument_info + end + def missing_previews? missing_preview = false self.jam_track_tracks.each do |track| @@ -171,7 +261,7 @@ module JamRuby end if options[:group_artist] - query = query.select("original_artist, array_agg(jam_tracks.id) AS id, MIN(name) AS name, MIN(description) AS description, MIN(recording_type) AS recording_type, MIN(original_artist) AS original_artist, MIN(songwriter) AS songwriter, MIN(publisher) AS publisher, MIN(sales_region) AS sales_region, MIN(price) AS price, MIN(version) AS version, MIN(genre_id) AS genre_id") + query = query.select("original_artist, array_agg(jam_tracks.id) AS id, MIN(name) AS name, MIN(description) AS description, MIN(recording_type) AS recording_type, MIN(original_artist) AS original_artist, MIN(songwriter) AS songwriter, MIN(publisher) AS publisher, MIN(sales_region) AS sales_region, MIN(price) AS price, MIN(version) AS version") query = query.group("original_artist") query = query.order('jam_tracks.original_artist') else @@ -180,7 +270,12 @@ module JamRuby end query = query.where("jam_tracks.status = ?", 'Production') unless user.admin - query = query.where("jam_tracks.genre_id = '#{options[:genre]}'") unless options[:genre].blank? + + unless options[:genre].blank? + query = query.joins(:genres) + query = query.where('genre_id = ? ', options[:genre]) + end + query = query.where("jam_track_tracks.instrument_id = '#{options[:instrument]}' and jam_track_tracks.track_type != 'Master'") unless options[:instrument].blank? query = query.where("jam_tracks.sales_region = '#{options[:availability]}'") unless options[:availability].blank? @@ -231,7 +326,12 @@ module JamRuby query = query.order('jam_tracks.original_artist') query = query.where("jam_tracks.status = ?", 'Production') unless user.admin - query = query.where("jam_tracks.genre_id = '#{options[:genre]}'") unless options[:genre].blank? + + unless options[:genre].blank? + query = query.joins(:genres) + query = query.where('genre_id = ? ', options[:genre]) + end + query = query.where("jam_track_tracks.instrument_id = '#{options[:instrument]}'") unless options[:instrument].blank? query = query.where("jam_tracks.sales_region = '#{options[:availability]}'") unless options[:availability].blank? diff --git a/ruby/lib/jam_ruby/models/jam_track_file.rb b/ruby/lib/jam_ruby/models/jam_track_file.rb new file mode 100644 index 000000000..e7c880165 --- /dev/null +++ b/ruby/lib/jam_ruby/models/jam_track_file.rb @@ -0,0 +1,78 @@ +module JamRuby + + # holds a click track or precount file + class JamTrackFile < ActiveRecord::Base + include JamRuby::S3ManagerMixin + + # there should only be one Master per JamTrack, but there can be N Track per JamTrack + FILE_TYPE = %w{ClickWav ClickTxt Precount} + + @@log = Logging.logger[JamTrackFile] + + before_destroy :delete_s3_files + + attr_accessible :jam_track_id, :file_type, :filename, as: :admin + attr_accessible :url, :md5, :length, as: :admin + + attr_accessor :original_audio_s3_path, :skip_uploader, :preview_generate_error + + before_destroy :delete_s3_files + + validates :file_type, inclusion: {in: FILE_TYPE } + + belongs_to :jam_track, class_name: "JamRuby::JamTrack" + + # create storage directory that will house this jam_track, as well as + def store_dir + "jam_track_files" + end + + # create name of the file + def filename(original_name) + "#{store_dir}/#{jam_track.original_artist}/#{jam_track.name}/#{original_name}" + end + + def manually_uploaded_filename + if click_wav? + filename('click.wav') + elsif click_txt? + filename('click.txt') + elsif precount? + filename('precount.wav') + else + raise 'unknown file type: ' + file_type + end + + end + + def click_wav? + track_type == 'ClickWav' + end + + def click_txt? + track_type == 'ClickTxt' + end + + def precount? + track_type == 'Precount' + end + + # creates a short-lived URL that has access to the object. + # the idea is that this is used when a user who has the rights to this tries to download this JamTrack + # we would verify their rights (can_download?), and generates a URL in response to the click so that they can download + # but the url is short lived enough so that it wouldn't be easily shared + def sign_url(expiration_time = 120) + s3_manager.sign_url(self[url], {:expires => expiration_time, :response_content_type => 'audio/wav', :secure => true}) + end + + def can_download?(user) + # I think we have to make a special case for 'previews', but maybe that's just up to the controller to not check can_download? + jam_track.owners.include?(user) + end + + + def delete_s3_files + s3_manager.delete(self[:url]) if self[:url] && s3_manager.exists?(self[:url]) + end + end +end diff --git a/ruby/lib/jam_ruby/models/jam_track_track.rb b/ruby/lib/jam_ruby/models/jam_track_track.rb index e20469076..c99246876 100644 --- a/ruby/lib/jam_ruby/models/jam_track_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track_track.rb @@ -131,81 +131,19 @@ module JamRuby end + def generate_preview begin Dir.mktmpdir do |tmp_dir| input = File.join(tmp_dir, 'in.ogg') - output = File.join(tmp_dir, 'out.ogg') - output_mp3 = File.join(tmp_dir, 'out.mp3') - - start = self.preview_start_time.to_f / 1000 - stop = start + 20 raise 'no track' unless self["url_44"] s3_manager.download(self.url_by_sample_rate(44), input) - command = "sox \"#{input}\" \"#{output}\" trim #{sprintf("%.3f", start)} =#{sprintf("%.3f", stop)}" - - @@log.debug("trimming using: " + command) - - sox_output = `#{command}` - - result_code = $?.to_i - - if result_code != 0 - @@log.debug("fail #{result_code}") - @preview_generate_error = "unable to execute cut command #{sox_output}" - else - # now create mp3 off of ogg preview - - convert_mp3_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{output}\" -ab 192k \"#{output_mp3}\"" - - @@log.debug("converting to mp3 using: " + convert_mp3_cmd) - - convert_output = `#{convert_mp3_cmd}` - - result_code = $?.to_i - - if result_code != 0 - @@log.debug("fail #{result_code}") - @preview_generate_error = "unable to execute mp3 convert command #{convert_output}" - else - ogg_digest = ::Digest::MD5.file(output) - mp3_digest = ::Digest::MD5.file(output_mp3) - self["preview_md5"] = ogg_md5 = ogg_digest.hexdigest - self["preview_mp3_md5"] = mp3_md5 = mp3_digest.hexdigest - - @@log.debug("uploading ogg preview to #{self.preview_filename('ogg')}") - s3_public_manager.upload(self.preview_filename(ogg_md5, 'ogg'), output, content_type: 'audio/ogg', content_md5: ogg_digest.base64digest) - @@log.debug("uploading mp3 preview to #{self.preview_filename('mp3')}") - s3_public_manager.upload(self.preview_filename(mp3_md5, 'mp3'), output_mp3, content_type: 'audio/mpeg', content_md5: mp3_digest.base64digest) - - self.skip_uploader = true - - original_ogg_preview_url = self["preview_url"] - original_mp3_preview_url = self["preview_mp3_url"] - - # and finally update the JamTrackTrack with the new info - self["preview_url"] = self.preview_filename(ogg_md5, 'ogg') - self["preview_length"] = File.new(output).size - # and finally update the JamTrackTrack with the new info - self["preview_mp3_url"] = self.preview_filename(mp3_md5, 'mp3') - self["preview_mp3_length"] = File.new(output_mp3).size - self.save! - - # if all that worked, now delete old previews, if present - begin - s3_public_manager.delete(original_ogg_preview_url) if original_ogg_preview_url && original_ogg_preview_url != self["preview_url"] - s3_public_manager.delete(original_mp3_preview_url) if original_mp3_preview_url && original_mp3_preview_url != track["preview_mp3_url"] - rescue - puts "UNABLE TO CLEANUP OLD PREVIEW URL" - end - - end - end + process_preview(input, tmp_dir) end rescue Exception => e @@log.error("error in sox command #{e.to_s}") @@ -214,6 +152,76 @@ module JamRuby end + # input is the original ogg file for the track. tmp_dir is where this code can safely generate output stuff and have it cleaned up later + def process_preview(input, tmp_dir) + uuid = SecureRandom.uuid + output = File.join(tmp_dir, "#{uuid}.ogg") + output_mp3 = File.join(tmp_dir, "#{uuid}.mp3") + + start = self.preview_start_time.to_f / 1000 + stop = start + 20 + + command = "sox \"#{input}\" \"#{output}\" trim #{sprintf("%.3f", start)} =#{sprintf("%.3f", stop)}" + + @@log.debug("trimming using: " + command) + + sox_output = `#{command}` + + result_code = $?.to_i + + if result_code != 0 + @@log.debug("fail #{result_code}") + @preview_generate_error = "unable to execute cut command #{sox_output}" + else + # now create mp3 off of ogg preview + + convert_mp3_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{output}\" -ab 192k \"#{output_mp3}\"" + + @@log.debug("converting to mp3 using: " + convert_mp3_cmd) + + convert_output = `#{convert_mp3_cmd}` + + result_code = $?.to_i + + if result_code != 0 + @@log.debug("fail #{result_code}") + @preview_generate_error = "unable to execute mp3 convert command #{convert_output}" + else + ogg_digest = ::Digest::MD5.file(output) + mp3_digest = ::Digest::MD5.file(output_mp3) + self["preview_md5"] = ogg_md5 = ogg_digest.hexdigest + self["preview_mp3_md5"] = mp3_md5 = mp3_digest.hexdigest + + @@log.debug("uploading ogg preview to #{self.preview_filename('ogg')}") + s3_public_manager.upload(self.preview_filename(ogg_md5, 'ogg'), output, content_type: 'audio/ogg', content_md5: ogg_digest.base64digest) + @@log.debug("uploading mp3 preview to #{self.preview_filename('mp3')}") + s3_public_manager.upload(self.preview_filename(mp3_md5, 'mp3'), output_mp3, content_type: 'audio/mpeg', content_md5: mp3_digest.base64digest) + + self.skip_uploader = true + + original_ogg_preview_url = self["preview_url"] + original_mp3_preview_url = self["preview_mp3_url"] + + # and finally update the JamTrackTrack with the new info + self["preview_url"] = self.preview_filename(ogg_md5, 'ogg') + self["preview_length"] = File.new(output).size + # and finally update the JamTrackTrack with the new info + self["preview_mp3_url"] = self.preview_filename(mp3_md5, 'mp3') + self["preview_mp3_length"] = File.new(output_mp3).size + self.save! + + # if all that worked, now delete old previews, if present + begin + s3_public_manager.delete(original_ogg_preview_url) if original_ogg_preview_url && original_ogg_preview_url != self["preview_url"] + s3_public_manager.delete(original_mp3_preview_url) if original_mp3_preview_url && original_mp3_preview_url != track["preview_mp3_url"] + rescue + puts "UNABLE TO CLEANUP OLD PREVIEW URL" + end + + end + end + end + private def normalize_position diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb index 90cd48c44..531d3cc46 100644 --- a/ruby/spec/factories.rb +++ b/ruby/spec/factories.rb @@ -740,7 +740,7 @@ FactoryGirl.define do licensor_royalty_amount 0.999 sequence(:plan_code) { |n| "jamtrack-#{n}" } - genre JamRuby::Genre.first + genres [JamRuby::Genre.first] association :licensor, factory: :jam_track_licensor factory :jam_track_with_tracks do diff --git a/ruby/spec/jam_ruby/jam_track_importer_spec.rb b/ruby/spec/jam_ruby/jam_track_importer_spec.rb index a2cf96620..fbdc3d9cc 100644 --- a/ruby/spec/jam_ruby/jam_track_importer_spec.rb +++ b/ruby/spec/jam_ruby/jam_track_importer_spec.rb @@ -22,11 +22,13 @@ describe JamTrackImporter do in_directory_with_file(metafile) before(:each) do + JamTrackImporter.storage_format = 'default' content_for_file(YAML.dump(sample_yml)) end it "no meta" do s3_metalocation = 'audio/Artist 1/Bogus Place/meta.yml' + JamTrackImporter.storage_format = 'default' JamTrackImporter.load_metalocation(s3_metalocation).should be_nil end @@ -38,9 +40,105 @@ describe JamTrackImporter do end end + describe "sort_tracks" do + let(:jam_track) { FactoryGirl.create(:jam_track) } + let(:importer) { JamTrackImporter.new() } + let(:vocal) {Instrument.find('voice')} + let(:drums) {Instrument.find('drums')} + let(:bass_guitar) {Instrument.find('bass guitar')} + let(:piano) {Instrument.find('piano')} + let(:keyboard) {Instrument.find('keyboard')} + let(:acoustic_guitar) {Instrument.find('acoustic guitar')} + let(:electric_guitar) {Instrument.find('electric guitar')} + let(:other) {Instrument.find('other')} + + it "the big sort" do + # specified in https://jamkazam.atlassian.net/browse/VRFS-3296 + vocal_lead = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: vocal, part: 'Lead') + vocal_lead_female = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: vocal, part: 'Lead Female') + vocal_lead_male = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: vocal, part: 'Lead Male') + vocal_backing = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: vocal, part: 'Backing') + vocal_random = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: vocal, part: 'Random') + drums_drums = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: drums, part: 'Drums') + drums_percussion = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: drums, part: 'Percussion') + drums_random_1 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: drums, part: 'A') + drums_random_2 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: drums, part: 'C') + bass_guitar_bass = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: bass_guitar, part: 'Bass') + bass_guitar_random_1 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: bass_guitar, part: 'some bass') + bass_guitar_random_2 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: bass_guitar, part: 'zome bass') + piano_piano = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: piano, part: 'Piano') + keyboard_synth_1 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: keyboard, part: 'Synth 1') + keyboard_synth_2 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: keyboard, part: 'Synth 2') + keyboard_pads = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: keyboard, part: 'Pads') + keyboard_random_1 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: keyboard, part: 'A') + keyboard_random_2 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: keyboard, part: 'Z') + acoust_guitar_lead = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: acoustic_guitar, part: 'Lead') + acoust_guitar_lead_x = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: acoustic_guitar, part: 'Lead X') + acoust_guitar_solo_1 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: acoustic_guitar, part: 'Solo 1') + acoust_guitar_solo_2 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: acoustic_guitar, part: 'Solo 2') + acoust_guitar_rhythm = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: acoustic_guitar, part: 'Rhythm') + acoust_guitar_random_1 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: acoustic_guitar, part: 'A') + acoust_guitar_random_2 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: acoustic_guitar, part: 'Z') + elect_guitar_lead = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: electric_guitar, part: 'Lead') + elect_guitar_lead_x = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: electric_guitar, part: 'Lead X') + elect_guitar_solo_1 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: electric_guitar, part: 'Solo 1') + elect_guitar_solo_2 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: electric_guitar, part: 'Solo 2') + elect_guitar_rhythm = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: electric_guitar, part: 'Rhythm') + elect_guitar_random_1 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: electric_guitar, part: 'A') + elect_guitar_random_2 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: electric_guitar, part: 'Z') + other_1 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: other, part: 'Other 1') + other_2 = FactoryGirl.build(:jam_track_track, jam_track: jam_track, instrument: other, part: 'Other 2') + + expected = [ + vocal_lead, + vocal_lead_female, + vocal_lead_male, + vocal_backing, + vocal_random, + drums_drums, + drums_percussion, + drums_random_1, + drums_random_2, + bass_guitar_bass, + piano_piano, + keyboard_synth_1, + keyboard_synth_2, + keyboard_pads, + keyboard_random_1, + keyboard_random_2, + acoust_guitar_lead, + acoust_guitar_lead_x, + acoust_guitar_rhythm, + acoust_guitar_random_1, + acoust_guitar_solo_1, + acoust_guitar_solo_2, + acoust_guitar_random_2, + elect_guitar_lead, + elect_guitar_lead_x, + elect_guitar_solo_1, + elect_guitar_solo_2, + elect_guitar_rhythm, + elect_guitar_random_1, + elect_guitar_random_2, + bass_guitar_random_1, + bass_guitar_random_2, + other_1, + other_2 + ] + shuffled = expected.shuffle + sorted_tracks = importer.sort_tracks(shuffled) + + importer.set_custom_weight(vocal_lead).should eq(100) + + expected.each_with_index do |expected_track, i| + sorted_tracks[i].should eq(expected_track) + end + end + end + describe "synchronize" do let(:jam_track) { JamTrack.new } - let(:importer) { JamTrackImporter.new } + let(:importer) { JamTrackImporter.new() } let(:minimum_meta) { nil } let(:metalocation) { 'audio/Artist 1/Song 1/meta.yml' } let(:options) {{ skip_audio_upload:true }} @@ -64,7 +162,7 @@ describe JamTrackImporter do describe "parse_wav" do it "Guitar" do - result = JamTrackImporter.new.parse_wav('blah/Ready for Love Stem - Guitar - Main.wav') + result = JamTrackImporter.new.parse_file('blah/Ready for Love Stem - Guitar - Main.wav') result[:instrument].should eq('electric guitar') result[:part].should eq('Main') end diff --git a/ruby/spec/jam_ruby/models/jam_track_spec.rb b/ruby/spec/jam_ruby/models/jam_track_spec.rb index d17019df7..c1aecf71d 100644 --- a/ruby/spec/jam_ruby/models/jam_track_spec.rb +++ b/ruby/spec/jam_ruby/models/jam_track_spec.rb @@ -12,6 +12,90 @@ describe JamTrack do jam_track = FactoryGirl.create(:jam_track) jam_track.licensor.should_not be_nil jam_track.licensor.jam_tracks.should == [jam_track] + jam_track.genres.length.should eq(1) + end + + describe 'sync_reproduction_royalty' do + it "all possible conditions" do + jam_track = FactoryGirl.create(:jam_track) + jam_track.reproduction_royalty_amount.should be_nil + + jam_track.duration = 0 + jam_track.save! + jam_track.reproduction_royalty_amount.to_f.should eq(0.091) + + jam_track.duration = 1 + jam_track.save! + jam_track.reproduction_royalty_amount.to_f.should eq(0.091) + + jam_track.duration = 5 * 60 - 1 # just under 5 minutes + jam_track.save! + jam_track.reproduction_royalty_amount.to_f.should eq(0.091) + + jam_track.duration = 5 * 60 + jam_track.save! + jam_track.reproduction_royalty_amount.to_f.should eq(0.091) + + jam_track.duration = 6 * 60 - 1 # just under 6 minutes + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175) + + jam_track.duration = 6 * 60 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175) + + jam_track.duration = 7 * 60 - 1 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 2) + + jam_track.duration = 7 * 60 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 2) + + jam_track.duration = 8 * 60 - 1 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 3) + + jam_track.duration = 8 * 60 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 3) + + jam_track.duration = 9 * 60 - 1 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 4) + + jam_track.duration = 9 * 60 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 4) + + jam_track.duration = 10 * 60 - 1 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 5) + + jam_track.duration = 10 * 60 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 5) + + jam_track.duration = 11 * 60 - 1 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 6) + + jam_track.duration = 11 * 60 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 6) + + jam_track.duration = 12 * 60 - 1 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 7) + + jam_track.duration = 12 * 60 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 7) + + jam_track.duration = 13 * 60 + jam_track.save! + jam_track.reproduction_royalty_amount.should eq(0.091 + 0.0175 * 8) + end end describe 'plays' do @@ -98,6 +182,26 @@ describe JamTrack do query[1].should eq(jam_track1) end + it "queries on genre" do + jam_track1 = FactoryGirl.create(:jam_track_with_tracks, original_artist: 'artist', name: 'a') + jam_track2 = FactoryGirl.create(:jam_track_with_tracks, original_artist: 'artist', name: 'b') + jam_track1.genres = [Genre.find('rock')] + jam_track2.genres = [Genre.find('asian')] + jam_track1.save! + jam_track2.save! + + query, pager = JamTrack.index({genre: 'rock'}, user) + query.size.should == 1 + query[0].should eq(jam_track1) + + query, pager = JamTrack.index({genre: 'asian'}, user) + query.size.should == 1 + query[0].should eq(jam_track2) + + query, pager = JamTrack.index({genre: 'african'}, user) + query.size.should == 0 + end + it "supports showing purchased only" do jam_track1 = FactoryGirl.create(:jam_track_with_tracks, name: 'a') @@ -170,7 +274,7 @@ describe JamTrack do end it "100.1234" do - jam_track = FactoryGirl.build(:jam_track, reproduction_royalty_amount: 100.1234) + jam_track = FactoryGirl.build(:jam_track, reproduction_royalty_amount: 100.12345) jam_track.valid?.should be_false jam_track.errors[:reproduction_royalty_amount].should == ['is invalid'] end diff --git a/ruby/spec/jam_ruby/models/jam_track_track_spec.rb b/ruby/spec/jam_ruby/models/jam_track_track_spec.rb index 6fb4343f6..67a50ec22 100644 --- a/ruby/spec/jam_ruby/models/jam_track_track_spec.rb +++ b/ruby/spec/jam_ruby/models/jam_track_track_spec.rb @@ -7,6 +7,7 @@ describe JamTrackTrack do it "created" do jam_track_track = FactoryGirl.create(:jam_track_track) jam_track_track.jam_track.should_not be_nil + jam_track_track.jam_track.reload jam_track_track.jam_track.jam_track_tracks.should == [jam_track_track] end diff --git a/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee index d4d50a8ae..fdbaa40e9 100644 --- a/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee @@ -263,10 +263,12 @@ ChannelGroupIds = context.JK.ChannelGroupIds # All the JamTracks mediaTracks.push(``) + if @state.metronome? @state.metronome.mode = MIX_MODES.PERSONAL mediaTracks.push(``) + for jamTrack in @state.jamTracks jamTrack.mode = MIX_MODES.PERSONAL mediaTracks.push(``) diff --git a/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee index aa7654c7e..afd9567da 100644 --- a/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee @@ -32,6 +32,7 @@ MIX_MODES = context.JK.MIX_MODES componentClasses = classNames({ "session-track" : true "metronome" : true + "in-jam-track" : @props.location == 'jam-track' "no-mixer" : @props.mode == MIX_MODES.MASTER # show it as disabled if in master mode "in-jam-track" : @props.location == 'jam-track' }) diff --git a/web/app/assets/stylesheets/client/react-components/SessionTrack.css.scss b/web/app/assets/stylesheets/client/react-components/SessionTrack.css.scss index 57c2bbe03..82614b21e 100644 --- a/web/app/assets/stylesheets/client/react-components/SessionTrack.css.scss +++ b/web/app/assets/stylesheets/client/react-components/SessionTrack.css.scss @@ -175,8 +175,10 @@ .track-controls { margin-left:0; } + &.in-jam-track { min-height:56px; + .track-buttons { margin-top:2px; } diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index f1beaa5f9..c7433ea5a 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -482,7 +482,7 @@ class ApiMusicSessionsController < ApiController comment.save if comment.errors.any? - render :json => { :message => "Unexpected error occurred" }, :status => 500 + render :json => { :errors => comment.errors }, :status => 422 return else render :json => {}, :status => 201 @@ -508,7 +508,7 @@ class ApiMusicSessionsController < ApiController comment.save if comment.errors.any? - render :json => { :message => "Unexpected error occurred" }, :status => 500 + render :json => { :errors => comment.errors }, :status => 422 return else music_session = MusicSession.find(params[:id]) diff --git a/web/app/controllers/api_recordings_controller.rb b/web/app/controllers/api_recordings_controller.rb index b4012be5d..0767d9053 100644 --- a/web/app/controllers/api_recordings_controller.rb +++ b/web/app/controllers/api_recordings_controller.rb @@ -155,7 +155,7 @@ class ApiRecordingsController < ApiController comment.save if comment.errors.any? - render :json => { :message => "Unexpected error occurred" }, :status => 500 + render :json => { :errors => comment.errors }, :status => 422 return else render :json => {}, :status => 201 @@ -178,7 +178,7 @@ class ApiRecordingsController < ApiController liker.save if liker.errors.any? - render :json => { :message => "Unexpected error occurred" }, :status => 500 + render :json => { :errors => liker.errors }, :status => 422 return else render :json => {}, :status => 201 diff --git a/web/app/controllers/api_users_controller.rb b/web/app/controllers/api_users_controller.rb index 5c8f27377..18c2db8f8 100644 --- a/web/app/controllers/api_users_controller.rb +++ b/web/app/controllers/api_users_controller.rb @@ -796,7 +796,7 @@ class ApiUsersController < ApiController play.save if play.errors.any? - render :json => { :message => "Unexpected error occurred" }, :status => 500 + render :json => { :errors => play.errors }, :status => 422 else render :json => {}, :status => 201 end diff --git a/web/app/views/api_jam_tracks/show.rabl b/web/app/views/api_jam_tracks/show.rabl index 028180632..e05ca0cbf 100644 --- a/web/app/views/api_jam_tracks/show.rabl +++ b/web/app/views/api_jam_tracks/show.rabl @@ -3,7 +3,7 @@ object @jam_track attributes :id, :name, :description, :recording_type, :original_artist, :songwriter, :publisher, :sales_region, :price, :version, :duration node :genres do |item| - [item.genre.description] # XXX: need to return single genre; not array + item.genres.select(:description).map(&:description) end node :added_cart do |item| diff --git a/web/app/views/api_jam_tracks/show_for_client.rabl b/web/app/views/api_jam_tracks/show_for_client.rabl index bc212f46d..ce60ba00b 100644 --- a/web/app/views/api_jam_tracks/show_for_client.rabl +++ b/web/app/views/api_jam_tracks/show_for_client.rabl @@ -1,9 +1,9 @@ object @jam_track -attributes :id, :name, :description, :initial_play_silence, :original_artist, :version, :genre +attributes :id, :name, :description, :initial_play_silence, :original_artist, :version -node :genre do |jam_track| - jam_track.genre.present? ? jam_track.genre.id : nil +node :genres do |item| + item.genres.select(:description).map(&:description) end node :jmep do |jam_track| diff --git a/web/lib/tasks/jam_tracks.rake b/web/lib/tasks/jam_tracks.rake index 4d28e89a4..1774cfc64 100644 --- a/web/lib/tasks/jam_tracks.rake +++ b/web/lib/tasks/jam_tracks.rake @@ -4,15 +4,49 @@ namespace :jam_tracks do JamTrackImporter.dry_run end + task tency_dry_run: :environment do |task, args| + JamTrackImporter.storage_format = 'Tency' + JamTrackImporter.dry_run + end + + task tency_create_masters: :environment do |task, args| + JamTrackImporter.storage_format = 'Tency' + JamTrackImporter.create_masters + end + + + task tency_create_master: :environment do |task, args| + JamTrackImporter.storage_format = 'Tency' + + path = ENV['TRACK_PATH'] + + if !path + puts "TRACK_PATH must be set to something like audio/AC DC/Back in Black or mapped/50 Cent - In Da Club - 12401" + exit(1) + end + + JamTrackImporter.create_master(path) + end + + + task tency_delta: :environment do |task, args| + JamTrackImporter.storage_format = 'Tency' + JamTrackImporter.tency_delta + end + task sync: :environment do |task, args| path = ENV['TRACK_PATH'] if !path - puts "TRACK_PATH must be set to something like AD DC/Back in Black" + puts "TRACK_PATH must be set to something like audio/AC DC/Back in Black or mapped/50 Cent - In Da Club - 12401" exit(1) end - JamTrackImporter.synchronize_from_meta("audio/#{path}/meta.yml", skip_audio_upload:false) + if path.start_with?('mapped') + JamTrackImporter.storage_format = 'Tency' + end + + JamTrackImporter.synchronize_from_meta("#{path}/meta.yml", skip_audio_upload:false) end task resync_audio: :environment do |task, args| @@ -26,6 +60,20 @@ namespace :jam_tracks do JamTrackImporter.synchronize_from_meta("audio/#{path}/meta.yml", resync_audio:true, skip_audio_upload:false) end + task tency_genre_dump: :environment do |task, args| + JamTrackImporter.storage_format = 'Tency' + JamTrackImporter.genre_dump + end + + task sync_tency: :environment do |task, args| + JamTrackImporter.storage_format = 'Tency' + JamTrackImporter.synchronize_all(skip_audio_upload:false) + end + + task onboarding_exceptions: :environment do |task, args| + JamTrackImporter.onboarding_exceptions + end + task sync_all: :environment do |task, args| JamTrackImporter.synchronize_all(skip_audio_upload:false) end @@ -91,4 +139,10 @@ namespace :jam_tracks do task download_masters: :environment do |task, arg| JamTrackImporter.download_masters end + + + task tency: :environment do |task, arg| + mapper = TencyStemMapping.new + mapper.correlate + end end diff --git a/web/spec/controllers/api_jam_tracks_controller_spec.rb b/web/spec/controllers/api_jam_tracks_controller_spec.rb index 74bc1da94..25f971ec9 100644 --- a/web/spec/controllers/api_jam_tracks_controller_spec.rb +++ b/web/spec/controllers/api_jam_tracks_controller_spec.rb @@ -128,6 +128,7 @@ describe ApiJamTracksController do # of this process is checked in other tests: @ogg_path = File.join('spec', 'files', 'on.ogg') @jam_track = FactoryGirl.create(:jam_track) #jam_track_track.jam_track + @jam_track.reload jam_track_track = @jam_track.jam_track_tracks.first # 48 kHz: diff --git a/web/spec/factories.rb b/web/spec/factories.rb index 52edb7820..48f2ef3af 100644 --- a/web/spec/factories.rb +++ b/web/spec/factories.rb @@ -731,7 +731,7 @@ FactoryGirl.define do make_track true end - genre JamRuby::Genre.first + genres [JamRuby::Genre.first] association :licensor, factory: :jam_track_licensor after(:create) do |jam_track, evaluator| diff --git a/web/spec/features/jamtrack_shopping_spec.rb b/web/spec/features/jamtrack_shopping_spec.rb index 23da6a3f4..a3171a282 100644 --- a/web/spec/features/jamtrack_shopping_spec.rb +++ b/web/spec/features/jamtrack_shopping_spec.rb @@ -5,8 +5,8 @@ describe "JamTrack Shopping", :js => true, :type => :feature, :capybara_feature let(:user) { FactoryGirl.create(:user, has_redeemable_jamtrack: false) } let(:jt_us) { FactoryGirl.create(:jam_track, :name=>'jt_us', sales_region: 'Worldwide', make_track: true, original_artist: "foobar") } let(:jt_ww) { FactoryGirl.create(:jam_track, :name=>'jt_ww', sales_region: 'Worldwide', make_track: true, original_artist: "barfoo") } - let(:jt_rock) { FactoryGirl.create(:jam_track, :name=>'jt_rock', genre: JamRuby::Genre.find('rock'), make_track: true, original_artist: "badfood") } - let(:jt_blues) { FactoryGirl.create(:jam_track, :name=>'jt_blues', genre: JamRuby::Genre.find('blues'), make_track: true, original_artist: "foodbart") } + let(:jt_rock) { FactoryGirl.create(:jam_track, :name=>'jt_rock', genres: [JamRuby::Genre.find('rock')], make_track: true, original_artist: "badfood") } + let(:jt_blues) { FactoryGirl.create(:jam_track, :name=>'jt_blues', genres: [JamRuby::Genre.find('blues')], make_track: true, original_artist: "foodbart") } before(:all) do Capybara.javascript_driver = :poltergeist From af355ec096c85f54f61bb22518449315b6f7bf55 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 9 Aug 2015 13:47:49 -0500 Subject: [PATCH 54/66] * get activeadmin working for JamTracks after onboarding enhancements were added --- admin/app/admin/jam_tracks.rb | 14 ++++++++++++-- admin/app/views/admin/jam_tracks/_form.html.slim | 2 +- ruby/lib/jam_ruby/models/jam_track.rb | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/admin/app/admin/jam_tracks.rb b/admin/app/admin/jam_tracks.rb index d51e92f31..2e8422305 100644 --- a/admin/app/admin/jam_tracks.rb +++ b/admin/app/admin/jam_tracks.rb @@ -24,11 +24,21 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do column :original_artist column :name - column :onboarding_flags do |jam_track| jam_track.onboard_warnings end + column :onboarding_exceptions do |jam_track| + if jam_track.onboarding_exceptions + exceptions = JSON.parse(jam_track.onboarding_exceptions) + exceptions.keys.join(',') + else + '' + end + + end column :status column :master_track do |jam_track| jam_track.master_track.nil? ? 'None' : (link_to "Download", jam_track.master_track.url_by_sample_rate(44)) end column :licensor - column :genre + column :genres do |jam_track| + jam_track.genres.map(&:description).join(',') + end column :price column :reproduction_royalty column :public_performance_royalty diff --git a/admin/app/views/admin/jam_tracks/_form.html.slim b/admin/app/views/admin/jam_tracks/_form.html.slim index 51341d812..334cdc27e 100644 --- a/admin/app/views/admin/jam_tracks/_form.html.slim +++ b/admin/app/views/admin/jam_tracks/_form.html.slim @@ -12,7 +12,7 @@ = f.input :songwriter, :input_html => { :rows=>1, :maxlength=>1000 } = f.input :publisher, :input_html => { :rows=>1, :maxlength=>1000 } = f.input :licensor, collection: JamRuby::JamTrackLicensor.all, include_blank: true - = f.input :genre, collection: JamRuby::Genre.all, include_blank: false + = f.input :genres = f.input :duration, hint: 'this should rarely need editing because it comes from the import process' = f.input :sales_region, collection: JamRuby::JamTrack::SALES_REGION, include_blank: false = f.input :price, :required => true, :input_html => {type: 'numeric'} diff --git a/ruby/lib/jam_ruby/models/jam_track.rb b/ruby/lib/jam_ruby/models/jam_track.rb index 3338124be..2352d0af4 100644 --- a/ruby/lib/jam_ruby/models/jam_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track.rb @@ -17,7 +17,7 @@ module JamRuby :original_artist, :songwriter, :publisher, :licensor, :licensor_id, :pro, :genres_jam_tracks_attributes, :sales_region, :price, :reproduction_royalty, :public_performance_royalty, :reproduction_royalty_amount, :licensor_royalty_amount, :pro_royalty_amount, :plan_code, :initial_play_silence, :jam_track_tracks_attributes, - :jam_track_tap_ins_attributes, :version, :jmep_json, :jmep_text, :pro_ascap, :pro_bmi, :pro_sesac, :duration, as: :admin + :jam_track_tap_ins_attributes, :genre_ids, :version, :jmep_json, :jmep_text, :pro_ascap, :pro_bmi, :pro_sesac, :duration, as: :admin validates :name, presence: true, uniqueness: true, length: {maximum: 200} validates :plan_code, presence: true, uniqueness: true, length: {maximum: 50 } From eba12807080eb67adcbdba2bf68cbf3ba6683ea1 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 9 Aug 2015 13:57:19 -0500 Subject: [PATCH 55/66] * make it so it's easy to find jam tracks with problems --- admin/app/admin/jam_tracks.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/admin/app/admin/jam_tracks.rb b/admin/app/admin/jam_tracks.rb index 2e8422305..3a3fc3b17 100644 --- a/admin/app/admin/jam_tracks.rb +++ b/admin/app/admin/jam_tracks.rb @@ -5,9 +5,12 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do config.sort_order = 'name_asc' config.batch_actions = false - filter :genre + filter :genres filter :status, :as => :select, collection: JamRuby::JamTrack::STATUS + scope("Default", default: true) { |scope| scope } + scope("Onboarding TODO") { |scope| scope.where('onboarding_exceptions is not null') } + form :partial => 'form' index do From da726a574be947a421c72263d01c3354fddf76af Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 9 Aug 2015 14:20:21 -0500 Subject: [PATCH 56/66] * remove unique constraint on jamtrack name --- db/manifest | 1 + db/up/jam_track_name_drop_unique.sql | 1 + ruby/lib/jam_ruby/jam_track_importer.rb | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 db/up/jam_track_name_drop_unique.sql diff --git a/db/manifest b/db/manifest index 81df91ca8..f7212acc1 100755 --- a/db/manifest +++ b/db/manifest @@ -299,3 +299,4 @@ enhance_band_profile.sql alter_band_profile_rate_defaults.sql repair_band_profile.sql jam_track_onboarding_enhancements.sql +jam_track_name_drop_unique.sql \ No newline at end of file diff --git a/db/up/jam_track_name_drop_unique.sql b/db/up/jam_track_name_drop_unique.sql new file mode 100644 index 000000000..d283b34cd --- /dev/null +++ b/db/up/jam_track_name_drop_unique.sql @@ -0,0 +1 @@ +ALTER TABLE jam_tracks DROP CONSTRAINT jam_tracks_name_key; \ No newline at end of file diff --git a/ruby/lib/jam_ruby/jam_track_importer.rb b/ruby/lib/jam_ruby/jam_track_importer.rb index 502f88f0c..aaf12de70 100644 --- a/ruby/lib/jam_ruby/jam_track_importer.rb +++ b/ruby/lib/jam_ruby/jam_track_importer.rb @@ -93,7 +93,6 @@ module JamRuby tracks.each do |track| sample_rate = `soxi -r "#{track}"`.strip - puts "SAMPLE RATE #{sample_rate}" if first_sample_rate.nil? first_sample_rate = sample_rate else From aec3d106fafccef05cd23b242edd714db8149806 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 9 Aug 2015 17:27:30 -0500 Subject: [PATCH 57/66] * more scopes for onboarding --- admin/app/admin/jam_tracks.rb | 2 ++ ruby/lib/jam_ruby/models/jam_track.rb | 2 +- ruby/lib/jam_ruby/models/jam_track_licensor.rb | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/admin/app/admin/jam_tracks.rb b/admin/app/admin/jam_tracks.rb index 3a3fc3b17..534b65903 100644 --- a/admin/app/admin/jam_tracks.rb +++ b/admin/app/admin/jam_tracks.rb @@ -10,6 +10,8 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do scope("Default", default: true) { |scope| scope } scope("Onboarding TODO") { |scope| scope.where('onboarding_exceptions is not null') } + scope("Tency Only") { |scope| scope.joins('INNER JOIN jam_track_licensors as licensors ON jam_tracks.licensor_id = licensors.id').where("licensors.name = 'Tency Music'") } + scope("Onboarding TODO w/ Tency Only") { |scope| scope.joins('INNER JOIN jam_track_licensors as licensors ON jam_tracks.licensor_id = licensors.id').where("licensors.name = 'Tency Music'").where('onboarding_exceptions is not null') } form :partial => 'form' diff --git a/ruby/lib/jam_ruby/models/jam_track.rb b/ruby/lib/jam_ruby/models/jam_track.rb index 2352d0af4..7f1e66e1b 100644 --- a/ruby/lib/jam_ruby/models/jam_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track.rb @@ -42,7 +42,7 @@ module JamRuby validates_format_of :reproduction_royalty_amount, with: /^\d+\.*\d{0,4}$/, :allow_blank => true validates_format_of :licensor_royalty_amount, with: /^\d+\.*\d{0,4}$/, :allow_blank => true - belongs_to :licensor , class_name: 'JamRuby::JamTrackLicensor', foreign_key: 'licensor_id' + belongs_to :licensor , class_name: 'JamRuby::JamTrackLicensor', foreign_key: 'licensor_id', :inverse_of => :jam_tracks has_many :genres_jam_tracks, :class_name => "JamRuby::GenreJamTrack", :foreign_key => "jam_track_id" has_many :genres, :through => :genres_jam_tracks, :class_name => "JamRuby::Genre", :source => :genre diff --git a/ruby/lib/jam_ruby/models/jam_track_licensor.rb b/ruby/lib/jam_ruby/models/jam_track_licensor.rb index d5ee3df75..e06e292bc 100644 --- a/ruby/lib/jam_ruby/models/jam_track_licensor.rb +++ b/ruby/lib/jam_ruby/models/jam_track_licensor.rb @@ -1,6 +1,8 @@ module JamRuby class JamTrackLicensor < ActiveRecord::Base + table_name = 'jam_track_licensors' + attr_accessible :name, :description, :attention, :address_line_1, :address_line_2, :city, :state, :zip_code, :contact, :email, :phone, as: :admin @@ -16,6 +18,6 @@ module JamRuby validates :email, length: {maximum: 200} validates :phone, length: {maximum: 200} - has_many :jam_tracks, :class_name => "JamRuby::JamTrack", foreign_key: 'licensor_id' + has_many :jam_tracks, :class_name => "JamRuby::JamTrack", foreign_key: 'licensor_id', :inverse_of => :licensor end end From 795f0b5375dfc6531e55f26b1cc69922887ae44d Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 10 Aug 2015 11:05:24 -0500 Subject: [PATCH 58/66] * allow a non-video client into a session on a server configured with video --- ruby/lib/jam_ruby/models/jam_track.rb | 2 +- web/app/assets/javascripts/webcam_viewer.js.coffee | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ruby/lib/jam_ruby/models/jam_track.rb b/ruby/lib/jam_ruby/models/jam_track.rb index 7f1e66e1b..244cbc6f1 100644 --- a/ruby/lib/jam_ruby/models/jam_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track.rb @@ -19,7 +19,7 @@ module JamRuby :licensor_royalty_amount, :pro_royalty_amount, :plan_code, :initial_play_silence, :jam_track_tracks_attributes, :jam_track_tap_ins_attributes, :genre_ids, :version, :jmep_json, :jmep_text, :pro_ascap, :pro_bmi, :pro_sesac, :duration, as: :admin - validates :name, presence: true, uniqueness: true, length: {maximum: 200} + validates :name, presence: true, length: {maximum: 200} validates :plan_code, presence: true, uniqueness: true, length: {maximum: 50 } validates :description, length: {maximum: 1000} validates :time_signature, inclusion: {in: [nil] + [''] + TIME_SIGNATURES} # the empty string is needed because of activeadmin diff --git a/web/app/assets/javascripts/webcam_viewer.js.coffee b/web/app/assets/javascripts/webcam_viewer.js.coffee index 87e6a7f93..a5538167a 100644 --- a/web/app/assets/javascripts/webcam_viewer.js.coffee +++ b/web/app/assets/javascripts/webcam_viewer.js.coffee @@ -32,7 +32,9 @@ context.JK.WebcamViewer = class WebcamViewer this.loadResolutions() this.selectResolution() @initialScan = true - @client.SessStopVideoSharing() + # protect against non-video clients pointed at video-enabled server from getting into a session + if @client.SessStopVideoSharing + @client.SessStopVideoSharing() #client.SessSetInsetPosition(5) #client.SessSetInsetSize(1) #client.FTUESetAutoSelectVideoLayout(false) @@ -82,14 +84,16 @@ context.JK.WebcamViewer = class WebcamViewer selectedDeviceName:() => webcamName="None Configured" - webcam = @client.FTUECurrentSelectedVideoDevice() + # protect against non-video clients pointed at video-enabled server from getting into a session + webcam = if @client.FTUECurrentSelectedVideoDevice? then @client.FTUECurrentSelectedVideoDevice() else null if (webcam? && Object.keys(webcam).length>0) webcamName = _.values(webcam)[0] webcamName loadWebCams:() => - devices = @client.FTUEGetVideoCaptureDeviceNames() + # protect against non-video clients pointed at video-enabled server from getting into a session + devices = if @client.FTUEGetVideoCaptureDeviceNames? then @client.FTUEGetVideoCaptureDeviceNames() else [] selectedDevice = this.selectedDeviceName() selectControl = @webcamSelect context._.each devices, (device) -> @@ -107,7 +111,8 @@ context.JK.WebcamViewer = class WebcamViewer @root.find('.no-webcam-msg').addClass 'hidden' loadResolutions:() => - resolutions = @client.FTUEGetAvailableEncodeVideoResolutions() + # protect against non-video clients pointed at video-enabled server from getting into a session + resolutions = if @client.FTUEGetAvailableEncodeVideoResolutions? then @client.FTUEGetAvailableEncodeVideoResolutions() else {} selectControl = @resolutionSelect @logger.debug 'FOUND THESE RESOLUTIONS', resolutions, selectControl context._.each resolutions, (value, key, obj) -> From 5300f6206394c7dac2b1a9e88a4219dc4c852ee2 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Tue, 11 Aug 2015 05:51:58 -0500 Subject: [PATCH 59/66] * don't eat up horns part if specified --- ruby/lib/jam_ruby/jam_track_importer.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/lib/jam_ruby/jam_track_importer.rb b/ruby/lib/jam_ruby/jam_track_importer.rb index aaf12de70..8b34c99a6 100644 --- a/ruby/lib/jam_ruby/jam_track_importer.rb +++ b/ruby/lib/jam_ruby/jam_track_importer.rb @@ -501,7 +501,7 @@ module JamRuby part = 'Clock' elsif potential_instrument == 'horns' || potential_instrument == 'horn' instrument = 'other' - part = 'Horns' + part = 'Horns' if potential_part.nil? elsif potential_instrument == 'english horn' instrument = 'other' part = 'English Horn' @@ -1650,7 +1650,7 @@ module JamRuby count+=1 end - if count > 100 + if count > 500 break end end From 96fa38f611e49a51a068b0e9c8077e3b921132bb Mon Sep 17 00:00:00 2001 From: Seth Call Date: Tue, 11 Aug 2015 10:41:37 -0500 Subject: [PATCH 60/66] * fix db migration for production --- db/up/jam_track_onboarding_enhancements.sql | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/db/up/jam_track_onboarding_enhancements.sql b/db/up/jam_track_onboarding_enhancements.sql index 1336ecdf4..2a373eb5c 100644 --- a/db/up/jam_track_onboarding_enhancements.sql +++ b/db/up/jam_track_onboarding_enhancements.sql @@ -1,4 +1,17 @@ +-- "rsvp_slots_instrument_id_fkey" FOREIGN KEY (instrument_id) REFERENCES instruments(id) +-- "musicians_instruments_instrument_id_fkey" FOREIGN KEY (instrument_id) REFERENCES instruments(id) ON DELETE CASCADE +-- "saved_tracks_instrument_id_fkey" FOREIGN KEY (instrument_id) REFERENCES instruments(id) ON DELETE CASCADE +ALTER TABLE rsvp_slots DROP CONSTRAINT rsvp_slots_instrument_id_fkey; +ALTER TABLE musicians_instruments DROP CONSTRAINT musicians_instruments_instrument_id_fkey; +ALTER TABLE recorded_tracks DROP CONSTRAINT saved_tracks_instrument_id_fkey; UPDATE instruments SET id = 'double bass', description = 'Double Bass' WHERE id = 'upright bass'; +UPDATE rsvp_slots SET instrument_id = 'double bass' where instrument_id = 'upright bass'; +UPDATE musicians_instruments SET instrument_id = 'double bass' where instrument_id = 'upright bass'; +UPDATE recorded_tracks SET instrument_id = 'double bass' where instrument_id = 'upright bass'; +ALTER TABLE rsvp_slots ADD CONSTRAINT rsvp_slots_instrument_id_fkey FOREIGN KEY (instrument_id) REFERENCES instruments(id) ON DELETE SET NULL; +ALTER TABLE musicians_instruments ADD CONSTRAINT musicians_instruments_instrument_id_fkey FOREIGN KEY (instrument_id) REFERENCES instruments(id) ON DELETE CASCADE; +ALTER TABLE recorded_tracks ADD CONSTRAINT saved_tracks_instrument_id_fkey FOREIGN KEY (instrument_id) REFERENCES instruments(id) ON DELETE CASCADE; + INSERT INTO instruments (id, description, popularity) VALUES ('steel guitar', 'Steel Guitar', 1); INSERT INTO instruments (id, description, popularity) VALUES ('orchestra', 'Orchestra', 1); INSERT INTO instruments (id, description, popularity) VALUES ('glockenspiel', 'Glockenspiel', 1); From 03f5407727bf283084ce48257076029c97283003 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Wed, 12 Aug 2015 09:36:42 -0500 Subject: [PATCH 61/66] * deal with duplicate instrument/parts better than failing --- ruby/lib/jam_ruby/jam_track_importer.rb | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ruby/lib/jam_ruby/jam_track_importer.rb b/ruby/lib/jam_ruby/jam_track_importer.rb index 8b34c99a6..9fcafab35 100644 --- a/ruby/lib/jam_ruby/jam_track_importer.rb +++ b/ruby/lib/jam_ruby/jam_track_importer.rb @@ -774,6 +774,36 @@ module JamRuby instrument_weight end + def deduplicate_parts(tracks) + unique_instruments = {} + + tracks.each do |track| + + found = unique_instruments[[track.instrument_id, track.part]] + if !found + found = [] + end + + found << track + end + + unique_instruments.each do |key, value| + if value.length > 1 + count = 0 + + value.each do |track| + if track.part.nil? + track.part = (count + 1).to_s + else + track.part = "#{track.part} #{count + 1}" + end + end + + count += 1 + end + end + end + def sort_tracks(tracks) sorted_tracks = tracks.sort do |a, b| @@ -914,6 +944,8 @@ module JamRuby @@log.info("sorting tracks") tracks = sort_tracks(tracks) + deduplicate_parts(tracks) + jam_track.jam_track_tracks = tracks jam_track.jam_track_files = addt_files From 40f3b7d83ea1d25886d540e767eedc4bf2e7be4b Mon Sep 17 00:00:00 2001 From: Seth Call Date: Wed, 12 Aug 2015 10:14:54 -0500 Subject: [PATCH 62/66] * correct part deduplicator --- ruby/lib/jam_ruby/jam_track_importer.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ruby/lib/jam_ruby/jam_track_importer.rb b/ruby/lib/jam_ruby/jam_track_importer.rb index 9fcafab35..f929a8545 100644 --- a/ruby/lib/jam_ruby/jam_track_importer.rb +++ b/ruby/lib/jam_ruby/jam_track_importer.rb @@ -779,9 +779,11 @@ module JamRuby tracks.each do |track| - found = unique_instruments[[track.instrument_id, track.part]] + key = "#{track.instrument_id} | #{track.part}" + found = unique_instruments[key] if !found found = [] + unique_instruments[key] = found end found << track @@ -797,13 +799,19 @@ module JamRuby else track.part = "#{track.part} #{count + 1}" end + count += 1 end - count += 1 end end + + # debug output + tracks.each do |track| + puts "TRACK #{track.instrument_id} #{track.part}" + end end + def sort_tracks(tracks) sorted_tracks = tracks.sort do |a, b| From d36999032f24c0def3df71a9875b317fe2b95845 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 13 Aug 2015 11:09:54 -0500 Subject: [PATCH 63/66] * expand part size --- ruby/lib/jam_ruby/models/jam_track_track.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/lib/jam_ruby/models/jam_track_track.rb b/ruby/lib/jam_ruby/models/jam_track_track.rb index c99246876..c0548e6fd 100644 --- a/ruby/lib/jam_ruby/models/jam_track_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track_track.rb @@ -24,7 +24,7 @@ module JamRuby before_destroy :delete_s3_files validates :position, presence: true, numericality: {only_integer: true}, length: {in: 1..1000} - validates :part, length: {maximum: 25} + validates :part, length: {maximum: 35} validates :track_type, inclusion: {in: TRACK_TYPE } validates :preview_start_time, numericality: {only_integer: true}, length: {in: 1..1000}, :allow_nil => true validates_uniqueness_of :part, scope: [:jam_track_id, :instrument_id] From c4981376ac0e7585f9b1c2df809edd8ebd0c55e0 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 13 Aug 2015 11:13:13 -0500 Subject: [PATCH 64/66] * set storage format for sync_all_dev --- web/lib/tasks/jam_tracks.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/web/lib/tasks/jam_tracks.rake b/web/lib/tasks/jam_tracks.rake index 1774cfc64..18942fe02 100644 --- a/web/lib/tasks/jam_tracks.rake +++ b/web/lib/tasks/jam_tracks.rake @@ -79,6 +79,7 @@ namespace :jam_tracks do end task sync_all_dev: :environment do |task, args| + JamTrackImporter.storage_format = 'default' JamTrackImporter.synchronize_all(skip_audio_upload:true) end From e62d9e126fd46047a37d2895239d65fcc2e554db Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sat, 15 Aug 2015 06:22:46 -0500 Subject: [PATCH 65/66] * VRFS-3435 allow multiple onboarders to execute --- ruby/lib/jam_ruby/jam_track_importer.rb | 52 +++++++++++++++++++++-- ruby/lib/jam_ruby/models/generic_state.rb | 1 - 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/ruby/lib/jam_ruby/jam_track_importer.rb b/ruby/lib/jam_ruby/jam_track_importer.rb index f929a8545..43f75c9cd 100644 --- a/ruby/lib/jam_ruby/jam_track_importer.rb +++ b/ruby/lib/jam_ruby/jam_track_importer.rb @@ -355,14 +355,54 @@ module JamRuby found[0] # 3 letter code end + #http://stackoverflow.com/questions/22740252/how-to-generate-javas-string-hashcode-using-ruby + def jhash(str) + result = 0 + mul = 1 + max_mod = 2**31 - 1 + + str.chars.reverse_each do |c| + result += mul * c.ord + result %= max_mod + mul *= 31 + end + + result + end + + def prevent_concurrent_processing(metalocation) + + # use a PG advisory lock to see if someone else is doing this same unit of work right now + track_code = jhash(metalocation) + locked = ActiveRecord::Base.connection.execute("SELECT pg_try_advisory_xact_lock(#{track_code})").values[0][0] + if locked == 'f' + finish("other_processing", "") + raise ActiveRecord::Rollback + end + end + def synchronize_metadata(jam_track, metadata, metalocation, original_artist, name, options) metadata ||= {} self.name = metadata["name"] || name + prevent_concurrent_processing(metalocation) + if jam_track.new_record? latest_jamtrack = JamTrack.order('created_at desc').first + id = latest_jamtrack.nil? ? 1 : latest_jamtrack.id.to_i + 1 + if ENV['NODE_NUMBER'] + # complicated goofy code to support parallel processing of importers + + node_number = ENV['NODE_NUMBER'].to_i + node_count = ENV['NODE_COUNT'].to_i + raise "NO NODE_COUNT" if node_count == 0 + r = id % node_count + id = r + id # get to the same base number if both are working at the same time + id = id + node_number # offset by your node number + @@log.debug("JAM TRACK ID: #{id}") + end jam_track.id = "#{id}" # default is UUID, but the initial import was based on auto-increment ID, so we'll maintain that jam_track.status = 'Staging' jam_track.metalocation = metalocation @@ -399,6 +439,7 @@ module JamRuby end + @@log.debug("about to save") saved = jam_track.save if !saved @@ -1566,7 +1607,7 @@ module JamRuby @@log.info("-------") importers.each do |importer| if importer - if importer.reason == "success" || importer.reason == "jam_track_exists" + if importer.reason == "success" || importer.reason == "jam_track_exists" || importer.reason == "other_processing" @@log.info("#{importer.name} #{importer.reason}") else @@log.error("#{importer.name} failed to import.") @@ -1613,7 +1654,7 @@ module JamRuby @@log.info("-------") importers.each do |importer| if importer - if importer.reason == "success" || importer.reason == "jam_track_exists" + if importer.reason == "success" || importer.reason == "jam_track_exists" || importer.reason == "other_processing" @@log.info("#{importer.name} #{importer.reason}") else @@log.error("#{importer.name} failed to import.") @@ -1686,7 +1727,7 @@ module JamRuby importer = synchronize_from_meta(metalocation, options) importers << importer - if importer.reason != 'jam_track_exists' + if importer.reason != 'jam_track_exists' && importer.reason != "other_processing" count+=1 end @@ -1700,7 +1741,7 @@ module JamRuby @@log.info("-------") importers.each do |importer| if importer - if importer.reason == "success" || importer.reason == "jam_track_exists" + if importer.reason == "success" || importer.reason == "jam_track_exists" || importer.reason == "other_processing" @@log.info("#{importer.name} #{importer.reason}") else @@log.error("#{importer.name} failed to import.") @@ -1851,7 +1892,10 @@ module JamRuby def sync_from_metadata(jam_track, meta, metalocation, options) jam_track_importer = JamTrackImporter.new(@storage_format) + JamTrack.connection.execute('SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED') + JamTrack.transaction do + #begin jam_track_importer.synchronize(jam_track, meta, metalocation, options) #rescue Exception => e diff --git a/ruby/lib/jam_ruby/models/generic_state.rb b/ruby/lib/jam_ruby/models/generic_state.rb index 6ed4ec7f4..9d6a23904 100644 --- a/ruby/lib/jam_ruby/models/generic_state.rb +++ b/ruby/lib/jam_ruby/models/generic_state.rb @@ -31,6 +31,5 @@ module JamRuby GenericState.find('default') end - end end From efbecded54e8908b426f8f40148765f190db948e Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sat, 15 Aug 2015 14:26:54 -0500 Subject: [PATCH 66/66] * fix importer on oriental/asian --- ruby/lib/jam_ruby/jam_track_importer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/lib/jam_ruby/jam_track_importer.rb b/ruby/lib/jam_ruby/jam_track_importer.rb index 43f75c9cd..fc34eeac3 100644 --- a/ruby/lib/jam_ruby/jam_track_importer.rb +++ b/ruby/lib/jam_ruby/jam_track_importer.rb @@ -316,7 +316,7 @@ module JamRuby elsif genre == 'humour' # swallow elsif genre == 'oriental' - genres << genre.find('asian') + genres << Genre.find('asian') else found = Genre.find_by_id(genre) genres << found if found