diff --git a/db/manifest b/db/manifest index bc10f39b4..50a8269d5 100755 --- a/db/manifest +++ b/db/manifest @@ -78,4 +78,5 @@ add_user_bio.sql users_geocoding.sql recordings_public_launch.sql notification_band_invite.sql -band_photo_filepicker.sql \ No newline at end of file +band_photo_filepicker.sql +bands_geocoding.sql diff --git a/db/up/bands_geocoding.sql b/db/up/bands_geocoding.sql new file mode 100644 index 000000000..cf612ac0e --- /dev/null +++ b/db/up/bands_geocoding.sql @@ -0,0 +1,4 @@ +ALTER TABLE bands ADD COLUMN lat NUMERIC(15,10); +ALTER TABLE bands ADD COLUMN lng NUMERIC(15,10); + +UPDATE bands SET country = 'US' WHERE country = 'USA'; diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 640f6c2a0..3ce6fee36 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -2,8 +2,8 @@ module JamRuby class Band < ActiveRecord::Base attr_accessible :name, :website, :biography, :city, :state, - :country, :original_fpfile_photo, :cropped_fpfile_photo, - :cropped_s3_path_photo, :crop_selection_photo, :photo_url + :country, :original_fpfile_photo, :cropped_fpfile_photo, + :cropped_s3_path_photo, :crop_selection_photo, :photo_url attr_accessor :updating_photo @@ -13,6 +13,8 @@ module JamRuby validate :validate_photo_info validates :biography, no_profanity: true + before_save :check_lat_lng + # musicians has_many :band_musicians, :class_name => "JamRuby::BandMusician" has_many :users, :through => :band_musicians, :class_name => "JamRuby::User" @@ -40,6 +42,9 @@ module JamRuby has_many :music_sessions, :class_name => "JamRuby::MusicSession", :foreign_key => "band_id" has_many :music_session_history, :class_name => "JamRuby::MusicSessionHistory", :foreign_key => "band_id", :inverse_of => :band + include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable) + acts_as_mappable + def liker_count return self.likers.size end @@ -96,11 +101,11 @@ module JamRuby if hide_private recordings = Recording.joins(:band_recordings) - .where(:bands_recordings => {:band_id => "#{band_id}"}, :public => true) + .where(:bands_recordings => {:band_id => "#{band_id}"}, :public => true) else recordings = Recording.joins(:band_recordings) - .where(:bands_recordings => {:band_id => "#{band_id}"}) + .where(:bands_recordings => {:band_id => "#{band_id}"}) end return recordings @@ -125,11 +130,10 @@ module JamRuby # helper method for creating / updating a Band def self.save(id, name, website, biography, city, state, country, genres, user_id, photo_url, logo_url) - user = User.find(user_id) # new band - if id.nil? + if id.blank? # ensure person creating this Band is a Musician unless user.musician? @@ -139,7 +143,7 @@ module JamRuby validate_genres(genres, false) band = Band.new() - # band update + # band update else validate_genres(genres, true) band = Band.find(id) @@ -168,35 +172,28 @@ module JamRuby # country band.country = country unless country.nil? - # genres - unless genres.nil? - ActiveRecord::Base.transaction do - # delete all genres for this band first - unless band.id.nil? || band.id.length == 0 - band.genres.delete_all - end - - # loop through each genre in the array and save to the db - genres.each do |genre_id| - g = Genre.find(genre_id) - band.genres << g - end - end - end - # photo url band.photo_url = photo_url unless photo_url.nil? # logo url band.logo_url = logo_url unless logo_url.nil? - band.updated_at = Time.now.getutc - band.save + # band.updated_at = Time.now.getutc + band.save! + band.reload + + # genres + unless genres.nil? + ActiveRecord::Base.transaction do + # delete all genres for this band first + band.genres.delete_all if id.present? + # loop through each genre in the array and save to the db + genres.each { |genre_id| band.genres << Genre.find(genre_id) } + end + end # add the creator as the admin - if id.nil? - BandMusician.create(:band_id => band.id, :user_id => user_id, :admin => true) - end + BandMusician.create(:band_id => band.id, :user_id => user_id, :admin => true) if id.blank? return band end @@ -207,61 +204,83 @@ module JamRuby cropped_s3_path = cropped_fpfile["key"] return self.update_attributes( - :original_fpfile_photo => original_fpfile, - :cropped_fpfile_photo => cropped_fpfile, - :cropped_s3_path_photo => cropped_s3_path, - :crop_selection_photo => crop_selection, - :photo_url => S3Util.url(aws_bucket, cropped_s3_path, :secure => false) - ) + :original_fpfile_photo => original_fpfile, + :cropped_fpfile_photo => cropped_fpfile, + :cropped_s3_path_photo => cropped_s3_path, + :crop_selection_photo => crop_selection, + :photo_url => S3Util.url(aws_bucket, cropped_s3_path, :secure => false) + ) end def delete_photo(aws_bucket) Band.transaction do - unless self.cropped_s3_path.nil? - S3Util.delete(aws_bucket, File.dirname(self.cropped_s3_path) + '/cropped.jpg') - S3Util.delete(aws_bucket, self.cropped_s3_path) + unless self.cropped_s3_path_photo.nil? + S3Util.delete(aws_bucket, File.dirname(self.cropped_s3_path_photo) + '/cropped.jpg') + S3Util.delete(aws_bucket, self.cropped_s3_path_photo) end return self.update_attributes( - :original_fpfile_photo => nil, - :cropped_fpfile_photo => nil, - :cropped_s3_path_photo => nil, - :crop_selection_photo => nil, - :photo_url => nil - ) + :original_fpfile_photo => nil, + :cropped_fpfile_photo => nil, + :cropped_s3_path_photo => nil, + :crop_selection_photo => nil, + :photo_url => nil + ) end + end + def check_lat_lng + if (city_changed? || state_changed? || country_changed?) + update_lat_lng + end + true + end + + def update_lat_lng + if self.city + query = { :city => self.city } + query[:region] = self.state unless self.state.blank? + query[:country] = self.country unless self.country.blank? + if geo = MaxMindGeo.where(query).limit(1).first + if geo.lat && geo.lng && (self.lat != geo.lat || self.lng != geo.lng) + self.lat, self.lng = geo.lat, geo.lng + return true + end + end + end + self.lat, self.lng = nil, nil + false end private - def self.validate_genres(genres, is_nil_ok) - if is_nil_ok && genres.nil? - return - end + def self.validate_genres(genres, is_nil_ok) + if is_nil_ok && genres.nil? + return + end - if genres.nil? + if genres.nil? + raise JamRuby::JamArgumentError, ValidationMessages::GENRE_MINIMUM_NOT_MET + else + if genres.size < Limits::MIN_GENRES_PER_BAND raise JamRuby::JamArgumentError, ValidationMessages::GENRE_MINIMUM_NOT_MET - else - if genres.size < Limits::MIN_GENRES_PER_BAND - raise JamRuby::JamArgumentError, ValidationMessages::GENRE_MINIMUM_NOT_MET - end + end - if genres.size > Limits::MAX_GENRES_PER_BAND - raise JamRuby::JamArgumentError, ValidationMessages::GENRE_LIMIT_EXCEEDED - end + if genres.size > Limits::MAX_GENRES_PER_BAND + raise JamRuby::JamArgumentError, ValidationMessages::GENRE_LIMIT_EXCEEDED end end + end - def stringify_photo_info - # fpfile comes in as a hash, which is a easy-to-use and validate form. However, we store it as a VARCHAR, - # so we need t oconvert it to JSON before storing it (otherwise it gets serialized as a ruby object) - # later, when serving this data out to the REST API, we currently just leave it as a string and make a JSON capable - # client parse it, because it's very rare when it's needed at all - self.original_fpfile_photo = original_fpfile_photo.to_json if !original_fpfile_photo.nil? - self.cropped_fpfile_photo = cropped_fpfile_photo.to_json if !cropped_fpfile_photo.nil? - self.crop_selection_photo = crop_selection_photo.to_json if !crop_selection_photo.nil? - end + def stringify_photo_info + # fpfile comes in as a hash, which is a easy-to-use and validate form. However, we store it as a VARCHAR, + # so we need t oconvert it to JSON before storing it (otherwise it gets serialized as a ruby object) + # later, when serving this data out to the REST API, we currently just leave it as a string and make a JSON capable + # client parse it, because it's very rare when it's needed at all + self.original_fpfile_photo = original_fpfile_photo.to_json if !original_fpfile_photo.nil? + self.cropped_fpfile_photo = cropped_fpfile_photo.to_json if !cropped_fpfile_photo.nil? + self.crop_selection_photo = crop_selection_photo.to_json if !crop_selection_photo.nil? + end end end diff --git a/ruby/lib/jam_ruby/models/max_mind_geo.rb b/ruby/lib/jam_ruby/models/max_mind_geo.rb index 81868c4cd..713938552 100644 --- a/ruby/lib/jam_ruby/models/max_mind_geo.rb +++ b/ruby/lib/jam_ruby/models/max_mind_geo.rb @@ -40,7 +40,35 @@ module JamRuby end end User.find_each { |usr| usr.update_lat_lng } + Band.find_each { |bnd| bnd.update_lat_lng } end + + def self.where_latlng(relation, params, current_user=nil) + if 0 < (distance = params[:distance].to_i) + latlng = [] + if location_city = params[:city] + if geo = self.where(:city => params[:city]).limit(1).first + latlng = [geo.lat, geo.lng] + end + elsif current_user + if current_user.lat.nil? || current_user.lng.nil? + if params[:remote_ip] && (geo = self.ip_lookup(params[:remote_ip])) + latlng = [geo.lat, geo.lng] if geo.lat && geo.lng + end + else + latlng = [current_user.lat, current_user.lng] + end + elsif params[:remote_ip] && (geo = self.ip_lookup(params[:remote_ip])) + latlng = [geo.lat, geo.lng] if geo.lat && geo.lng + end + if latlng.present? + relation = relation.where(['lat IS NOT NULL AND lng IS NOT NULL']) + .within(distance, :origin => latlng) + end + end + relation + end + end end diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 63221d8aa..930bb109c 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -2,6 +2,7 @@ module JamRuby # not a active_record model; just a search result class Search attr_accessor :bands, :musicians, :fans, :recordings, :friends, :search_type + attr_accessor :bands_filter, :musicians_filter LIMIT = 10 # performs a site-white search @@ -30,6 +31,8 @@ module JamRuby @fans = [] @recordings = [] @friends = [] + @musicians_filter = [] + @bands_filter = [] if search_results.nil? return @@ -39,7 +42,6 @@ module JamRuby if result.class == User if result.musician @musicians.push(result) - @search_type = PARAM_MUSICIAN else @fans.push(result) end @@ -84,19 +86,23 @@ module JamRuby attr_accessor :user_counters, :page_num, :page_count PARAM_MUSICIAN = :srch_m + PARAM_BAND = :srch_b - M_PER_PAGE = 10 + B_PER_PAGE = M_PER_PAGE = 10 M_MILES_DEFAULT = 500 + B_MILES_DEFAULT = 0 M_ORDER_FOLLOWS = ['Most Followed', :followed] M_ORDER_PLAYS = ['Most Plays', :plays] M_ORDER_PLAYING = ['Playing Now', :playing] - M_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING] - M_ORDERING_KEYS = M_ORDERINGS.collect { |oo| oo[1] } + ORDERINGS = B_ORDERINGS = M_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING] + B_ORDERING_KEYS = M_ORDERING_KEYS = M_ORDERINGS.collect { |oo| oo[1] } - def self.musician_order_param(params) + DISTANCE_OPTS = B_DISTANCE_OPTS = M_DISTANCE_OPTS = [['Any', 0], [1000.to_s, 1000], [500.to_s, 500], [250.to_s, 250], [100.to_s, 100], [50.to_s, 50], [25.to_s, 25]] + + def self.order_param(params, keys=M_ORDERING_KEYS) ordering = params[:orderby] - ordering.blank? ? M_ORDERING_KEYS[0] : M_ORDERING_KEYS.detect { |oo| oo.to_s == ordering } + ordering.blank? ? keys[0] : keys.detect { |oo| oo.to_s == ordering } end def self.musician_search(params={}, current_user=nil) @@ -106,31 +112,10 @@ module JamRuby .where(['minst.instrument_id = ? AND users.id IS NOT NULL', instrument]) end - location_distance, location_city = params[:distance], params[:city] - distance, latlng = nil, [] - if location_distance && location_city - if geo = MaxMindGeo.where(:city => params[:city]).limit(1).first - distance, latlng = location_distance, [geo.lat, geo.lng] - end - elsif current_user - if current_user.lat.nil? || current_user.lng.nil? - if params[:remote_ip] && (geo = MaxMindGeo.ip_lookup(params[:remote_ip])) - latlng = [geo.lat, geo.lng] if geo.lat && geo.lng - end - else - latlng = [current_user.lat, current_user.lng] - end - elsif params[:remote_ip] && (geo = MaxMindGeo.ip_lookup(params[:remote_ip])) - latlng = [geo.lat, geo.lng] if geo.lat && geo.lng - end - if latlng.present? - distance ||= location_distance || M_MILES_DEFAULT - rel = rel.where(['lat IS NOT NULL AND lng IS NOT NULL']) - .within(distance, :origin => latlng) - end + rel = MaxMindGeo.where_latlng(rel, params, current_user) sel_str = 'users.*' - case ordering = self.musician_order_param(params) + case ordering = self.order_param(params) when :plays # FIXME: double counting? sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}" rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.user_id = users.id") @@ -150,9 +135,7 @@ module JamRuby end rel = rel.select(sel_str) - perpage = [(params[:per_page] || M_PER_PAGE).to_i, 100].min - page = [params[:page].to_i, 1].max - rel = rel.paginate(:page => page, :per_page => perpage) + rel, page = self.relation_pagination(rel, params) rel = rel.includes([:instruments, :followings, :friends]) objs = rel.all @@ -161,6 +144,12 @@ module JamRuby srch.musician_results_for_user(objs, current_user) end + def self.relation_pagination(rel, params) + perpage = [(params[:per_page] || M_PER_PAGE).to_i, 100].min + page = [params[:page].to_i, 1].max + [rel.paginate(:page => page, :per_page => perpage), page] + end + RESULT_FOLLOW = :follows RESULT_FRIEND = :friends @@ -171,10 +160,10 @@ module JamRuby COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] def musician_results_for_user(results, user) - @search_type, @musicians = PARAM_MUSICIAN, results + @search_type, @musicians_filter = PARAM_MUSICIAN, results if user @user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh } - mids = "'#{@musicians.map(&:id).join("','")}'" + mids = "'#{@musicians_filter.map(&:id).join("','")}'" # this gets counts for each search result on friends/follows/records/sessions results.each do |uu| @@ -258,5 +247,73 @@ module JamRuby end end + def self.band_search(params={}, current_user=nil) + rel = Band.scoped + + unless (genre = params[:genre]).blank? + rel = Band.joins("RIGHT JOIN bands_genres AS bgenres ON bgenres.band_id = bands.id") + .where(['bgenres.genre_id = ? AND bands.id IS NOT NULL', genre]) + end + + rel = MaxMindGeo.where_latlng(rel, params, current_user) + + sel_str = 'bands.*' + case ordering = self.order_param(params) + when :plays # FIXME: double counting? + sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}" + rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.band_id = bands.id") + .joins("LEFT JOIN recordings AS records ON records.band_id = bands.id") + .group("bands.id") + .order("play_count DESC, bands.created_at DESC") + when :followed + sel_str = "COUNT(follows) AS search_follow_count, #{sel_str}" + rel = rel.joins("LEFT JOIN bands_followers AS follows ON follows.band_id = bands.id") + .group("bands.id") + .order("COUNT(follows) DESC, bands.created_at DESC") + when :playing + rel = rel.joins("LEFT JOIN music_sessions_history AS msh ON msh.band_id = bands.id") + .where('msh.music_session_id IS NOT NULL AND msh.session_removed_at IS NULL') + .order("bands.created_at DESC") + end + + rel = rel.select(sel_str) + rel, page = self.relation_pagination(rel, params) + rel = rel.includes([{ :users => :instruments }, :genres ]) + + objs = rel.all + srch = Search.new + srch.page_num, srch.page_count = page, objs.total_pages + srch.band_results_for_user(objs, current_user) + end + + def band_results_for_user(results, user) + @search_type, @bands_filter = PARAM_BAND, results + if user + @user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh } + mids = "'#{@bands_filter.map(&:id).join("','")}'" + + # this gets counts for each search result + results.each do |bb| + counters = { } + counters[COUNT_FOLLOW] = BandFollowing.where(:band_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 bands_followers AS follows ON follows.follower_id = '#{user.id}'") + rel = rel.where(["bands.id IN (#{mids}) AND follows.band_id = bands.id"]) + rel.all.each { |val| @user_counters[val.bid] << RESULT_FOLLOW } + + else + @user_counters = {} + end + self + end + end 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 new file mode 100644 index 000000000..51e43f403 --- /dev/null +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -0,0 +1,187 @@ +require 'spec_helper' + +describe 'Band search' do + + before(:each) do + @geocode1 = FactoryGirl.create(:geocoder) + @geocode2 = FactoryGirl.create(:geocoder) + @bands = [] + @bands << @band1 = FactoryGirl.create(:band) + @bands << @band2 = FactoryGirl.create(:band) + @bands << @band3 = FactoryGirl.create(:band) + @bands << @band4 = FactoryGirl.create(:band) + + @bands.each do |bb| + FactoryGirl.create(:band_musician, :band => bb, :user => FactoryGirl.create(:user)) + (rand(4)+1).downto(1) do |nn| + FactoryGirl.create(:band_musician, :band => bb, :user => FactoryGirl.create(:user)) + end + end + + end + + context 'default filter settings' do + + it "finds all bands" do + # expects all the bands + num = Band.count + results = Search.band_search({ :per_page => num }) + expect(results.bands_filter.count).to eq(num) + end + + it "finds bands with proper ordering" do + # the ordering should be create_at since no followers exist + expect(BandFollower.count).to eq(0) + results = Search.band_search({ :per_page => Band.count }) + results.bands_filter.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) } + + # 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(BandFollower.count).to be 7 + + # refresh the order to ensure it works right + @band2.followers.concat(users[1..-1]) + results = Search.band_search({ :per_page => @bands.size }, users[0]) + expect(results.bands_filter[0].id).to eq(@band2.id) + + # check the follower count for given entry + expect(results.bands_filter[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_search(params) + expect(results.bands_filter.count).to be 2 + end + + end + + def make_session(band) + usr = band.users[0] + session = FactoryGirl.create(: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) } + + # establish sorting order + @band1.followers.concat(users) + results = Search.band_search({},@band1) + uu = results.bands_filter.detect { |mm| mm.id == @band1.id } + expect(uu).to_not be_nil + expect(results.follow_count(uu)).to eq(users.count) + end + + it "session stat shows session count" do + make_session(@band1) + @band1.reload + results = Search.band_search({},@band1) + uu = results.bands_filter.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_search({ :orderby => 'plays' }) + expect(results.bands_filter[0].id).to eq(@band2.id) + expect(results.bands_filter[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(:music_session_history, :music_session => session) + + results = Search.band_search({ :orderby => 'playing' }) + expect(results.bands_filter.count).to be 1 + expect(results.bands_filter.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(:music_session_history, :music_session => session) + results = Search.band_search({ :orderby => 'playing' }) + expect(results.bands_filter.count).to be 2 + expect(results.bands_filter[0].id).to eq(@band4.id) + expect(results.bands_filter[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_search({ :genre => ggg.id }) + results.bands_filter.each do |rr| + expect(rr.genres.detect { |gg| gg.id==ggg.id }.id).to eq(genre.id) + end + expect(results.bands_filter.count).to be 1 + end + + it "finds bands within a given distance of given location" do + num = Band.count + expect(@band1.lat).to_not be_nil + # short distance + results = Search.band_search({ :per_page => num, + :distance => 10, + :city => 'Apex' }, @band1) + expect(results.bands_filter.count).to be num + # long distance + results = Search.band_search({ :per_page => num, + :distance => 1000, + :city => 'Miami', + :state => 'FL' }, @band1) + expect(results.bands_filter.count).to be num + end + + it "finds bands within a given distance of bands location" do + expect(@band1.lat).to_not be_nil + # uses the location of @band1 + results = Search.band_search({ :distance => 10, :per_page => Band.count }, @band1) + expect(results.bands_filter.count).to be Band.count + end + + it "finds no bands within a given distance of location" do + expect(@band1.lat).to_not be_nil + results = Search.band_search({ :distance => 10, :city => 'San Francisco' }, @band1) + expect(results.bands_filter.count).to be 0 + end + + end + +end diff --git a/ruby/spec/jam_ruby/models/band_location_spec.rb b/ruby/spec/jam_ruby/models/band_location_spec.rb new file mode 100644 index 000000000..fae562a53 --- /dev/null +++ b/ruby/spec/jam_ruby/models/band_location_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe Band do + + before do + @geocode1 = FactoryGirl.create(:geocoder) + @geocode2 = FactoryGirl.create(:geocoder) + @band = FactoryGirl.create(:band) + end + + describe "with profile location data" do + it "should have lat/lng values" do + geo = MaxMindGeo.find_by_city(@band.city) + @band.lat.should == geo.lat + @band.lng.should == geo.lng + end + it "should have updated lat/lng values" do + @band.update_attributes({ :city => @geocode2.city, + :state => @geocode2.region, + :country => @geocode2.country, + }) + geo = MaxMindGeo.find_by_city(@band.city) + @band.lat.should == geo.lat + @band.lng.should == geo.lng + end + end + + describe "without location data" do + it "should have nil lat/lng values without address" do + @band.update_attributes({ :city => nil, + :state => nil, + :country => nil, + }) + @band.lat.should == nil + @band.lng.should == nil + end + end + +end diff --git a/ruby/spec/jam_ruby/models/band_search_spec.rb b/ruby/spec/jam_ruby/models/band_search_spec.rb index 2af217b3f..40e26d50f 100644 --- a/ruby/spec/jam_ruby/models/band_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_search_spec.rb @@ -5,7 +5,9 @@ describe User do let(:user) { FactoryGirl.create(:user) } before(:each) do - + @geocode1 = FactoryGirl.create(:geocoder) + @geocode2 = FactoryGirl.create(:geocoder) + @user = FactoryGirl.create(:user) @band = Band.save(nil, "Example Band", "www.bands.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil) end diff --git a/ruby/spec/jam_ruby/models/musician_search_spec.rb b/ruby/spec/jam_ruby/models/musician_search_spec.rb index 6eda4ae28..955b2f04f 100644 --- a/ruby/spec/jam_ruby/models/musician_search_spec.rb +++ b/ruby/spec/jam_ruby/models/musician_search_spec.rb @@ -18,14 +18,14 @@ describe 'Musician search' do # expects all the users num = User.musicians.count results = Search.musician_search({ :per_page => num }) - expect(results.musicians.count).to eq(num) + expect(results.musicians_filter.count).to eq(num) end it "finds musicians with proper ordering" do # the ordering should be create_at since no followers exist expect(UserFollower.count).to eq(0) results = Search.musician_search({ :per_page => User.musicians.count }) - results.musicians.each_with_index do |uu, idx| + results.musicians_filter.each_with_index do |uu, idx| expect(uu.id).to eq(@users.reverse[idx].id) end end @@ -41,10 +41,10 @@ describe 'Musician search' do # refresh the order to ensure it works right @user2.followers.concat([@user3, @user4, @user2]) results = Search.musician_search({ :per_page => @users.size }, @user3) - expect(results.musicians[0].id).to eq(@user2.id) + expect(results.musicians_filter[0].id).to eq(@user2.id) # check the follower count for given entry - expect(results.musicians[0].search_follow_count.to_i).not_to eq(0) + expect(results.musicians_filter[0].search_follow_count.to_i).not_to eq(0) # check the follow relationship between current_user and result expect(results.is_follower?(@user2)).to be true end @@ -53,7 +53,7 @@ describe 'Musician search' do # make sure pagination works right params = { :per_page => 2, :page => 1 } results = Search.musician_search(params) - expect(results.musicians.count).to be 2 + expect(results.musicians_filter.count).to be 2 end end @@ -96,7 +96,7 @@ describe 'Musician search' do Friendship.save(@user1.id, @user2.id) # search on user2 results = Search.musician_search({}, @user2) - friend = results.musicians.detect { |mm| mm.id == @user1.id } + friend = results.musicians_filter.detect { |mm| mm.id == @user1.id } expect(friend).to_not be_nil expect(results.friend_count(friend)).to be 1 @user1.reload @@ -115,7 +115,7 @@ describe 'Musician search' do expect(@user1.recordings.detect { |rr| rr == recording }).to_not be_nil results = Search.musician_search({},@user1) - uu = results.musicians.detect { |mm| mm.id == @user1.id } + uu = results.musicians_filter.detect { |mm| mm.id == @user1.id } expect(uu).to_not be_nil expect(results.record_count(uu)).to be 1 @@ -130,28 +130,28 @@ describe 'Musician search' do make_recording(@user1) # order results by num recordings results = Search.musician_search({ :orderby => 'plays' }, @user2) - expect(results.musicians[0].id).to eq(@user1.id) + expect(results.musicians_filter[0].id).to eq(@user1.id) # add more data and make sure order still correct make_recording(@user2); make_recording(@user2) results = Search.musician_search({ :orderby => 'plays' }, @user2) - expect(results.musicians[0].id).to eq(@user2.id) + expect(results.musicians_filter[0].id).to eq(@user2.id) end it "by now playing" do # should get 1 result with 1 active session make_session(@user3) results = Search.musician_search({ :orderby => 'playing' }, @user2) - expect(results.musicians.count).to be 1 - expect(results.musicians.first.id).to eq(@user3.id) + expect(results.musicians_filter.count).to be 1 + expect(results.musicians_filter.first.id).to eq(@user3.id) # should get 2 results with 2 active sessions # sort order should be created_at DESC make_session(@user4) results = Search.musician_search({ :orderby => 'playing' }, @user2) - expect(results.musicians.count).to be 2 - expect(results.musicians[0].id).to eq(@user4.id) - expect(results.musicians[1].id).to eq(@user3.id) + expect(results.musicians_filter.count).to be 2 + expect(results.musicians_filter[0].id).to eq(@user4.id) + expect(results.musicians_filter[1].id).to eq(@user3.id) end end @@ -166,10 +166,10 @@ describe 'Musician search' do ii = @user1.instruments.detect { |inst| inst.id == 'tuba' } expect(ii).to_not be_nil results = Search.musician_search({ :instrument => ii.id }) - results.musicians.each do |rr| + results.musicians_filter.each do |rr| expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id) end - expect(results.musicians.count).to be 1 + expect(results.musicians_filter.count).to be 1 end it "finds musicians within a given distance of given location" do @@ -179,26 +179,26 @@ describe 'Musician search' do results = Search.musician_search({ :per_page => num, :distance => 10, :city => 'Apex' }, @user1) - expect(results.musicians.count).to be num + expect(results.musicians_filter.count).to be num # long distance results = Search.musician_search({ :per_page => num, :distance => 1000, :city => 'Miami', :state => 'FL' }, @user1) - expect(results.musicians.count).to be num + expect(results.musicians_filter.count).to be num end it "finds musicians within a given distance of users location" do expect(@user1.lat).to_not be_nil # uses the location of @user1 results = Search.musician_search({ :distance => 10, :per_page => User.musicians.count }, @user1) - expect(results.musicians.count).to be User.musicians.count + expect(results.musicians_filter.count).to be User.musicians.count end it "finds no musicians within a given distance of location" do expect(@user1.lat).to_not be_nil results = Search.musician_search({ :distance => 10, :city => 'San Francisco' }, @user1) - expect(results.musicians.count).to be 0 + expect(results.musicians_filter.count).to be 0 end end diff --git a/web/app/assets/javascripts/band_setup.js b/web/app/assets/javascripts/band_setup.js index 5752a35e4..996190051 100644 --- a/web/app/assets/javascripts/band_setup.js +++ b/web/app/assets/javascripts/band_setup.js @@ -229,8 +229,8 @@ userNames = []; userIds = []; userPhotoUrls = []; - //bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c"; - bandId = $("#hdn-band-id").val(); + bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c"; + //bandId = $("#hdn-band-id").val(); resetForm(); } diff --git a/web/app/assets/javascripts/findBand.js b/web/app/assets/javascripts/findBand.js new file mode 100644 index 000000000..a8a9714db --- /dev/null +++ b/web/app/assets/javascripts/findBand.js @@ -0,0 +1,228 @@ +(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; + + function loadBands(queryString) { + // squelch nulls and undefines + queryString = !!queryString ? queryString : ""; + + $.ajax({ + type: "GET", + url: "/api/search.json?" + queryString, + async: true, + 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(); + } + } + } + + /** + * Render a list of bands + */ + 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 bVals, bb, renderings=''; + var instr_logos, instr; + var players, playerVals, aPlayer; + + for (ii=0, len=bands.length; ii < len; ii++) { + bb = bands[ii]; + instr_logos = ''; + /*for (var jj=0, ilen=bb['instruments'].length; jj '; + }*/ + players = ''; + playerVals = {}; + for (var jj=0, ilen=bb['players'].length; jj '; + }*/ + + playerVals = { + player_name: aPlayer.name, + profile_url: '/#/profile/' + aPlayer.user_id, + avatar_url: context.JK.resolveAvatarUrl(aPlayer.photo_url), + player_instruments: player_instrs + }; + players += context.JK.fillTemplate(pTemplate, playerVals); + } + var actionVals = { + profile_url: "/#/profile/" + bb.id, + button_follow: bb['is_following'] ? '' : 'button-orange', + button_message: 'button-orange' + }; + var band_actions = context.JK.fillTemplate(aTemplate, actionVals); + + bVals = { + avatar_url: context.JK.resolveAvatarUrl(bb.photo_url), + profile_url: "/#/profile/" + bb.id, + band_name: bb.name, + band_location: bb.city + ', ' + bb.state, + 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_follow_template: players, + band_action_template: band_actions + }; + var band_row = context.JK.fillTemplate(mTemplate, bVals); + renderings += band_row; + } + $('#band-filter-results').append(renderings); + + $('.search-m-follow').on('click', followBand); + } + + 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.user_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 + $('div[data-band-id='+newFollowing.user_id+'] .search-m-follow').removeClass('button-orange'); + }, + error: app.ajaxError + }); + } + + function events() { + $('#band_query_distance').change(refreshDisplay); + $('#band_genre').change(refreshDisplay); + $('#band_order_by').change(refreshDisplay); + + $('#band-filter-results').bind('scroll', function() { + if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { + if (page_num < page_count) { + page_num += 1; + search(); + } + } + }); + } + + /** + * Initialize, + */ + 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/findMusician.js b/web/app/assets/javascripts/findMusician.js index 7da599797..7c1e2e93a 100644 --- a/web/app/assets/javascripts/findMusician.js +++ b/web/app/assets/javascripts/findMusician.js @@ -29,12 +29,12 @@ var queryString = 'srch_m=1&page='+page_num+'&'; // order by - var orderby = $('.musician-order-by').val(); + var orderby = $('#musician_order_by').val(); if (typeof orderby != 'undefined' && orderby.length > 0) { queryString += "orderby=" + orderby + '&'; } // instrument filter - var instrument = $('.instrument-list').val(); + var instrument = $('#musician_instrument').val(); if (typeof instrument != 'undefined' && !(instrument === '')) { queryString += "instrument=" + instrument + '&'; } @@ -197,13 +197,9 @@ } function events() { - $("#musician_query_distance").keypress(function(evt) { - if (evt.which === 13) { - evt.preventDefault(); - refreshDisplay(); - } - }); - $('#btn-refresh-musicians').on("click", refreshDisplay); + $('#musician_query_distance').change(refreshDisplay); + $('#musician_instrument').change(refreshDisplay); + $('#musician_order_by').change(refreshDisplay); $('#musician-filter-results').bind('scroll', function() { if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { diff --git a/web/app/assets/stylesheets/client/search.css.scss b/web/app/assets/stylesheets/client/search.css.scss index 0cb2f25ff..352a3b644 100644 --- a/web/app/assets/stylesheets/client/search.css.scss +++ b/web/app/assets/stylesheets/client/search.css.scss @@ -56,20 +56,9 @@ } .query-distance-params { - float:left; - width:50px; + float: left; + width: 80px; margin-left: 10px; - -webkit-border-radius: 6px; - border-radius: 6px; - background-color:$ColorTextBoxBackground; border: none; - color:#333; - font-weight:400; - padding:0px 0px 0px 8px; - height:18px; - line-height:18px; - overflow:hidden; - -webkit-box-shadow: inset 2px 2px 3px 0px #888; - box-shadow: inset 2px 2px 3px 0px #888; } diff --git a/web/app/controllers/api_bands_controller.rb b/web/app/controllers/api_bands_controller.rb index 483237bae..1d441e21c 100644 --- a/web/app/controllers/api_bands_controller.rb +++ b/web/app/controllers/api_bands_controller.rb @@ -197,9 +197,9 @@ class ApiBandsController < ApiController @band.update_photo(original_fpfile, cropped_fpfile, crop_selection, Rails.application.config.aws_bucket_public) if @band.errors.any? - respond_with @band, status: :unprocessable_entity + render :json => { :message => "Unexpected error updating photo."}, :status => :unprocessable_entity else - respond_with @band, responder: ApiResponder, status: 200 + render :json => {}, :status => :ok end end @@ -207,9 +207,9 @@ class ApiBandsController < ApiController @band.delete_photo(Rails.application.config.aws_bucket_public) if @band.errors.any? - respond_with @band, status: :unprocessable_entity + render :json => { :message => "Unexpected error deleting photo."}, :status => :unprocessable_entity else - respond_with @band, responder: ApiResponder, status: 204 + render :json => {}, :status => :ok end end diff --git a/web/app/controllers/api_search_controller.rb b/web/app/controllers/api_search_controller.rb index 006b64783..63c0ff8d9 100644 --- a/web/app/controllers/api_search_controller.rb +++ b/web/app/controllers/api_search_controller.rb @@ -7,11 +7,15 @@ class ApiSearchController < ApiController def index if 1 == params[Search::PARAM_MUSICIAN].to_i - logger.debug("*** params = #{params.inspect}") query = params.clone query[:remote_ip] = request.remote_ip @search = Search.musician_search(query, current_user) respond_with @search, responder: ApiResponder, :status => 200 + elsif 1 == params[Search::PARAM_BAND].to_i + query = params.clone + query[:remote_ip] = request.remote_ip + @search = Search.band_search(query, current_user) + respond_with @search, responder: ApiResponder, :status => 200 else @search = Search.search(params[:query], current_user.id) end diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index f4ec6a6e8..581566cd8 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -1,12 +1,26 @@ object @search -unless @search.bands.nil? || @search.bands.size == 0 +if @search.bands.present? child(:bands => :bands) { attributes :id, :name, :location, :photo_url, :logo_url } end -unless @search.musicians.nil? || @search.musicians.size == 0 +if @search.musicians.present? + child(:musicians => :musicians) { + attributes :id, :first_name, :last_name, :name, :location, :photo_url + + node :is_friend do |musician| + musician.friends?(current_user) + end + + child :musician_instruments => :instruments do + attributes :instrument_id, :description, :proficiency_level, :priority + end + } +end + +if @search.musicians_filter.present? node :city do |user| current_user.try(:location) @@ -16,7 +30,7 @@ unless @search.musicians.nil? || @search.musicians.size == 0 @search.page_count end - child(:musicians => :musicians) { + child(:musicians_filter => :musicians) { attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url, :biography node :is_friend do |musician| @@ -44,6 +58,36 @@ unless @search.musicians.nil? || @search.musicians.size == 0 } end +if @search.bands_filter.present? + + node :page_count do |foo| + @search.page_count + end + + child(:bands_filter => :bands) { + attributes :id, :name, :city, :state, :country, :email, :photo_url, :biography, :logo_url + + node :is_following do |band| + @search.is_follower?(band) + end + + child :genres => :genre 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 + unless @search.fans.nil? || @search.fans.size == 0 child(:fans => :fans) { attributes :id, :first_name, :last_name, :name, :location, :photo_url diff --git a/web/app/views/clients/_bands.html.erb b/web/app/views/clients/_bands.html.erb index 8505890b1..091244ff5 100644 --- a/web/app/views/clients/_bands.html.erb +++ b/web/app/views/clients/_bands.html.erb @@ -1,13 +1,61 @@ -
-
+<%= content_tag(:div, :layout => 'screen', 'layout-id' => 'bands', :class => "screen secondary") 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 -%> + <%= form_tag('', :id => 'find-band-form') do -%> + <%= content_tag(:div, render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_BAND}), :class => 'band-filter', :id => 'session-controls') %> + <%= content_tag(:div, :class => 'content-scroller') do -%> + <%= content_tag(:div, content_tag(:div, '', :id => 'band-filter-results'), :class => 'content-wrapper band-wrapper') %> + <% end -%> + <% end -%> + <% end -%> +<% end -%> -
- <%= image_tag "content/icon_bands.png", {:height => 19, :width => 19} %> -
- -

bands

- <%= render "screen_navigation" %> + + + + + + + diff --git a/web/app/views/clients/_musician_filter.html.erb b/web/app/views/clients/_musician_filter.html.erb index 4a351876e..917136950 100644 --- a/web/app/views/clients/_musician_filter.html.erb +++ b/web/app/views/clients/_musician_filter.html.erb @@ -7,29 +7,19 @@ <%= content_tag(:div, :class => 'filter-element') do -%> <%= content_tag(:div, 'Instrument:', :class => 'filter-element') %> - <%= content_tag(:div, :class => 'filter-element', :id => "find-musician-instrument") do -%> - <%= select_tag(:instrument, - options_for_select([['Any', '']].concat(JamRuby::Instrument.all.collect { |ii| [ii.description, ii.id] })), - {:class => 'instrument-list'} ) %> + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= select_tag(:musician_instrument, + options_for_select([['Any', '']].concat(JamRuby::Instrument.all.collect { |ii| [ii.description, ii.id] }))) %> <% end -%> <% end -%> <%= content_tag(:div, :class => 'filter-element') do -%> <%= content_tag(:div, 'Within', :class => 'filter-element') %> - <%= content_tag(:div, :class => 'query-distance-params', :style => "height:25px;") do -%> - <%= text_field_tag(:query_distance, - Search::M_MILES_DEFAULT.to_s, - :id => :musician_query_distance, - :placeholder => Search::M_MILES_DEFAULT.to_s) %> + <%= content_tag(:div, :class => 'query-distance-params') do -%> + <%= select_tag('musician_query_distance', options_for_select(Search::M_DISTANCE_OPTS, Search::M_MILES_DEFAULT)) %> <% end -%> <%= content_tag(:div, :class => 'filter-element') do -%> miles of <%= content_tag(:span, current_user.current_city(request.remote_ip), :id => 'musician-filter-city') %> <% end -%> <% end -%> - <%= content_tag(:div, - link_to('REFRESH', '#', - :id => 'btn-refresh-musicians', - :style => 'text-decoration:none', - :class => 'button-grey'), - :class => 'right mr10') %> <% end -%> diff --git a/web/app/views/clients/_musicians.html.erb b/web/app/views/clients/_musicians.html.erb index 3d3e25793..973b93880 100644 --- a/web/app/views/clients/_musicians.html.erb +++ b/web/app/views/clients/_musicians.html.erb @@ -7,7 +7,7 @@ <%= render "screen_navigation" %> <% end -%> <%= form_tag('', :id => 'find-musician-form') do -%> - <%= content_tag(:div, render(:partial => "musician_filter"), :class => 'musician-filter', :id => 'session-controls') %> + <%= content_tag(:div, render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_MUSICIAN}), :class => 'musician-filter', :id => 'session-controls') %> <%= content_tag(:div, :class => 'content-scroller') do -%> <%= content_tag(:div, content_tag(:div, '', :id => 'musician-filter-results'), :class => 'content-wrapper musician-wrapper') %> <% end -%> diff --git a/web/app/views/clients/_web_filter.html.erb b/web/app/views/clients/_web_filter.html.erb new file mode 100644 index 000000000..16568bfe6 --- /dev/null +++ b/web/app/views/clients/_web_filter.html.erb @@ -0,0 +1,36 @@ +<% filter_label = defined?(search_type) && search_type == Search::PARAM_BAND ? :band : :musician %> +<%= content_tag(:div, :style => "min-width:770px;") do -%> + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= content_tag(:div, 'Filter By:', :class => 'filter-element', :style => "padding-top:3px;") %> + + <%= select_tag("#{filter_label}_order_by", options_for_select(Search::ORDERINGS), {:class => "#{filter_label}-order-by"} ) %> + <% end -%> + <%= content_tag(:div, :class => 'filter-element') do -%> + <% if :musician == filter_label %> + + <%= content_tag(:div, 'Instrument:', :class => 'filter-element') %> + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= select_tag("#{filter_label}_instrument", + options_for_select([['Any', '']].concat(JamRuby::Instrument.all.collect { |ii| [ii.description, ii.id] }))) %> + <% end -%> + <% elsif :band == filter_label %> + + <%= content_tag(:div, 'Genre:', :class => 'filter-element') %> + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= select_tag("#{filter_label}_genre", + options_for_select([['Any', '']].concat(JamRuby::Genre.all.collect { |ii| [ii.description, ii.id] }))) %> + <% end -%> + <% end %> + <% end -%> + + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= content_tag(:div, 'Within', :class => 'filter-element') %> + <%= content_tag(:div, :class => 'query-distance-params') do -%> + <% default_distance = :musician == filter_label ? Search::M_MILES_DEFAULT : Search::B_MILES_DEFAULT %> + <%= select_tag("#{filter_label}_query_distance", options_for_select(Search::DISTANCE_OPTS, default_distance)) %> + <% end -%> + <%= content_tag(:div, :class => 'filter-element') do -%> + miles of <%= content_tag(:span, current_user.current_city(request.remote_ip), :id => "#{filter_label}-filter-city") %> + <% end -%> + <% end -%> +<% end -%> diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index c8e8300a8..1e8a95051 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -155,6 +155,9 @@ var findMusicianScreen = new JK.FindMusicianScreen(JK.app); findMusicianScreen.initialize(); + var findBandScreen = new JK.FindBandScreen(JK.app); + findBandScreen.initialize(); + var sessionScreen = new JK.SessionScreen(JK.app); sessionScreen.initialize(); var sessionSettingsDialog = new JK.SessionSettingsDialog(JK.app, sessionScreen); diff --git a/web/lib/tasks/sample_data.rake b/web/lib/tasks/sample_data.rake index cd8d77f07..dee36061d 100644 --- a/web/lib/tasks/sample_data.rake +++ b/web/lib/tasks/sample_data.rake @@ -14,6 +14,14 @@ namespace :db do make_friends end + task populate_bands: :environment do + make_bands + end + + task populate_band_members: :environment do + make_band_members + end + desc "Fill database with music session sample data" task populate_music_sessions: :environment do make_users(10) if 14 > User.count @@ -56,16 +64,24 @@ def make_music_sessions_user_history end 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}) + end + end +end + def make_bands 10.times do |nn| name = Faker::Name.name website = Faker::Internet.url biography = Faker::Lorem.sentence - city = Faker::Address.city - state = Faker::Address.state_abbr - country = Faker::Address.country + city = 'Austin' # Faker::Address.city + state = 'TX' # Faker::Address.state_abbr + country = 'US' - Band.create!( + bb = Band.new( name: name, website: website, biography: biography, @@ -73,6 +89,11 @@ def make_bands state: state, country: country, ) + begin + bb.save! + rescue + puts $!.to_s + ' ' + bb.errors.inspect + end end end diff --git a/web/spec/features/musician_search_spec.rb b/web/spec/features/musician_search_spec.rb index b2ce07802..e7c29d7aa 100644 --- a/web/spec/features/musician_search_spec.rb +++ b/web/spec/features/musician_search_spec.rb @@ -24,14 +24,12 @@ describe "Musician Search", :js => true, :type => :feature, :capybara_feature => end it "shows submits query" do - find("a#btn-refresh-musicians").trigger(:click) expect(page).to have_selector('#musician-filter-results .musician-list-result') end it "shows blank result set" do - expect(page).to have_selector('#instrument') - find('#instrument').find(:xpath, 'option[2]').select_option - find("a#btn-refresh-musicians").trigger(:click) + expect(page).to have_selector('#musician_instrument') + find('#musician_instrument').find(:xpath, 'option[2]').select_option expect(page).to_not have_selector('#musician-filter-results .musician-list-result') end diff --git a/web/spec/requests/musician_search_api_spec.rb b/web/spec/requests/musician_search_api_spec.rb index 11680a2a5..a48a1c6b1 100644 --- a/web/spec/requests/musician_search_api_spec.rb +++ b/web/spec/requests/musician_search_api_spec.rb @@ -29,7 +29,7 @@ describe "Musician Search API", :type => :api do it "default search" do get_query good_response - expect(json['musicians'].count).to be [Search::M_PER_PAGE, User.musicians_geocoded.count].min + expect(json['musicians'].count).to be [Search::M_PER_PAGE, User.musicians.count].min end context 'location filtering' do