From 06b7792d490bee9d2f1a701f3a3047f9c5345400 Mon Sep 17 00:00:00 2001 From: Vladmir Upirov Date: Fri, 2 Feb 2018 16:29:42 +0100 Subject: [PATCH 1/5] - fix loginWithGooglePlusSdk method --- src/users/social/google.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/users/social/google.js b/src/users/social/google.js index 463d3d53..4b72ae9f 100644 --- a/src/users/social/google.js +++ b/src/users/social/google.js @@ -21,9 +21,8 @@ export const loginWithGooglePlusSdk = (fieldsMapping, stayLoggedIn) => { gapi.auth.authorize({ client_id: fieldsMapping.client_id, scope : 'https://www.googleapis.com/auth/plus.login' - }, response => { - delete response['g-oauth-window'] - sendSocialLoginRequest(response, 'googleplus', fieldsMapping, stayLoggedIn, asyncHandler) + }, ({ access_token }) => { + sendSocialLoginRequest({ accessToken: access_token }, 'googleplus', fieldsMapping, stayLoggedIn, asyncHandler) }) }) } From 1556d12f314f9bf7c23096380b2597beaf0e9804 Mon Sep 17 00:00:00 2001 From: Vladmir Upirov Date: Fri, 2 Feb 2018 18:23:31 +0100 Subject: [PATCH 2/5] - add an ability to login with "accessToken" of GooglePlus and Facebook --- examples/user-service/UserLogin.iml | 10 - .../css/bootstrap.css | 0 .../css/userLogin.css | 0 .../{ => simple-register-login}/index.html | 0 .../js/bootstrap.js | 0 .../{ => simple-register-login}/js/jquery.js | 0 .../js/user-example.js | 0 .../user-service/social-login/css/main.css | 31 +++ examples/user-service/social-login/index.html | 58 +++++ examples/user-service/social-login/js/main.js | 232 ++++++++++++++++++ src/users/social/facebook.js | 29 ++- src/users/social/google.js | 22 +- src/users/social/request.js | 12 +- 13 files changed, 362 insertions(+), 32 deletions(-) delete mode 100644 examples/user-service/UserLogin.iml rename examples/user-service/{ => simple-register-login}/css/bootstrap.css (100%) rename examples/user-service/{ => simple-register-login}/css/userLogin.css (100%) rename examples/user-service/{ => simple-register-login}/index.html (100%) rename examples/user-service/{ => simple-register-login}/js/bootstrap.js (100%) rename examples/user-service/{ => simple-register-login}/js/jquery.js (100%) rename examples/user-service/{ => simple-register-login}/js/user-example.js (100%) create mode 100644 examples/user-service/social-login/css/main.css create mode 100644 examples/user-service/social-login/index.html create mode 100644 examples/user-service/social-login/js/main.js diff --git a/examples/user-service/UserLogin.iml b/examples/user-service/UserLogin.iml deleted file mode 100644 index 284429d9..00000000 --- a/examples/user-service/UserLogin.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/examples/user-service/css/bootstrap.css b/examples/user-service/simple-register-login/css/bootstrap.css similarity index 100% rename from examples/user-service/css/bootstrap.css rename to examples/user-service/simple-register-login/css/bootstrap.css diff --git a/examples/user-service/css/userLogin.css b/examples/user-service/simple-register-login/css/userLogin.css similarity index 100% rename from examples/user-service/css/userLogin.css rename to examples/user-service/simple-register-login/css/userLogin.css diff --git a/examples/user-service/index.html b/examples/user-service/simple-register-login/index.html similarity index 100% rename from examples/user-service/index.html rename to examples/user-service/simple-register-login/index.html diff --git a/examples/user-service/js/bootstrap.js b/examples/user-service/simple-register-login/js/bootstrap.js similarity index 100% rename from examples/user-service/js/bootstrap.js rename to examples/user-service/simple-register-login/js/bootstrap.js diff --git a/examples/user-service/js/jquery.js b/examples/user-service/simple-register-login/js/jquery.js similarity index 100% rename from examples/user-service/js/jquery.js rename to examples/user-service/simple-register-login/js/jquery.js diff --git a/examples/user-service/js/user-example.js b/examples/user-service/simple-register-login/js/user-example.js similarity index 100% rename from examples/user-service/js/user-example.js rename to examples/user-service/simple-register-login/js/user-example.js diff --git a/examples/user-service/social-login/css/main.css b/examples/user-service/social-login/css/main.css new file mode 100644 index 00000000..3dd1ce86 --- /dev/null +++ b/examples/user-service/social-login/css/main.css @@ -0,0 +1,31 @@ +body { + background: #161a24; + font: 12px Arial, Helvetica, sans-serif; +} + +.form { + text-align: center; + background: #fff; + margin: 150px 0 0 -125px; + width: 250px; + position: relative; + left: 50%; + padding: 10px; + border-radius: 5px; +} + +.login, +.logout { + display: none +} + +.social-login-buttons { + width: 210px; + margin: 0 auto; +} + +.social-login-btn { + display: block; + width: 100%; + margin: 5px 0 0 0; +} diff --git a/examples/user-service/social-login/index.html b/examples/user-service/social-login/index.html new file mode 100644 index 00000000..234ea957 --- /dev/null +++ b/examples/user-service/social-login/index.html @@ -0,0 +1,58 @@ + + + + + + Backendless Social Login + + + + +
+
+

Loading...

+
+ +
+
+

Backendless Social Login

+
+ You are logged in now +
+
+ +
+
+
+ +
+ + + + + + + + + + + + + + diff --git a/examples/user-service/social-login/js/main.js b/examples/user-service/social-login/js/main.js new file mode 100644 index 00000000..802a0094 --- /dev/null +++ b/examples/user-service/social-login/js/main.js @@ -0,0 +1,232 @@ +(function($, Backendless) { + var SERVER_URL = "https://api.backendless.com"; + var APPLICATION_ID = ''; + var API_KEY = ''; + var GOOGLE_CLIENT_ID = ''; + var FACEBOOK_APP_ID = ''; + + var app = { + ui: { + preloader : '.preloader', + loginForm : '.form.login', + logoutForm : '.form.logout', + googleLoginBtn : '#google-plus-login', + facebookLoginBtn: '#facebook-login', + twitterLoginBtn : '#twitter-login', + logoutBtn : '#logout' + }, + + toBind: [ + 'onLogoutClick', + 'onGoogleLoginClick', + 'onFacebookLoginClick', + 'onTwitterLoginClick', + 'onLoggedIn' + ], + + init: function() { + this.initBackendless(); + + this.bindMethods(); + this.collectUiElements(); + this.initEventHandlers(); + + this.setInitialState(); + }, + + initBackendless: function() { + Backendless.serverURL = SERVER_URL; + Backendless.initApp(APPLICATION_ID, API_KEY); + + if (!APPLICATION_ID || !API_KEY) { + alert( + 'Missing application ID or api key arguments. ' + + 'Login to Backendless Console, select your app and get the ID and key from the Manage > App Settings screen. ' + + 'Copy/paste the values into the Backendless.initApp call located in js/main.js' + ) + } + }, + + setInitialState: function() { + var app = this; + var cache = Backendless.LocalCache.getAll(); + + if (cache.stayLoggedIn) { + Backendless.UserService.isValidLogin().then(function(isLoginValid) { + if (isLoginValid) { + app.showLogoutForm(); + } else { + Backendless.LocalCache.clear(); + app.showLoginForm(); + } + }, this.onError); + + return; + } + + this.showLoginForm(); + }, + + collectUiElements: function() { + for (var key in this.ui) { + this.ui[key] = $(this.ui[key]) + } + }, + + bindMethods: function() { + var app = this; + + this.toBind.forEach(function(methodName) { + app[methodName] = app[methodName].bind(app) + }) + }, + + initEventHandlers: function() { + this.ui.googleLoginBtn.on('click', this.onGoogleLoginClick); + this.ui.facebookLoginBtn.on('click', this.onFacebookLoginClick); + this.ui.twitterLoginBtn.on('click', this.onTwitterLoginClick); + this.ui.logoutBtn.on('click', this.onLogoutClick) + }, + + showLoginForm: function() { + this.ui.preloader.hide(); + this.ui.logoutForm.hide(); + this.ui.loginForm.show(); + }, + + showLogoutForm: function() { + this.ui.preloader.hide(); + this.ui.loginForm.hide(); + this.ui.logoutForm.show(); + + console.log(Backendless.UserService.getUserRolesSync()); + }, + + onGoogleLoginClick: function() { + if (!gapi) { + return alert("Google+ SDK not found"); + } + + if (!GOOGLE_CLIENT_ID) { + return alert( + 'Missing Google client ID. ' + + 'Select client ID from your account on https://console.developers.google.com' + ); + } + + var app = this; + + gapi.auth.authorize({ + client_id: GOOGLE_CLIENT_ID, + scope : "https://www.googleapis.com/auth/plus.login" + }, function(response) { + var accessToken = response && response.access_token; + + app.backendlessLoginWithGooglePlusSDK(accessToken); + }); + }, + + onFacebookLoginClick: function() { + if (!FB) { + return alert("Facebook SDK not found"); + } + + if (!FACEBOOK_APP_ID) { + return alert("Facebook App Id cannot be empty"); + } + + // description of options parameter: https://developers.facebook.com/docs/reference/javascript/FB.login/v2.9 + var fbLoginOptions = {}; + var app = this; + + FB.init({ + appId : FACEBOOK_APP_ID, + cookie : true, + xfbml : true, + version: 'v2.12' + }); + + FB.getLoginStatus(function(response) { + if (response.status === 'connected') { + app.backendlessLoginWithFacebookSDK(response); + } else { + FB.login(function(response) { + app.backendlessLoginWithFacebookSDK(response); + }, fbLoginOptions); + } + }); + }, + + onTwitterLoginClick: function() { + Backendless.UserService.loginWithTwitter().then(this.onLoggedIn, this.onError); + }, + + /* + * Backendless Login with Facebook SDK + * + * @param {Object} Facebook login status + */ + backendlessLoginWithFacebookSDK: function(loginStatus) { + var accessToken = loginStatus && loginStatus.authResponse && loginStatus.authResponse.accessToken; + var fieldsMapping = { 'email': 'email', 'first_name': 'first_name' }; + var stayLoggedIn = false; + + Backendless.UserService.loginWithFacebookSdk(accessToken, fieldsMapping, stayLoggedIn) + .then(this.onLoggedIn, this.onError); + }, + + /* + * Backendless Login with Google+ SDK + * + * @param {accessToken} Google+ access token + */ + backendlessLoginWithGooglePlusSDK: function(accessToken) { + var fieldsMapping = {}; + var stayLoggedIn = true; + + Backendless.UserService.loginWithGooglePlusSdk(accessToken, fieldsMapping, stayLoggedIn) + .then(this.onLoggedIn, this.onError); + }, + + /* + * Login with Twitter + */ + onTwitterLoginClick: function() { + Backendless.UserService.loginWithTwitter().then(this.onLoggedIn, this.onError); + }, + + /* + * Logout + */ + onLogoutClick: function() { + Backendless.UserService.logout().then(this.onLoggedOut, this.onError); + }, + + onLoggedIn: function(user) { + this.showLogoutForm(); + + console.log(user); + }, + + onLoggedOut: function() { + location.reload(); + }, + + onError: function(err) { + err = err || {}; + + console.log(err) + + console.error("error message - " + err.message); + + if (err.statusCode) { + console.error("error statusCode - " + err.statusCode); + } + } + }; + + app.init(); + +})($, Backendless); + + \ No newline at end of file diff --git a/src/users/social/facebook.js b/src/users/social/facebook.js index ea88e807..7564d928 100644 --- a/src/users/social/facebook.js +++ b/src/users/social/facebook.js @@ -8,28 +8,35 @@ export const loginWithFacebook = (fieldsMapping, permissions, stayLoggedIn, asyn return loginSocial('Facebook', fieldsMapping, permissions, null, stayLoggedIn, asyncHandler) } -export const loginWithFacebookSdk = (fieldsMapping, stayLoggedIn, options) => { +export const loginWithFacebookSdk = (accessToken, fieldsMapping, stayLoggedIn, options) => { Utils.checkPromiseSupport() + if (typeof accessToken !== 'string') { + options = stayLoggedIn + stayLoggedIn = fieldsMapping + fieldsMapping = accessToken + accessToken = null + } + return new Promise((resolve, reject) => { - if (!FB) { - return reject(new Error('Facebook SDK not found')) + function loginRequest() { + sendSocialLoginRequest(accessToken, 'facebook', fieldsMapping, stayLoggedIn, new Async(resolve, reject)) } - function loginRequest(response) { - const requestData = { - ...response, - accessToken: response.authResponse.accessToken - } + if (accessToken || !fieldsMapping) { + return loginRequest() + } - sendSocialLoginRequest(requestData, 'facebook', fieldsMapping, stayLoggedIn, new Async(resolve, reject)) + if (!FB) { + return reject(new Error('Facebook SDK not found')) } FB.getLoginStatus(response => { if (response.status === 'connected') { - loginRequest(response) + loginRequest(accessToken = response.authResponse.accessToken) + } else { - FB.login(response => loginRequest(response), options) + FB.login(response => loginRequest(accessToken = response.authResponse.accessToken), options) } }) }) diff --git a/src/users/social/google.js b/src/users/social/google.js index 4b72ae9f..a4d73ce0 100644 --- a/src/users/social/google.js +++ b/src/users/social/google.js @@ -8,21 +8,31 @@ export const loginWithGooglePlus = (fieldsMapping, permissions, container, stayL return loginSocial('GooglePlus', fieldsMapping, permissions, container, stayLoggedIn, asyncHandler) } -export const loginWithGooglePlusSdk = (fieldsMapping, stayLoggedIn) => { +export const loginWithGooglePlusSdk = (accessToken, fieldsMapping, stayLoggedIn) => { Utils.checkPromiseSupport() + if (typeof accessToken !== 'string') { + stayLoggedIn = fieldsMapping + fieldsMapping = accessToken + accessToken = null + } + return new Promise((resolve, reject) => { + function loginRequest() { + sendSocialLoginRequest(accessToken, 'googleplus', fieldsMapping, stayLoggedIn, new Async(resolve, reject)) + } + + if (accessToken || !fieldsMapping) { + return loginRequest() + } + if (!gapi) { return reject(new Error('Google Plus SDK not found')) } - const asyncHandler = new Async(resolve, reject) - gapi.auth.authorize({ client_id: fieldsMapping.client_id, scope : 'https://www.googleapis.com/auth/plus.login' - }, ({ access_token }) => { - sendSocialLoginRequest({ accessToken: access_token }, 'googleplus', fieldsMapping, stayLoggedIn, asyncHandler) - }) + }, ({ access_token }) => loginRequest(accessToken = access_token)) }) } diff --git a/src/users/social/request.js b/src/users/social/request.js index 411d7c93..155200d4 100644 --- a/src/users/social/request.js +++ b/src/users/social/request.js @@ -4,12 +4,11 @@ import Request from '../../request' import LocalCache from '../../local-cache' import { getLocalCurrentUser, setLocalCurrentUser } from '../current-user' - import { parseResponse, getUserFromResponse } from '../utils' -export const sendSocialLoginRequest = (response, socialType, fieldsMapping, stayLoggedIn, asyncHandler) => { - if (fieldsMapping) { - response['fieldsMapping'] = fieldsMapping +export const sendSocialLoginRequest = (accessToken, socialType, fieldsMapping, stayLoggedIn, asyncHandler) => { + if (!accessToken) { + return asyncHandler.fault('"accessToken" is missing.') } const interimCallback = new Async(function(r) { @@ -24,6 +23,9 @@ export const sendSocialLoginRequest = (response, socialType, fieldsMapping, stay url : Urls.userSocialLogin(socialType), isAsync : true, asyncHandler: interimCallback, - data : response + data : { + accessToken, + fieldsMapping + } }) } From f42003af7783ed7c508383ad9c115da6999179eb Mon Sep 17 00:00:00 2001 From: Vladmir Upirov Date: Thu, 8 Feb 2018 11:27:59 +0100 Subject: [PATCH 3/5] - add warn message of deprecation GooglePlus and Facebook easy login methods --- src/users/social/facebook.js | 7 +++++++ src/users/social/google.js | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/users/social/facebook.js b/src/users/social/facebook.js index 7564d928..8674b702 100644 --- a/src/users/social/facebook.js +++ b/src/users/social/facebook.js @@ -5,6 +5,11 @@ import { loginSocial } from './login' import { sendSocialLoginRequest } from './request' export const loginWithFacebook = (fieldsMapping, permissions, stayLoggedIn, asyncHandler) => { + console.warn( + 'Method "loginWithFacebook" is deprecated. and will be removed in the nearest release.\n' + + 'Use method "loginWithFacebookSdk" instead.' + ) + return loginSocial('Facebook', fieldsMapping, permissions, null, stayLoggedIn, asyncHandler) } @@ -27,6 +32,8 @@ export const loginWithFacebookSdk = (accessToken, fieldsMapping, stayLoggedIn, o return loginRequest() } + console.warn('You must pass "accessToken" as the first argument into "loginWithFacebook(accessToken:String, fieldsMapping:Object, stayLoggedIn?:Boolean)" method') + if (!FB) { return reject(new Error('Facebook SDK not found')) } diff --git a/src/users/social/google.js b/src/users/social/google.js index a4d73ce0..4cf6737b 100644 --- a/src/users/social/google.js +++ b/src/users/social/google.js @@ -5,6 +5,11 @@ import { loginSocial } from './login' import { sendSocialLoginRequest } from './request' export const loginWithGooglePlus = (fieldsMapping, permissions, container, stayLoggedIn, asyncHandler) => { + console.warn( + 'Method "loginWithGooglePlus" is deprecated. and will be removed in the nearest release.\n' + + 'Use method "loginWithGooglePlusSdk" instead.' + ) + return loginSocial('GooglePlus', fieldsMapping, permissions, container, stayLoggedIn, asyncHandler) } @@ -26,6 +31,8 @@ export const loginWithGooglePlusSdk = (accessToken, fieldsMapping, stayLoggedIn) return loginRequest() } + console.warn('You must pass "accessToken" as the first argument into "loginWithGooglePlusSdk(accessToken:String, fieldsMapping:Object, stayLoggedIn?:Boolean)" method') + if (!gapi) { return reject(new Error('Google Plus SDK not found')) } From de5dd65a0f44d87ed67e7fd2a294b29713ca1349 Mon Sep 17 00:00:00 2001 From: Vladmir Upirov Date: Thu, 8 Feb 2018 11:39:29 +0100 Subject: [PATCH 4/5] - fix type definition for social login methods --- backendless.d.ts | 8 ++++++++ test/tsd.ts | 8 ++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/backendless.d.ts b/backendless.d.ts index 4348f5ef..745be327 100644 --- a/backendless.d.ts +++ b/backendless.d.ts @@ -924,21 +924,29 @@ declare module __Backendless { update(user: Backendless.User): Promise; update(user: T): Promise; + /**@deprecated */ loginWithFacebookSync(fields?: Object, permissions?: Object, stayLoggedIn?: boolean): void; + /**@deprecated */ loginWithFacebook(fields?: Object, permissions?: Object, stayLoggedIn?: boolean): Promise; + /**@deprecated */ loginWithGooglePlusSync(fields?: Object, permissions?: Object, container?: HTMLElement, stayLoggedIn?: boolean): void; + /**@deprecated */ loginWithGooglePlus(fields?: Object, permissions?: Object, container?: HTMLElement, stayLoggedIn?: boolean): Promise; loginWithTwitterSync(fields?: Object, stayLoggedIn?: boolean): void; loginWithTwitter(fields?: Object, stayLoggedIn?: boolean): Promise; + /**@deprecated */ loginWithFacebookSdk(fields?: Object, stayLoggedIn?: boolean): Promise; + loginWithFacebookSdk(accessToken: String, fields: Object, stayLoggedIn?: boolean): Promise; + /**@deprecated */ loginWithGooglePlusSdk(fields?: Object, stayLoggedIn?: boolean): Promise; + loginWithGooglePlusSdk(accessToken: String, fields?: Object, stayLoggedIn?: boolean): Promise; isValidLoginSync(): boolean; diff --git a/test/tsd.ts b/test/tsd.ts index f3e3bd41..4df6e7c7 100644 --- a/test/tsd.ts +++ b/test/tsd.ts @@ -335,14 +335,18 @@ function testUserService() { promiseVoid = Backendless.UserService.loginWithTwitter({}, true); promiseVoid = Backendless.UserService.loginWithTwitter(null, true); - promiseVoid = Backendless.UserService.loginWithFacebookSdk(); promiseVoid = Backendless.UserService.loginWithFacebookSdk({}); promiseVoid = Backendless.UserService.loginWithFacebookSdk({}, true); - promiseVoid = Backendless.UserService.loginWithGooglePlusSdk(); + promiseVoid = Backendless.UserService.loginWithFacebookSdk('accessToken', {}); + promiseVoid = Backendless.UserService.loginWithFacebookSdk('accessToken', {},true); + promiseVoid = Backendless.UserService.loginWithGooglePlusSdk({}); promiseVoid = Backendless.UserService.loginWithGooglePlusSdk({}, true); + promiseVoid = Backendless.UserService.loginWithGooglePlusSdk('accessToken', {}); + promiseVoid = Backendless.UserService.loginWithGooglePlusSdk('accessToken', {},true); + bol = Backendless.UserService.isValidLoginSync(); promiseObject = Backendless.UserService.isValidLogin(); From d174491f4afe9f0e28765c258cd634579bd55e52 Mon Sep 17 00:00:00 2001 From: Vladmir Upirov Date: Thu, 8 Feb 2018 12:02:58 +0100 Subject: [PATCH 5/5] - fix errors handling loginWithGooglePlusSdk methods --- src/users/social/google.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/users/social/google.js b/src/users/social/google.js index 4cf6737b..470b3fd2 100644 --- a/src/users/social/google.js +++ b/src/users/social/google.js @@ -40,6 +40,12 @@ export const loginWithGooglePlusSdk = (accessToken, fieldsMapping, stayLoggedIn) gapi.auth.authorize({ client_id: fieldsMapping.client_id, scope : 'https://www.googleapis.com/auth/plus.login' - }, ({ access_token }) => loginRequest(accessToken = access_token)) + }, ({ access_token, error }) => { + if (error) { + reject(error) + } else { + loginRequest(accessToken = access_token) + } + }) }) }