From 15167a4f8140facc9015aea9ae9ed646b7e3efbc Mon Sep 17 00:00:00 2001 From: Salakar Date: Mon, 13 Mar 2017 20:02:44 +0000 Subject: [PATCH] added auth method result interceptor - grab user objects and shim into currentUser --- .../firebase/auth/RNFirebaseAuth.java | 224 ++++++++++++------ lib/modules/auth/index.js | 60 +++-- 2 files changed, 183 insertions(+), 101 deletions(-) diff --git a/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuth.java b/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuth.java index 8bbe2c70..d1d2a813 100644 --- a/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuth.java +++ b/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuth.java @@ -68,7 +68,7 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { @ReactMethod - public void createAuthStateListener() { + public void addAuthStateListener() { if (mAuthListener == null) { mAuthListener = new FirebaseAuth.AuthStateListener() { @Override @@ -79,7 +79,7 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { if (user != null) { // TODO move to helper - WritableMap userMap = getUserMap(user); + WritableMap userMap = firebaseUserToMap(user); msgMap.putBoolean("authenticated", true); msgMap.putMap("user", userMap); @@ -94,38 +94,88 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { } } + /** + * Removes the current auth state listener + * @param callback + */ @ReactMethod - public void unlistenForAuth(final Callback callback) { + public void removeAuthStateListener(final Callback callback) { if (mAuthListener != null) { mAuth.removeAuthStateListener(mAuthListener); - // TODO move to helper WritableMap resp = Arguments.createMap(); resp.putString("status", "complete"); - callback.invoke(null, resp); } } + /** + * signOut + * @param promise + */ @ReactMethod - public void createUserWithEmail(final String email, final String password, final Callback callback) { - mAuth.createUserWithEmailAndPassword(email, password) - .addOnCompleteListener(new OnCompleteListener() { + public void signOut(final Promise promise) { + if (mAuth == null || mAuth.getCurrentUser() == null) { + promiseNoUser(promise, true); + } else { + mAuth.signOut(); + promiseNoUser(promise, false); + } + } + + /** + * signInAnonymously + * @param promise + */ + @ReactMethod + public void signInAnonymously(final Promise promise) { + Log.d(TAG, "signInAnonymously"); + mAuth.signInAnonymously() + .addOnSuccessListener(new OnSuccessListener() { @Override - public void onComplete(@NonNull Task task) { - try { - if (task.isSuccessful()) { - userCallback(task.getResult().getUser(), callback); - } else { - userErrorCallback(task, callback); - } - } catch (Exception ex) { - userExceptionCallback(ex, callback); - } + public void onSuccess(AuthResult authResult) { + Log.d(TAG, "signInAnonymously:onComplete:success"); + promiseWithUser(authResult.getUser(), promise); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception exception) { + WritableMap error = authExceptionToMap(exception); + Log.e(TAG, "signInAnonymously:onComplete:failure", exception); + promise.reject(error.getString("code"), error.getString("message"), exception); } }); } + /** + * createUserWithEmailAndPassword + * @param email + * @param password + * @param promise + */ + @ReactMethod + public void createUserWithEmailAndPassword(final String email, final String password, final Promise promise) { + Log.d(TAG, "createUserWithEmailAndPassword"); + mAuth.createUserWithEmailAndPassword(email, password) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(AuthResult authResult) { + Log.d(TAG, "createUserWithEmailAndPassword:onComplete:success"); + promiseWithUser(authResult.getUser(), promise); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception exception) { + WritableMap error = authExceptionToMap(exception); + Log.e(TAG, "createUserWithEmailAndPassword:onComplete:failure", exception); + promise.reject(error.getString("code"), error.getString("message"), exception); + } + }); + } + + @ReactMethod public void signInWithEmail(final String email, final String password, final Callback callback) { @@ -194,27 +244,6 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { Utils.todoNote(TAG, "linkWithProvider", callback); } - @ReactMethod - public void signInAnonymously(final Promise promise) { - Log.d(TAG, "signInAnonymously"); - mAuth.signInAnonymously() - .addOnSuccessListener(new OnSuccessListener() { - @Override - public void onSuccess(AuthResult authResult) { - Log.d(TAG, "signInAnonymously:onComplete:success"); - promise.resolve(authResult.getUser()); - } - }) - .addOnFailureListener(new OnFailureListener() { - @Override - public void onFailure(@NonNull Exception exception) { - WritableMap error = authExceptionToMap(exception); - Log.e(TAG, "signInAnonymously:onComplete:failure", exception); - promise.reject(error.getString("code"), error.getString("message"), exception); - } - }); - } - @ReactMethod public void signInWithCustomToken(final String customToken, final Callback callback) { mAuth.signInWithCustomToken(customToken) @@ -453,15 +482,6 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { } } - @ReactMethod - public void signOut(final Callback callback) { - mAuth.signOut(); - - WritableMap resp = Arguments.createMap(); - resp.putString("status", "complete"); - resp.putString("msg", "User signed out"); - callback.invoke(null, resp); - } @ReactMethod public void reloadUser(final Callback callback) { @@ -543,10 +563,53 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { * ---------------- */ /** - * + * Resolves or rejects an auth method promise without a user (user was missing) + * @param promise + * @param isError + */ + private void promiseNoUser(Promise promise, Boolean isError) { + if (isError) { + promise.reject("auth/no_current_user", "No user currently signed in."); + } else { + promise.resolve(null); + } + } + + /** + * @param user + * @param promise + */ + private void promiseWithUser(final FirebaseUser user, final Promise promise) { + if (user != null) { + user.getToken(true) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(GetTokenResult getTokenResult) { + Log.d(TAG, "promiseWithUser:getToken:success"); + WritableMap userMap = firebaseUserToMap(user); + userMap.putString("token", getTokenResult.getToken()); + promise.resolve(userMap); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception exception) { + WritableMap error = authExceptionToMap(exception); + Log.e(TAG, "promiseWithUser:getToken::failure", exception); + promise.reject(error.getString("code"), error.getString("message"), exception); + } + }); + } else { + promiseNoUser(promise, true); + } + } + + + /** * @param user * @param callback */ + @Deprecated private void userCallback(final FirebaseUser user, final Callback callback) { if (user != null) { user.getToken(true).addOnCompleteListener(new OnCompleteListener() { @@ -554,7 +617,7 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { - WritableMap userMap = getUserMap(user); + WritableMap userMap = firebaseUserToMap(user); userMap.putString("token", task.getResult().getToken()); callback.invoke(null, userMap); } else { @@ -570,8 +633,39 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { } } + /** + * @param user + * @return + */ + private WritableMap firebaseUserToMap(FirebaseUser user) { + WritableMap userMap = Arguments.createMap(); + + final String email = user.getEmail(); + final String uid = user.getUid(); + final String provider = user.getProviderId(); + final String name = user.getDisplayName(); + final Boolean verified = user.isEmailVerified(); + final Uri photoUrl = user.getPhotoUrl(); + + userMap.putString("email", email); + userMap.putString("uid", uid); + userMap.putString("providerId", provider); + userMap.putBoolean("emailVerified", verified); + + if (name != null) { + userMap.putString("name", name); + } + + if (photoUrl != null) { + userMap.putString("photoURL", photoUrl.toString()); + } + + return userMap; + } + /** * Returns web code and message values. + * * @param exception Auth exception * @return WritableMap writable map with code and message string values */ @@ -647,6 +741,7 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { * * @param callback JS callback */ + @Deprecated private void callbackNoUser(Callback callback, Boolean isError) { WritableMap err = Arguments.createMap(); err.putInt("code", NO_CURRENT_USER); @@ -671,33 +766,4 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule { error.putString("message", ex.getMessage()); onFail.invoke(error); } - - private WritableMap getUserMap(FirebaseUser user) { - WritableMap userMap = Arguments.createMap(); - if (user != null) { - final String email = user.getEmail(); - final String uid = user.getUid(); - final String provider = user.getProviderId(); - final String name = user.getDisplayName(); - final Boolean verified = user.isEmailVerified(); - final Uri photoUrl = user.getPhotoUrl(); - - userMap.putString("email", email); - userMap.putString("uid", uid); - userMap.putString("providerId", provider); - userMap.putBoolean("emailVerified", verified); - - if (name != null) { - userMap.putString("name", name); - } - - if (photoUrl != null) { - userMap.putString("photoURL", photoUrl.toString()); - } - } else { - userMap.putString("msg", "no user"); - } - - return userMap; - } } diff --git a/lib/modules/auth/index.js b/lib/modules/auth/index.js index 5f8acb7f..e0eb0d1b 100644 --- a/lib/modules/auth/index.js +++ b/lib/modules/auth/index.js @@ -28,21 +28,49 @@ export default class Auth extends Base { // generally though the initial event fired will get ignored // but this is ok as we fake it with the getCurrentUser below FirebaseAuthEvt.addListener('onAuthStateChanged', this._onAuthStateChanged.bind(this)); - FirebaseAuth.createAuthStateListener(); + FirebaseAuth.addAuthStateListener(); } /** * Internal auth changed listener * @param auth + * @param emit * @private */ - _onAuthStateChanged(auth: AuthResultType) { + _onAuthStateChanged(auth: AuthResultType, emit: Boolean = true) { this._authResult = auth; this.authenticated = auth ? auth.authenticated || false : false; if (auth && auth.user && !this._user) this._user = new User(this, auth); else if ((!auth || !auth.user) && this._user) this._user = null; else if (this._user) this._user._updateValues(auth); - this.emit('onAuthStateChanged', this._authResult.user || null); + if (emit) this.emit('onAuthStateChanged', this._authResult.user || null); + return auth ? this._user : null; + } + + + /** + * Remove auth change listener + * @param listener + */ + _offAuthStateChanged(listener: Function) { + this.log.info('Removing onAuthStateChanged listener'); + this.removeListener('onAuthStateChanged', listener); + } + + /** + * Intercept all user actions and send their results to + * auth state change before resolving + * @param promise + * @returns {Promise.|*} + * @private + */ + _interceptUserValue(promise) { + return promise.then((result) => { + if (!result) return this._onAuthStateChanged(null, false); + if (result.user) return this._onAuthStateChanged(result, false); + if (result.uid) return this._onAuthStateChanged({ user: result }, false); + return result; + }); } /* @@ -61,21 +89,19 @@ export default class Auth extends Base { } /** - * Remove auth change listener - * @param listener + * Sign the current user out + * @return {Promise} */ - _offAuthStateChanged(listener: Function) { - this.log.info('Removing onAuthStateChanged listener'); - this.removeListener('onAuthStateChanged', listener); + signOut(): Promise { + return this._interceptUserValue(FirebaseAuth.signOut()); } - /** * Sign a user in anonymously - * @return {Promise} A promise resolved upon completion + * @return {Promise} A promise resolved upon completion */ signInAnonymously(): Promise { - return FirebaseAuth.signInAnonymously(); + return this._interceptUserValue(FirebaseAuth.signInAnonymously()); } /** @@ -85,8 +111,7 @@ export default class Auth extends Base { * @return {Promise} A promise indicating the completion */ createUserWithEmailAndPassword(email: string, password: string): Promise { - this.log.info('Creating user with email and password', email); - return promisify('createUserWithEmail', FirebaseAuth, 'auth/')(email, password); + return this._interceptUserValue(FirebaseAuth.createUserWithEmailAndPassword(email, password)); } /** @@ -201,15 +226,6 @@ export default class Auth extends Base { return promisify('getToken', FirebaseAuth, 'auth/')(); } - - /** - * Sign the current user out - * @return {Promise} - */ - signOut(): Promise { - return promisify('signOut', FirebaseAuth, 'auth/')(); - } - /** * Get the currently signed in user * @return {Promise}