diff --git a/.gitignore b/.gitignore index 2790ab5..8c5de3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .git.safe /node_modules .DS_Store +*.iml +.idea \ No newline at end of file diff --git a/package.json b/package.json index 1cfa6cf..af66fad 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "cordova-plugin-firestore", - "version": "1.1.0", + "name": "engage-cordova-plugin-firestore", + "version": "1.1.14", "cordova": { - "id": "cordova-plugin-firestore", + "id": "engage-cordova-plugin-firestore", "platforms": [ "android", "ios", @@ -16,7 +16,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/ReallySmallSoftware/cordova-plugin-firestore.git" + "url": "https://github.com/EngageMobile/cordova-plugin-firestore.git" }, "author": "Richard Windley (http://www.reallysmall.co.uk)", "license": "Apache-2.0", diff --git a/plugin.xml b/plugin.xml index f0fcba0..bef9fcb 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,6 +1,6 @@ - + Cordova Firestore Plugin Google Firebase Firestore MIT @@ -30,7 +30,9 @@ + + @@ -72,6 +74,12 @@ + + + + + + @@ -84,7 +92,8 @@ - + + diff --git a/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionDeleteHandler.java b/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionDeleteHandler.java new file mode 100644 index 0000000..1fe35ad --- /dev/null +++ b/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionDeleteHandler.java @@ -0,0 +1,62 @@ +package uk.co.reallysmall.cordova.plugin.firestore; + + +import android.support.annotation.NonNull; +import android.util.Log; + +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.firebase.firestore.DocumentReference; + +import org.apache.cordova.CallbackContext; +import org.json.JSONArray; +import org.json.JSONException; + +public class DocOfSubCollectionDeleteHandler implements ActionHandler { + + private FirestorePlugin firestorePlugin; + + public DocOfSubCollectionDeleteHandler(FirestorePlugin firestorePlugin) { + this.firestorePlugin = firestorePlugin; + } + + @Override + public boolean handle(JSONArray args, final CallbackContext callbackContext) { + try { + final String collectionPath = args.getString(0); + final String doc = args.getString(1); + final String subCollection = args.getString(2); + final String docOfSubCollectionId = args.getString(3); + + Log.d(FirestorePlugin.TAG, "Deleting document of sub collection"); + + try { + DocumentReference documentRef = firestorePlugin.getDatabase().collection(collectionPath).document(doc).collection(subCollection).document(docOfSubCollectionId); + Log.d(FirestorePlugin.TAG, "Get for document of sub collection" + collectionPath + "/" + doc); + + documentRef.delete().addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + callbackContext.success(0); + Log.d(FirestorePlugin.TAG, "Successfully deleted document of sub collection"); + } + }).addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + Log.w(FirestorePlugin.TAG, "Error deleting document of sub collection", e); + callbackContext.error(e.getMessage()); + } + }); + } catch (Exception e) { + Log.e(FirestorePlugin.TAG, "Error processing document of sub collection delete in thread", e); + callbackContext.error(e.getMessage()); + } + + } catch (JSONException e) { + Log.e(FirestorePlugin.TAG, "Error processing document of sub collection delete", e); + callbackContext.error(e.getMessage()); + } + + return true; + } +} diff --git a/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionGetHandler.java b/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionGetHandler.java new file mode 100644 index 0000000..ce575f5 --- /dev/null +++ b/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionGetHandler.java @@ -0,0 +1,64 @@ +package uk.co.reallysmall.cordova.plugin.firestore; + + +import android.support.annotation.NonNull; +import android.util.Log; + +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; + +import org.apache.cordova.CallbackContext; +import org.json.JSONArray; +import org.json.JSONException; + +import static uk.co.reallysmall.cordova.plugin.firestore.PluginResultHelper.createPluginResult; + +public class DocOfSubCollectionGetHandler implements ActionHandler { + + private FirestorePlugin firestorePlugin; + + public DocOfSubCollectionGetHandler(FirestorePlugin firestorePlugin) { + this.firestorePlugin = firestorePlugin; + } + + @Override + public boolean handle(JSONArray args, final CallbackContext callbackContext) { + try { + final String collectionPath = args.getString(0); + final String docId = args.getString(1); + final String subCollection = args.getString(2); + final String docOfSubCollectionId = args.getString(3); + + Log.d(FirestorePlugin.TAG, "Listening to document of sub collection"); + + try { + DocumentReference documentRef = firestorePlugin.getDatabase().collection(collectionPath).document(docId).collection(subCollection).document(docOfSubCollectionId); + + documentRef.get().addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(DocumentSnapshot documentSnapshot) { + callbackContext.sendPluginResult(createPluginResult(documentSnapshot, false)); + Log.d(FirestorePlugin.TAG, "Successfully got document of sub collection"); + } + }).addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + Log.w(FirestorePlugin.TAG, "Error getting document of sub collection", e); + callbackContext.error(e.getMessage()); + } + }); + } catch (Exception e) { + Log.e(FirestorePlugin.TAG, "Error processing document of sub collection get in thread", e); + callbackContext.error(e.getMessage()); + } + + } catch (JSONException e) { + Log.e(FirestorePlugin.TAG, "Error processing document of sub collection snapshot", e); + callbackContext.error(e.getMessage()); + } + + return true; + } +} diff --git a/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionSetHandler.java b/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionSetHandler.java new file mode 100644 index 0000000..0ecd11d --- /dev/null +++ b/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionSetHandler.java @@ -0,0 +1,81 @@ +package uk.co.reallysmall.cordova.plugin.firestore; + +import android.support.annotation.NonNull; +import android.util.Log; + +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.SetOptions; + +import org.apache.cordova.CallbackContext; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class DocOfSubCollectionSetHandler implements ActionHandler { + + private FirestorePlugin firestorePlugin; + + public DocOfSubCollectionSetHandler(FirestorePlugin firestorePlugin) { + this.firestorePlugin = firestorePlugin; + } + + @Override + public boolean handle(JSONArray args, final CallbackContext callbackContext) { + try { + final String collection = args.getString(0); + final String docId = args.getString(1); + final String subCollection = args.getString(2); + final String docOfSubCollectionId = args.getString(3); + final JSONObject data = args.getJSONObject(4); + + final JSONObject options; + + if (!args.isNull(5)) { + options = args.getJSONObject(5); + } else { + options = null; + } + + try { + + SetOptions setOptions = DocSetOptions.getSetOptions(options); + + Log.d(FirestorePlugin.TAG, "Setting document of sub collection"); + + DocumentReference documentReference = firestorePlugin.getDatabase().collection(collection).document(docId).collection(subCollection).document(docOfSubCollectionId); + + OnSuccessListener onSuccessListener = new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + callbackContext.success(); + Log.d(FirestorePlugin.TAG, "Successfully written document of sub collection"); + } + }; + + OnFailureListener onFailureListener = new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + Log.w(FirestorePlugin.TAG, "Error writing document of sub collection", e); + callbackContext.error(e.getMessage()); + } + }; + + if (setOptions == null) { + documentReference.set(JSONHelper.toSettableMap(data)).addOnSuccessListener(onSuccessListener).addOnFailureListener(onFailureListener); + } else { + documentReference.set(JSONHelper.toSettableMap(data), setOptions).addOnSuccessListener(onSuccessListener).addOnFailureListener(onFailureListener); + } + } catch (Exception e) { + Log.e(FirestorePlugin.TAG, "Error processing document of sub collection set in thread", e); + callbackContext.error(e.getMessage()); + } + } catch (JSONException e) { + Log.e(FirestorePlugin.TAG, "Error processing document of sub collection set", e); + callbackContext.error(e.getMessage()); + } + + return true; + } +} diff --git a/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionUpdateHandler.java b/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionUpdateHandler.java new file mode 100644 index 0000000..b649da0 --- /dev/null +++ b/src/android/uk/co/reallysmall/cordova/plugin/firestore/DocOfSubCollectionUpdateHandler.java @@ -0,0 +1,59 @@ +package uk.co.reallysmall.cordova.plugin.firestore; + +import android.support.annotation.NonNull; +import android.util.Log; + +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; + +import org.apache.cordova.CallbackContext; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + + +public class DocOfSubCollectionUpdateHandler implements ActionHandler { + private FirestorePlugin firestorePlugin; + + public DocOfSubCollectionUpdateHandler(FirestorePlugin firestorePlugin) { + this.firestorePlugin = firestorePlugin; + } + + @Override + public boolean handle(JSONArray args, final CallbackContext callbackContext) { + try { + final String collection = args.getString(0); + final String docId = args.getString(1); + final String subCollection = args.getString(2); + final String docOfSubCollectionId = args.getString(3); + final JSONObject data = args.getJSONObject(4); + + Log.d(FirestorePlugin.TAG, "Updating document of sub collection"); + + try { + firestorePlugin.getDatabase().collection(collection).document(docId).collection(subCollection).document(docOfSubCollectionId).update(JSONHelper.toSettableMap(data)).addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + callbackContext.success(); + Log.d(FirestorePlugin.TAG, "Successfully updated document of sub collection"); + } + }).addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + callbackContext.error(e.getMessage()); + Log.w(FirestorePlugin.TAG, "Error updating document of sub collection", e); + } + }); + } catch (Exception e) { + Log.e(FirestorePlugin.TAG, "Error processing document of sub collection update in thread", e); + callbackContext.error(e.getMessage()); + } + ; + } catch (JSONException e) { + Log.e(FirestorePlugin.TAG, "Error processing document of sub collection update", e); + callbackContext.error(e.getMessage()); + } + + return true; + } +} diff --git a/src/android/uk/co/reallysmall/cordova/plugin/firestore/FirestorePlugin.java b/src/android/uk/co/reallysmall/cordova/plugin/firestore/FirestorePlugin.java index 9f50b45..259d502 100644 --- a/src/android/uk/co/reallysmall/cordova/plugin/firestore/FirestorePlugin.java +++ b/src/android/uk/co/reallysmall/cordova/plugin/firestore/FirestorePlugin.java @@ -32,7 +32,7 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) { handlers.put("collectionUnsubscribe", new CollectionUnsubscribeHandler(this)); handlers.put("collectionAdd", new CollectionAddHandler(this)); handlers.put("collectionGet", new CollectionGetHandler(this)); - handlers.put("initialise", new InitialiseHandler(this)); + handlers.put("initialise", new InitialiseHandler(webView.getContext().getApplicationContext(), this)); handlers.put("docSet", new DocSetHandler(this)); handlers.put("docUpdate", new DocUpdateHandler(this)); handlers.put("docOnSnapshot", new DocOnSnapshotHandler(this)); @@ -45,6 +45,12 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) { handlers.put("transactionDocSet", new TransactionDocSetHandler(this)); handlers.put("transactionDocDelete", new TransactionDocDeleteHandler(this)); handlers.put("transactionResolve", new TransactionResolveHandler(this)); + handlers.put("logEvent", new LogEventHandler(webView.getContext().getApplicationContext(),this)); + handlers.put("docOfSubCollectionSet", new DocOfSubCollectionSetHandler(this)); + handlers.put("docOfSubCollectionGet", new DocOfSubCollectionGetHandler(this)); + handlers.put("docOfSubCollectionUpdate", new DocOfSubCollectionUpdateHandler(this)); + handlers.put("docOfSubCollectionDelete", new DocOfSubCollectionDeleteHandler(this)); + handlers.put("subCollectionGet", new SubCollectionGetHandler(this)); Log.d(TAG, "Initializing FirestorePlugin"); } diff --git a/src/android/uk/co/reallysmall/cordova/plugin/firestore/InitialiseHandler.java b/src/android/uk/co/reallysmall/cordova/plugin/firestore/InitialiseHandler.java index abe1505..a40f747 100644 --- a/src/android/uk/co/reallysmall/cordova/plugin/firestore/InitialiseHandler.java +++ b/src/android/uk/co/reallysmall/cordova/plugin/firestore/InitialiseHandler.java @@ -1,7 +1,10 @@ package uk.co.reallysmall.cordova.plugin.firestore; +import android.content.Context; import android.util.Log; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; import com.google.firebase.firestore.FirebaseFirestore; import com.google.firebase.firestore.FirebaseFirestoreSettings; @@ -17,9 +20,12 @@ public class InitialiseHandler implements ActionHandler { public static final String DATE_PREFIX = "datePrefix"; public static final String FIELDVALUE_DELETE = "fieldValueDelete"; public static final String FIELDVALUE_SERVERTIMESTAMP = "fieldValueServerTimestamp"; + public static final String CONFIG = "config"; private FirestorePlugin firestorePlugin; + private Context context; - public InitialiseHandler(FirestorePlugin firestorePlugin) { + public InitialiseHandler(Context context, FirestorePlugin firestorePlugin) { + this.context = context; this.firestorePlugin = firestorePlugin; } @@ -27,41 +33,64 @@ public InitialiseHandler(FirestorePlugin firestorePlugin) { public boolean handle(final JSONArray args, CallbackContext callbackContext) { try { - if (firestorePlugin.getDatabase() == null) { - Log.d(FirestorePlugin.TAG, "Initialising Firestore..."); - final JSONObject options = args.getJSONObject(0); + Log.d(FirestorePlugin.TAG, "Initialising Firestore..."); - FirebaseFirestore.setLoggingEnabled(true); - firestorePlugin.setDatabase(FirebaseFirestore.getInstance()); + final JSONObject options = args.getJSONObject(0); - boolean persist = false; + FirebaseFirestore.setLoggingEnabled(true); + if (options.has(CONFIG)) { + JSONObject config = options.getJSONObject(CONFIG); - if (options.has(PERSIST) && options.getBoolean(PERSIST)) { - persist = true; - } + FirebaseOptions customOptions = new FirebaseOptions.Builder() + .setApplicationId(config.getString("applicationId")) + .setGcmSenderId(config.getString("gcmSenderID")) + .setApiKey(config.getString("apiKey")) + .setProjectId(config.getString("projectID")) + .setDatabaseUrl(config.getString("databaseURL")) + .setStorageBucket(config.getString("storageBucket")) + .build(); - if (options.has(DATE_PREFIX)) { - JSONDateWrapper.setDatePrefix(options.getString(DATE_PREFIX)); + FirebaseApp customApp; + try { + customApp = FirebaseApp.getInstance(config.getString("apiKey")); + } catch (Exception err) { + FirebaseApp.initializeApp(this.context, customOptions, config.getString("apiKey")); + customApp = FirebaseApp.getInstance(config.getString("apiKey")); + err.printStackTrace(); } - if (options.has(FIELDVALUE_DELETE)) { - FieldValueHelper.setDeletePrefix(options.getString(FIELDVALUE_DELETE)); - } + firestorePlugin.setDatabase(FirebaseFirestore.getInstance(customApp)); + } else{ + firestorePlugin.setDatabase(FirebaseFirestore.getInstance()); + } - if (options.has(FIELDVALUE_SERVERTIMESTAMP)) { - FieldValueHelper.setServerTimestampPrefix(options.getString(FIELDVALUE_SERVERTIMESTAMP)); - } + boolean persist = false; - Log.d(FirestorePlugin.TAG, "Setting Firestore persistance to " + persist); + if (options.has(PERSIST) && options.getBoolean(PERSIST)) { + persist = true; + } - FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder() - .setPersistenceEnabled(persist) - .build(); - firestorePlugin.getDatabase().setFirestoreSettings(settings); + if (options.has(DATE_PREFIX)) { + JSONDateWrapper.setDatePrefix(options.getString(DATE_PREFIX)); + } + + if (options.has(FIELDVALUE_DELETE)) { + FieldValueHelper.setDeletePrefix(options.getString(FIELDVALUE_DELETE)); + } - callbackContext.success(); + if (options.has(FIELDVALUE_SERVERTIMESTAMP)) { + FieldValueHelper.setServerTimestampPrefix(options.getString(FIELDVALUE_SERVERTIMESTAMP)); } + + Log.d(FirestorePlugin.TAG, "Setting Firestore persistance to " + persist); + + FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder() + .setPersistenceEnabled(persist) + .build(); + firestorePlugin.getDatabase().setFirestoreSettings(settings); + + callbackContext.success(); } catch (JSONException e) { Log.e(FirestorePlugin.TAG, "Error initialising Forestore", e); callbackContext.error(e.getMessage()); diff --git a/src/android/uk/co/reallysmall/cordova/plugin/firestore/LogEventHandler.java b/src/android/uk/co/reallysmall/cordova/plugin/firestore/LogEventHandler.java new file mode 100644 index 0000000..7d9f8ae --- /dev/null +++ b/src/android/uk/co/reallysmall/cordova/plugin/firestore/LogEventHandler.java @@ -0,0 +1,65 @@ +package uk.co.reallysmall.cordova.plugin.firestore; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; + +import com.google.firebase.analytics.FirebaseAnalytics; + +import org.apache.cordova.CallbackContext; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Iterator; + +public class LogEventHandler implements ActionHandler { + + private FirestorePlugin firestorePlugin; + private Context context; + private FirebaseAnalytics firebaseAnalytics; + + public LogEventHandler(Context context, FirestorePlugin firestorePlugin) { + this.context = context; + this.firestorePlugin = firestorePlugin; + } + + @Override + public boolean handle(final JSONArray args, CallbackContext callbackContext) { + + try { + this.firebaseAnalytics = FirebaseAnalytics.getInstance(this.context); + + final String name = args.getString(0); + final JSONObject params = args.getJSONObject(1); + Bundle bundle = new Bundle(); + Iterator it = params.keys(); + + while (it.hasNext()) { + String key = it.next(); + Object value = params.get(key); + + if (value instanceof String) { + bundle.putString(key, (String)value); + } else if (value instanceof Integer) { + bundle.putInt(key, (Integer)value); + } else if (value instanceof Double) { + bundle.putDouble(key, (Double)value); + } else if (value instanceof Long) { + bundle.putLong(key, (Long)value); + } else { + Log.w(this.firestorePlugin.TAG, "Value for key " + key + " not one of (String, Integer, Double, Long)"); + } + } + + this.firebaseAnalytics.logEvent(name, bundle); + + callbackContext.success(); + } catch (JSONException e) { + Log.e(FirestorePlugin.TAG, "Error logEvent", e); + callbackContext.error(e.getMessage()); + } + + return true; + } +} diff --git a/src/android/uk/co/reallysmall/cordova/plugin/firestore/SubCollectionGetHandler.java b/src/android/uk/co/reallysmall/cordova/plugin/firestore/SubCollectionGetHandler.java new file mode 100644 index 0000000..2aa6449 --- /dev/null +++ b/src/android/uk/co/reallysmall/cordova/plugin/firestore/SubCollectionGetHandler.java @@ -0,0 +1,62 @@ +package uk.co.reallysmall.cordova.plugin.firestore; + +import android.support.annotation.NonNull; +import android.util.Log; + +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.firebase.firestore.CollectionReference; +import com.google.firebase.firestore.Query; +import com.google.firebase.firestore.QuerySnapshot; + +import org.apache.cordova.CallbackContext; +import org.json.JSONArray; +import org.json.JSONException; + +import static uk.co.reallysmall.cordova.plugin.firestore.PluginResultHelper.createPluginResult; + +public class SubCollectionGetHandler implements ActionHandler { + + private FirestorePlugin firestorePlugin; + + public SubCollectionGetHandler(FirestorePlugin firestorePlugin) { + this.firestorePlugin = firestorePlugin; + } + + public boolean handle(JSONArray args, final CallbackContext callbackContext) { + try { + final String collectionPath = args.getString(0); + final String docId = args.getString(1); + final String subCollection = args.getString(2); + + Log.d(FirestorePlugin.TAG, "Getting document from sub collection"); + + try { + CollectionReference collectionRef = firestorePlugin.getDatabase().collection(collectionPath).document(docId).collection(subCollection); + + collectionRef.get().addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(QuerySnapshot querySnapshot) { + callbackContext.sendPluginResult(createPluginResult(querySnapshot, false)); + Log.d(FirestorePlugin.TAG, "Successfully got sub collection"); + } + }).addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + Log.w(FirestorePlugin.TAG, "Error getting sub collection", e); + callbackContext.error(e.getMessage()); + } + }); + } catch (Exception e) { + Log.e(FirestorePlugin.TAG, "Error processing sub collection get in thread", e); + callbackContext.error(e.getMessage()); + } + + } catch (JSONException e) { + Log.e(FirestorePlugin.TAG, "Error processing sub collection get", e); + callbackContext.error(e.getMessage()); + } + + return true; + } +} diff --git a/src/ios/FirestorePlugin.h b/src/ios/FirestorePlugin.h index 76693e9..46c6b8e 100644 --- a/src/ios/FirestorePlugin.h +++ b/src/ios/FirestorePlugin.h @@ -23,6 +23,12 @@ - (void)transactionDocDelete:(CDVInvokedUrlCommand *)command; - (void)runTransaction:(CDVInvokedUrlCommand *)command; - (void)transactionResolve:(CDVInvokedUrlCommand *)command; +- (void)logEvent:(CDVInvokedUrlCommand*)command; +- (void)docOfSubCollectionSet:(CDVInvokedUrlCommand *)command; +- (void)docOfSubCollectionGet:(CDVInvokedUrlCommand *)command; +- (void)docOfSubCollectionUpdate:(CDVInvokedUrlCommand *)command; +- (void)docOfSubCollectionDelete:(CDVInvokedUrlCommand *)command; +- (void)subCollectionGet:(CDVInvokedUrlCommand *)command; - (FIRQuery *)processQueries:(NSArray *)queries ForQuery:(FIRQuery *)query; - (FIRQuery *)processQueryLimit:(FIRQuery *)query ForValue:(NSObject *)value; diff --git a/src/ios/FirestorePlugin.m b/src/ios/FirestorePlugin.m index a89cbae..968788e 100644 --- a/src/ios/FirestorePlugin.m +++ b/src/ios/FirestorePlugin.m @@ -21,6 +21,16 @@ - (void)pluginInitialize { self.transactions = [NSMutableDictionary new]; } +- (void)logEvent:(CDVInvokedUrlCommand *)command { + NSString* name = [command.arguments objectAtIndex:0]; + NSDictionary* parameters = [command.arguments objectAtIndex:1]; + + [FIRAnalytics logEventWithName:name parameters:parameters]; + + CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; +} + - (void)collectionOnSnapshot:(CDVInvokedUrlCommand *)command { NSString *collection =[command argumentAtIndex:0 withDefault:@"/" andClass:[NSString class]]; NSArray *queries = [command argumentAtIndex:1 withDefault:@[] andClass:[NSArray class]]; @@ -257,7 +267,25 @@ - (void)collectionGet:(CDVInvokedUrlCommand *)command { - (void)initialise:(CDVInvokedUrlCommand *)command { NSDictionary *options = [command argumentAtIndex:0 withDefault:@{} andClass:[NSDictionary class]]; - self.firestore = [FIRFirestore firestore]; + + NSDictionary *config = options[@"config"]; + if (config != NULL) { + FIROptions *customOptions = [[FIROptions alloc] initWithGoogleAppID:config[@"googleAppID"] GCMSenderID:config[@"gcmSenderID"]]; + customOptions.bundleID = config[@"bundleID"]; + customOptions.APIKey = config[@"apiKey"]; + customOptions.clientID = config[@"clientID"]; + customOptions.databaseURL = config[@"databaseURL"]; + customOptions.storageBucket = config[@"storageBucket"]; + customOptions.projectID = config[@"projectID"]; + + if ([FIRApp appNamed:config[@"apiKey"]] == nil) { + [FIRApp configureWithName:config[@"apiKey"] options:customOptions]; + } + FIRApp *customApp = [FIRApp appNamed:config[@"apiKey"]]; + self.firestore = [FIRFirestore firestoreForApp:customApp]; + } else { + self.firestore = [FIRFirestore firestore]; + } asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "Initialising Firestore..."); @@ -813,5 +841,159 @@ - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script { return resultString; } +- (void)docOfSubCollectionSet:(CDVInvokedUrlCommand *)command { + NSString *collection = [command argumentAtIndex:0 withDefault:@"/" andClass:[NSString class]]; + NSString *docId = [command argumentAtIndex:1 withDefault:@"/" andClass:[NSString class]]; + NSString *subCollection = [command argumentAtIndex:2 withDefault:@"/" andClass:[NSString class]]; + NSString *docOfSubCollectionId = [command argumentAtIndex:3 withDefault:@"/" andClass:[NSString class]]; + NSDictionary *data = [command argumentAtIndex:4 withDefault:@{} andClass:[NSDictionary class]]; + NSDictionary *options = [command argumentAtIndex:5 withDefault:@{} andClass:[NSDictionary class]]; + + NSDictionary *parsedData = [FirestorePluginJSONHelper fromJSON:data]; + + FIRSetOptions *setOptions = [self getSetOptions:options]; + + asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "Setting document of sub collection"); + + FIRDocumentReference *documentOfSubCollectionReference = [[[[self.firestore collectionWithPath:collection] documentWithPath:docId] collectionWithPath:subCollection] documentWithPath:docOfSubCollectionId]; + + DocumentSetBlock block = ^(NSError * _Nullable error) { + + CDVPluginResult *pluginResult; + + if (error != nil) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:@{ + @"code" : @(error.code), + @"message" : error.description} + ]; + + NSLog(@"Error writing document of sub collection %s", [self localError:error]); + + } else { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + + asl_log(NULL,NULL, ASL_LEVEL_DEBUG, "Successfully written document of sub collection"); + } + + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + }; + + if (setOptions == nil) { + [documentOfSubCollectionReference setData:parsedData completion:block]; + } else { + [documentOfSubCollectionReference setData:parsedData options:setOptions completion:block]; + } +} + +- (void)docOfSubCollectionGet:(CDVInvokedUrlCommand *)command { + NSString *collection = [command argumentAtIndex:0 withDefault:@"/" andClass:[NSString class]]; + NSString *docId = [command argumentAtIndex:1 withDefault:@"/" andClass:[NSString class]]; + NSString *subCollection = [command argumentAtIndex:2 withDefault:@"/" andClass:[NSString class]]; + NSString *docOfSubCollectionId = [command argumentAtIndex:3 withDefault:@"/" andClass:[NSString class]]; + + asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "Listening to document of sub collection"); + + FIRDocumentReference *documentOfSubCollectionReference = [[[[self.firestore collectionWithPath:collection] documentWithPath:docId] collectionWithPath:subCollection] documentWithPath:docOfSubCollectionId]; + + FIRDocumentSnapshotBlock snapshotBlock =^(FIRDocumentSnapshot * _Nullable snapshot, NSError * _Nullable error) { + if (snapshot == nil) { + NSLog(@"Error getting document of sub collection %s", [self localError:error]); + return; + } + + CDVPluginResult *pluginResult = [FirestorePluginResultHelper createDocumentPluginResult:snapshot :YES]; + + asl_log(NULL,NULL,ASL_LEVEL_DEBUG,"Successfully got document of sub collection"); + + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + }; + + [documentOfSubCollectionReference getDocumentWithCompletion:snapshotBlock]; +} + +- (void)docOfSubCollectionUpdate:(CDVInvokedUrlCommand *)command { + NSString *collection =[command argumentAtIndex:0 withDefault:@"/" andClass:[NSString class]]; + NSString *docId =[command argumentAtIndex:1 withDefault:@"/" andClass:[NSString class]]; + NSString *subCollection = [command argumentAtIndex:2 withDefault:@"/" andClass:[NSString class]]; + NSString *docOfSubCollectionId = [command argumentAtIndex:3 withDefault:@"/" andClass:[NSString class]]; + NSDictionary *data = [command argumentAtIndex:4 withDefault:@{} andClass:[NSDictionary class]]; + + NSDictionary *parsedData = [FirestorePluginJSONHelper fromJSON:data]; + + asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "Updating document of sub collection"); + + FIRDocumentReference *documentOfSubCollectionReference = [[[[self.firestore collectionWithPath:collection] documentWithPath:docId] collectionWithPath:subCollection] documentWithPath:docOfSubCollectionId]; + + [documentOfSubCollectionReference updateData:parsedData completion:^(NSError * _Nullable error) { + + CDVPluginResult *pluginResult; + + if (error != nil) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:@{ + @"code" : @(error.code), + @"message" : error.description} + ]; + + NSLog(@"Error updating document of sub collection %s", [self localError:error]); + + } else { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + + asl_log(NULL,NULL,ASL_LEVEL_DEBUG,"Successfully updated document of sub collection"); + } + + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + }]; +} + +- (void)docOfSubCollectionDelete:(CDVInvokedUrlCommand *)command { + NSString *collection = [command argumentAtIndex:0 withDefault:@"/" andClass:[NSString class]]; + NSString *docId = [command argumentAtIndex:1 withDefault:@"/" andClass:[NSString class]]; + NSString *subCollection = [command argumentAtIndex:2 withDefault:@"/" andClass:[NSString class]]; + NSString *docOfSubCollectionId = [command argumentAtIndex:3 withDefault:@"/" andClass:[NSString class]]; + + asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "Deleting document of sub collection"); + + FIRDocumentReference *documentOfSubCollectionReference = [[[[self.firestore collectionWithPath:collection] documentWithPath:docId] collectionWithPath:subCollection] documentWithPath:docOfSubCollectionId]; + + [documentOfSubCollectionReference deleteDocumentWithCompletion:^(NSError * _Nullable error) { + + CDVPluginResult *pluginResult; + + if (error != nil) { + NSLog(@"Error deleting document of sub collection %s", [self localError:error]); + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; + } else { + asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "Successfully deleted document of sub collection"); + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } + + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + }]; +} + +- (void)subCollectionGet:(CDVInvokedUrlCommand *)command { + NSString *collection = [command argumentAtIndex:0 withDefault:@"/" andClass:[NSString class]]; + NSString *docId = [command argumentAtIndex:1 withDefault:@"/" andClass:[NSString class]]; + NSString *subCollection = [command argumentAtIndex:2 withDefault:@"/" andClass:[NSString class]]; + + asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "Getting document from sub collection"); + + FIRCollectionReference *collectionReference = [[[self.firestore collectionWithPath:collection] documentWithPath:docId] collectionWithPath:subCollection]; + + [collectionReference getDocumentsWithCompletion:^(FIRQuerySnapshot * snapshot, NSError * error) { + if (error != nil) { + NSLog(@"Error getting sub collection %s", [self localError:error]); + return; + } + + CDVPluginResult *pluginResult = [FirestorePluginResultHelper createQueryPluginResult:snapshot :NO]; + + asl_log(NULL, NULL,ASL_LEVEL_DEBUG, "Successfully got sub collection"); + + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + }]; +} + @end diff --git a/www/firestore.js b/www/firestore.js index af69c09..1fed0c2 100644 --- a/www/firestore.js +++ b/www/firestore.js @@ -311,7 +311,7 @@ DocumentReference.prototype = { return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; }, collection: function(collectionPath) { - throw "DocumentReference.collection(): Not supported"; + return new SubCollectionReference(this, collectionPath); }, delete: function() { var args = [this._collectionReference._path, this._id]; @@ -511,8 +511,91 @@ CollectionReference.prototype.doc = function(id) { return new DocumentReference(this, id); }; +function SubCollectionReference(documentReference, id) { + this._id = id; + this._documentReference = documentReference; +} + +SubCollectionReference.prototype.doc = function(id) { + return new DocumentOfSubCollectionReference(this, id); +}; + +SubCollectionReference.prototype.get = function() { + var args = [this._documentReference._collectionReference._path, + this._documentReference._id, + this._id]; + + return new Promise(function(resolve, reject) { + exec(resolve, reject, PLUGIN_NAME, 'subCollectionGet', args); + }).then(function(data) { + return new QuerySnapshot(data); + }); +}; + +function DocumentOfSubCollectionReference(subCollectionReference, id) { + this._id = id; + this._subCollectionReference = subCollectionReference; +} + +DocumentOfSubCollectionReference.prototype = { + delete: function() { + var args = [this._subCollectionReference._documentReference._collectionReference._path, + this._subCollectionReference._documentReference._id, + this._subCollectionReference._id, + this._id]; + + return new Promise(function(resolve, reject) { + exec(resolve, reject, PLUGIN_NAME, 'docOfSubCollectionDelete', args); + }).then(function() { + return; + }); + }, + get: function() { + var args = [this._subCollectionReference._documentReference._collectionReference._path, + this._subCollectionReference._documentReference._id, + this._subCollectionReference._id, + this._id]; + + return new Promise(function(resolve, reject) { + exec(resolve, reject, PLUGIN_NAME, 'docOfSubCollectionGet', args); + }).then(function(data) { + return new DocumentSnapshot(data); + }); + }, + set: function(data, options) { + + var args = [ + this._subCollectionReference._documentReference._collectionReference._path, + this._subCollectionReference._documentReference._id, + this._subCollectionReference._id, + this._id, + __wrap(data), + options]; + + return new Promise(function(resolve, reject) { + exec(resolve, reject, PLUGIN_NAME, 'docOfSubCollectionSet', args); + }); + }, + update: function(data) { + + var args = [this._subCollectionReference._documentReference._collectionReference._path, + this._subCollectionReference._documentReference._id, + this._subCollectionReference._id, + this._id, + __wrap(data)]; + + return new Promise(function(resolve, reject) { + exec(resolve, reject, PLUGIN_NAME, 'docOfSubCollectionUpdate', args); + }); + } +}; module.exports = { + logEvent: function(name, params) { + return new Promise(function(resolve, reject) { + exec(resolve, reject, PLUGIN_NAME, "logEvent", [name, params || {}]); + }); + }, initialise: function(options) { return new Promise(function(resolve, reject) { resolve(new Firestore(options));