* VRFS-1077 done

This commit is contained in:
Seth Call 2014-02-06 16:31:52 +00:00
parent 10573fd37a
commit 17961e676d
42 changed files with 866 additions and 84 deletions

View File

@ -1,5 +1,5 @@
GEM
remote: https://rubygems.org/
remote: http://rubygems.org/
specs:
little-plugger (1.1.3)
logging (1.7.2)

View File

@ -98,4 +98,5 @@ invited_users_facebook_support.sql
first_recording_at.sql
share_token.sql
facebook_signup.sql
audiomixer_mp3.sql
audiomixer_mp3.sql
large_photo_url.sql

View File

@ -0,0 +1,7 @@
ALTER TABLE users ADD COLUMN large_photo_url VARCHAR(2048);
ALTER TABLE users ADD COLUMN cropped_large_s3_path VARCHAR(512);
ALTER TABLE users ADD COLUMN cropped_large_fpfile VARCHAR(8000);
ALTER TABLE bands ADD COLUMN large_photo_url VARCHAR(2048);
ALTER TABLE bands ADD COLUMN cropped_large_s3_path_photo VARCHAR(512);
ALTER TABLE bands ADD COLUMN cropped_large_fpfile_photo VARCHAR(8000);

View File

@ -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_large_fpfile_photo,
:cropped_s3_path_photo, :cropped_large_s3_path_photo, :crop_selection_photo, :photo_url, :large_photo_url
attr_accessor :updating_photo
@ -88,6 +88,7 @@ module JamRuby
# we want to mak sure that original_fpfile and cropped_fpfile seems like real fpfile info objects (i.e, json objects from filepicker.io)
errors.add(:original_fpfile_photo, ValidationMessages::INVALID_FPFILE) if self.original_fpfile_photo.nil? || self.original_fpfile_photo["key"].nil? || self.original_fpfile_photo["url"].nil?
errors.add(:cropped_fpfile_photo, ValidationMessages::INVALID_FPFILE) if self.cropped_fpfile_photo.nil? || self.cropped_fpfile_photo["key"].nil? || self.cropped_fpfile_photo["url"].nil?
errors.add(:cropped_large_fpfile_photo, ValidationMessages::INVALID_FPFILE) if self.cropped_large_fpfile_photo.nil? || self.cropped_large_fpfile_photo["key"].nil? || self.cropped_large_fpfile_photo["url"].nil?
end
end
@ -196,18 +197,21 @@ module JamRuby
return band
end
def update_photo(original_fpfile, cropped_fpfile, crop_selection, aws_bucket)
def update_photo(original_fpfile, cropped_fpfile, cropped_large_fpfile, crop_selection, aws_bucket)
self.updating_photo = true
cropped_s3_path = cropped_fpfile["key"]
cropped_large_s3_path = cropped_large_fpfile["key"]
return self.update_attributes(
:original_fpfile_photo => original_fpfile,
:cropped_fpfile_photo => cropped_fpfile,
:cropped_large_fpfile_photo => cropped_large_fpfile,
:cropped_s3_path_photo => cropped_s3_path,
:cropped_large_s3_path_photo => cropped_large_s3_path,
:crop_selection_photo => crop_selection,
:photo_url => S3Util.url(aws_bucket, cropped_s3_path, :secure => false)
)
:photo_url => S3Util.url(aws_bucket, cropped_s3_path, :secure => false),
:large_photo_url => S3Util.url(aws_bucket, cropped_large_s3_path, :secure => false))
end
def delete_photo(aws_bucket)
@ -217,15 +221,18 @@ module JamRuby
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)
S3Util.delete(aws_bucket, self.cropped_large_s3_path_photo)
end
return self.update_attributes(
:original_fpfile_photo => nil,
:cropped_fpfile_photo => nil,
:cropped_large_fpfile_photo => nil,
:cropped_s3_path_photo => nil,
:cropped_large_s3_path_photo => nil,
:crop_selection_photo => nil,
:photo_url => nil
)
:photo_url => nil,
:large_photo_url => nil)
end
end

View File

@ -124,6 +124,10 @@ module JamRuby
session_history.save!
end
def is_over?
!session_removed_at.nil?
end
def end_history
self.update_attribute(:session_removed_at, Time.now)

View File

@ -13,7 +13,7 @@ module JamRuby
after_save :check_lat_lng
attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_s3_path, :photo_url, :crop_selection, :lat, :lng
attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection, :lat, :lng
# updating_password corresponds to a lost_password
attr_accessor :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field
@ -187,6 +187,7 @@ module JamRuby
# we want to mak sure that original_fpfile and cropped_fpfile seems like real fpfile info objects (i.e, json objects from filepicker.io)
errors.add(:original_fpfile, ValidationMessages::INVALID_FPFILE) if self.original_fpfile.nil? || self.original_fpfile["key"].nil? || self.original_fpfile["url"].nil?
errors.add(:cropped_fpfile, ValidationMessages::INVALID_FPFILE) if self.cropped_fpfile.nil? || self.cropped_fpfile["key"].nil? || self.cropped_fpfile["url"].nil?
errors.add(:cropped_large_fpfile, ValidationMessages::INVALID_FPFILE) if self.cropped_large_fpfile.nil? || self.cropped_large_fpfile["key"].nil? || self.cropped_large_fpfile["url"].nil?
end
end
@ -898,17 +899,21 @@ module JamRuby
self.save
end
def update_avatar(original_fpfile, cropped_fpfile, crop_selection, aws_bucket)
def update_avatar(original_fpfile, cropped_fpfile, cropped_large_fpfile, crop_selection, aws_bucket)
self.updating_avatar = true
cropped_s3_path = cropped_fpfile["key"]
cropped_large_s3_path = cropped_large_fpfile["key"]
return self.update_attributes(
:original_fpfile => original_fpfile,
:cropped_fpfile => cropped_fpfile,
:cropped_large_fpfile => cropped_large_fpfile,
:cropped_s3_path => cropped_s3_path,
:cropped_large_s3_path => cropped_large_s3_path,
:crop_selection => crop_selection,
:photo_url => S3Util.url(aws_bucket, cropped_s3_path, :secure => false)
:photo_url => S3Util.url(aws_bucket, cropped_s3_path, :secure => false),
:large_photo_url => S3Util.url(aws_bucket, cropped_large_s3_path, :secure => false)
)
end
@ -919,14 +924,18 @@ module JamRuby
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)
S3Util.delete(aws_bucket, self.cropped_large_s3_path)
end
return self.update_attributes(
:original_fpfile => nil,
:cropped_fpfile => nil,
:cropped_large_fpfile => nil,
:cropped_s3_path => nil,
:cropped_large_s3_path => nil,
:photo_url => nil,
:crop_selection => nil
:crop_selection => nil,
:large_photo_url => nil
)
end

View File

@ -13,6 +13,7 @@
var avatar;
var selection = null;
var targetCropSize = 88;
var largerCropSize = 200;
var updatingAvatar = false;
var userDropdown;
@ -320,15 +321,32 @@
signature: filepickerPolicy.signature
}, { path: createStorePath(self.userDetail), access: 'public' },
function(scaled) {
logger.debug("converted and scaled final image %o", scaled);
rest.updateAvatar({
original_fpfile: determineCurrentFpfile(),
cropped_fpfile: scaled,
crop_selection: currentSelection
})
.done(updateAvatarSuccess)
.fail(app.ajaxError)
.always(function() { removeAvatarSpinner(); self.updatingAvatar = false;})
filepicker.convert(cropped, {
height: largerCropSize,
width: largerCropSize,
fit: 'scale',
format: 'jpg',
quality: 75,
policy: filepickerPolicy.policy,
signature: filepickerPolicy.signature
}, { path: createStorePath(self.userDetail) + 'large.jpg', access: 'public' },
function(scaledLarger) {
logger.debug("converted and scaled final image %o", scaled);
rest.updateAvatar({
original_fpfile: determineCurrentFpfile(),
cropped_fpfile: scaled,
cropped_large_fpfile: scaledLarger,
crop_selection: currentSelection
})
.done(updateAvatarSuccess)
.fail(app.ajaxError)
.always(function() { removeAvatarSpinner(); self.updatingAvatar = false;})
},
function(fperror) {
alert("unable to scale larger selection. error code: " + fperror.code);
removeAvatarSpinner();
self.updatingAvatar = false;
});
},
function(fperror) {
alert("unable to scale selection. error code: " + fperror.code);

View File

@ -192,7 +192,7 @@
if (bandId.length === 0) {
rest.createBand(band).done(function(response) {
createBandInvitations(response.id, function() {
context.location = "#/bandProfile/" + response.id;
context.location = "/client#/bandProfile/" + response.id;
});
});
}
@ -200,7 +200,7 @@
band.id = bandId;
rest.updateBand(band).done(function(response) {
createBandInvitations(band.id, function() {
context.location = "#/bandProfile/" + band.id;
context.location = "/client#/bandProfile/" + band.id;
});
});
}
@ -473,7 +473,7 @@
$('#btn-band-setup-cancel').click(function() {
resetForm();
context.location = "#/home";
context.location = "/client#/home";
});
$('#btn-band-setup-next').click(function() {
@ -510,7 +510,7 @@
$('#band-change-photo').click(function(evt) {
evt.stopPropagation();
$("#hdn-band-id").val(bandId);
context.location = '#/band/setup/photo';
context.location = '/client#/band/setup/photo';
return false;
});

View File

@ -14,13 +14,14 @@
var bandPhoto;
var selection = null;
var targetCropSize = 88;
var largeCropSize = 200;
var updatingBandPhoto = false;
function beforeShow(data) {
bandId = $("#hdn-band-id").val();
logger.debug("bandId=" + bandId);
if (!bandId) {
context.location = '#/home';
context.location = '/client#/home';
}
}
@ -143,7 +144,7 @@
function navToEditProfile() {
resetForm();
$("#hdn-band-id").val(bandId);
context.location = '#/band/setup';
context.location = '/client#/band/setup';
}
function renderBandPhotoSpinner() {
@ -322,16 +323,34 @@
signature: filepickerPolicy.signature
}, { path: createStorePath(self.bandDetail), access: 'public' },
function(scaled) {
logger.debug("converted and scaled final image %o", scaled);
rest.updateBandPhoto({
original_fpfile: determineCurrentFpfile(),
cropped_fpfile: scaled,
crop_selection: currentSelection,
id: bandId
})
.done(updateBandPhotoSuccess)
.fail(app.ajaxError)
.always(function() { removeBandPhotoSpinner(); self.updatingBandPhoto = false;})
filepicker.convert(cropped, {
height: largeCropSize,
width: largeCropSize,
fit: 'scale',
format: 'jpg',
quality: 75,
policy: filepickerPolicy.policy,
signature: filepickerPolicy.signature
}, { path: createStorePath(self.bandDetail) + 'large.jpg', access: 'public' },
function(scaledLarger) {
logger.debug("converted and scaled final image %o", scaled);
rest.updateBandPhoto({
original_fpfile: determineCurrentFpfile(),
cropped_fpfile: scaled,
cropped_large_fpfile: scaledLarger,
crop_selection: currentSelection,
id: bandId
})
.done(updateBandPhotoSuccess)
.fail(app.ajaxError)
.always(function() { removeBandPhotoSpinner(); self.updatingBandPhoto = false;})
},
function(fperror) {
alert("unable to scale larger selection. error code: " + fperror.code);
removeBandPhotoSpinner();
self.updatingBandPhoto = false;
})
},
function(fperror) {
alert("unable to scale selection. error code: " + fperror.code);

View File

@ -165,7 +165,7 @@
success: function(response) {
var newSessionId = response.id;
var invitationCount = inviteMusiciansUtil.createInvitations(newSessionId, function() {
context.location = '#/session/' + newSessionId;
context.location = '/client#/session/' + newSessionId;
});
// Re-loading the session settings will cause the form to reset with the right stuff in it.
// This is an extra xhr call, but it keeps things to a single codepath

View File

@ -94,7 +94,7 @@
function events() {
$('body').on('click', 'div[layout="header"] h1', function() {
context.location = '#/home';
context.location = '/client#/home';
});
$('#account-identity-form').submit(handleIdentitySubmit);

View File

@ -284,11 +284,13 @@
var original_fpfile = options['original_fpfile'];
var cropped_fpfile = options['cropped_fpfile'];
var cropped_large_fpfile = options['cropped_large_fpfile'];
var crop_selection = options['crop_selection'];
logger.debug(JSON.stringify({
original_fpfile : original_fpfile,
cropped_fpfile : cropped_fpfile,
cropped_large_fpfile : cropped_large_fpfile,
crop_selection : crop_selection
}));
@ -302,6 +304,7 @@
data: JSON.stringify({
original_fpfile : original_fpfile,
cropped_fpfile : cropped_fpfile,
cropped_large_fpfile : cropped_large_fpfile,
crop_selection : crop_selection
})
});
@ -338,11 +341,13 @@
var original_fpfile = options['original_fpfile'];
var cropped_fpfile = options['cropped_fpfile'];
var cropped_large_fpfile = options['cropped_large_fpfile'];
var crop_selection = options['crop_selection'];
logger.debug(JSON.stringify({
original_fpfile : original_fpfile,
cropped_fpfile : cropped_fpfile,
cropped_large_fpfile : cropped_large_fpfile,
crop_selection : crop_selection
}));
@ -356,6 +361,7 @@
data: JSON.stringify({
original_fpfile : original_fpfile,
cropped_fpfile : cropped_fpfile,
cropped_large_fpfile : cropped_large_fpfile,
crop_selection : crop_selection
})
});
@ -761,6 +767,34 @@
});
}
function getShareSession(options) {
var id = getId(options);
var provider = options['provider'];
delete options['provider']
return $.ajax({
type: "GET",
dataType: "json",
contentType: 'application/json',
url: "/api/users/" + id + "/share/session/" + provider,
data: options
})
}
function getShareRecording(options) {
var id = getId(options);
var provider = options['provider'];
delete options['provider']
return $.ajax({
type: "GET",
dataType: "json",
contentType: 'application/json',
url: "/api/users/" + id + "/share/recording/" + provider,
data: options
})
}
function initialize() {
return self;
}
@ -827,6 +861,8 @@
this.updateBandInvitation = updateBandInvitation;
this.removeBandMember = removeBandMember;
this.login = login;
this.getShareSession = getShareSession;
this.getShareRecording = getShareRecording;
return this;
};

View File

@ -328,7 +328,7 @@
hash = null;
}
var url = '#/home';
var url = '/client#/home';
if (hash) {
url = hash;
}

View File

@ -400,7 +400,7 @@
var destination = $(evt.currentTarget).attr('layout-link');
var destinationType = $('[layout-id="' + destination + '"]').attr("layout");
if (destinationType === "screen") {
context.location = '#/' + destination;
context.location = '/client#/' + destination;
} else if (destinationType === "dialog") {
showDialog(destination);
}

View File

@ -44,7 +44,7 @@
$('#search-results').empty();
var query = $('#search-input').val();
if (query) {
context.location = '#/searchResults/:' + query;
context.location = '/client#/searchResults/:' + query;
} else {
query = $('#query').html();
}

View File

@ -249,7 +249,7 @@
}
function onTermsAccepted(sessionId) {
context.location = '#/session/' + sessionId;
context.location = '/client#/session/' + sessionId;
}
function events() {

View File

@ -15,28 +15,137 @@
RECORDED: "RECORDED"
};
function handleShareWithFacebook() {
facebookHelper.promptLogin()
.done(function(response) {
if(response.status == "connected") {
facebookRest.post({
access_token: response.authResponse.accessToken,
message: 'A Message',
caption: 'A Caption',
description: 'A description',
link: 'http://staging.jamkazam.com',
name: 'JamKazam',
picture: 'http://staging.jamkazam.com/assets/logo.png'
})
.done(function(response) {
alert("zong")
})
.fail(function(response) {
console.log("failed %o", response);
})
}
})
function showSpinner() {
$('#share-dialog .dialog-inner').hide();
var spinner = $('<div class="spinner spinner-large"></div>')
$('#share-dialog .content-head').after(spinner);
}
function hideSpinner() {
$('#share-dialog .spinner').remove();
$('#share-dialog .dialog-inner').show();
}
function handleRecordingShareWithGoogle(message) {
var defer = $.Deferred();
defer.resolve(); // remove when implemented
return defer;
}
function handleRecordingShareWithTwitter(message) {
var defer = $.Deferred();
defer.resolve(); // remove when implemented
return defer;
}
function handleRecordingShareWithFacebook(message) {
var defer = $.Deferred();
rest.getShareRecording({ provider:'facebook', claimed_recording: entityId})
.done(function(data) {
facebookHelper.promptLogin()
.done(function(response) {
if(response.status == "connected") {
facebookRest.post({
access_token: response.authResponse.accessToken,
message: message,
description: data.description,
caption: data.caption,
name: data.title,
picture: data.photo_url
})
.done(function(response) {
defer.resolve();
})
.fail(function(response) {
app.notify({
title : "Unable to Share with Facebook",
text : "Error: " + response,
"icon_url": "/assets/content/icon_alert_big.png"
});
defer.reject();
})
}
else {
// user doesn't want to auth; this is a form of success
defer.resolve();
}
})
})
.fail(function(jqXHR) {
app.notifyServerError(jqXHR, "Unable to Populate Share Data");
defer.reject();
})
return defer;
}
function handleSessionShareWithGoogle(message) {
var defer = $.Deferred();
defer.resolve(); // remove when implemented
return defer;
}
function handleSessionShareWithTwitter(message) {
var defer = $.Deferred();
defer.resolve(); // remove when implemented
return defer;
}
function handleSessionShareWithFacebook(message) {
var defer = $.Deferred();
rest.getShareSession({ provider:'facebook', music_session: entityId})
.done(function(data) {
facebookHelper.promptLogin()
.done(function(response) {
if(response.status == "connected") {
facebookRest.post({
access_token: response.authResponse.accessToken,
message: message,
description: data.description,
caption: data.caption,
name: data.title,
picture: data.photo_url
})
.done(function(response) {
defer.resolve();
})
.fail(function(response) {
app.notify({
title : "Unable to Share with Facebook",
text : "Error: " + response,
"icon_url": "/assets/content/icon_alert_big.png"
});
defer.reject();
})
}
else {
// user doesn't want to auth; this is a form of success
defer.resolve();
}
})
})
.fail(function(jqXHR) {
app.notifyServerError(jqXHR, "Unable to Populate Share Data");
defer.reject();
})
return defer;
}
function socialShare() {
var shareWithFacebook = $('.share-with-facebook').is(':checked');
var shareWithGoogle = $('.share-with-google').is(':checked');
@ -50,9 +159,46 @@
$('.share-options').removeClass('error')
}
if(shareWithFacebook) {
handleShareWithFacebook();
var message = $('.share-message').val();
if(!message) { message = undefined; }
showSpinner();
var chain = [];
if(entityType == 'session') {
if(shareWithFacebook) {
chain.push(handleSessionShareWithFacebook(message))
}
if(shareWithTwitter) {
chain.push(handleSessionShareWithTwitter(message))
}
if(shareWithGoogle) {
chain.push(handleSessionShareWithGoogle(message))
}
}
else {
if(shareWithFacebook) {
chain.push(handleRecordingShareWithFacebook(message))
}
if(shareWithTwitter) {
chain.push(handleRecordingShareWithTwitter(message))
}
if(shareWithGoogle) {
chain.push(handleRecordingShareWithGoogle(message))
}
}
$.when.apply($, chain)
.done(function() {
app.layout.closeDialog('share-dialog');
})
.fail(function() {
logger.error("share failed")
})
.always(function() {
hideSpinner();
});
}
function registerEvents(onOff) {
@ -137,6 +283,7 @@
}
function afterHide() {
hideSpinner();
registerEvents(false);
}

View File

@ -585,7 +585,7 @@
function onTermsAccepted(args) {
deleteNotification(args.notification_id);
context.location = '#/session/' + args.session_id;
context.location = '/client#/session/' + args.session_id;
}
function registerSessionEnded() {

View File

@ -191,10 +191,11 @@ class ApiBandsController < ApiController
def update_photo
original_fpfile = params[:original_fpfile]
cropped_fpfile = params[:cropped_fpfile]
cropped_large_fpfile = params[:cropped_large_fpfile]
crop_selection = params[:crop_selection]
# public bucket to allow images to be available to public
@band.update_photo(original_fpfile, cropped_fpfile, crop_selection, Rails.application.config.aws_bucket_public)
@band.update_photo(original_fpfile, cropped_fpfile, cropped_large_fpfile, crop_selection, Rails.application.config.aws_bucket_public)
if @band.errors.any?
render :json => { :message => "Unexpected error updating photo."}, :status => :unprocessable_entity

View File

@ -11,10 +11,19 @@ class ApiClaimedRecordingsController < ApiController
end
def show
if !@claimed_recording.is_public && @claimed_recording.user_id != current_user.id
raise PermissionError, 'this claimed recording is not public'
end
@claimed_recording
end
def update
if @claimed_recording.user_id != current_user.id
raise PermissionError, 'only owner of claimed_recording can update it'
end
begin
@claimed_recording.update_fields(current_user, params)
respond_with responder: ApiResponder, :status => 204
@ -24,6 +33,9 @@ class ApiClaimedRecordingsController < ApiController
end
def delete
if @claimed_recording.user_id != current_user.id
raise PermissionError, 'only owner of claimed_recording can update it'
end
#begin
#@claimed_recording.discard(current_user)
#render :json => {}, :status => 204
@ -37,7 +49,7 @@ class ApiClaimedRecordingsController < ApiController
def look_up_claimed_recording
@claimed_recording = ClaimedRecording.find(params[:id])
if @claimed_recording.nil? || @claimed_recording.user_id != current_user.id
if @claimed_recording.nil?
render :json => { :message => "claimed_recording not found" }, :status => 404
end
end

View File

@ -10,7 +10,9 @@ class ApiUsersController < ApiController
:friend_show, :friend_destroy, # friends
:notification_index, :notification_destroy, # notifications
:band_invitation_index, :band_invitation_show, :band_invitation_update, # band invitations
:set_password, :begin_update_email, :update_avatar, :delete_avatar, :generate_filepicker_policy]
:set_password, :begin_update_email, :update_avatar, :delete_avatar, :generate_filepicker_policy,
:share_session, :share_recording]
respond_to :json
def index
@ -411,10 +413,11 @@ class ApiUsersController < ApiController
def update_avatar
original_fpfile = params[:original_fpfile]
cropped_fpfile = params[:cropped_fpfile]
cropped_large_fpfile = params[:cropped_large_fpfile]
crop_selection = params[:crop_selection]
# public bucket to allow images to be available to public
@user.update_avatar(original_fpfile, cropped_fpfile, crop_selection, Rails.application.config.aws_bucket_public)
@user.update_avatar(original_fpfile, cropped_fpfile, cropped_large_fpfile, crop_selection, Rails.application.config.aws_bucket_public)
if @user.errors.any?
respond_with @user, status: :unprocessable_entity
@ -547,6 +550,46 @@ class ApiUsersController < ApiController
render :json => {}, :status => 200
end
# creates display-ready session data for sharing
def share_session
provider = params[:provider]
music_session_id = params[:music_session]
history = MusicSessionHistory.find_by_music_session_id!(music_session_id)
if provider == 'facebook'
render json: {
description: view_context.facebook_description_for_music_session_history(history),
title: view_context.facebook_title_for_music_session_history(history, current_user),
photo_url: view_context.facebook_image_for_music_session_history(history),
caption: 'www.jamkazam.com'
}, status: 200
else
render :json => { :errors => {:provider => ['not valid']} }, :status => 422
end
end
# creates display-ready recording data for sharing
def share_recording
provider = params[:provider]
claimed_recording_id = params[:claimed_recording]
claimed_recording = ClaimedRecording.find(claimed_recording_id)
if provider == 'facebook'
render json: {
description: view_context.facebook_description_for_claimed_recording(claimed_recording),
title: view_context.facebook_title_for_claimed_recording(claimed_recording, current_user),
photo_url: view_context.facebook_image_for_claimed_recording(claimed_recording),
caption: 'www.jamkazam.com'
}, status: 200
else
render :json => { :errors => {:provider => ['not valid']} }, :status => 422
end
end
###################### RECORDINGS #######################
# def recording_index
# @recordings = User.recording_index(current_user, params[:id])

View File

@ -39,7 +39,6 @@ class SessionsController < ApplicationController
# For debugging - to see what all is there:
# render :text => auth_hash.to_yaml
#FbGraph.debug!
#app = FbGraph::Application.new '468555793186398', :secret => '546a5b253972f3e2e8b36d9a3dd5a06e'
token = auth_hash[:credentials][:token]
# FIXME:

View File

@ -0,0 +1,48 @@
module MusicSessionHelper
def facebook_image_for_music_session_history(music_session)
if music_session.band
path = !music_session.band.large_photo_url.blank? ? music_session.band.large_photo_url : "/assets/web/logo-256.png"
else
path = "/assets/web/logo-256.png"
end
request.protocol + request.host_with_port + path
end
# careful; this mirrors logic of facebook_image_for_music_session_history
def facebook_image_size_for_music_session_history(music_session)
if music_session.band
!music_session.band.large_photo_url.blank? ? 200 : 256
else
256
end
end
def facebook_title_for_music_session_history(music_session, sharer = nil)
if music_session.band
"LIVE SESSION: #{music_session.band.name}"
else
unique_users = music_session.unique_users
if sharer && unique_users.exists?(sharer)
"LIVE SESSION: #{sharer.name}#{additional_member_count(unique_users)}"
else
"LIVE SESSION: #{music_session.user.name}#{additional_member_count(unique_users)}"
end
end
end
def additional_member_count(unique_users)
length = unique_users.length
if length < 2
""
else
" & #{length} OTHERS"
end
end
def facebook_description_for_music_session_history(music_session)
truncate(music_session.description, length:250)
end
end

View File

@ -0,0 +1,48 @@
module RecordingHelper
def facebook_image_for_claimed_recording(claimed_recording)
if claimed_recording.recording.band
path = !claimed_recording.recording.band.large_photo_url.blank? ? claimed_recording.recording.band.large_photo_url : "/assets/web/logo-256.png"
else
path = "/assets/web/logo-256.png"
end
request.protocol + request.host_with_port + path
end
# careful; this mirrors logic of facebook_image_for_music_session_history
def facebook_image_size_for_claimed_recording(claimed_recording)
if claimed_recording.recording.band
!claimed_recording.recording.band.large_photo_url.blank? ? 200 : 256
else
256
end
end
def facebook_title_for_claimed_recording(claimed_recording, sharer = nil)
if claimed_recording.recording.band
"RECORDING: #{claimed_recording.recording.band.name}"
else
unique_users = claimed_recording.recording.users
if sharer && unique_users.exists?(sharer)
"RECORDING: #{sharer.name}#{additional_member_count(unique_users)}"
else
"RECORDING: #{claimed_recording.user.name}#{additional_member_count(unique_users)}"
end
end
end
def additional_member_count(unique_users)
length = unique_users.length
if length < 2
""
else
" & #{length} OTHERS"
end
end
def facebook_description_for_claimed_recording(claimed_recording)
truncate(claimed_recording.name, length:250)
end
end

View File

@ -7,7 +7,7 @@
<tr>
<td valign="top" width="45%" class="border-right"><h3 class="mb5">Share to Social Media:</h3>
<textarea class="w95" rows="3">Add a Message...</textarea><br />
<textarea class="w95 share-message" rows="3" placeholder="Add a Message..."></textarea><br />
<div class="left share-options">
<input type="checkbox" class="share-with-facebook"/>
<%= image_tag "content/icon_facebook.png", :size => "24x24", :align => "absmiddle", :alt => "", :style => "vertical-align:middle" %>&nbsp;
@ -22,7 +22,7 @@
<td valign="top" width="48%">
<div class="ml10">
<h3>Share a Link:</h3><br />
<% unless share_token.blank? %>
<% unless true# share_token.blank? %>
<%= "#{root_url}#{share_token}" %>
<% end %><br/><br/>
<div class="right"><a class="button-orange">COPY LINK</a></div>

View File

@ -100,10 +100,10 @@
var recordingManager = new JK.RecordingManager();
var facebookHelper = new JK.FacebookHelper(JK.app);
facebookHelper.initialize('<%= SampleApp::Application.config.facebook_key %>');
facebookHelper.initialize(gon.global.facebook_app_id);
var invitationDialog = new JK.InvitationDialog(JK.app);
invitationDialog.initialize('<%= SampleApp::Application.config.facebook_key %>');
invitationDialog.initialize(gon.global.facebook_app_id);
var shareDialog = new JK.ShareDialog(JK.app);
shareDialog.initialize(facebookHelper);

View File

@ -0,0 +1,8 @@
<meta property="fb:app_id" content="<%= Rails.application.config.facebook_app_id %>" />
<meta property="og:title" content="<%= "JamKazam" %>" />
<meta property="og:url" content="<%= request.original_url %>" />
<meta property="og:description" content="Play music together over the Internet as if in the same room." />
<meta property="og:image" content="<%= request.protocol + request.host_with_port + image_path("web/logo-256.png") %>" />
<meta property="og:image:width" content="256" />
<meta property="og:image:height" content="256" />
<meta property="og:type" content="website" />

View File

@ -14,6 +14,11 @@
<%= include_gon %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
<% if content_for?(:facebook_meta) %>
<%= yield(:facebook_meta) %>
<% else %>
<%= render "layouts/facebook_meta" %>
<% end %>
</head>
<body>
<%= yield %>

View File

@ -12,6 +12,11 @@
<%= include_gon(:init => true) %>
<%= javascript_include_tag "corp/corporate" %>
<%= csrf_meta_tags %>
<% if content_for?(:facebook_meta) %>
<%= yield(:facebook_meta) %>
<% else %>
<%= render "layouts/facebook_meta" %>
<% end %>
</head>
<body class="corporate" data-purpose="<%= yield(:purpose) %>">

View File

@ -14,6 +14,11 @@
<% end %>
<%= include_gon(:init => true) %>
<%= csrf_meta_tags %>
<% if content_for?(:facebook_meta) %>
<%= yield(:facebook_meta) %>
<% else %>
<%= render "layouts/facebook_meta" %>
<% end %>
</head>
<body>
<div id="landing-container">

View File

@ -14,6 +14,11 @@
<% end %>
<%= include_gon(:init => true) %>
<%= csrf_meta_tags %>
<% if content_for?(:facebook_meta) %>
<%= yield(:facebook_meta) %>
<% else %>
<%= render "layouts/facebook_meta" %>
<% end %>
</head>
<body class="web">
<%= javascript_include_tag "web/web" %>
@ -72,7 +77,7 @@
var facebookHelper = new JK.FacebookHelper(JK.app);
JK.FacebookHelperInstance = facebookHelper;
facebookHelper.initialize('<%= SampleApp::Application.config.facebook_key %>');
facebookHelper.initialize(gon.global.facebook_app_id);
var invitationDialog = new JK.InvitationDialog(JK.app);
invitationDialog.initialize(facebookHelper);

View File

@ -1,5 +1,16 @@
<% provide(:title, "#{@music_session.description}") %>
<% content_for :facebook_meta do %>
<meta property="fb:app_id" content="<%= Rails.application.config.facebook_app_id %>" />
<meta property="og:title" content="<%= facebook_title_for_music_session_history(@music_session) %>" />
<meta property="og:url" content="<%= request.original_url %>" />
<meta property="og:description" content="<%= facebook_description_for_music_session_history(@music_session) %>" />
<meta property="og:image" content="<%= facebook_image_for_music_session_history(@music_session) %>" />
<meta property="og:image:width" content="<%= facebook_image_size_for_music_session_history(@music_session) %>" />
<meta property="og:image:height" content="<%= facebook_image_size_for_music_session_history(@music_session) %>" />
<meta property="og:type" content="website" />
<% end %>
<div class="landing-band">
<% unless @music_session.band.nil? %>
<div class="landing-avatar">

View File

@ -1,5 +1,17 @@
<% provide(:title, "#{@claimed_recording.name}") %>
<% content_for :facebook_meta do %>
<meta property="fb:app_id" content="<%= Rails.application.config.facebook_app_id %>" />
<meta property="og:title" content="<%= facebook_title_for_claimed_recording(@claimed_recording) %>" />
<meta property="og:url" content="<%= request.original_url %>" />
<meta property="og:description" content="<%= facebook_description_for_claimed_recording(@claimed_recording) %>" />
<meta property="og:image" content="<%= facebook_image_for_claimed_recording(@claimed_recording) %>" />
<meta property="og:image:width" content="<%= facebook_image_size_for_claimed_recording(@claimed_recording) %>" />
<meta property="og:image:height" content="<%= facebook_image_size_for_claimed_recording(@claimed_recording) %>" />
<meta property="og:type" content="website" />
<% end %>
<div class="landing-band">
<% unless @claimed_recording.recording.band.nil? %>
<div class="landing-avatar">

View File

@ -29,7 +29,7 @@
window.fbAsyncInit = function() {
// init the FB JS SDK
FB.init({
appId : '<%= SampleApp::Application.config.facebook_key %>', // App ID from the App Dashboard
appId : gon.global.facebook_app_id, // App ID from the App Dashboard
// channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File for x-domain communication
status : true, // check the login status upon init?
cookie : true, // set sessions cookies to allow your server to access the session?

View File

@ -133,9 +133,6 @@ include JamRuby
# cloudfront host
config.cloudfront_host = "d34f55ppvvtgi3.cloudfront.net"
# facebook keys
config.facebook_key = '468555793186398'
# google api keys
config.google_client_id = '785931784279-gd0g8on6sc0tuesj7cu763pitaiv2la8.apps.googleusercontent.com'
config.google_secret = 'UwzIcvtErv9c2-GIsNfIo7bA'
@ -196,7 +193,7 @@ include JamRuby
config.email_smtp_password = 'jamjamblueberryjam'
config.email_smtp_starttls_auto = true
config.facebook_app_id = '468555793186398'
config.facebook_app_secret = '546a5b253972f3e2e8b36d9a3dd5a06e'
config.facebook_app_id = ENV['FACEBOOK_APP_ID'] || '468555793186398'
config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e'
end
end

View File

@ -0,0 +1 @@
Gon.global.facebook_app_id = Rails.application.config.facebook_app_id

View File

@ -215,6 +215,10 @@ SampleApp::Application.routes.draw do
match '/users/progression/certified_gear' => 'api_users#qualified_gear', :via => :post
match '/users/progression/social_promoted' => 'api_users#social_promoted', :via => :post
# social
match '/users/:id/share/session/:provider' => 'api_users#share_session', :via => :get
match '/users/:id/share/recording/:provider' => 'api_users#share_recording', :via => :get
# user recordings
# match '/users/:id/recordings' => 'api_users#recording_index', :via => :get
# match '/users/:id/recordings/:recording_id' => 'api_users#recording_show', :via => :get, :as => 'api_recording_detail'

View File

@ -66,6 +66,7 @@ FactoryGirl.define do
}
end
factory :music_session_user_history, :class => JamRuby::MusicSessionUserHistory do
end

View File

@ -0,0 +1,115 @@
require 'spec_helper'
describe "facebook metadata" do
include MusicSessionHelper
include RecordingHelper
subject { page }
share_examples_for :has_default_metadata do
it "should have default metadata" do
page.find('meta[property="fb:app_id"]', :visible => false)['content'].should == Rails.application.config.facebook_app_id
page.find('meta[property="og:title"]', :visible => false)['content'].should == "JamKazam"
page.find('meta[property="og:description"]', :visible => false)['content'].should == "Play music together over the Internet as if in the same room."
page.find('meta[property="og:image"]', :visible => false)['content'].include?("/assets/web/logo-256.png").should be_true
page.find('meta[property="og:image:width"]', :visible => false)['content'].should == "256"
page.find('meta[property="og:image:height"]', :visible => false)['content'].should == "256"
page.find('meta[property="og:type"]', :visible => false)['content'].should == "website"
end
end
describe "default layout metadata" do
let(:user) {FactoryGirl.create(:user) }
describe "web layout" do
before(:each) do
visit '/'
end
it_behaves_like :has_default_metadata
end
describe "corp layout" do
before(:each) do
visit '/corp/about'
end
it_behaves_like :has_default_metadata
end
describe "client layout" do
before(:each) do
sign_in user
visit '/client'
end
it_behaves_like :has_default_metadata
end
describe "landing layout" do
before(:each) do
visit '/signin'
end
it_behaves_like :has_default_metadata
end
end
describe "music session metadata" do
let(:user) { FactoryGirl.create(:user) }
let(:connection) { FactoryGirl.create(:connection, :user => user) }
let(:instrument) { FactoryGirl.create(:instrument, :description => 'a great instrument') }
let(:track) { FactoryGirl.create(:track, :connection => connection, :instrument => instrument) }
let(:music_session) { ms = FactoryGirl.create(:music_session, :creator => user, :musician_access => true); ms.connections << connection; ms.save!; ms }
it "renders facebook metadata" do
visit "/sessions/#{music_session.id}"
page.find('meta[property="fb:app_id"]', :visible => false)['content'].should == Rails.application.config.facebook_app_id
page.find('meta[property="og:title"]', :visible => false)['content'].should == facebook_title_for_music_session_history(music_session.music_session_history)
page.find('meta[property="og:url"]', :visible => false)['content'].include?("/sessions/#{music_session.id}").should be_true
page.find('meta[property="og:description"]', :visible => false)['content'].should == music_session.music_session_history.description
page.find('meta[property="og:image"]', :visible => false)['content'].include?("/assets/web/logo-256.png").should be_true
page.find('meta[property="og:image:width"]', :visible => false)['content'].should == "256"
page.find('meta[property="og:image:height"]', :visible => false)['content'].should == "256"
page.find('meta[property="og:type"]', :visible => false)['content'].should == "website"
end
end
describe "recording metadata" do
before(:each) do
@user = FactoryGirl.create(:user)
@connection = FactoryGirl.create(:connection, :user => @user)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
@music_session = FactoryGirl.create(:music_session, :creator => @user, :musician_access => true)
@music_session.connections << @connection
@music_session.save
@recording = Recording.start(@music_session, @user)
@recording.stop
@recording.reload
@genre = FactoryGirl.create(:genre)
@recording.claim(@user, "name", "description", @genre, true, true)
@recording.reload
@claimed_recording = @recording.claimed_recordings.first
end
it "renders facebook metadata" do
visit "/recordings/#{@claimed_recording.id}"
page.find('meta[property="fb:app_id"]', :visible => false)['content'].should == Rails.application.config.facebook_app_id
page.find('meta[property="og:title"]', :visible => false)['content'].should == facebook_title_for_claimed_recording(@claimed_recording)
page.find('meta[property="og:url"]', :visible => false)['content'].include?("/recordings/#{@claimed_recording.id}").should be_true
page.find('meta[property="og:description"]', :visible => false)['content'].should == @claimed_recording.name
page.find('meta[property="og:image"]', :visible => false)['content'].include?("/assets/web/logo-256.png").should be_true
page.find('meta[property="og:image:width"]', :visible => false)['content'].should == "256"
page.find('meta[property="og:image:height"]', :visible => false)['content'].should == "256"
page.find('meta[property="og:type"]', :visible => false)['content'].should == "website"
end
end
end

View File

@ -0,0 +1,70 @@
require 'spec_helper'
describe MusicSessionHelper do
describe "facebook_image_for_music_session_history" do
it "with band with no photo url" do
music_session = FactoryGirl.create(:music_session, band: FactoryGirl.create(:band), creator: FactoryGirl.create(:user))
result = helper.facebook_image_for_music_session_history(music_session.music_session_history)
result.include?("/assets/web/logo-256.png").should be_true
end
it "with band with photo url" do
music_session = FactoryGirl.create(:music_session, band: FactoryGirl.create(:band, large_photo_url: 'abc.png'), creator: FactoryGirl.create(:user))
result = helper.facebook_image_for_music_session_history(music_session.music_session_history)
result.include?(music_session.band.large_photo_url).should be_true
end
it "with user with no photo url" do
music_session = FactoryGirl.create(:music_session, creator: FactoryGirl.create(:user))
result = helper.facebook_image_for_music_session_history(music_session.music_session_history)
result.include?("/assets/web/logo-256.png").should be_true
end
it "with user with photo url" do
music_session = FactoryGirl.create(:music_session, creator: FactoryGirl.create(:user, large_photo_url: 'abc.png'))
result = helper.facebook_image_for_music_session_history(music_session.music_session_history)
result.include?("/assets/web/logo-256.png").should be_true
end
it "with sharer with no photo url" do
sharer = FactoryGirl.create(:user)
music_session = FactoryGirl.create(:music_session, creator: FactoryGirl.create(:user))
result = helper.facebook_image_for_music_session_history(music_session.music_session_history)
result.include?("/assets/web/logo-256.png").should be_true
end
it "with sharer with photo url" do
sharer = FactoryGirl.create(:user, large_photo_url: 'abc.png')
music_session = FactoryGirl.create(:music_session, creator: FactoryGirl.create(:user, large_photo_url: 'abc.png'))
result = helper.facebook_image_for_music_session_history(music_session.music_session_history)
result.include?("/assets/web/logo-256.png").should be_true
end
end
describe "facebook_title_for_music_session_history" do
it "with band" do
music_session = FactoryGirl.create(:music_session, band: FactoryGirl.create(:band), creator: FactoryGirl.create(:user))
result = helper.facebook_title_for_music_session_history(music_session.music_session_history)
result.start_with?("LIVE SESSION").should be_true
result.end_with?(music_session.band.name).should be_true
end
it "with user" do
music_session = FactoryGirl.create(:music_session, creator: FactoryGirl.create(:user))
result = helper.facebook_title_for_music_session_history(music_session.music_session_history)
result.start_with?("LIVE SESSION").should be_true
result.end_with?(music_session.music_session_history.user.name).should be_true
end
end
describe "additional_member_count" do
it "no unique users" do
helper.additional_member_count([]).should == ""
end
it "has 2 users" do
helper.additional_member_count(['', '']).should == " & 2 OTHERS"
end
end
end

View File

@ -0,0 +1,92 @@
require 'spec_helper'
describe MusicSessionHelper do
before(:each) do
@user = FactoryGirl.create(:user)
@connection = FactoryGirl.create(:connection, :user => @user)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
@music_session = FactoryGirl.create(:music_session, :creator => @user, :musician_access => true)
@music_session.connections << @connection
@music_session.save
@recording = Recording.start(@music_session, @user)
@recording.stop
@recording.reload
@genre = FactoryGirl.create(:genre)
@recording.claim(@user, "name", "description", @genre, true, true)
@recording.reload
@claimed_recording = @recording.claimed_recordings.first
end
describe "facebook_image_for_claimed_recording" do
it "with band with no photo url" do
@recording.band = FactoryGirl.create(:band)
@recording.save!(:validate => false)
@claimed_recording.reload
result = helper.facebook_image_for_claimed_recording(@claimed_recording)
result.include?('/assets/web/logo-256.png').should be_true
end
it "with band with photo url" do
@recording.band = FactoryGirl.create(:band, large_photo_url: 'abc.png')
@recording.save!(:validate => false)
@claimed_recording.reload
result = helper.facebook_image_for_claimed_recording(@claimed_recording)
result.include?(@claimed_recording.recording.band.large_photo_url).should be_true
end
it "with user with no photo url" do
result = helper.facebook_image_for_claimed_recording(@claimed_recording)
result.include?("/assets/web/logo-256.png").should be_true
end
it "with user with photo url" do
@claimed_recording.user.large_photo_url = 'abc.png'
@claimed_recording.user.save!
@claimed_recording.save!
@claimed_recording.reload
result = helper.facebook_image_for_claimed_recording(@claimed_recording)
result.include?("/assets/web/logo-256.png").should be_true
end
it "with sharer with no photo url" do
sharer = FactoryGirl.create(:user)
result = helper.facebook_image_for_claimed_recording(@claimed_recording)
result.include?("/assets/web/logo-256.png").should be_true
end
it "with sharer with photo url" do
sharer = FactoryGirl.create(:user, large_photo_url: 'abc.png')
result = helper.facebook_image_for_claimed_recording(@claimed_recording)
result.include?("/assets/web/logo-256.png").should be_true
end
end
describe "facebook_title_for_claimed_recording" do
it "with band" do
@recording.band = FactoryGirl.create(:band)
@recording.save!(:validate => false)
@claimed_recording.reload
result = helper.facebook_title_for_claimed_recording(@claimed_recording)
result.start_with?("RECORDING").should be_true
result.end_with?(@claimed_recording.recording.band.name).should be_true
end
it "with user" do
result = helper.facebook_title_for_claimed_recording(@claimed_recording)
result.start_with?("RECORDING").should be_true
result.end_with?(@claimed_recording.user.name).should be_true
end
end
describe "additional_member_count" do
it "no unique users" do
helper.additional_member_count([]).should == ""
end
it "has 2 users" do
helper.additional_member_count(['', '']).should == " & 2 OTHERS"
end
end
end

View File

@ -975,5 +975,57 @@ describe "User API", :type => :api do
end
end
end
describe "share_session" do
let(:connection) { FactoryGirl.create(:connection, :user => user) }
let(:instrument) { FactoryGirl.create(:instrument, :description => 'a great instrument') }
let(:track) { FactoryGirl.create(:track, :connection => connection, :instrument => instrument) }
let(:music_session) { ms = FactoryGirl.create(:music_session, :creator => user, :musician_access => true); ms.connections << connection; ms.save!; ms }
it "fetches facebook successfully" do
login(user.email, user.password, 200, true)
get "/api/users/#{user.id}/share/session/facebook.json?music_session=#{music_session.id}", nil, "CONTENT_TYPE" => 'application/json'
last_response.status.should == 200
response = JSON.parse(last_response.body)
response['title'].include?("LIVE SESSION:").should be_true
response['description'].should == music_session.description
response['photo_url'].include?('logo-256.png').should be_true
response['caption'].should == 'www.jamkazam.com'
end
end
describe "share_recording" do
before(:each) do
@connection = FactoryGirl.create(:connection, :user => user)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
@music_session = FactoryGirl.create(:music_session, :creator => user, :musician_access => true)
@music_session.connections << @connection
@music_session.save
@recording = Recording.start(@music_session, user)
@recording.stop
@recording.reload
@genre = FactoryGirl.create(:genre)
@recording.claim(user, "name", "description", @genre, true, true)
@recording.reload
@claimed_recording = @recording.claimed_recordings.first
end
it "fetches facebook successfully" do
login(user.email, user.password, 200, true)
get "/api/users/#{user.id}/share/recording/facebook.json?claimed_recording=#{@claimed_recording.id}", nil, "CONTENT_TYPE" => 'application/json'
last_response.status.should == 200
response = JSON.parse(last_response.body)
response['title'].include?("RECORDING:").should be_true
response['description'].should == @claimed_recording.name
response['photo_url'].include?('logo-256.png').should be_true
response['caption'].should == 'www.jamkazam.com'
end
end
end
end