243 lines
7.6 KiB
Ruby
243 lines
7.6 KiB
Ruby
module JamRuby
|
|
# not a active_record model; just a search result
|
|
class Search
|
|
attr_accessor :bands, :musicians, :fans, :recordings, :friends, :search_type
|
|
LIMIT = 10
|
|
|
|
# performs a site-white search
|
|
def self.search(query, user_id = nil)
|
|
|
|
users = User.search(query, :limit => LIMIT)
|
|
bands = Band.search(query, :limit => LIMIT)
|
|
# NOTE: I removed recordings from search here. This is because we switched
|
|
# to "claimed_recordings" so it's not clear what should be searched.
|
|
|
|
friends = Friendship.search(query, user_id, :limit => LIMIT)
|
|
|
|
return Search.new(users + bands + friends)
|
|
end
|
|
|
|
# performs a friend search scoped to a specific user
|
|
# def self.search_by_user(query, user_id)
|
|
# friends = Friendship.search(query, user_id, :limit => LIMIT)
|
|
# return Search.new(friends)
|
|
# end
|
|
|
|
# search_results - results from a Tire search across band/user/recording
|
|
def initialize(search_results=nil)
|
|
@bands = []
|
|
@musicians = []
|
|
@fans = []
|
|
@recordings = []
|
|
@friends = []
|
|
|
|
if search_results.nil?
|
|
return
|
|
end
|
|
|
|
search_results.take(LIMIT).each do |result|
|
|
if result.class == User
|
|
if result.musician
|
|
@musicians.push(result)
|
|
@search_type = PARAM_MUSICIAN
|
|
else
|
|
@fans.push(result)
|
|
end
|
|
elsif result.class == Band
|
|
@bands.push(result)
|
|
elsif result.class == Recording
|
|
@recordings.push(result)
|
|
elsif result.class == Friendship
|
|
@friends.push(result.friend)
|
|
else
|
|
raise Exception, "unknown class #{result.class} returned in search results"
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.create_tsquery(query)
|
|
# empty queries don't hit back to elasticsearch
|
|
if query.nil? || query.length == 0
|
|
return nil
|
|
end
|
|
|
|
search_terms = query.split
|
|
|
|
if search_terms.length == 0
|
|
return nil
|
|
end
|
|
|
|
args = nil
|
|
search_terms.each do |search_term|
|
|
if args == nil
|
|
args = search_term
|
|
else
|
|
args = args + " & " + search_term
|
|
end
|
|
|
|
end
|
|
args = args + ":*"
|
|
|
|
return args
|
|
end
|
|
|
|
attr_accessor :user_counters, :page_num, :page_count
|
|
|
|
PARAM_MUSICIAN = :search_m
|
|
|
|
M_PER_PAGE = 10
|
|
|
|
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] }
|
|
|
|
def self.musician_order_param(params)
|
|
ordering = params[:orderby]
|
|
ordering.blank? ? M_ORDERING_KEYS[0] : M_ORDERING_KEYS.detect { |oo| oo.to_s == ordering }
|
|
end
|
|
|
|
def self.musician_search(params={}, current_user=nil)
|
|
rel = User.where(:musician => true)
|
|
unless (instrument = params[:instrument]).blank?
|
|
rel = rel.joins("RIGHT JOIN musicians_instruments AS minst ON minst.user_id = users.id")
|
|
.where(['minst.instrument_id = ? AND users.id IS NOT NULL', instrument])
|
|
end
|
|
|
|
location_distance, location_city = params[:distance], params[:city]
|
|
if location_distance && location_city
|
|
if geo = MaxMindGeo.where(:city => params[:city]).limit(1).first
|
|
citylatlng = [geo.lat, geo.lng]
|
|
rel = rel.within(location_distance, :origin => citylatlng)
|
|
end
|
|
elsif current_user
|
|
latlng = []
|
|
if current_user.lat.nil?
|
|
if params[:remote_ip]
|
|
if geo = MaxMindGeo.ip_lookup(params[:remote_ip])
|
|
latlng = [geo.lat, geo.lng] if geo.lat && geo.lng
|
|
end
|
|
end
|
|
else
|
|
latlng = [current_user.lat, current_user.lng]
|
|
end
|
|
distance = location_distance || 50
|
|
unless latlng.blank?
|
|
rel = rel.where(['lat IS NOT NULL AND lng IS NOT NULL'])
|
|
.within(distance, :origin => latlng)
|
|
end
|
|
end
|
|
|
|
sel_str = 'users.*'
|
|
case ordering = self.musician_order_param(params)
|
|
when :plays
|
|
when :followed
|
|
sel_str = "COUNT(follows) AS search_follow_count, #{sel_str}"
|
|
rel = rel.joins("LEFT JOIN users_followers AS follows ON follows.user_id = users.id")
|
|
rel = rel.group("users.id")
|
|
rel = rel.order("COUNT(follows) DESC, users.created_at DESC")
|
|
when :playing
|
|
end
|
|
|
|
rel = rel.select(sel_str)
|
|
perpage = params[:per_page] || M_PER_PAGE
|
|
page = [params[:page].to_i, 1].max
|
|
rel = rel.paginate(:page => page, :per_page => perpage)
|
|
rel.includes([:instruments, :followings, :friends])
|
|
|
|
srch = Search.new
|
|
srch.page_num, srch.page_count = page, rel.all.total_pages
|
|
srch.musician_results_for_user(rel.all, current_user)
|
|
end
|
|
|
|
RESULT_FOLLOW = :follows
|
|
RESULT_LIKE = :likes
|
|
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 musician_results_for_user(results, user)
|
|
@search_type, @musicians = PARAM_MUSICIAN, results
|
|
if user
|
|
@user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh }
|
|
mids = "'#{@musicians.map(&:id).join("','")}'"
|
|
results.each do |uu|
|
|
counters = { }
|
|
counters[COUNT_FRIEND] = Friendship.where(:user_id => uu.id).count
|
|
counters[COUNT_FOLLOW] = UserFollowing.where(:user_id => uu.id).count
|
|
counters[COUNT_RECORD] = ClaimedRecording.where(:user_id => uu.id).count
|
|
counters[COUNT_SESSION] = MusicSession.where(:user_id => uu.id).count
|
|
@user_counters[uu.id] << counters
|
|
end
|
|
|
|
rel = User.select("users.id AS uid")
|
|
rel = rel.joins("LEFT JOIN users_followers AS follows ON follows.follower_id = '#{user.id}'")
|
|
rel = rel.where(["users.id IN (#{mids}) AND follows.user_id = users.id"])
|
|
rel.all.each { |val| @user_counters[val.uid] << RESULT_FOLLOW }
|
|
|
|
rel = User.select("users.id AS uid")
|
|
rel = rel.joins("LEFT JOIN users_likers AS likers ON likers.liker_id = '#{user.id}'")
|
|
rel = rel.where(["users.id IN (#{mids}) AND likers.user_id = users.id"])
|
|
rel.all.each { |val| @user_counters[val.uid] << RESULT_LIKE }
|
|
|
|
rel = User.select("users.id AS uid")
|
|
rel = rel.joins("LEFT JOIN friendships AS friends ON friends.friend_id = '#{user.id}'")
|
|
rel = rel.where(["users.id IN (#{mids}) AND friends.user_id = users.id"])
|
|
rel.all.each { |val| @user_counters[val.uid] << RESULT_FRIEND }
|
|
|
|
else
|
|
@user_counters = {}
|
|
end
|
|
self
|
|
end
|
|
|
|
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
|
|
|
|
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 is_liker?(musician)
|
|
if mm = @user_counters[musician.id]
|
|
return mm.include?(RESULT_LIKE)
|
|
end if @user_counters
|
|
false
|
|
end
|
|
|
|
end
|
|
end
|