From 44a9f4148d30b324c7cad9385f750e79add10e7f Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Fri, 18 Nov 2016 17:40:25 +0000 Subject: [PATCH 01/15] Merge iOS database changes from fullstackreact/react-native-firestack#132 --- ios/Firestack/FirestackDatabase.m | 59 +++++++++++++++++++------------ 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/ios/Firestack/FirestackDatabase.m b/ios/Firestack/FirestackDatabase.m index 918feae..459e0d2 100644 --- a/ios/Firestack/FirestackDatabase.m +++ b/ios/Firestack/FirestackDatabase.m @@ -321,7 +321,8 @@ @implementation FirestackDatabase props:(NSDictionary *) props callback:(RCTResponseSenderBlock) callback) { - FIRDatabaseReference *ref = [[self getRefAtPath:path] childByAutoId]; + FIRDatabaseReference *pathRef = [self getRefAtPath:path]; + FIRDatabaseReference *ref = [pathRef childByAutoId]; NSURL *url = [NSURL URLWithString:ref.URL]; NSString *newPath = [url path]; @@ -351,12 +352,12 @@ @implementation FirestackDatabase RCT_EXPORT_METHOD(on:(NSString *) path modifiersString:(NSString *) modifiersString - modifiersArray:(NSArray *) modifiersArray + modifiers:(NSArray *) modifiers name:(NSString *) eventName callback:(RCTResponseSenderBlock) callback) { - FirestackDBReference *r = [self getDBHandle:path]; - FIRDatabaseQuery *query = [r getQueryWithModifiers:modifiersArray]; + FirestackDBReference *r = [self getDBHandle:path withModifiers:modifiersString]; + FIRDatabaseQuery *query = [r getQueryWithModifiers:modifiers]; if (![r isListeningTo:eventName]) { id withBlock = ^(FIRDataSnapshot * _Nonnull snapshot) { @@ -368,6 +369,7 @@ @implementation FirestackDatabase props: @{ @"eventName": eventName, @"path": path, + @"modifiersString": modifiersString, @"snapshot": props }]; }; @@ -399,14 +401,14 @@ @implementation FirestackDatabase } RCT_EXPORT_METHOD(onOnce:(NSString *) path - modifiersString:(NSString *) modifiersString - modifiersArray:(NSArray *) modifiersArray - name:(NSString *) name - callback:(RCTResponseSenderBlock) callback) + modifiersString:(NSString *) modifiersString + modifiers:(NSArray *) modifiers + name:(NSString *) name + callback:(RCTResponseSenderBlock) callback) { - FirestackDBReference *r = [self getDBHandle:path]; + FirestackDBReference *r = [self getDBHandle:path withModifiers:modifiersString]; int eventType = [r eventTypeFromName:name]; - FIRDatabaseQuery *ref = [r getQueryWithModifiers:modifiersArray]; + FIRDatabaseQuery *ref = [r getQueryWithModifiers:modifiers]; [ref observeSingleEventOfType:eventType withBlock:^(FIRDataSnapshot * _Nonnull snapshot) { @@ -414,6 +416,7 @@ @implementation FirestackDatabase callback(@[[NSNull null], @{ @"eventName": name, @"path": path, + @"modifiersString": modifiersString, @"snapshot": props }]); } @@ -431,14 +434,14 @@ @implementation FirestackDatabase eventName:(NSString *) eventName callback:(RCTResponseSenderBlock) callback) { - FirestackDBReference *r = [self getDBHandle:path]; + FirestackDBReference *r = [self getDBHandle:path withModifiers:modifiersString]; if (eventName == nil || [eventName isEqualToString:@""]) { [r cleanup]; - [self removeDBHandle:path]; + [self removeDBHandle:path withModifiersString:modifiersString]; } else { [r removeEventHandler:eventName]; if (![r hasListeners]) { - [self removeDBHandle:path]; + [self removeDBHandle:path withModifiersString:modifiersString]; } } @@ -447,6 +450,7 @@ @implementation FirestackDatabase callback(@[[NSNull null], @{ @"result": @"success", @"path": path, + @"modifiersString": modifiersString, @"remainingListeners": [r listenerKeys], }]); } @@ -540,10 +544,9 @@ - (FIRDatabaseReference *) getRef return self.ref; } -- (FIRDatabaseReference *) getRefAtPath:(NSString *) str +- (FIRDatabaseReference *) getRefAtPath:(NSString *) path { - FirestackDBReference *r = [self getDBHandle:str]; - return [r getRef]; + return [[FIRDatabase database] referenceWithPath:path]; } // Handles @@ -555,36 +558,48 @@ - (NSDictionary *) storedDBHandles return __DBHandles; } +- (NSString *) getDBListenerKey:(NSString *) path + withModifiers:(NSString *) modifiersString +{ + return [NSString stringWithFormat:@"%@ | %@", path, modifiersString, nil]; +} + - (FirestackDBReference *) getDBHandle:(NSString *) path + withModifiers:modifiersString { NSDictionary *stored = [self storedDBHandles]; - FirestackDBReference *r = [stored objectForKey:path]; + NSString *key = [self getDBListenerKey:path withModifiers:modifiersString]; + FirestackDBReference *r = [stored objectForKey:key]; if (r == nil) { r = [[FirestackDBReference alloc] initWithPath:path]; - [self saveDBHandle:path dbRef:r]; + [self saveDBHandle:path withModifiersString:modifiersString dbRef:r]; } return r; } - (void) saveDBHandle:(NSString *) path + withModifiersString:(NSString*)modifiersString dbRef:(FirestackDBReference *) dbRef { NSMutableDictionary *stored = [[self storedDBHandles] mutableCopy]; - if ([stored objectForKey:path]) { - FirestackDBReference *r = [stored objectForKey:path]; + NSString *key = [self getDBListenerKey:path withModifiers:modifiersString]; + if ([stored objectForKey:key]) { + FirestackDBReference *r = [stored objectForKey:key]; [r cleanup]; } - [stored setObject:dbRef forKey:path]; + [stored setObject:dbRef forKey:key]; self._DBHandles = stored; } - (void) removeDBHandle:(NSString *) path + withModifiersString:(NSString*)modifiersString { NSMutableDictionary *stored = [[self storedDBHandles] mutableCopy]; + NSString *key = [self getDBListenerKey:path withModifiers:modifiersString]; - FirestackDBReference *r = [stored objectForKey:path]; + FirestackDBReference *r = [stored objectForKey:key]; if (r != nil) { [r cleanup]; } From 92de517199b9c415e621aada0ddffed7b806a497 Mon Sep 17 00:00:00 2001 From: Michael Diarmid Date: Fri, 18 Nov 2016 18:18:57 +0000 Subject: [PATCH 02/15] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ca064bd..d4596ad 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,11 @@ Featuring; authentication, storage, real-time database, presence, analytics, clo ## Firestack vs Firebase JS lib -Although the [Firebase](https://www.npmjs.com/package/firebase) JavaScript library will work with React Native, it's designed for the web and/or server. The native SDKs provide much needed features specifically for mobile applications such as offline persistance. Firestack provides a JavaScript interface into the native SDKs to allow your React Native application to utilise these features, and more! +Although the [Firebase](https://www.npmjs.com/package/firebase) JavaScript library will work with React Native, it is mainly designed for the web. + +The native SDK's are much better for performance compared to the web SDK. The web SDK will run on the same thread as your apps ([JS thread](https://facebook.github.io/react-native/docs/performance.html#javascript-frame-rate)) therefore limiting your JS framerate, potentially affecting things touch events and transitions/animations. + +The native SDK's also contains functionality that the web SDK's do not, for example [Analytics](/docs/api/analytics.md). ## Example app From d97c21e2e110d511ec1bf95885135e95727e6be4 Mon Sep 17 00:00:00 2001 From: Matt Jeanes Date: Fri, 18 Nov 2016 15:06:01 -0500 Subject: [PATCH 03/15] Fix Disconnect not being referenced in reference.js --- lib/modules/database/reference.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/modules/database/reference.js b/lib/modules/database/reference.js index ece4f74..a42a046 100644 --- a/lib/modules/database/reference.js +++ b/lib/modules/database/reference.js @@ -5,6 +5,7 @@ import { NativeModules } from 'react-native'; import promisify from './../../utils/promisify'; import { ReferenceBase } from './../base'; import Snapshot from './snapshot.js'; +import Disconnect from './disconnect.js'; import Query from './query.js'; const FirestackDatabase = NativeModules.FirestackDatabase; From 4494eeab6eb87663fe925816c438f2db69452e7b Mon Sep 17 00:00:00 2001 From: Matt Jeanes Date: Fri, 18 Nov 2016 15:27:20 -0500 Subject: [PATCH 04/15] Fix missing promisify in disconnect.js, add flow --- lib/modules/database/disconnect.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/modules/database/disconnect.js b/lib/modules/database/disconnect.js index 4b1733e..4c9fdcb 100644 --- a/lib/modules/database/disconnect.js +++ b/lib/modules/database/disconnect.js @@ -1,5 +1,7 @@ +/* @flow */ import { NativeModules } from 'react-native'; +import promisify from './../../utils/promisify'; import Reference from './reference'; const FirestackDatabase = NativeModules.FirestackDatabase; From 2d7901add988ba9dc9bc7fb488a4039b7f162ba9 Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Sat, 19 Nov 2016 13:29:44 +0000 Subject: [PATCH 05/15] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d4596ad..ef887fe 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Although the [Firebase](https://www.npmjs.com/package/firebase) JavaScript libra The native SDK's are much better for performance compared to the web SDK. The web SDK will run on the same thread as your apps ([JS thread](https://facebook.github.io/react-native/docs/performance.html#javascript-frame-rate)) therefore limiting your JS framerate, potentially affecting things touch events and transitions/animations. -The native SDK's also contains functionality that the web SDK's do not, for example [Analytics](/docs/api/analytics.md). +The native SDK's also contains functionality that the web SDK's do not, for example [Analytics](/docs/api/analytics.md) and [Remote Config](/docs/api/remote-config.md). ## Example app @@ -40,6 +40,7 @@ We have a working application example available in at [fullstackreact/FirestackA * [Presence](docs/api/presence.md) * [ServerValue](docs/api/server-value.md) * [Cloud Messaging](docs/api/cloud-messaging.md) + * [Remote Config](docs/api/remote-config.md) * [Events](docs/api/events.md) * [Redux](docs/redux.md) From 42bdbfb1d487fd0c1a1c69ed68961c7e02f4bc3c Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Sat, 19 Nov 2016 13:31:35 +0000 Subject: [PATCH 06/15] Create remote-config.md --- docs/api/remote-config.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/api/remote-config.md diff --git a/docs/api/remote-config.md b/docs/api/remote-config.md new file mode 100644 index 0000000..413c634 --- /dev/null +++ b/docs/api/remote-config.md @@ -0,0 +1 @@ +# Remote Config From 15bd34346581c86068cbbc8898e4bcaffe4e2fff Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Sat, 19 Nov 2016 13:42:00 +0000 Subject: [PATCH 07/15] Update authentication.md --- docs/api/authentication.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/api/authentication.md b/docs/api/authentication.md index dd234cf..9d8e9aa 100644 --- a/docs/api/authentication.md +++ b/docs/api/authentication.md @@ -26,7 +26,7 @@ class Example extends React.Component { } componentDidMount() { - this.unsubscribe = firebase.auth().onAuthStateChanged(function(user) { + this.unsubscribe = firebase.auth().onAuthStateChanged((user) => { if (user) { // User is signed in. } @@ -34,7 +34,7 @@ class Example extends React.Component { } componentWillUnmount() { - if (this.listener) { + if (this.unsubscribe) { this.unsubscribe(); } } @@ -48,7 +48,7 @@ We can create a user by calling the `createUserWithEmailAndPassword()` function. The method accepts two parameters, an email and a password. ```javascript -firestack.auth().createUserWithEmailAndPassword('ari@fullstack.io', '123456') +firestack.auth().createUserWithEmailAndPassword('foo@bar.com', '123456') .then((user) => { console.log('user created', user) }) @@ -63,7 +63,7 @@ To sign a user in with their email and password, use the `signInWithEmailAndPass It accepts two parameters, the user's email and password: ```javascript -firestack.auth().signInWithEmailAndPassword('ari@fullstack.io', '123456') +firestack.auth().signInWithEmailAndPassword('foo@bar.com', '123456') .then((user) => { console.log('User successfully logged in', user) }) @@ -111,7 +111,7 @@ firestack.auth().signInWithCredential(credential) }) .catch((err) => { console.error('User signin error', err); - }) + }); ``` #### [`signInWithCustomToken(token: string): Promise`](https://firebase.google.com/docs/reference/js/firebase.auth.Auth#signInWithCustomToken) From c97f4a7804c6bd46f522d654119b69ea703d7775 Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Sat, 19 Nov 2016 13:42:38 +0000 Subject: [PATCH 08/15] Update authentication.md --- docs/api/authentication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/authentication.md b/docs/api/authentication.md index 9d8e9aa..de481b4 100644 --- a/docs/api/authentication.md +++ b/docs/api/authentication.md @@ -9,7 +9,7 @@ Firestack handles authentication for us out of the box, both with email/password ### Properties ##### `authenticated: boolean` - Returns the current Firebase authentication state. -##### `currentUser: User | null` - Returns the currently signed-in user (or null). See the [User](/docs/api/authentication#user) class documentation for further usage. +##### `currentUser: User | null` - Returns the currently signed-in user (or null). See the [User](/docs/api/authentication.md#user) class documentation for further usage. ### Methods From 7329028073f744434f5fa6bfd049593cf1175baa Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Sat, 19 Nov 2016 13:43:32 +0000 Subject: [PATCH 09/15] Update authentication.md --- docs/api/authentication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/authentication.md b/docs/api/authentication.md index de481b4..0cc439b 100644 --- a/docs/api/authentication.md +++ b/docs/api/authentication.md @@ -2,7 +2,7 @@ Firestack handles authentication for us out of the box, both with email/password-based authentication and through oauth providers (with a separate library to handle oauth providers). -> Android requires the Google Play services to installed for authentication to function. +> Authentication requires Google Play services to be installed on Android. ## Auth From 99f1463bac776fd411dd7492274574287f7cfd34 Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Sat, 19 Nov 2016 17:41:57 +0000 Subject: [PATCH 10/15] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef887fe..e4a609d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ npm i react-native-firestack --save [![npm version](https://img.shields.io/npm/v/react-native-firestack.svg)](https://www.npmjs.com/package/react-native-firestack) [![License](https://img.shields.io/npm/l/react-native-firestack.svg)](/LICENSE) -Firestack is a _light-weight_ layer sitting on-top of the native Firebase libraries for both iOS and Android which mirrors the React Native JS api as closely as possible. It features: +Firestack is a _light-weight_ layer sitting on-top of the native Firebase libraries for both iOS and Android which mirrors the React Native JS api as closely as possible. Featuring; authentication, storage, real-time database, presence, analytics, cloud messaging, remote configuration, redux support and more! From 91ace7a974b9ea2147e595647d111db4db8dd5e9 Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Sun, 20 Nov 2016 15:25:18 +0000 Subject: [PATCH 11/15] Simplify Java auth and remove possibility of user synchronisation issues --- .../io/fullstack/firestack/FirestackAuth.java | 105 ++++++------------ lib/modules/auth.js | 7 -- 2 files changed, 31 insertions(+), 81 deletions(-) diff --git a/android/src/main/java/io/fullstack/firestack/FirestackAuth.java b/android/src/main/java/io/fullstack/firestack/FirestackAuth.java index b4cc28e..b41ea12 100644 --- a/android/src/main/java/io/fullstack/firestack/FirestackAuth.java +++ b/android/src/main/java/io/fullstack/firestack/FirestackAuth.java @@ -19,7 +19,6 @@ import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; -import com.google.firebase.FirebaseApp; import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.AuthResult; @@ -42,14 +41,12 @@ class FirestackAuthModule extends ReactContextBaseJavaModule { // private Context context; private ReactContext mReactContext; private FirebaseAuth mAuth; - private FirebaseApp app; - private FirebaseUser user; private FirebaseAuth.AuthStateListener mAuthListener; public FirestackAuthModule(ReactApplicationContext reactContext) { super(reactContext); - // this.context = reactContext; mReactContext = reactContext; + mAuth = FirebaseAuth.getInstance(); Log.d(TAG, "New FirestackAuth instance"); } @@ -78,16 +75,17 @@ private void callbackNoUser(Callback callback, Boolean isError) { @ReactMethod public void listenForAuth() { - if (mAuthListener == null || mAuth == null) { + if (mAuthListener == null) { mAuthListener = new FirebaseAuth.AuthStateListener() { @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { + FirebaseUser user = firebaseAuth.getCurrentUser(); WritableMap msgMap = Arguments.createMap(); msgMap.putString("eventName", "listenForAuth"); - if (FirestackAuthModule.this.user != null) { + if (user != null) { // TODO move to helper - WritableMap userMap = getUserMap(); + WritableMap userMap = getUserMap(user); msgMap.putBoolean("authenticated", true); msgMap.putMap("user", userMap); @@ -98,8 +96,6 @@ public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { } } }; - - mAuth = FirebaseAuth.getInstance(); mAuth.addAuthStateListener(mAuthListener); } } @@ -119,16 +115,13 @@ public void unlistenForAuth(final Callback callback) { @ReactMethod public void createUserWithEmail(final String email, final String password, final Callback callback) { - mAuth = FirebaseAuth.getInstance(); - mAuth.createUserWithEmailAndPassword(email, password) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { - FirestackAuthModule.this.user = task.getResult().getUser(); - userCallback(FirestackAuthModule.this.user, callback); + userCallback(task.getResult().getUser(), callback); } else { userErrorCallback(task, callback); } @@ -141,7 +134,6 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void signInWithEmail(final String email, final String password, final Callback callback) { - mAuth = FirebaseAuth.getInstance(); mAuth.signInWithEmailAndPassword(email, password) .addOnCompleteListener(new OnCompleteListener() { @@ -149,8 +141,7 @@ public void signInWithEmail(final String email, final String password, final Cal public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { - FirestackAuthModule.this.user = task.getResult().getUser(); - userCallback(FirestackAuthModule.this.user, callback); + userCallback(task.getResult().getUser(), callback); } else { userErrorCallback(task, callback); } @@ -175,9 +166,6 @@ public void signInWithProvider(final String provider, final String authToken, fi @ReactMethod public void signInAnonymously(final Callback callback) { Log.d(TAG, "signInAnonymously:called:"); - mAuth = FirebaseAuth.getInstance(); - - mAuth.signInAnonymously() .addOnCompleteListener(new OnCompleteListener() { @Override @@ -186,8 +174,7 @@ public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { - FirestackAuthModule.this.user = task.getResult().getUser(); - userCallback(FirestackAuthModule.this.user, callback); + userCallback(task.getResult().getUser(), callback); } else { userErrorCallback(task, callback); } @@ -200,8 +187,6 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void signInWithCustomToken(final String customToken, final Callback callback) { - mAuth = FirebaseAuth.getInstance(); - mAuth.signInWithCustomToken(customToken) .addOnCompleteListener(new OnCompleteListener() { @Override @@ -209,8 +194,7 @@ public void onComplete(@NonNull Task task) { Log.d(TAG, "signInWithCustomToken:onComplete:" + task.isSuccessful()); try { if (task.isSuccessful()) { - FirestackAuthModule.this.user = task.getResult().getUser(); - userCallback(FirestackAuthModule.this.user, callback); + userCallback(task.getResult().getUser(), callback); } else { userErrorCallback(task, callback); } @@ -231,7 +215,7 @@ public void reauthenticateWithCredentialForProvider(final String provider, final @ReactMethod public void updateUserEmail(final String email, final Callback callback) { - FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + FirebaseUser user = mAuth.getCurrentUser(); if (user != null) { user @@ -242,8 +226,7 @@ public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { Log.d(TAG, "User email address updated"); - FirebaseUser u = FirebaseAuth.getInstance().getCurrentUser(); - userCallback(u, callback); + userCallback(mAuth.getCurrentUser(), callback); } else { userErrorCallback(task, callback); } @@ -259,7 +242,7 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void updateUserPassword(final String newPassword, final Callback callback) { - FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + FirebaseUser user = mAuth.getCurrentUser(); if (user != null) { user.updatePassword(newPassword) @@ -269,9 +252,7 @@ public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { Log.d(TAG, "User password updated"); - - FirebaseUser u = FirebaseAuth.getInstance().getCurrentUser(); - userCallback(u, callback); + userCallback(mAuth.getCurrentUser(), callback); } else { userErrorCallback(task, callback); } @@ -287,8 +268,6 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void sendPasswordResetWithEmail(final String email, final Callback callback) { - mAuth = FirebaseAuth.getInstance(); - mAuth.sendPasswordResetEmail(email) .addOnCompleteListener(new OnCompleteListener() { @Override @@ -310,7 +289,7 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void deleteUser(final Callback callback) { - FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + FirebaseUser user = mAuth.getCurrentUser(); if (user != null) { user.delete() .addOnCompleteListener(new OnCompleteListener() { @@ -339,7 +318,7 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void sendEmailVerification(final Callback callback) { - FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + FirebaseUser user = mAuth.getCurrentUser(); if (user != null) { user.sendEmailVerification() @@ -371,7 +350,7 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void getToken(final Callback callback) { - FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + FirebaseUser user = mAuth.getCurrentUser(); if (user != null) { user.getToken(true) @@ -403,7 +382,7 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void updateUserProfile(ReadableMap props, final Callback callback) { - FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + FirebaseUser user = mAuth.getCurrentUser(); if (user != null) { UserProfileChangeRequest.Builder profileBuilder = new UserProfileChangeRequest.Builder(); @@ -430,8 +409,7 @@ public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { Log.d(TAG, "User profile updated"); - FirebaseUser u = FirebaseAuth.getInstance().getCurrentUser(); - userCallback(u, callback); + userCallback(mAuth.getCurrentUser(), callback); } else { userErrorCallback(task, callback); } @@ -447,8 +425,7 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void signOut(final Callback callback) { - FirebaseAuth.getInstance().signOut(); - this.user = null; + mAuth.signOut(); WritableMap resp = Arguments.createMap(); resp.putString("status", "complete"); @@ -458,22 +435,18 @@ public void signOut(final Callback callback) { @ReactMethod public void getCurrentUser(final Callback callback) { - mAuth = FirebaseAuth.getInstance(); - - this.user = mAuth.getCurrentUser(); - if (this.user == null) { + FirebaseUser user = mAuth.getCurrentUser(); + if (user == null) { callbackNoUser(callback, false); } else { - Log.d("USRC", this.user.getUid()); - userCallback(this.user, callback); + Log.d("USRC", user.getUid()); + userCallback(user, callback); } } // TODO: Check these things @ReactMethod public void googleLogin(String IdToken, final Callback callback) { - mAuth = FirebaseAuth.getInstance(); - AuthCredential credential = GoogleAuthProvider.getCredential(IdToken, null); mAuth.signInWithCredential(credential) .addOnCompleteListener(new OnCompleteListener() { @@ -481,8 +454,7 @@ public void googleLogin(String IdToken, final Callback callback) { public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { - FirestackAuthModule.this.user = task.getResult().getUser(); - userCallback(FirestackAuthModule.this.user, callback); + userCallback(task.getResult().getUser(), callback); } else { userErrorCallback(task, callback); } @@ -495,8 +467,6 @@ public void onComplete(@NonNull Task task) { @ReactMethod public void facebookLogin(String Token, final Callback callback) { - mAuth = FirebaseAuth.getInstance(); - AuthCredential credential = FacebookAuthProvider.getCredential(Token); mAuth.signInWithCredential(credential) .addOnCompleteListener(new OnCompleteListener() { @@ -504,8 +474,7 @@ public void facebookLogin(String Token, final Callback callback) { public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { - FirestackAuthModule.this.user = task.getResult().getUser(); - userCallback(FirestackAuthModule.this.user, callback); + userCallback(task.getResult().getUser(), callback); } else { userErrorCallback(task, callback); } @@ -517,24 +486,15 @@ public void onComplete(@NonNull Task task) { } // Internal helpers - private void userCallback(FirebaseUser passedUser, final Callback callback) { - - if (passedUser == null) { - mAuth = FirebaseAuth.getInstance(); - this.user = mAuth.getCurrentUser(); - } else { - this.user = passedUser; - } - - if (this.user != null) { - this.user.getToken(true).addOnCompleteListener(new OnCompleteListener() { + private void userCallback(final FirebaseUser user, final Callback callback) { + if (user != null) { + user.getToken(true).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { try { if (task.isSuccessful()) { - WritableMap userMap = getUserMap(); - final String token = task.getResult().getToken(); - userMap.putString("token", token); + WritableMap userMap = getUserMap(user); + userMap.putString("token", task.getResult().getToken()); callback.invoke(null, userMap); } else { userErrorCallback(task, callback); @@ -567,11 +527,8 @@ private void userExceptionCallback(Exception ex, final Callback onFail) { onFail.invoke(error); } - private WritableMap getUserMap() { + private WritableMap getUserMap(FirebaseUser user) { WritableMap userMap = Arguments.createMap(); - - FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); - if (user != null) { final String email = user.getEmail(); final String uid = user.getUid(); diff --git a/lib/modules/auth.js b/lib/modules/auth.js index 6963fbf..04e5775 100644 --- a/lib/modules/auth.js +++ b/lib/modules/auth.js @@ -26,13 +26,6 @@ export default class Auth extends Base { // but this is ok as we fake it with the getCurrentUser below FirestackAuthEvt.addListener('listenForAuth', this._onAuthStateChanged.bind(this)); FirestackAuth.listenForAuth(); - - this.getCurrentUser().then((u: Object) => { - this._onAuthStateChanged({ authenticated: !!u, user: u || null }); - }).catch(() => { - // todo check if error contains user disabled message maybe and add a disabled flag? - this._onAuthStateChanged({ authenticated: false, user: null }); - }); } /** From 911924f4f7ab4914e7db20cc48c299a147fcb5b0 Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Mon, 21 Nov 2016 08:10:41 +0000 Subject: [PATCH 12/15] Allow Java database module to deal with Array data types in the same way as iOS --- .../firestack/FirestackDatabase.java | 50 -------- .../fullstack/firestack/FirestackUtils.java | 111 ++++++++++++++---- 2 files changed, 86 insertions(+), 75 deletions(-) diff --git a/android/src/main/java/io/fullstack/firestack/FirestackDatabase.java b/android/src/main/java/io/fullstack/firestack/FirestackDatabase.java index 4cdf613..334857d 100644 --- a/android/src/main/java/io/fullstack/firestack/FirestackDatabase.java +++ b/android/src/main/java/io/fullstack/firestack/FirestackDatabase.java @@ -618,54 +618,4 @@ private DatabaseReference getDatabaseReferenceAtPath(final String path) { DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference(path); return mDatabase; } - - - //private WritableMap dataSnapshotToMap(String name, String path, DataSnapshot dataSnapshot) { - // return FirestackUtils.dataSnapshotToMap(name, path, dataSnapshot); - //} - - private Any castSnapshotValue(DataSnapshot snapshot) { - if (snapshot.hasChildren()) { - WritableMap data = Arguments.createMap(); - for (DataSnapshot child : snapshot.getChildren()) { - Any castedChild = castSnapshotValue(child); - switch (castedChild.getClass().getName()) { - case "java.lang.Boolean": - data.putBoolean(child.getKey(), (Boolean) castedChild); - break; - case "java.lang.Long": - data.putDouble(child.getKey(), (Long) castedChild); - break; - case "java.lang.Double": - data.putDouble(child.getKey(), (Double) castedChild); - break; - case "java.lang.String": - data.putString(child.getKey(), (String) castedChild); - break; - case "com.facebook.react.bridge.WritableNativeMap": - data.putMap(child.getKey(), (WritableMap) castedChild); - break; - } - } - return (Any) data; - } else { - if (snapshot.getValue() != null) { - String type = snapshot.getValue().getClass().getName(); - switch (type) { - case "java.lang.Boolean": - return (Any)((Boolean) snapshot.getValue()); - case "java.lang.Long": - return (Any) ((Long) snapshot.getValue()); - case "java.lang.Double": - return (Any)((Double) snapshot.getValue()); - case "java.lang.String": - return (Any)((String) snapshot.getValue()); - default: - return (Any) null; - } - } else { - return (Any) null; - } - } - } } diff --git a/android/src/main/java/io/fullstack/firestack/FirestackUtils.java b/android/src/main/java/io/fullstack/firestack/FirestackUtils.java index ae1bb95..669e337 100644 --- a/android/src/main/java/io/fullstack/firestack/FirestackUtils.java +++ b/android/src/main/java/io/fullstack/firestack/FirestackUtils.java @@ -109,32 +109,11 @@ public static WritableMap dataSnapshotToMap( public static Any castSnapshotValue(DataSnapshot snapshot) { if (snapshot.hasChildren()) { - WritableMap data = Arguments.createMap(); - for (DataSnapshot child : snapshot.getChildren()) { - Any castedChild = castSnapshotValue(child); - switch (castedChild.getClass().getName()) { - case "java.lang.Boolean": - data.putBoolean(child.getKey(), (Boolean) castedChild); - break; - case "java.lang.Long": - Long longVal = (Long) castedChild; - data.putDouble(child.getKey(), (double) longVal); - break; - case "java.lang.Double": - data.putDouble(child.getKey(), (Double) castedChild); - break; - case "java.lang.String": - data.putString(child.getKey(), (String) castedChild); - break; - case "com.facebook.react.bridge.WritableNativeMap": - data.putMap(child.getKey(), (WritableMap) castedChild); - break; - default: - Log.w(TAG, "Invalid type: " + castedChild.getClass().getName()); - break; - } + if (isArray(snapshot)) { + return (Any) buildArray(snapshot); + } else { + return (Any) buildMap(snapshot); } - return (Any) data; } else { if (snapshot.getValue() != null) { String type = snapshot.getValue().getClass().getName(); @@ -156,6 +135,88 @@ public static Any castSnapshotValue(DataSnapshot snapshot) { } } + private static boolean isArray(DataSnapshot snapshot) { + long expectedKey = 0; + for (DataSnapshot child : snapshot.getChildren()) { + try { + long key = Long.parseLong(child.getKey()); + if (key == expectedKey) { + expectedKey++; + } else { + return false; + } + } catch (NumberFormatException ex) { + return false; + } + } + return true; + } + + private static WritableArray buildArray(DataSnapshot snapshot) { + WritableArray array = Arguments.createArray(); + for (DataSnapshot child : snapshot.getChildren()) { + Any castedChild = castSnapshotValue(child); + switch (castedChild.getClass().getName()) { + case "java.lang.Boolean": + array.pushBoolean((Boolean) castedChild); + break; + case "java.lang.Long": + Long longVal = (Long) castedChild; + array.pushDouble((double) longVal); + break; + case "java.lang.Double": + array.pushDouble((Double) castedChild); + break; + case "java.lang.String": + array.pushString((String) castedChild); + break; + case "com.facebook.react.bridge.WritableNativeMap": + array.pushMap((WritableMap) castedChild); + break; + case "com.facebook.react.bridge.WritableNativeArray": + array.pushArray((WritableArray) castedChild); + break; + default: + Log.w(TAG, "Invalid type: " + castedChild.getClass().getName()); + break; + } + } + return array; + } + + private static WritableMap buildMap(DataSnapshot snapshot) { + WritableMap map = Arguments.createMap(); + for (DataSnapshot child : snapshot.getChildren()) { + Any castedChild = castSnapshotValue(child); + + switch (castedChild.getClass().getName()) { + case "java.lang.Boolean": + map.putBoolean(child.getKey(), (Boolean) castedChild); + break; + case "java.lang.Long": + Long longVal = (Long) castedChild; + map.putDouble(child.getKey(), (double) longVal); + break; + case "java.lang.Double": + map.putDouble(child.getKey(), (Double) castedChild); + break; + case "java.lang.String": + map.putString(child.getKey(), (String) castedChild); + break; + case "com.facebook.react.bridge.WritableNativeMap": + map.putMap(child.getKey(), (WritableMap) castedChild); + break; + case "com.facebook.react.bridge.WritableNativeArray": + map.putArray(child.getKey(), (WritableArray) castedChild); + break; + default: + Log.w(TAG, "Invalid type: " + castedChild.getClass().getName()); + break; + } + } + return map; + } + public static WritableArray getChildKeys(DataSnapshot snapshot) { WritableArray childKeys = Arguments.createArray(); From b3ea010c75b9824e73aa950b5a01c04f7723e58e Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Mon, 21 Nov 2016 11:15:40 +0000 Subject: [PATCH 13/15] Allow Java file upload to work with Camera Roll asset URLs in the same way that iOS does --- .../fullstack/firestack/FirestackStorage.java | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/android/src/main/java/io/fullstack/firestack/FirestackStorage.java b/android/src/main/java/io/fullstack/firestack/FirestackStorage.java index 0794f65..b41301d 100644 --- a/android/src/main/java/io/fullstack/firestack/FirestackStorage.java +++ b/android/src/main/java/io/fullstack/firestack/FirestackStorage.java @@ -49,11 +49,8 @@ class FirestackStorageModule extends ReactContextBaseJavaModule { private static final String FileTypeRegular = "FILETYPE_REGULAR"; private static final String FileTypeDirectory = "FILETYPE_DIRECTORY"; - private ReactContext mReactContext; - public FirestackStorageModule(ReactApplicationContext reactContext) { super(reactContext); - mReactContext = reactContext; Log.d(TAG, "New instance"); } @@ -142,7 +139,13 @@ public void uploadFile(final String urlStr, final String name, final String file Log.i(TAG, "From file: " + filepath + " to " + urlStr + " with name " + name); try { - Uri file = Uri.fromFile(new File(filepath)); + Uri file; + if (filepath.startsWith("content://")) { + String realPath = getRealPathFromURI(filepath); + file = Uri.fromFile(new File(realPath)); + } else { + file = Uri.fromFile(new File(filepath)); + } StorageMetadata.Builder metadataBuilder = new StorageMetadata.Builder(); Map m = FirestackUtils.recursivelyDeconstructReadableMap(metadata); @@ -190,7 +193,7 @@ public void onProgress(UploadTask.TaskSnapshot taskSnapshot) { WritableMap data = Arguments.createMap(); data.putString("eventName", "upload_progress"); data.putDouble("progress", progress); - FirestackUtils.sendEvent(mReactContext, "upload_progress", data); + FirestackUtils.sendEvent(getReactApplicationContext(), "upload_progress", data); } } }) @@ -203,7 +206,7 @@ public void onPaused(UploadTask.TaskSnapshot taskSnapshot) { WritableMap data = Arguments.createMap(); data.putString("eventName", "upload_paused"); data.putString("ref", bucket); - FirestackUtils.sendEvent(mReactContext, "upload_paused", data); + FirestackUtils.sendEvent(getReactApplicationContext(), "upload_paused", data); } }); } catch (Exception ex) { @@ -214,14 +217,7 @@ public void onPaused(UploadTask.TaskSnapshot taskSnapshot) { @ReactMethod public void getRealPathFromURI(final String uri, final Callback callback) { try { - Context context = getReactApplicationContext(); - String[] proj = {MediaStore.Images.Media.DATA}; - Cursor cursor = context.getContentResolver().query(Uri.parse(uri), proj, null, null, null); - int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - cursor.moveToFirst(); - String path = cursor.getString(column_index); - cursor.close(); - + String path = getRealPathFromURI(uri); callback.invoke(null, path); } catch (Exception ex) { ex.printStackTrace(); @@ -229,6 +225,21 @@ public void getRealPathFromURI(final String uri, final Callback callback) { } } + private String getRealPathFromURI(final String uri) { + Cursor cursor = null; + try { + String[] proj = {MediaStore.Images.Media.DATA}; + cursor = getReactApplicationContext().getContentResolver().query(Uri.parse(uri), proj, null, null, null); + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + return cursor.getString(column_index); + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + private WritableMap getDownloadData(final UploadTask.TaskSnapshot taskSnapshot) { Uri downloadUrl = taskSnapshot.getDownloadUrl(); StorageMetadata d = taskSnapshot.getMetadata(); From 363c1b6ce29c5b3b9d625817827d73b6b864759b Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Mon, 21 Nov 2016 11:17:10 +0000 Subject: [PATCH 14/15] Quick fix to prevent duplicate child event listeners on Java database module --- .../java/io/fullstack/firestack/FirestackDatabase.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/io/fullstack/firestack/FirestackDatabase.java b/android/src/main/java/io/fullstack/firestack/FirestackDatabase.java index 334857d..b12289c 100644 --- a/android/src/main/java/io/fullstack/firestack/FirestackDatabase.java +++ b/android/src/main/java/io/fullstack/firestack/FirestackDatabase.java @@ -10,6 +10,7 @@ import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReactMethod; @@ -79,11 +80,9 @@ public void onCancelled(DatabaseError error) { self.handleDatabaseError(name, mPath, error); } }; + Query ref = this.getDatabaseQueryAtPathAndModifiers(modifiersArray); + ref.addChildEventListener(mEventListener); } - - Query ref = this.getDatabaseQueryAtPathAndModifiers(modifiersArray); - ref.addChildEventListener(mEventListener); - //this.setListeningTo(mPath, modifiersString, name); } public void addValueEventListener(final String name, final ReadableArray modifiersArray, final String modifiersString) { From 1882af742444606ea391acc5730856d479f8b39e Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Mon, 21 Nov 2016 12:20:12 +0000 Subject: [PATCH 15/15] Update authentication.md --- docs/api/authentication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/authentication.md b/docs/api/authentication.md index 0cc439b..d787374 100644 --- a/docs/api/authentication.md +++ b/docs/api/authentication.md @@ -258,7 +258,7 @@ firestack.auth().updateUserEmail('foo@bar.com') Important: this is a security sensitive operation that requires the user to have recently signed in. If this requirement isn't met, ask the user to authenticate again and then call firebase.User#reauthenticate. This will Promise reject is the user is anonymous. ```javascript -firestack.auth().updateUserPassword('foobar1234') +firestack.auth().updatePassword('foobar1234') .then() .catch(); ```