diff --git a/db/manifest b/db/manifest
index c11589332..24dbab76d 100755
--- a/db/manifest
+++ b/db/manifest
@@ -94,4 +94,5 @@ integrate_icecast_into_sessions.sql
ms_recording_anonymous_likes.sql
ms_user_history_add_instruments.sql
icecast_config_changed.sql
+invited_users_facebook_support.sql
first_recording_at.sql
\ No newline at end of file
diff --git a/db/up/invited_users_facebook_support.sql b/db/up/invited_users_facebook_support.sql
new file mode 100644
index 000000000..efc79b5de
--- /dev/null
+++ b/db/up/invited_users_facebook_support.sql
@@ -0,0 +1,3 @@
+ALTER TABLE invited_users ALTER COLUMN email DROP NOT NULL;
+ALTER TABLE invited_users ADD COLUMN invite_medium VARCHAR(64);
+
diff --git a/ruby/lib/jam_ruby/app/mailers/invited_user_mailer.rb b/ruby/lib/jam_ruby/app/mailers/invited_user_mailer.rb
index a443f9c6d..ce1a007ac 100644
--- a/ruby/lib/jam_ruby/app/mailers/invited_user_mailer.rb
+++ b/ruby/lib/jam_ruby/app/mailers/invited_user_mailer.rb
@@ -48,7 +48,8 @@ module JamRuby
end
def generate_signup_url(invited_user)
- "http://www.jamkazam.com/signup?invitation_code=#{invited_user.invitation_code}"
+ invited_user.generate_signup_url
+ # "http://www.jamkazam.com/signup?invitation_code=#{invited_user.invitation_code}"
end
end
end
diff --git a/ruby/lib/jam_ruby/models/invited_user.rb b/ruby/lib/jam_ruby/models/invited_user.rb
index 6481a6bdb..579766cf7 100644
--- a/ruby/lib/jam_ruby/models/invited_user.rb
+++ b/ruby/lib/jam_ruby/models/invited_user.rb
@@ -14,13 +14,15 @@ module JamRuby
belongs_to :sender , :inverse_of => :invited_users, :class_name => "JamRuby::User", :foreign_key => "sender_id"
# who is the invitation sent to?
- validates :email, :presence => true, format: {with: VALID_EMAIL_REGEX}
+ validates :email, format: {with: VALID_EMAIL_REGEX}, :if => lambda { |iu| iu.email.present? }
validates :autofriend, :inclusion => {:in => [nil, true, false]}
validates :invitation_code, :presence => true
validates :note, length: {maximum: 400}, no_profanity: true # 400 == arbitrary.
+ validate :one_facebook_invite_per_user, :if => lambda { |iu| iu.invite_medium == FB_MEDIUM }
validate :valid_personalized_invitation
- validate :not_accepted_twice
+ # validate :not_accepted_twice
+ validate :not_accepted_twice, :if => lambda { |iu| iu.email }
validate :can_invite?
after_save :track_user_progression
@@ -31,6 +33,12 @@ module JamRuby
self.sender_id = nil if self.sender_id.blank? # this coercion was done just to make activeadmin work
end
+ FB_MEDIUM = 'facebook'
+
+ def self.facebook_invite(user)
+ where(:sender_id => user.id, :invite_medium => FB_MEDIUM).limit(1).first
+ end
+
def track_user_progression
self.sender.update_progression_field(:first_invited_at) unless self.sender.nil?
end
@@ -54,6 +62,15 @@ module JamRuby
def invited_by_administrator?
sender.nil? || sender.admin # a nil sender can only be created by someone using jam-admin
end
+
+ def generate_signup_url
+ if 'development'==Rails.env
+ "http://jamkazamdev.local:3000/signup?invitation_code=#{self.invitation_code}"
+ else
+ "http://www.jamkazam.com/signup?invitation_code=#{self.invitation_code}"
+ end
+ end
+
private
def can_invite?
@@ -67,5 +84,12 @@ module JamRuby
def not_accepted_twice
errors.add(:accepted, "you can only accept an invitation once") if accepted_twice
end
+
+ def one_facebook_invite_per_user
+ rel = InvitedUser.where(:invite_medium => FB_MEDIUM, :sender_id => self.sender_id)
+ rel = rel.where(['id != ?',self.id]) if self.id
+ errors.add(:invite_medium, "one facebook invite allowed per user") if 0 < rel.count
+ end
+
end
end
diff --git a/ruby/lib/jam_ruby/models/invited_user_observer.rb b/ruby/lib/jam_ruby/models/invited_user_observer.rb
index a4a007a93..cd62bd2d1 100644
--- a/ruby/lib/jam_ruby/models/invited_user_observer.rb
+++ b/ruby/lib/jam_ruby/models/invited_user_observer.rb
@@ -8,7 +8,7 @@ module JamRuby
InvitedUserMailer.welcome_betauser(invited_user).deliver
else
InvitedUserMailer.friend_invitation(invited_user).deliver
- end
+ end if invited_user.email.present?
end
end
-end
\ No newline at end of file
+end
diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb
index 7fe2f24f3..5af2ebf7b 100644
--- a/ruby/lib/jam_ruby/models/user.rb
+++ b/ruby/lib/jam_ruby/models/user.rb
@@ -1007,10 +1007,21 @@ module JamRuby
end
end
- #def first_recording_at
- # Recording.where(:owner_id => self.id).order('created_at ASC').first.try(:created_at)
- #end
-
+ def first_recording_at
+ Recording.where(:owner_id => self.id).order('created_at ASC').first.try(:created_at)
+ end
+
+ def facebook_invite!
+ unless iu = InvitedUser.facebook_invite(self)
+ iu = InvitedUser.new
+ iu.sender = self
+ iu.autofriend = true
+ iu.invite_medium = InvitedUser::FB_MEDIUM
+ iu.save
+ end
+ iu
+ end
+
# devise compatibility
#def encrypted_password
diff --git a/ruby/spec/jam_ruby/models/invited_user_spec.rb b/ruby/spec/jam_ruby/models/invited_user_spec.rb
index 0ccf6865e..ca4288939 100644
--- a/ruby/spec/jam_ruby/models/invited_user_spec.rb
+++ b/ruby/spec/jam_ruby/models/invited_user_spec.rb
@@ -104,4 +104,28 @@ describe InvitedUser do
invited_user.valid?.should be_false
end
+ it 'accepts empty emails' do
+ user1 = FactoryGirl.create(:user)
+ invited_user = FactoryGirl.create(:invited_user, :sender_id => user1.id, :email => '')
+ expect(invited_user.valid?).to eq(true)
+ end
+
+ it 'accepts one facebook invite per user' do
+ user1 = FactoryGirl.create(:user)
+ invited_user = FactoryGirl.create(:invited_user, :sender_id => user1.id, :invite_medium => InvitedUser::FB_MEDIUM)
+ expect(invited_user.valid?).to eq(true)
+ invited_user.autofriend = !invited_user.autofriend
+ invited_user.save
+ expect(invited_user.valid?).to eq(true)
+ invited_user1 = InvitedUser.new(:email => 'foobar@example.com', :sender_id => user1.id)
+ invited_user1.autofriend = true
+ invited_user1.invite_medium = InvitedUser::FB_MEDIUM
+ invited_user1.save
+ expect(invited_user1.valid?).to eq(false)
+ expect(InvitedUser.facebook_invite(user1).id).to eq(invited_user.id)
+ user2 = FactoryGirl.create(:user)
+ iu = user1.facebook_invite!
+ expect(user1.facebook_invite!.id).to eq(iu.id)
+ end
+
end
diff --git a/web/app/assets/javascripts/createSession.js b/web/app/assets/javascripts/createSession.js
index ae3e5ff92..2d2c58f10 100644
--- a/web/app/assets/javascripts/createSession.js
+++ b/web/app/assets/javascripts/createSession.js
@@ -200,8 +200,8 @@
invitationDialog.showGoogleDialog();
});
- $('div[layout-id="createSession"] .btn-facebook-invitation').click(function() {
- invitationDialog.showFacebookDialog();
+ $('div[layout-id="createSession"] .btn-facebook-invitation').click(function(e) {
+ invitationDialog.showFacebookDialog(e);
});
$('#friend-input').focus(function() { $(this).val(''); })
diff --git a/web/app/assets/javascripts/invitationDialog.js b/web/app/assets/javascripts/invitationDialog.js
index a3c569f59..f268554b7 100644
--- a/web/app/assets/javascripts/invitationDialog.js
+++ b/web/app/assets/javascripts/invitationDialog.js
@@ -1,5 +1,4 @@
(function(context,$) {
-
"use strict";
context.JK = context.JK || {};
context.JK.InvitationDialog = function(app) {
@@ -7,6 +6,7 @@
var rest = context.JK.Rest();
var waitForUserToStopTypingTimer;
var sendingEmail = false;
+ var fbInviteURL_ = null;
function trackMetrics(emails, googleInviteCount) {
var allInvitations = emails.length; // all email invites, regardless of how they got in the form
@@ -152,49 +152,114 @@
};
window._oauth_win = window.open("/auth/google_login", "_blank", "height=500,width=500,menubar=no,resizable=no,status=no");
}
+
+ //////////////
+ // FB handlers
- function showFacebookDialog() {
- /*
- $('#invitation-textarea-container').hide();
- $('#invitation-checkbox-container').show();
- $('#btn-send-invitation').hide();
- $('#btn-next-invitation').show();
- invitationDialog.showDialog();
- $('#invitation-checkboxes').html('
Loading your contacts...
');
- */
- window._oauth_callback = function() {
- window._oauth_win.close();
- window._oauth_win = null;
- window._oauth_callback = null;
- /*
- $.ajax({
- type: "GET",
- url: "/gmail_contacts",
- success: function(response) {
- $('#invitation-checkboxes').html('');
- for (var i in response) {
- $('#invitation-checkboxes').append("");
- }
-
- $('.invitation-checkbox').change(function() {
- var checkedBoxes = $('.invitation-checkbox:checkbox:checked');
- var emails = '';
- for (var i = 0; i < checkedBoxes.length; i++) {
- emails += $(checkedBoxes[i]).data('email') + ', ';
- }
- emails = emails.replace(/, $/, '');
- $('#txt-emails').val(emails);
- });
- },
- error: function() {
- $('#invitation-checkboxes').html("Load failed");
- }
- });
- */
- };
- window._oauth_win = window.open("/auth/facebook_login", "_blank", "height=500,width=500,menubar=no,resizable=no,status=no");
+ // 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";
+ }
}
+ this.fb_login = function() {
+ FB.login(function(response) {
+ handle_fblogin_response(response);
+ }, {scope:'publish_stream'});
+ }
+
+ 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_;
+ }
+
+ 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'])
+ }
+ 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));
+ }
+
+ // END FB handlers
+ //////////////
+
+
function clearTextFields() {
$('#txt-emails').val('').removeData('google_invite_count');
$('#txt-message').val('');
@@ -211,16 +276,17 @@
registerEvents(false);
}
- function initialize(){
+ function initialize(fbAppID){
var dialogBindings = {
'beforeShow' : beforeShow,
'afterHide': afterHide
};
app.bindDialog('inviteUsers', dialogBindings);
+
+ callFB(fbAppID);
};
-
this.initialize = initialize;
this.showEmailDialog = showEmailDialog;
this.showGoogleDialog = showGoogleDialog;
@@ -228,4 +294,4 @@
}
return this;
-})(window,jQuery);
\ No newline at end of file
+})(window,jQuery);
diff --git a/web/app/assets/javascripts/shareDialog.js b/web/app/assets/javascripts/shareDialog.js
index ddf0640ce..dff0ce41b 100644
--- a/web/app/assets/javascripts/shareDialog.js
+++ b/web/app/assets/javascripts/shareDialog.js
@@ -10,6 +10,10 @@
}
+ function showDialog() {
+ app.layout.showDialog('share-dialog');
+ }
+
/*function showEmailDialog() {
$('#invitation-dialog').show();
$('#invitation-textarea-container').show();
@@ -94,8 +98,8 @@
app.bindDialog('shareSessionRecording', dialogBindings);
};
-
this.initialize = initialize;
+ this.showDialog = showDialog;
}
return this;
diff --git a/web/app/assets/javascripts/sidebar.js b/web/app/assets/javascripts/sidebar.js
index 23e84db36..f946c6149 100644
--- a/web/app/assets/javascripts/sidebar.js
+++ b/web/app/assets/javascripts/sidebar.js
@@ -442,6 +442,11 @@
invitationDialog.showGoogleDialog();
return false;
});
+
+ $('#sidebar-div .btn-facebook-invitation').click(function(evt) {
+ invitationDialog.showFacebookDialog(evt);
+ return false;
+ });
}
function registerFriendUpdate() {
diff --git a/web/app/assets/javascripts/user_dropdown.js b/web/app/assets/javascripts/user_dropdown.js
index b003f2d76..2973dda7d 100644
--- a/web/app/assets/javascripts/user_dropdown.js
+++ b/web/app/assets/javascripts/user_dropdown.js
@@ -37,6 +37,10 @@
invitationDialog.showEmailDialog();
});
+ $('.invite-friends .facebook-invite a').on('click', function(e) {
+ invitationDialog.showFacebookDialog(e);
+ });
+
$('#header-avatar').on('avatar_changed', function(event, newAvatarUrl) {
updateAvatar(newAvatarUrl);
event.preventDefault();
diff --git a/web/app/assets/stylesheets/client/content.css.scss b/web/app/assets/stylesheets/client/content.css.scss
index 440d926f2..a7a4d6584 100644
--- a/web/app/assets/stylesheets/client/content.css.scss
+++ b/web/app/assets/stylesheets/client/content.css.scss
@@ -430,7 +430,7 @@ ul.shortcuts {
color:#FFCC00;
}
- li.google-invite, li.email-invite {
+ li.google-invite, li.email-invite, li.facebook-invite {
padding-left:9px;
}
diff --git a/web/app/controllers/api_invited_users_controller.rb b/web/app/controllers/api_invited_users_controller.rb
index d0540f24d..66c1a9340 100644
--- a/web/app/controllers/api_invited_users_controller.rb
+++ b/web/app/controllers/api_invited_users_controller.rb
@@ -10,7 +10,11 @@ class ApiInvitedUsersController < ApiController
end
def show
- @invited_user = InvitedUser.find(params[:id])
+ if 'facebook' == params[:id]
+ @invited_user = current_user.facebook_invite!
+ else
+ @invited_user = InvitedUser.find(params[:id])
+ end
end
def create
diff --git a/web/app/controllers/users_controller.rb b/web/app/controllers/users_controller.rb
index 1192408f7..24411b3d4 100644
--- a/web/app/controllers/users_controller.rb
+++ b/web/app/controllers/users_controller.rb
@@ -29,7 +29,7 @@ class UsersController < ApplicationController
@invited_user = load_invited_user(params)
- if !@invited_user.nil? && @invited_user.accepted
+ if !@invited_user.nil? && @invited_user.email && @invited_user.accepted
# short-circuit out if this invitation is already accepted
render "already_signed_up", :layout => 'landing'
return
diff --git a/web/app/views/api_invited_users/invited_user.rabl b/web/app/views/api_invited_users/invited_user.rabl
index 3bce327fa..f86d788c1 100644
--- a/web/app/views/api_invited_users/invited_user.rabl
+++ b/web/app/views/api_invited_users/invited_user.rabl
@@ -1,3 +1,4 @@
object @invited_user
-attributes :id, :created_at, :updated_at, :email, :note, :accepted
\ No newline at end of file
+attributes :id, :created_at, :updated_at, :email, :note, :accepted
+
diff --git a/web/app/views/api_invited_users/show.rabl b/web/app/views/api_invited_users/show.rabl
index e62c95f69..4e95e7c91 100644
--- a/web/app/views/api_invited_users/show.rabl
+++ b/web/app/views/api_invited_users/show.rabl
@@ -1,3 +1,5 @@
object @invited_user
extends "api_invited_users/invited_user"
+
+node :signup_url do @invited_user.generate_signup_url end
diff --git a/web/app/views/clients/_createSession.html.erb b/web/app/views/clients/_createSession.html.erb
index 7a0b3f565..c37a4af3e 100644
--- a/web/app/views/clients/_createSession.html.erb
+++ b/web/app/views/clients/_createSession.html.erb
@@ -98,16 +98,14 @@
E-mail
-
diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb
index 2a504baab..7ddf73b83 100644
--- a/web/app/views/clients/index.html.erb
+++ b/web/app/views/clients/index.html.erb
@@ -45,6 +45,7 @@
<%= render "clients/banners/disconnected" %>
<%= render "overlay_small" %>
<%= render "help" %>
+