VRFS-1028 hover bubble / like and follow refactor

This commit is contained in:
Brian Smith 2014-02-16 02:28:35 -05:00
parent c173582aa3
commit 36287d0b5f
39 changed files with 505 additions and 338 deletions

View File

@ -2,8 +2,6 @@ drop table users_followers;
drop table users_likers;
drop table bands_followers;
drop table bands_likers;
drop table music_sessions_likers;
drop table recordings_likers;
alter table music_sessions_history
add constraint music_sessions_history_pkey PRIMARY KEY (id);

View File

@ -1,6 +1,6 @@
alter table music_sessions_comments drop constraint music_sessions_comments_music_session_id_fkey;
alter table music_sessions_comments add constraint ms_comments_ms_history_fkey foreign key (music_session_id)
references music_sessions_history(music_session_id) match simple
references music_sessions_history(id) match simple
ON UPDATE NO ACTION ON DELETE CASCADE;
alter table music_sessions_likers drop constraint music_sessions_likers_music_session_id_fkey;

View File

@ -73,6 +73,7 @@ require "jam_ruby/models/friendship"
require "jam_ruby/models/music_session"
require "jam_ruby/models/music_session_comment"
require "jam_ruby/models/music_session_history"
require "jam_ruby/models/music_session_liker"
require "jam_ruby/models/music_session_user_history"
require "jam_ruby/models/music_session_perf_data"
require "jam_ruby/models/invitation"
@ -87,6 +88,7 @@ require "jam_ruby/models/track"
require "jam_ruby/models/search"
require "jam_ruby/models/recording"
require "jam_ruby/models/recording_comment"
require "jam_ruby/models/recording_liker"
require "jam_ruby/models/recording_play"
require "jam_ruby/models/recorded_track"
require "jam_ruby/models/recorded_track_observer"

View File

@ -2,7 +2,12 @@ module JamRuby
class Follow < ActiveRecord::Base
belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "user_id"
belongs_to :likable, :polymorphic => true
belongs_to :followable, :polymorphic => true
def type
type = self.followable_type.gsub("JamRuby::", "").downcase
type
end
end
end

View File

@ -21,7 +21,7 @@ module JamRuby
has_many :music_session_user_histories, :class_name => "JamRuby::MusicSessionUserHistory", :foreign_key => "music_session_id"
has_many :comments, :class_name => "JamRuby::MusicSessionComment", :foreign_key => "music_session_id"
has_many :likes, :as => :likable, :class_name => "JamRuby::Like", :dependent => :destroy
has_many :likes, :class_name => "JamRuby::MusicSessionLiker", :foreign_key => "session_id"
has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id'
before_create :generate_share_token

View File

@ -0,0 +1,17 @@
module JamRuby
class MusicSessionLiker < ActiveRecord::Base
self.table_name = "music_sessions_likers"
self.primary_key = 'id'
belongs_to(:music_session_history,
:class_name => "JamRuby::MusicSessionHistory",
:foreign_key => "music_session_id")
belongs_to(:user,
:class_name => "JamRuby::User",
:foreign_key => "liker_id")
end
end

View File

@ -64,7 +64,7 @@ module JamRuby
def retrieve_user_followers(connection, user_id)
follower_ids = []
connection.exec("SELECT uf.follower_id as friend_id FROM users_followers uf WHERE uf.user_id = $1", [user_id]) do |follower_results|
connection.exec("SELECT u.user_id as follower_id FROM follows f WHERE f.followable_id = $1", [user_id]) do |follower_results|
follower_results.each do |follower_result|
follower_ids.push(follower_result['follower_id'])
end
@ -460,11 +460,11 @@ module JamRuby
if music_session.musician_access || music_session.fan_access
friends = Friendship.where(:friend_id => user.id)
user_followers = UserFollower.where(:user_id => user.id)
user_followers = user.followers
# construct an array of User objects representing friends and followers
friend_users = friends.map { |fu| fu.user }
follower_users = user_followers.map { |uf| uf.follower }
follower_users = user_followers.map { |uf| uf.user }
friends_and_followers = friend_users.concat(follower_users).uniq
# remove anyone in the session
@ -509,22 +509,21 @@ module JamRuby
# if the session is private, don't send any notifications
if music_session.musician_access || music_session.fan_access
band_followers = BandFollower.where(:band_id => band.id)
notifications, online_followers, offline_followers = [], [], []
notification_msg = format_msg(NotificationTypes::BAND_SESSION_JOIN, nil, band)
band_followers.each do |bf|
if (bf.follower.musician && music_session.musician_access) || (!bf.follower.musician && music_session.fan_access)
band.followers.each do |bf|
follower = bf.user
if (follower.musician && music_session.musician_access) || (!follower.musician && music_session.fan_access)
notification = Notification.new
notification.band_id = band.id
notification.description = NotificationTypes::BAND_SESSION_JOIN
notification.target_user_id = bf.follower.id
notification.target_user_id = follower.id
notification.save
if bf.follower.online
if follower.online
msg = @@message_factory.band_session_join(
bf.follower.id,
follower.id,
music_session.id,
band.photo_url,
notification_msg,
@ -532,9 +531,9 @@ module JamRuby
notification.created_at.to_s
)
@@mq_router.publish_to_user(bf.follower.id, msg)
@@mq_router.publish_to_user(follower.id, msg)
else
offline_followers << bf.follower
offline_followers << follower
end
end
end
@ -551,11 +550,11 @@ module JamRuby
user = recording.owner
friends = Friendship.where(:friend_id => user.id)
user_followers = UserFollower.where(:user_id => user.id)
user_followers = user.followers
# construct an array of User objects representing friends and followers
friend_users = friends.map { |fu| fu.friend }
follower_users = user_followers.map { |uf| uf.follower }
follower_users = user_followers.map { |uf| uf.user }
friends_and_followers = friend_users.concat(follower_users).uniq
notifications, online_ff, offline_ff = [], [], []
@ -592,20 +591,20 @@ module JamRuby
def send_band_recording_saved(recording)
band_followers = BandFollower.where(:band_id => band.id)
notification_msg = format_msg(NotificationTypes::BAND_RECORDING_SAVED, nil, recording.band)
band_followers.each do |bf|
band.followers.each do |bf|
follower = bf.user
notification = Notification.new
notification.description = NotificationTypes::BAND_RECORDING_SAVED
notification.band_id = band.id
notification.target_user_id = bf.follower.id
notification.target_user_id = follower.id
notification.recording_id = recording.id
notification.save
if bf.follower.online
if follower.online
msg = @@message_factory.band_recording_saved(
bf.follower.id,
follower.id,
recording.id,
band.photo_url,
notification_msg,
@ -615,7 +614,7 @@ module JamRuby
@@mq_router.publish_to_user(of.id, notification_msg)
else
offline_followers << bf.follower
offline_followers << follower
end
end

View File

@ -10,8 +10,7 @@ module JamRuby
has_many :mixes, :class_name => "JamRuby::Mix", :inverse_of => :recording, :foreign_key => 'recording_id', :dependent => :destroy
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :foreign_key => :recording_id, :dependent => :destroy
has_many :comments, :class_name => "JamRuby::RecordingComment", :foreign_key => "recording_id"
# has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "recording_id"
has_many :likes, :as => :likable, :class_name => "JamRuby::Like", :dependent => :destroy
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "recording_id"
has_many :plays, :class_name => "JamRuby::RecordingPlay", :foreign_key => "recording_id"
belongs_to :owner, :class_name => "JamRuby::User", :inverse_of => :owned_recordings, :foreign_key => 'owner_id'

View File

@ -0,0 +1,12 @@
module JamRuby
class RecordingLiker < ActiveRecord::Base
self.table_name = "recordings_likers"
self.primary_key = 'id'
belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id"
belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "liker_id"
end
end

View File

@ -124,7 +124,7 @@ module JamRuby
.order("play_count DESC, users.created_at DESC")
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.joins("LEFT JOIN follows ON follows.followable_id = users.id")
.group("users.id")
.order("COUNT(follows) DESC, users.created_at DESC")
when :playing
@ -170,7 +170,7 @@ module JamRuby
@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_FOLLOW] = Follow.where(:followable_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
@ -179,8 +179,8 @@ module JamRuby
# this section determines follow/like/friend status for each search result
# so that action links can be activated or not
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 = rel.joins("LEFT JOIN follows ON follows.user_id = '#{user.id}'")
rel = rel.where(["users.id IN (#{mids}) AND follows.followable_id = users.id"])
rel.all.each { |val| @user_counters[val.uid] << RESULT_FOLLOW }
rel = User.select("users.id AS uid")
@ -288,7 +288,7 @@ module JamRuby
.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")
rel = rel.joins("LEFT JOIN follows ON follows.followable_id = bands.id")
.group("bands.id")
.order("COUNT(follows) DESC, bands.created_at DESC")
when :playing
@ -317,7 +317,7 @@ module JamRuby
# this gets counts for each search result
@results.each do |bb|
counters = { }
counters[COUNT_FOLLOW] = BandFollowing.where(:band_id => bb.id).count
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
@ -327,8 +327,8 @@ module JamRuby
# 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 = 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

View File

@ -238,7 +238,7 @@ module JamRuby
# check if "this user" likes entity
def likes?(entity)
self.likings.where(:user_id => self.id).where(:likable_id => entity.id).size > 0
self.likings.where(:likable_id => entity.id).size > 0
end
def liking_count
@ -251,7 +251,7 @@ module JamRuby
# check if "this user" follows entity
def following?(entity)
self.followings.where(:user_id => self.id).where(:likable_id => entity.id).size > 0
self.followings.where(:followable_id => entity.id).size > 0
end
def following_count
@ -547,8 +547,7 @@ module JamRuby
end
def create_user_following(targetUserId)
targetUser = User.new
targetUser.id = targetUserId
targetUser = User.find(targetUserId)
follow = Follow.new
follow.followable = targetUser
@ -556,14 +555,12 @@ module JamRuby
follow.save
# TODO: make this async
user = User.find(targetUserId)
Notification.send_new_user_follower(self, user)
Notification.send_new_user_follower(self, targetUser)
end
def create_band_following(targetBandId)
targetBand= Band.new
targetBand.id = targetBandId
targetBand= Band.find(targetBandId)
follow = Follow.new
follow.followable = targetBand
@ -571,17 +568,15 @@ module JamRuby
follow.save
# TODO: make this async
band = Band.find(targetBandId)
Notification.send_new_band_follower(self, band)
Notification.send_new_band_follower(self, targetBand)
end
def self.delete_following(likerId, targetEntityId)
Follow.delete_all "(user_id = '#{liker_id}' AND followable_id = '#{targetEntityId}')"
def self.delete_following(followerId, targetEntityId)
Follow.delete_all "(user_id = '#{followerId}' AND followable_id = '#{targetEntityId}')"
end
def create_user_like(targetUserId)
targetUser = User.new
targetUser.id = targetUserId
targetUser = User.find(targetUserId)
like = Like.new
like.likable = targetUser
@ -590,8 +585,7 @@ module JamRuby
end
def create_band_like(targetBandId)
targetBand = Band.new
targetBand.id = targetBandId
targetBand = Band.find(targetBandId)
like = Like.new
like.likable = targetBand
@ -599,6 +593,24 @@ module JamRuby
like.save
end
def create_session_like(targetSessionId)
targetSession = MusicSessionHistory.find(targetSessionId)
like = Like.new
like.likable = targetSession
like.user = self
like.save
end
def create_recording_like(targetRecordingId)
targetRecording = Recording.find(targetRecordingId)
like = Like.new
like.likable = targetRecording
like.user = self
like.save
end
def self.delete_like(likerId, targetEntityId)
Like.delete_all "(user_id = '#{liker_id}' AND likable_id = '#{targetEntityId}')"
end
@ -1075,8 +1087,8 @@ module JamRuby
end
def top_followings
@topf ||= User.joins("INNER JOIN users_followers AS follows ON follows.user_id = users.id")
.where(['follows.follower_id = ?',self.id])
@topf ||= User.joins("INNER JOIN follows ON follows.followable_id = users.id")
.where(['follows.user_id = ?',self.id])
.order('follows.created_at DESC')
.limit(3)
end

View File

@ -31,7 +31,7 @@ describe 'Band search' do
it "finds bands with proper ordering" do
# the ordering should be create_at since no followers exist
expect(BandFollower.count).to eq(0)
expect(Follow.count).to eq(0)
results = Search.band_filter({ :per_page => Band.count })
results.results.each_with_index do |uu, idx|
expect(uu.id).to eq(@bands.reverse[idx].id)
@ -42,17 +42,47 @@ describe 'Band search' 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])
# @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
expect(Follow.count).to be 7
# refresh the order to ensure it works right
@band2.followers.concat(users[1..-1])
users.each_with_index do |u, index|
f1 = Follow.new
f1.user = u
f1.followable = @band2
f1.save
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)
@ -85,8 +115,15 @@ describe 'Band search' 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)
# @band1.followers.concat(users)
results = Search.band_filter({},@band1)
uu = results.results.detect { |mm| mm.id == @band1.id }
expect(uu).to_not be_nil

View File

@ -24,7 +24,7 @@ describe 'Musician search' do
it "finds musicians with proper ordering" do
# the ordering should be create_at since no followers exist
expect(UserFollower.count).to eq(0)
expect(Follow.count).to eq(0)
results = Search.musician_filter({ :per_page => User.musicians.count })
results.results.each_with_index do |uu, idx|
expect(uu.id).to eq(@users.reverse[idx].id)
@ -33,14 +33,63 @@ describe 'Musician search' do
it "sorts musicians by followers" do
# establish sorting order
@user4.followers.concat([@user2, @user3, @user4])
@user3.followers.concat([@user3, @user4])
@user2.followers.concat([@user1])
# @user4
f1 = Follow.new
f1.user = @user2
f1.followable = @user4
f1.save
f2 = Follow.new
f2.user = @user3
f2.followable = @user4
f2.save
f3 = Follow.new
f3.user = @user4
f3.followable = @user4
f3.save
# @user3
f4 = Follow.new
f4.user = @user3
f4.followable = @user3
f4.save
f5 = Follow.new
f5.user = @user4
f5.followable = @user3
f5.save
# @user2
f6 = Follow.new
f6.user = @user1
f6.followable = @user2
f6.save
# @user4.followers.concat([@user2, @user3, @user4])
# @user3.followers.concat([@user3, @user4])
# @user2.followers.concat([@user1])
expect(@user4.followers.count).to be 3
expect(UserFollower.count).to be 6
expect(Follow.count).to be 6
# refresh the order to ensure it works right
@user2.followers.concat([@user3, @user4, @user2])
f1 = Follow.new
f1.user = @user3
f1.followable = @user2
f1.save
f2 = Follow.new
f2.user = @user4
f2.followable = @user2
f2.save
f3 = Follow.new
f3.user = @user2
f3.followable = @user2
f3.save
# @user2.followers.concat([@user3, @user4, @user2])
results = Search.musician_filter({ :per_page => @users.size }, @user3)
expect(results.results[0].id).to eq(@user2.id)
@ -85,9 +134,24 @@ describe 'Musician search' do
context 'musician stat counters' do
it "displays musicians top followings" do
@user4.followers.concat([@user4])
@user3.followers.concat([@user4])
@user2.followers.concat([@user4])
f1 = Follow.new
f1.user = @user4
f1.followable = @user4
f1.save
f2 = Follow.new
f2.user = @user4
f2.followable = @user3
f2.save
f3 = Follow.new
f3.user = @user4
f3.followable = @user2
f3.save
# @user4.followers.concat([@user4])
# @user3.followers.concat([@user4])
# @user2.followers.concat([@user4])
expect(@user4.top_followings.count).to be 3
expect(@user4.top_followings.map(&:id)).to match_array((@users - [@user1]).map(&:id))
end

View File

@ -13,7 +13,6 @@
function beforeShow(data) {
bandId = data.id;
setIsMember();
}
function afterShow(data) {
@ -49,12 +48,14 @@
rest.addFollowing(newFollowing)
.done(function() {
if (isBand) {
var newCount = parseInt($("#band-profile-follower-stats").text()) + 1;
var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower";
$('#band-profile-follower-stats').html(newCount + text);
configureBandFollowingButton(true);
}
else {
configureMemberFollowingButton(true, id);
}
configureFollowingButton();
})
.fail(app.ajaxError);
}
@ -67,6 +68,9 @@
.done(function() {
renderActive(); // refresh stats
if (isBand) {
var newCount = parseInt($("#band-profile-follower-stats").text()) - 1;
var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower";
$('#band-profile-follower-stats').html(newCount + text);
configureBandFollowingButton(false);
}
else {
@ -100,30 +104,6 @@
return alreadyFollowing;
}
function isFollowing() {
var alreadyFollowing = false;
var url = "/api/users/" + context.JK.currentUserId + "/band_followings/" + bandId;
$.ajax({
type: "GET",
dataType: "json",
url: url,
async: false,
processData: false,
success: function(response) {
if (response.id !== undefined) {
alreadyFollowing = true;
}
else {
alreadyFollowing = false;
}
},
error: app.ajaxError
});
return alreadyFollowing;
}
function configureBandFollowingButton(following) {
$('#btn-follow-band').unbind("click");
@ -201,45 +181,51 @@
}
function bindAbout() {
var url = "/api/bands/" + bandId;
$.ajax({
type: "GET",
dataType: "json",
url: url,
async: false,
processData:false,
success: function(response) {
band = response;
},
error: app.ajaxError
});
if (band) {
rest.getBand(bandId)
.done(function(response) {
band = response;
setIsMember();
if (band) {
// name
$('#band-profile-name').html(band.name);
// name
$('#band-profile-name').html(band.name);
// avatar
$('#band-profile-avatar').attr('src', context.JK.resolveAvatarUrl(band.photo_url));
// avatar
$('#band-profile-avatar').attr('src', context.JK.resolveAvatarUrl(band.photo_url));
// location
$('#band-profile-location').html(band.location);
// location
$('#band-profile-location').html(band.location);
// stats
var text = band.follower_count > 1 || band.follower_count == 0 ? " Followers" : " Follower";
$('#band-profile-follower-stats').html(band.follower_count + text);
// stats
var text = band.follower_count > 1 || band.follower_count == 0 ? " Followers" : " Follower";
$('#band-profile-follower-stats').html(band.follower_count + text);
text = band.session_count > 1 || band.session_count == 0 ? " Sessions" : " Session";
$('#band-profile-session-stats').html(band.session_count + text);
text = band.session_count > 1 || band.session_count == 0 ? " Sessions" : " Session";
$('#band-profile-session-stats').html(band.session_count + text);
text = band.recording_count > 1 || band.recording_count == 0 ? " Recordings" : " Recording";
$('#band-profile-recording-stats').html(band.recording_count + text);
text = band.recording_count > 1 || band.recording_count == 0 ? " Recordings" : " Recording";
$('#band-profile-recording-stats').html(band.recording_count + text);
$('#band-profile-biography').html(band.biography);
}
else {
logger.debug("No band found with bandId = " + bandId);
}
$('#band-profile-biography').html(band.biography);
// wire up Follow click
configureBandFollowingButton(band.is_following);
}
else {
logger.debug("No band found with bandId = " + bandId);
}
})
.fail(function(xhr) {
if(xhr.status >= 500) {
context.JK.fetchUserNetworkOrServerFailure();
}
else if(xhr.status == 404) {
context.JK.entityNotFound("Band");
}
else {
context.JK.app.ajaxError(arguments);
}
});
}
/****************** SOCIAL TAB *****************/
@ -270,6 +256,8 @@
$.each(response, function(index, val) {
var template = $('#template-band-profile-social').html();
var followerHtml = context.JK.fillTemplate(template, {
userId: val.user_id,
hoverAction: val.musician ? "musician" : "fan",
avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
userName: val.name,
location: val.location
@ -280,6 +268,7 @@
},
error: app.ajaxError
});
context.JK.bindHoverEvents();
}
/****************** HISTORY TAB *****************/
@ -445,10 +434,6 @@
$('#band-profile-members-link').click(renderMembers);
$('#band-profile-social-link').click(renderSocial);
// wire up Follow click
var following = isFollowing();
configureBandFollowingButton(following);
if (isMember) {
$("#btn-follow-band").hide();
$("#btn-edit-band-profile").show();

View File

@ -5,6 +5,7 @@
context.JK.FindMusicianScreen = function(app) {
var logger = context.JK.logger;
var rest = context.JK.Rest();
var musicians = {};
var musicianList;
var instrument_logo_map = context.JK.getInstrumentIconMap24();
@ -176,7 +177,7 @@
evt.stopPropagation();
var uid = $(this).parent().data('musician-id');
context.JK.sendFriendRequest(app, uid, friendRequestCallback);
rest.sendFriendRequest(app, uid, friendRequestCallback);
}
function friendRequestCallback(user_id) {

View File

@ -31,8 +31,19 @@
followingHtml += '<tr>';
}
followingHtml += '<td width="24"><a href="#" class="avatar-tiny"><img src="' + context.JK.resolveAvatarUrl(val.photo_url) + '" /></a></td>';
followingHtml += '<td><a href="/client#/profile/' + val.id + '"><strong>' + val.name + '</strong></a></td>';
var avatarUrl, profilePath;
if (val.type === "band") {
avatarUrl = context.JK.resolveBandAvatarUrl(val.photo_url);
profilePath = "bandProfile"
}
else {
avatarUrl = context.JK.resolveAvatarUrl(val.photo_url);
profilePath = "profile";
}
followingHtml += '<td width="24"><a href="#" class="avatar-tiny"><img src="' + avatarUrl + '" /></a></td>';
followingHtml += '<td><a href="/client#/' + profilePath + '/' + val.id + '"><strong>' + val.name + '</strong></a></td>';
if (index % 2 > 0) {
followingHtml += '</tr>';
@ -53,6 +64,7 @@
}
var musicianHtml = context.JK.fillTemplate(template, {
userId: response.id,
avatar_url: context.JK.resolveAvatarUrl(response.photo_url),
name: response.name,
location: response.location,

View File

@ -414,6 +414,26 @@
});
}
/** NOTE: This is only for Musician, Fan, and Band Likes. Recording and
Session Likes have their own section below since unauthenticated users
are allowed to Like these entities.
*/
function addLike(options) {
var id = getId(options);
return $.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: "/api/users/" + id + "/likes",
data: JSON.stringify(options),
processData: false
});
}
function removeLike(options) {
}
function addFollowing(options) {
var id = getId(options);
@ -462,29 +482,6 @@
});
}
function getBandFollowings(options) {
var userId = getId(options);
// FOLLOWINGS (BANDS)
return $.ajax({
type: "GET",
dataType: "json",
url: "/api/users/" + userId + "/band_followings",
processData:false
});
}
function getBandFollowing(options) {
var id = getId(options);
var bandId = options["band_id"];
return $.ajax({
type: "GET",
dataType: "json",
url: "/api/users/" + id + "/band_followings/" + bandId,
processData: false
});
}
function getBands(options) {
var userId = getId(options);
@ -495,13 +492,6 @@
processData:false
});
}
function getMusicianFollowers(userId) {
}
function getBandFollowers(bandId) {
}
function getClientDownloads(options) {
@ -562,6 +552,25 @@
});
}
function sendFriendRequest(app, userId, callback) {
var url = "/api/users/" + context.JK.currentUserId + "/friend_requests";
$.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: url,
data: '{"friend_id":"' + userId + '"}',
processData: false,
success: function(response) {
if (callback) {
callback(userId);
}
context.JK.GA.trackFriendConnect(context.JK.GA.FriendConnectTypes.request);
},
error: app.ajaxError
});
}
function acceptFriendRequest(options) {
var id = getId(options);
var friend_request_id = options["friend_request_id"];
@ -833,12 +842,12 @@
this.getFilepickerPolicy = getFilepickerPolicy;
this.getFriends = getFriends;
this.removeFriend = removeFriend;
this.addLike = addLike;
this.removeLike = removeLike;
this.addFollowing = addFollowing;
this.removeFollowing = removeFollowing;
this.getFollowings = getFollowings;
this.getFollowers = getFollowers;
this.getBandFollowings = getBandFollowings;
this.getBandFollowing = getBandFollowing;
this.getBands = getBands;
this.updateSession = updateSession;
this.getSessionHistory = getSessionHistory;
@ -852,6 +861,7 @@
this.createInvitation = createInvitation;
this.postFeedback = postFeedback;
this.serverHealthCheck = serverHealthCheck;
this.sendFriendRequest = sendFriendRequest;
this.acceptFriendRequest = acceptFriendRequest;
this.signout = signout;
this.userDownloadedClient = userDownloadedClient;

View File

@ -164,7 +164,7 @@
evt.stopPropagation();
setFriend(true); // TODO: you aren't a friend yet. just a request to be one really there are 3 states here.
sentFriendRequest = true;
context.JK.sendFriendRequest(app, userId, friendRequestCallback);
rest.sendFriendRequest(app, userId, friendRequestCallback);
}
function removeFriend(evt) {
@ -408,21 +408,6 @@
})
.fail(app.ajaxError);
rest.getBandFollowings({id: userId})
.done(function(response) {
$.each(response, function(index, val) {
var template = $('#template-profile-social').html();
var followingHtml = context.JK.fillTemplate(template, {
avatar_url: context.JK.resolveBandAvatarUrl(val.logo_url),
userName: val.name,
location: val.location
});
$('#profile-social-followings').append(followingHtml);
});
})
.fail(app.ajaxError);
rest.getFollowers({id: userId})
.done(function(response) {
$.each(response, function(index, val) {
@ -531,13 +516,7 @@
$('#profile-bands').append(bandHtml);
// wire up Band Follow button click handler
// XXX; we should return if you are following the band in the rabl, so we don't
// have to hit the server per band shown
rest.getBandFollowing({band_id: val.id})
.done(function(response) {
var alreadyFollowing = response.id !== undefined;
configureBandFollowingButton(alreadyFollowing, val.id);
});
configureBandFollowingButton(val.is_following, val.id);
});
if(response.length >= 3) {

View File

@ -5,6 +5,7 @@
context.JK = context.JK || {};
context.JK.SearchResultScreen = function(app) {
var logger = context.JK.logger;
var rest = context.JK.Rest();
var instrument_logo_map = context.JK.getInstrumentIconMap24();
function initializeSearchNavLinks() {
@ -215,10 +216,10 @@
var userId = $(this).parent().attr('user-id');
if ($(this).closest('#sidebar-search-results')) {
context.JK.sendFriendRequest(app, userId, friendRequestCallbackSidebar);
rest.sendFriendRequest(app, userId, friendRequestCallbackSidebar);
}
else {
context.JK.sendFriendRequest(app, userId, friendRequestCallbackSearchResults);
rest.sendFriendRequest(app, userId, friendRequestCallbackSearchResults);
}
}

View File

@ -384,35 +384,18 @@
}
context.JK.search = function(query, app, callback) {
logger.debug("search: "+query)
$.ajax({
type: "GET",
dataType: "json",
contentType: 'application/json',
url: "/api/search?query=" + query,
processData: false,
success: function(response) {
callback(response);
},
error: app.ajaxError
});
};
context.JK.sendFriendRequest = function(app, userId, callback) {
var url = "/api/users/" + context.JK.currentUserId + "/friend_requests";
$.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: url,
data: '{"friend_id":"' + userId + '"}',
processData: false,
success: function(response) {
callback(userId);
context.JK.GA.trackFriendConnect(context.JK.GA.FriendConnectTypes.request);
},
error: app.ajaxError
});
//logger.debug("search: "+ query)
$.ajax({
type: "GET",
dataType: "json",
contentType: 'application/json',
url: "/api/search?query=" + query,
processData: false,
success: function(response) {
callback(response);
},
error: app.ajaxError
});
};
/*

View File

@ -189,19 +189,15 @@ class ApiUsersController < ApiController
@user = User.find(params[:id])
end
def band_like_index
@user = User.find(params[:id])
end
def like_create
if !params[:user_id].nil?
@user.create_user_like(params[:user_id])
respond_with @user, responder: ApiResponder, :location => api_user_like_index_url(@user)
elsif !params[:band_id].nil?
@user.create_band_like(params[:band_id])
respond_with @user, responder: ApiResponder, :location => api_band_like_index_url(@user)
end
respond_with @user, responder: ApiResponder, :location => api_user_like_index_url(@user)
end
def like_destroy
@ -220,27 +216,15 @@ class ApiUsersController < ApiController
@user = User.find(params[:id])
end
# def following_show
# @following = UserFollowing.find_by_user_id_and_follower_id(params[:user_id], params[:id])
# end
def band_following_index
@user = User.find(params[:id])
end
# def band_following_show
# @following = BandFollowing.find_by_band_id_and_follower_id(params[:band_id], params[:id])
# end
def following_create
if !params[:user_id].nil?
@user.create_user_following(params[:user_id])
respond_with @user, responder: ApiResponder, :location => api_user_following_index_url(@user)
elsif !params[:band_id].nil?
@user.create_band_following(params[:band_id])
respond_with @user, responder: ApiResponder, :location => api_band_following_index_url(@user)
end
respond_with @user, responder: ApiResponder, :location => api_user_following_index_url(@user)
end
def following_destroy

View File

@ -1,21 +1,21 @@
collection @band.followers
node :user_id do |follower|
follower.id
follower.user.id
end
node :name do |follower|
follower.name
follower.user.name
end
node :location do |follower|
follower.location
follower.user.location
end
node :musician do |follower|
follower.musician
follower.user.musician
end
node :photo_url do |follower|
follower.photo_url
follower.user.photo_url
end

View File

@ -23,6 +23,6 @@ end
if current_user
node :is_following do |uu|
current_user.following_band?(@band)
current_user.following?(@band)
end
end

View File

@ -1,21 +0,0 @@
collection @user.band_followings
node :band_id do |following|
following.id
end
node :name do |following|
following.name
end
node :location do |following|
following.location
end
node :photo_url do |following|
following.photo_url
end
node :logo_url do |following|
following.logo_url
end

View File

@ -1,3 +0,0 @@
object @following
attributes :id, :band_id, :follower_id

View File

@ -31,3 +31,9 @@ end
node :biography do |band|
band.biography.nil? ? "" : band.biography
end
node :is_following do |band|
if current_user
current_user.following?(band)
end
end

View File

@ -1,21 +1,21 @@
collection @user.followers
node :user_id do |follower|
follower.id
follower.user.id
end
node :name do |follower|
follower.name
follower.user.name
end
node :location do |follower|
follower.location
follower.user.location
end
node :musician do |follower|
follower.musician
follower.user.musician
end
node :photo_url do |follower|
follower.photo_url
follower.user.photo_url
end

View File

@ -1,21 +1,23 @@
collection @user.followings
node :user_id do |following|
following.id
following.followable.id
end
node :name do |following|
following.name
following.followable.name
end
node :location do |following|
following.location
following.followable.location
end
node :musician do |following|
following.musician
if following.followable.instance_of?(JamRuby::User)
following.followable.musician
end
end
node :photo_url do |following|
following.photo_url
following.followable.photo_url
end

View File

@ -1,3 +1,3 @@
object @user.likes
object @user.likings
extends "api_users/like_index"

View File

@ -1,31 +1,31 @@
object @user.likes
object @user.likings
attributes :user_id
node :first_name do |like|
like.user.first_name
node :first_name do |liking|
liking.user.first_name
end
node :last_name do |like|
like.user.last_name
node :last_name do |liking|
liking.user.last_name
end
node :city do |like|
like.user.city
node :city do |liking|
liking.user.city
end
node :state do |like|
like.user.state
node :state do |liking|
liking.user.state
end
node :country do |like|
like.user.country
node :country do |liking|
liking.user.country
end
node :musician do |like|
like.user.musician
node :musician do |liking|
liking.user.musician
end
node :photo_url do |like|
like.user.photo_url
node :photo_url do |liking|
liking.user.photo_url
end

View File

@ -1,6 +1,6 @@
object @user
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :band_like_count, :follower_count, :following_count, :band_following_count, :recording_count, :session_count, :biography, :favorite_count
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :follower_count, :following_count, :recording_count, :session_count, :biography, :favorite_count
if @user.musician?
node :location do @user.location end
@ -20,7 +20,7 @@ elsif current_user
current_user.following?(@user)
end
node :is_liking do |uu|
current_user.likes
current_user.likes?(@user)
end
end
@ -29,7 +29,25 @@ child :friends => :friends do
end
child :followings => :followings do
attributes :id, :name, :location, :photo_url
attributes :type
node :id do |f|
f.followable.id
end
node :name do |f|
f.followable.name
end
node :location do |f|
f.followable.location
end
node :photo_url do |f|
f.followable.photo_url
end
end
child :band_musicians => :bands do

View File

@ -119,10 +119,10 @@
<script type="text/template" id="template-band-profile-social">
<div class="profile-block">
<div class="avatar-small">
<div user-id="{userId}" hoveraction="{hoverAction}" class="avatar-small">
<img src="{avatar_url}" />
</div>
<div class="profile-block-name">{userName}</div>
<div user-id="{userId}" hoveraction="{hoverAction}" class="profile-block-name">{userName}</div>
<div class="profile-block-city">{location}</div>
</div>
</script>

View File

@ -2,6 +2,30 @@
</div>
<script type="text/javascript">
var rest = JK.Rest();
function addLike(bandId) {
rest.addLike({band_id: bandId})
.done(function(response) {
$("#spnLikeCount", "#band-hover").html(parseInt($("#spnLikeCount", "#band-hover").text()) + 1);
var $btnLikeSelector = $("#btnLike", "#band-hover");
$btnLikeSelector.unbind("click");
$btnLikeSelector.html("LIKED");
});
}
function addFollowing(bandId) {
rest.addFollowing({band_id: bandId})
.done(function(response) {
$("#spnFollowCount", "#band-hover").html(parseInt($("#spnFollowCount", "#band-hover").text()) + 1);
var $btnFollowSelector = $("#btnFollow", "#band-hover");
$btnFollowSelector.unbind("click");
$btnFollowSelector.html("STOP FOLLOWING");
});
}
</script>
<script type="text/template" id="template-hover-band">
<div class="bubble-inner">
<a href="#" class="avatar_large left mr20"><img src="{avatar_url}" /></a>
@ -9,8 +33,8 @@
<h3>{name}</h3>
<small>{location}<br /><strong>{genres}</strong></small><br />
<br clear="all" />
{like_count} <img src="/assets/content/icon_like.png" align="absmiddle" />&nbsp;&nbsp;&nbsp;
{follower_count} <img src="/assets/content/icon_followers.png" width="22" height="12" align="absmiddle" />&nbsp;&nbsp;&nbsp;
<span id="spnLikeCount">{like_count}</span> <img src="/assets/content/icon_like.png" align="absmiddle" />&nbsp;&nbsp;&nbsp;
<span id="spnFollowCount">{follower_count}</span> <img src="/assets/content/icon_followers.png" width="22" height="12" align="absmiddle" />&nbsp;&nbsp;&nbsp;
{recording_count} <img src="/assets/content/icon_recordings.png" width="12" height="13" align="absmiddle" />&nbsp;&nbsp;&nbsp;
{session_count} <img src="/assets/content/icon_session_tiny.png" width="12" height="12" align="absmiddle" />
</div>

View File

@ -2,14 +2,32 @@
</div>
<script type="text/javascript">
var rest = JK.Rest();
function addFollowing(userId) {
rest.addFollowing({user_id: userId})
.done(function(response) {
$("#spnFollowCount", "#fan-hover").html(parseInt($("#spnFollowCount", "#fan-hover").text()) + 1);
var $btnFollowSelector = $("#btnFollow", "#fan-hover");
$btnFollowSelector.unbind("click");
$btnFollowSelector.html("STOP FOLLOWING");
});
}
function sendFriendRequest(userId) {
rest.sendFriendRequest(JK.app, userId);
}
</script>
<script type="text/template" id="template-hover-fan">
<div class="bubble-inner">
<div class="bubble-inner">
<a href="#" class="avatar_large left mr20"><img src="{avatar_url}" /></a>
<div class="left ib">
<h3>{name}</h3>
<small>{location}</small><br /><br />
{friend_count} <img src="/assets/content/icon_friend.png" align="absmiddle" />&nbsp;&nbsp;&nbsp;
{follower_count} <img src="/assets/content/icon_followers.png" width="22" height="12" align="absmiddle" />
<span id="spnFriendCount">{friend_count}</span> <img src="/assets/content/icon_friend.png" align="absmiddle" />&nbsp;&nbsp;&nbsp;
<span id="spnFollowCount">{follower_count}</span> <img src="/assets/content/icon_followers.png" width="22" height="12" align="absmiddle" />
</div>
<br clear="all" /><br />
<div class="f11">{biography}</div><br />
@ -20,7 +38,8 @@
<br />
<div align="center">
<div class="left"><a href="{profile_url}" class="button-orange">PROFILE</a></div>
<div class="left"><a class="button-orange">FOLLOW</a></div>
<div class="left"><a onclick="sendFriendRequest('{userId}');" class="button-orange">FRIEND</a></div>
<div class="left"><a onclick="addFollowing('{userId}');" class="button-orange">FOLLOW</a></div>
</div>
<br /><br />
</div>

View File

@ -2,16 +2,44 @@
</div>
<script type="text/javascript">
var rest = JK.Rest();
function addLike(userId) {
rest.addLike({user_id: userId})
.done(function(response) {
$("#spnLikeCount", "#musician-hover").html(parseInt($("#spnLikeCount", "#musician-hover").text()) + 1);
var $btnLikeSelector = $("#btnLike", "#musician-hover");
$btnLikeSelector.unbind("click");
$btnLikeSelector.html("LIKED");
});
}
function addFollowing(userId) {
rest.addFollowing({user_id: userId})
.done(function(response) {
$("#spnFollowCount", "#musician-hover").html(parseInt($("#spnFollowCount", "#musician-hover").text()) + 1);
var $btnFollowSelector = $("#btnFollow", "#musician-hover");
$btnFollowSelector.unbind("click");
$btnFollowSelector.html("STOP FOLLOWING");
});
}
function sendFriendRequest(userId) {
rest.sendFriendRequest(JK.app, userId);
}
</script>
<script type="text/template" id="template-hover-musician">
<div class="bubble-inner">
<div class="bubble-inner">
<a href="#" class="avatar_large left mr20"><img src="{avatar_url}" /></a>
<div class="left ib">
<h3>{name}</h3>
<small>{location}</small><br /><br />
{instruments}
<br clear="all" />
{friend_count} <img src="/assets/content/icon_friend.png" align="absmiddle" />&nbsp;&nbsp;&nbsp;
{follower_count} <img src="/assets/content/icon_followers.png" width="22" height="12" align="absmiddle" />&nbsp;&nbsp;&nbsp;
<span id="spnFriendCount">{friend_count}</span> <img src="/assets/content/icon_friend.png" align="absmiddle" />&nbsp;&nbsp;&nbsp;
<span id="spnFollowCount">{follower_count}</span> <img src="/assets/content/icon_followers.png" width="22" height="12" align="absmiddle" />&nbsp;&nbsp;&nbsp;
{recording_count} <img src="/assets/content/icon_recordings.png" width="12" height="13" align="absmiddle" />&nbsp;&nbsp;&nbsp;
{session_count} <img src="/assets/content/icon_session_tiny.png" width="12" height="12" align="absmiddle" />
</div>
@ -26,9 +54,9 @@
<br />
<div align="center">
<div class="left"><a href="{profile_url}" class="button-orange">PROFILE</a></div>
<div class="left"><a class="button-orange">LIKE</a></div>
<div class="left"><a class="button-orange">FRIEND</a></div>
<div class="left"><a class="button-orange">FOLLOW</a></div>
<div class="left"><a onclick="addLike('{userId}');" class="button-orange">LIKE</a></div>
<div class="left"><a onclick="sendFriendRequest('{userId}');" class="button-orange">FRIEND</a></div>
<div class="left"><a onclick="addFollowing('{userId}');" class="button-orange">FOLLOW</a></div>
</div>
<br /><br />
</div>

View File

@ -48,7 +48,7 @@ SampleApp::Application.configure do
config.assets.debug = false
# Set the logging destination(s)
# config.log_to = %w[stdout file]
config.log_to = %w[stdout file]
# Show the logging configuration on STDOUT
config.show_log_configuration = true

View File

@ -162,7 +162,6 @@ SampleApp::Application.routes.draw do
# user likes
match '/users/:id/likes' => 'api_users#like_index', :via => :get, :as => 'api_user_like_index'
match '/users/:id/band_likes' => 'api_users#band_like_index', :via => :get, :as => 'api_band_like_index'
match '/users/:id/likes' => 'api_users#like_create', :via => :post
match '/users/:id/likes' => 'api_users#like_destroy', :via => :delete
@ -171,11 +170,6 @@ SampleApp::Application.routes.draw do
# user followings
match '/users/:id/followings' => 'api_users#following_index', :via => :get, :as => 'api_user_following_index'
# match '/users/:id/followings/:user_id' => 'api_users#following_show', :via => :get, :as => 'api_following_detail'
match '/users/:id/band_followings' => 'api_users#band_following_index', :via => :get, :as => 'api_band_following_index'
# match '/users/:id/band_followings/:band_id' => 'api_users#band_following_show', :via => :get, :as => 'api_band_following_detail'
match '/users/:id/followings' => 'api_users#following_create', :via => :post
match '/users/:id/followings' => 'api_users#following_destroy', :via => :delete

View File

@ -173,8 +173,8 @@ def make_followings
users = User.all
users.each do |uu|
users[0..rand(users.count)].shuffle.each do |uuu|
uuu.followings << uu unless 0 < UserFollowing.where(:user_id => uu.id, :follower_id => uuu.id).count
uu.followings << uuu unless 0 < UserFollowing.where(:user_id => uuu.id, :follower_id => uu.id).count if rand(3)==0
uuu.followings << uu unless 0 < Follow.where(:followable_id => uu.id, :user_id => uuu.id).count
uu.followings << uuu unless 0 < Follow.where(:followable_id => uuu.id, :user_id => uu.id).count if rand(3)==0
end
end
end

View File

@ -103,17 +103,17 @@ describe "User API", :type => :api do
return last_response
end
def create_band_following(authenticated_user, source_user, target_band)
login(authenticated_user.email, authenticated_user.password, 200, true)
post "/api/users/#{source_user.id}/followings.json", { :band_id => target_band.id }.to_json, "CONTENT_TYPE" => 'application/json'
return last_response
end
# def create_band_following(authenticated_user, source_user, target_band)
# login(authenticated_user.email, authenticated_user.password, 200, true)
# post "/api/users/#{source_user.id}/followings.json", { :band_id => target_band.id }.to_json, "CONTENT_TYPE" => 'application/json'
# return last_response
# end
def get_band_followings(authenticated_user, source_user)
login(authenticated_user.email, authenticated_user.password, 200, true)
get "/api/users/#{source_user.id}/band_followings.json"
return last_response
end
# def get_band_followings(authenticated_user, source_user)
# login(authenticated_user.email, authenticated_user.password, 200, true)
# get "/api/users/#{source_user.id}/band_followings.json"
# return last_response
# end
def get_band_followers(authenticated_user, source_band)
login(authenticated_user.email, authenticated_user.password, 200, true)
@ -427,11 +427,11 @@ describe "User API", :type => :api do
last_response.status.should == 201
# get band followings
last_response = get_band_followings(user, user)
last_response.status.should == 200
followings = JSON.parse(last_response.body)
followings.size.should == 1
followings[0]["band_id"].should == band.id
# last_response = get_band_followings(user, user)
# last_response.status.should == 200
# followings = JSON.parse(last_response.body)
# followings.size.should == 1
# followings[0]["band_id"].should == band.id
# get followers for band
last_response = get_band_followers(user, band)