* VRFS-1082 and VRFS-1083 - centralize facebook logic for invitationDialog, and add twitter integration into share dialog

This commit is contained in:
Seth Call 2014-02-07 21:28:47 +00:00
parent b648c40587
commit 7661fc5e39
15 changed files with 169 additions and 140 deletions

View File

@ -75,6 +75,13 @@ module JamAdmin
# to make active_admin assets precompile
config.assets.precompile += ['active_admin.css', 'active_admin.js', 'active_admin/print.css']
###### THESE ARE JAM-WEB VALUES
config.external_hostname = ENV['EXTERNAL_HOSTNAME'] || 'localhost'
config.external_port = ENV['EXTERNAL_PORT'] || 3000
config.external_protocol = ENV['EXTERNAL_PROTOCOL'] || 'http://'
config.external_root_url = "#{config.external_protocol}#{config.external_hostname}#{(config.external_port == 80 || config.external_port == 443) ? '' : ':' + config.external_port.to_s}"
# set to false to instead use amazon. You will also need to supply amazon secrets
config.store_artifacts_to_disk = false
config.storage_type = :fog
@ -101,5 +108,11 @@ module JamAdmin
config.email_smtp_user_name = 'jamkazam'
config.email_smtp_password = 'jamjamblueberryjam'
config.email_smtp_starttls_auto = true
config.facebook_app_id = ENV['FACEBOOK_APP_ID'] || '468555793186398'
config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e'
config.twitter_app_id = ENV['TWITTER_APP_ID'] || 'nQj2oEeoJZxECC33tiTuIg'
config.twitter_app_secret = ENV['TWITTER_APP_SECRET'] || 'Azcy3QqfzYzn2fsojFPYXcn72yfwa0vG6wWDrZ3KT8'
end
end

View File

@ -34,4 +34,10 @@ JamAdmin::Application.configure do
# Print deprecation notices to the stderr
config.active_support.deprecation = :stderr
config.facebook_app_id = '1441492266082868'
config.facebook_app_secret = '233bd040a07e47dcec1cff3e490bfce7'
config.twitter_app_id = 'e7hGc71gmcBgo6Wvdta6Sg'
config.twitter_app_secret = 'PfG1jAUMnyrimPcDooUVQaJrG1IuDjUyGg5KciOo'
end

View File

@ -64,11 +64,7 @@ module JamRuby
end
def generate_signup_url
if 'development'==Rails.env
"http://localhost:3000/signup?invitation_code=#{self.invitation_code}"
else
"http://www.jamkazam.com/signup?invitation_code=#{self.invitation_code}"
end
"#{APP_CONFIG.external_root_url}/signup?invitation_code=#{self.invitation_code}"
end
def facebook_invite?

View File

@ -61,6 +61,22 @@ def app_config
5672
end
def external_hostname
'localhost'
end
def external_protocol
'http://'
end
def external_port
3000
end
def external_root_url
"#{external_protocol}#{external_hostname}#{(external_port == 80 || external_port == 443) ? '' : ':' + external_port.to_s}"
end
private

View File

@ -8,6 +8,15 @@
var $self = $(this);
var connected = false;
function deferredLoginStatus() {
return loginStatusDeferred;
}
// wrap calls in FB JS API calls in this
// if the user is not logged in, they will be prompted to log in to facebook
// if they are already logged in, the deferred object is immediately returned
// returns a deferred object that never calls .fail(). Just call .done(function(response)),
// and check: if(response && response.status == "connected") to know if you should carry on wih the FB JS API call
function promptLogin() {
if(connected) {
@ -67,6 +76,7 @@
this.initialize = initialize;
this.promptLogin = promptLogin;
this.deferredLoginStatus = deferredLoginStatus;
};

View File

@ -6,7 +6,8 @@
var rest = context.JK.Rest();
var waitForUserToStopTypingTimer;
var sendingEmail = false;
var fbInviteURL_ = null;
var deferredFbInvite = null;
var facebookHelper = null;
function trackMetrics(emails, googleInviteCount) {
var allInvitations = emails.length; // all email invites, regardless of how they got in the form
@ -17,6 +18,15 @@
}
}
function createFbInvite() {
if(deferredFbInvite == null || deferredFbInvite.isRejected()) {
deferredFbInvite = rest.createFbInviteUrl();
}
return deferredFbInvite;
}
function filterInvitations() {
waitForUserToStopTypingTimer = null;
@ -156,107 +166,46 @@
//////////////
// FB handlers
// Additional initialization code such as adding Event Listeners goes here
function handle_fblogin_response(response) {
if (response.status === 'connected') {
// the user is logged in and has authenticated your
// app, and response.authResponse supplies
// the user's ID, a valid access token, a signed
// request, and the time the access token
// and signed request each expire
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
window.fb_logged_in_state = "connected";
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
// TODO: popup authorization dialog
window.fb_logged_in_state = "not_authorized";
}
else {
// the user isn't logged in to Facebook.
window.fb_logged_in_state = "not_logged_in";
}
function handleFbStateChange(response) {
// if the UI needs to be updated based on the status of facebook, here's the place to do it
}
this.fb_login = function() {
FB.login(function(response) {
handle_fblogin_response(response);
}, {scope:'publish_stream'});
}
function showFeedDialog() {
function fbInviteURL() {
if (fbInviteURL_ === null) {
$.ajax({
type: "GET",
async: false,
url: '/api/invited_users/facebook',
success: function(response) {
fbInviteURL_ = response['signup_url'];
},
error: app.ajaxError
});
}
return fbInviteURL_;
}
createFbInvite()
.done(function(fbInviteResponse) {
var signupUrl = fbInviteResponse["signup_url"];
var obj = {
method: 'feed',
link: signupUrl,
picture: 'http://jamkazam.com/assets/logo.png',
name: 'Join me on JamKazam',
caption: 'Play live music in real-time sessions with others over the Internet, as if in the same room.',
description: '',
actions: [{ name: 'Signup', link: signupUrl }]
};
function fbFeedDialogCallback(response) {
//console.log("feedback dialog closed: " + response['post_id'])
if (response['post_id']) {
context.JK.GA.trackServiceInvitations(context.JK.GA.InvitationTypes.facebook, 1);
}
}
FB.ui(obj, fbFeedDialogCallback);
})
.fail(app.ajaxError)
function show_feed_dialog() {
var obj = {
method: 'feed',
link: fbInviteURL(),
picture: 'http://jamkazam.com/assets/logo.png',
name: 'Join me on JamKazam',
caption: 'Play live music in real-time sessions with others over the Internet, as if in the same room.',
description: '',
actions: [{ name: 'Signup', link: fbInviteURL() }]
};
function fbFeedDialogCallback(response) {
//console.log("feedback dialog closed: " + response['post_id'])
if (response['post_id']) {
context.JK.GA.trackServiceInvitations(context.JK.GA.InvitationTypes.facebook, 1);
}
}
FB.ui(obj, fbFeedDialogCallback);
}
function showFacebookDialog(evt) {
if (!(evt === undefined)) evt.stopPropagation();
var fb_state = window.fb_logged_in_state;
if (fb_state == "connected") {
show_feed_dialog();
} else if (fb_state == "not_authorized") {
this.fb_login();
} else {
this.fb_login();
}
}
function callFB(fbAppID){
var fbAppID_ = fbAppID;
window.fbAsyncInit = function() {
FB.init({
appId : fbAppID_,
// channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html',
status : true, // check the login status upon init?
cookie : true, // set sessions cookies to allow server to access the session?
xfbml : true, // parse XFBML tags on this page?
oauth : true, // enable OAuth 2.0
});
// listen to see if the user is known/logged in
FB.getLoginStatus(function(response) {
handle_fblogin_response(response);
});
};
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
d.getElementsByTagName('head')[0].appendChild(js);
}(document));
facebookHelper.promptLogin()
.done(function(response) {
if (response && response.status == "connected") {
showFeedDialog();
}
})
}
// END FB handlers
@ -279,15 +228,17 @@
registerEvents(false);
}
function initialize(fbAppID){
function initialize(_facebookHelper){
facebookHelper = _facebookHelper;
var dialogBindings = {
'beforeShow' : beforeShow,
'afterHide': afterHide
};
app.bindDialog('inviteUsers', dialogBindings);
//callFB(fbAppID);
facebookHelper.deferredLoginStatus().done(function(response) { handleFbStateChange(response); });
};
this.initialize = initialize;

View File

@ -805,6 +805,15 @@
})
}
function createFbInviteUrl() {
return $.ajax({
type: "GET",
url: '/api/invited_users/facebook',
dataType: "json",
contentType: 'application/json'
});
}
function initialize() {
return self;
}
@ -874,6 +883,7 @@
this.getShareSession = getShareSession;
this.getShareRecording = getShareRecording;
this.tweet = tweet;
this.createFbInviteUrl = createFbInviteUrl;
return this;
};

View File

@ -542,7 +542,6 @@
function centerDialog(dialog) {
var $dialog = $('[layout-id="' + dialog + '"]');
console.log("$dialog.width, height", $dialog.width(), $dialog.height())
$dialog.css({
left: width/2 - ($dialog.width()/2) + "px",
top: height/2 - ($dialog.height()/2) + "px"

View File

@ -32,6 +32,17 @@
}
function checkShareCheckbox(provider, checked) {
var checkbox = $(dialogId + ' .share-with-' + provider + ' input');
if(checked) {
checkbox.attr('checked', 'checked');
}
else {
checkbox.removeAttr('checked');
}
}
function handleRecordingShareWithGoogle(message) {
var defer = $.Deferred();
@ -41,31 +52,53 @@
return defer;
}
function handleRecordingShareWithTwitter(message) {
function handleShareWithTwitter(message) {
var defer = $.Deferred();
rest.tweet({message: message + ' ' + entity.share_url})
.done(function() {
// uncheck facebook, because we don't want the user to re-post to their timeline by accident
checkShareCheckbox('twitter', false);
defer.resolve();
})
.fail(function(jqXHR) {
if(jqXHR.status == 422) {
// implies twitter token error.
app.notify({
title : "Failed to Tweet",
text : "You need to re-authorize JamKazam to access your Twitter account. Click (sign in) in the Share Dialog.",
"icon_url": "/assets/content/icon_alert_big.png"
});
disableTwitter();
var response = JSON.parse(jqXHR.responseText);
if(response.errors.token) {
app.notify({
title : "Failed to Tweet",
text : "You need to re-authorize JamKazam to access your Twitter account. Click (sign in) in the Share Dialog.",
"icon_url": "/assets/content/icon_alert_big.png"
});
disableTwitter();
}
else if(response.errors.twitter) {
app.notify({
title : "Failed to Tweet",
text : "Twitter rejected the tweet because '" + response.errors.twitter[0] + "'",
"icon_url": "/assets/content/icon_alert_big.png"
});
}
else {
app.notifyServerError(jqXHR, "Unable to Share with Twitter");
}
}
else {
app.notifyServerError(jqXHR, "Unable to Share with Twitter");
}
defer.reject();
})
});
return defer;
}
function handleRecordingShareWithTwitter(message) {
return handleShareWithTwitter(message);
}
function handleRecordingShareWithFacebook(message) {
var defer = $.Deferred();
@ -83,6 +116,7 @@
picture: data.photo_url
})
.done(function(response) {
checkShareCheckbox('facebook', false);
defer.resolve();
})
.fail(function(response) {
@ -117,33 +151,8 @@
return defer;
}
// 116 characters
// abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdef
function handleSessionShareWithTwitter(message) {
var defer = $.Deferred();
rest.tweet({message: message + ' ' + entity.share_url})
.done(function() {
defer.resolve();
})
.fail(function(jqXHR) {
if(jqXHR.status == 422) {
// implies twitter token error.
app.notify({
title : "Failed to Tweet",
text : "You need to re-authorize JamKazam to access your Twitter account. Click (sign in) in the Share Dialog.",
"icon_url": "/assets/content/icon_alert_big.png"
});
disableTwitter();
}
else {
app.notifyServerError(jqXHR, "Unable to Share with Twitter");
}
defer.reject();
})
return defer;
return handleShareWithTwitter(message);
}
function handleSessionShareWithFacebook(message) {
@ -163,6 +172,7 @@
picture: data.photo_url
})
.done(function(response) {
checkShareCheckbox('facebook', false);
defer.resolve();
})
.fail(function(response) {
@ -476,9 +486,7 @@
initDialog();
$(facebookHelper).on('fb.login_response', function(e, data) {
handleFbStateChange(data.response);
})
facebookHelper.deferredLoginStatus().done(function(response) { handleFbStateChange(response); });
};
this.initialize = initialize;

View File

@ -38,6 +38,7 @@
}
function events() {
console.log($(dialogId + ' .signin-cancel'));
$(dialogId + ' .signin-cancel').click(function(e) {
app.layout.closeDialog('signin-dialog');
e.stopPropagation();
@ -55,6 +56,7 @@
});
$(dialogId + ' .show-signup-dialog').click(function(e) {
console.log("wtf")
app.layout.closeDialog('signin-dialog')
app.layout.showDialog('signup-dialog')
return false;

View File

@ -280,4 +280,10 @@
margin-bottom:20px;
}
}
.spinner-large {
vertical-align:middle;
text-align: center;
margin: 125px auto;
}
}

View File

@ -4,6 +4,10 @@ class ApiTwittersController < ApiController
respond_to :json
rescue_from 'Twitter::Error::Forbidden' do |exception|
render :json => { :errors => { :twitter => [exception.to_s] } }, :status => 422
end
rescue_from 'Twitter::Error::Unauthorized' do |exception|
# invalidate current tokens
current_user.invalidate_user_authorization('twitter')

View File

@ -102,10 +102,11 @@
var recordingManager = new JK.RecordingManager();
var facebookHelper = new JK.FacebookHelper(JK.app);
JK.FacebookHelperInstance = facebookHelper;
facebookHelper.initialize(gon.global.facebook_app_id);
var invitationDialog = new JK.InvitationDialog(JK.app);
invitationDialog.initialize(gon.global.facebook_app_id);
invitationDialog.initialize(facebookHelper);
var localRecordingsDialog = new JK.LocalRecordingsDialog(JK.app);
localRecordingsDialog.initialize();

View File

@ -91,6 +91,8 @@
var signupDialog = new JK.SignupDialog(JK.app);
signupDialog.initialize();
var signinDialog = new JK.SigninDialog(JK.app);
signinDialog.initialize();
})
</script>

View File

@ -115,6 +115,11 @@ include JamRuby
# Runs the websocket gateway within the web app
config.websocket_gateway_uri = "ws://localhost:#{config.websocket_gateway_port}/websocket"
config.external_hostname = ENV['EXTERNAL_HOSTNAME'] || 'localhost'
config.external_port = ENV['EXTERNAL_PORT'] || 3000
config.external_protocol = ENV['EXTERNAL_PROTOCOL'] || 'http://'
config.external_root_url = "#{config.external_protocol}#{config.external_hostname}#{(config.external_port == 80 || config.external_port == 443) ? '' : ':' + config.external_port.to_s}"
# set this to false if you want to disable signups (lock down public user creation)
config.signup_enabled = true