From c098a5be92292100325b1d0630e04a0e33f312d6 Mon Sep 17 00:00:00 2001 From: werner Date: Wed, 8 Jul 2020 17:22:30 +0100 Subject: [PATCH 01/22] Adding storage wrappers around the firebase storage sdk --- src/com/degel/re_frame_firebase.cljs | 7 ++- src/com/degel/re_frame_firebase/storage.cljs | 57 ++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/com/degel/re_frame_firebase/storage.cljs diff --git a/src/com/degel/re_frame_firebase.cljs b/src/com/degel/re_frame_firebase.cljs index e71dbc8..d777d3e 100644 --- a/src/com/degel/re_frame_firebase.cljs +++ b/src/com/degel/re_frame_firebase.cljs @@ -11,7 +11,8 @@ [com.degel.re-frame-firebase.core :as core] [com.degel.re-frame-firebase.auth :as auth] [com.degel.re-frame-firebase.database :as database] - [com.degel.re-frame-firebase.firestore :as firestore])) + [com.degel.re-frame-firebase.firestore :as firestore] + [com.degel.re-frame-firebase.storage :as storage])) ;;; Write a value to Firebase. ;;; See https://firebase.google.com/docs/reference/js/firebase.database.Reference#set @@ -361,6 +362,10 @@ (re-frame/reg-sub-raw :firestore/on-snapshot firestore/on-snapshot-sub) +(re-frame/reg-fx :storage/put storage/put-effect) +(re-frame/reg-fx :storage/delete storage/delete-effect) + + ;;; Start library and register callbacks. ;;; ;;; diff --git a/src/com/degel/re_frame_firebase/storage.cljs b/src/com/degel/re_frame_firebase/storage.cljs new file mode 100644 index 0000000..6e81734 --- /dev/null +++ b/src/com/degel/re_frame_firebase/storage.cljs @@ -0,0 +1,57 @@ +(ns com.degel.re-frame-firebase.storage + (:require + [firebase.storage :as firebase-storage])) + +(defn get-storage [bucket] + (if bucket + (.storage (.app js/firebase) (str "gs://" bucket)) + (js/firebase.storage))) ;default firebase bucket + +(defn put + ([path file metadata on-success on-error] + (put path file metadata on-success on-error nil)) + ([path file metadata on-success on-error bucket] + (let [upload-task (.put (-> (.ref (get-storage bucket)) + (.child path)) + file metadata)] + (.on + upload-task + "state_changed" + #(let [progress (* (/ (.-bytesTransferred %) (.-totalBytes %)) 100)] + (.log js/console (str "Upload is " progress))) + #(on-error %) + #(on-success))))) + +(defn delete + ([key on-success on-error] + (delete key on-success on-error nil)) + ([key on-success on-error bucket] + (.then (.delete (-> (.ref (get-storage bucket)) + (.child key))) + on-success + on-error))) + +(defn download-url + ([key on-success on-error] + (download-url key on-success on-error nil)) + ([key on-success on-error bucket] + (.then (.getDownloadURL (-> (.ref (get-storage bucket)) + (.child key))) + on-success + on-error))) + +(defn put-effect [items _] + (doseq [item items] + (let [{:keys [file metadata on-success on-error]} item] + (put (key file) (val file) + (clj->js metadata) + on-success on-error)))) + +(defn delete-effect [items _] + (doseq [item items] + (let [{:keys [file on-success on-error]} item] + (delete (key file) on-success on-error)))) + + + + From a709f18360c2141e2a9ac2110b5f3d15c5b43beb Mon Sep 17 00:00:00 2001 From: werner Date: Thu, 9 Jul 2020 12:26:42 +0100 Subject: [PATCH 02/22] Added basic support for Firebase Storage --- README.md | 69 ++++++++++++++++++ src/com/degel/re_frame_firebase.cljs | 56 +++++++++++++++ src/com/degel/re_frame_firebase/storage.cljs | 75 ++++++++++---------- 3 files changed, 161 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 38e9891..ed7f99d 100644 --- a/README.md +++ b/README.md @@ -528,6 +528,75 @@ as it is meant to be used as a subscription. ``` +### Storage + +[Storage](https://firebase.google.com/docs/storage) Cloud Storage for Firebase is a powerful, simple, and cost-effective object storage service. +It uses effects for put, delete, download operations. + +#### Put +Puts a collection of File objects into a Firebase Storage bucket. +See: https://firebase.google.com/docs/storage/web/upload-files + +Required arguments :path :file + + - :path Path to object in the Storage bucket + - :file File (https://developer.mozilla.org/en-US/docs/Web/API/File) + - :bucket If not supplied, will assume the default Firebase allocated bucket + - :metadata Map of metadata to set on Storage object + - :on-progress Will be provided with the percentage complete + - :on-success + - :on-error + + Example FX: + ```clojure + {:storage/put [{:path "path/to/object" + :file File + :metadata {:customMetadata {"some-key" "some-value"}} + :on-progress #(.log js/console (str "Upload is " % "% complete.")) + :on-success #(js/alert "Success!") + :on-error #(js/alert "Error: " %)}]} +``` + +#### Delete +Deletes a collection of object paths/keys from a Firebase Storage bucket. +See: https://firebase.google.com/docs/storage/web/delete-files + +Required arguments :path + +- :path Path to object in the Storage bucket +- :bucket If not supplied, will assume the default Firebase allocated bucket +- :on-success +- :on-error + +Example FX: + ```clojure + {:storage/delete [{:path "path/to/object" + :on-success #(js/alert "Success!") + :on-error #(js/alert "Error: " %)}]} + ``` + + +#### Download URL +Generates a url with which the browser can download an object from Firebase Storage +See: https://firebase.google.com/docs/storage/web/download-files + +Required arguments: :path + +- :path Path to object in the Storage bucket +- :bucket If not supplied, will assume the default Firebase allocated bucket +- :on-success Will be provided with the download url +- :on-error + +Example FX: + ```clojure + {:storage/download-url {:path "path/to/object" + :on-success #(js/window.open %) + :on-error #(js/alert "Error: " %)}} + ``` + + + + ## Examples and projects There are examples provided in the [examples](examples) folder. It is great to diff --git a/src/com/degel/re_frame_firebase.cljs b/src/com/degel/re_frame_firebase.cljs index d777d3e..abc739d 100644 --- a/src/com/degel/re_frame_firebase.cljs +++ b/src/com/degel/re_frame_firebase.cljs @@ -362,10 +362,66 @@ (re-frame/reg-sub-raw :firestore/on-snapshot firestore/on-snapshot-sub) +;;; Puts a collection of File objects into a Firebase Storage bucket. +;;; See: https://firebase.google.com/docs/storage/web/upload-files +;;; +;;; Required arguments: :path :file +;;; +;;; - :path Path to object in the Storage bucket +;;; - :file File (https://developer.mozilla.org/en-US/docs/Web/API/File) +;;; - :bucket If not supplied, will assume the default Firebase allocated bucket +;;; - :metadata Map of metadata to set on Storage object +;;; - :on-progress Will be provided with the percentage complete +;;; - :on-success +;;; - :on-error +;;; +;;; Example FX: +;;; {:storage/put [{:path "path/to/object" +;;; :file File +;;; :metadata {:customMetadata {"some-key" "some-value"}} +;;; :on-progress #(.log js/console (str "Upload is " % "% complete.")) +;;; :on-success #(js/alert "Success!") +;;; :on-error #(js/alert "Error: " %)}]} +;;; (re-frame/reg-fx :storage/put storage/put-effect) + + +;;; Deletes a collection of object paths/keys from a Firebase Storage bucket. +;;; See: https://firebase.google.com/docs/storage/web/delete-files +;;; +;;; Required arguments: :path +;;; +;;; - :path Path to object in the Storage bucket +;;; - :bucket If not supplied, will assume the default Firebase allocated bucket +;;; - :on-success +;;; - :on-error +;;; +;;; Example FX: +;;; {:storage/delete [{:path "path/to/object" +;;; :on-success #(js/alert "Success!") +;;; :on-error #(js/alert "Error: " %)}]} +;;; (re-frame/reg-fx :storage/delete storage/delete-effect) +;;; Generates a url with which the browser can download an object from Firebase Storage +;;; See: https://firebase.google.com/docs/storage/web/download-files +;;; +;;; Required arguments: :path +;;; +;;; - :path Path to object in the Storage bucket +;;; - :bucket If not supplied, will assume the default Firebase allocated bucket +;;; - :on-success Will be provided with the download url +;;; - :on-error +;;; +;;; Example FX: +;;; {:storage/download-url {:path "path/to/object" +;;; :on-success #(js/window.open %) +;;; :on-error #(js/alert "Error: " %)}} +;;; +(re-frame/reg-fx :storage/download-url storage/download-url-effect) + + ;;; Start library and register callbacks. ;;; ;;; diff --git a/src/com/degel/re_frame_firebase/storage.cljs b/src/com/degel/re_frame_firebase/storage.cljs index 6e81734..4192dc1 100644 --- a/src/com/degel/re_frame_firebase/storage.cljs +++ b/src/com/degel/re_frame_firebase/storage.cljs @@ -1,56 +1,53 @@ (ns com.degel.re-frame-firebase.storage (:require - [firebase.storage :as firebase-storage])) + [firebase.storage :as firebase-storage] + [com.degel.re-frame-firebase.helpers :refer [promise-wrapper]])) -(defn get-storage [bucket] +(defn- get-storage [bucket] (if bucket (.storage (.app js/firebase) (str "gs://" bucket)) (js/firebase.storage))) ;default firebase bucket -(defn put - ([path file metadata on-success on-error] - (put path file metadata on-success on-error nil)) - ([path file metadata on-success on-error bucket] - (let [upload-task (.put (-> (.ref (get-storage bucket)) - (.child path)) - file metadata)] - (.on - upload-task - "state_changed" - #(let [progress (* (/ (.-bytesTransferred %) (.-totalBytes %)) 100)] - (.log js/console (str "Upload is " progress))) - #(on-error %) - #(on-success))))) - -(defn delete - ([key on-success on-error] - (delete key on-success on-error nil)) - ([key on-success on-error bucket] - (.then (.delete (-> (.ref (get-storage bucket)) - (.child key))) - on-success - on-error))) - -(defn download-url - ([key on-success on-error] - (download-url key on-success on-error nil)) - ([key on-success on-error bucket] - (.then (.getDownloadURL (-> (.ref (get-storage bucket)) - (.child key))) - on-success - on-error))) +(defn- put [path file metadata on-success on-error on-progress bucket] + (let [upload-task (.put (-> (.ref (get-storage bucket)) + (.child path)) + file metadata)] + (.on + upload-task + "state_changed" + #(if on-progress + (on-progress (* (/ (.-bytesTransferred %) (.-totalBytes %)) 100)) + (fn [])) + #(if on-error + (on-error %) + (fn [])) + #(if on-success + (on-success) + (fn []))))) + +(defn- delete [path on-success on-error bucket] + (promise-wrapper (.delete (-> (.ref (get-storage bucket)) + (.child path))) + on-success + on-error)) + +(defn download-url-effect [{:keys [path on-success on-error bucket]}] + (promise-wrapper (.getDownloadURL (-> (.ref (get-storage bucket)) + (.child path))) + on-success + on-error)) (defn put-effect [items _] (doseq [item items] - (let [{:keys [file metadata on-success on-error]} item] - (put (key file) (val file) + (let [{:keys [path file metadata on-success on-error on-progress bucket]} item] + (put path file (clj->js metadata) - on-success on-error)))) + on-success on-error on-progress bucket)))) (defn delete-effect [items _] (doseq [item items] - (let [{:keys [file on-success on-error]} item] - (delete (key file) on-success on-error)))) + (let [{:keys [path on-success on-error bucket]} item] + (delete path on-success on-error bucket)))) From 2762e9f52a594701e90f0e93743b942fb8da534c Mon Sep 17 00:00:00 2001 From: werner Date: Sat, 11 Jul 2020 13:47:56 +0100 Subject: [PATCH 03/22] Implemented firebase callable function effect --- src/com/degel/re_frame_firebase.cljs | 22 ++++++++++++++++++- .../degel/re_frame_firebase/functions.cljs | 16 ++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/com/degel/re_frame_firebase/functions.cljs diff --git a/src/com/degel/re_frame_firebase.cljs b/src/com/degel/re_frame_firebase.cljs index abc739d..cccbc54 100644 --- a/src/com/degel/re_frame_firebase.cljs +++ b/src/com/degel/re_frame_firebase.cljs @@ -12,7 +12,8 @@ [com.degel.re-frame-firebase.auth :as auth] [com.degel.re-frame-firebase.database :as database] [com.degel.re-frame-firebase.firestore :as firestore] - [com.degel.re-frame-firebase.storage :as storage])) + [com.degel.re-frame-firebase.storage :as storage] + [com.degel.re-frame-firebase.functions :as functions])) ;;; Write a value to Firebase. ;;; See https://firebase.google.com/docs/reference/js/firebase.database.Reference#set @@ -422,6 +423,25 @@ (re-frame/reg-fx :storage/download-url storage/download-url-effect) +;;; Executes a Callable Firebase Cloud Function +;;; See: https://firebase.google.com/docs/functions/callable +;;; +;;; Required arguments: :cfn-name :data +;;; +;;; - :cfn-name Cloud Function name +;;; - :data Map containing request data +;;; - :on-success Will be called with a clojure Map containing the response data +;;; - :on-error +;;; +;;; Example FX: +;;; {:functions/call {:cfn-name "my-function-name" +;;; :data {:foo "bar"} +;;; :on-success #(js/alert (:foobar %)) +;;; :on-error #(js/alert "Error: " %)}} +;;; +(re-frame/reg-fx :functions/call functions/call-effect) + + ;;; Start library and register callbacks. ;;; ;;; diff --git a/src/com/degel/re_frame_firebase/functions.cljs b/src/com/degel/re_frame_firebase/functions.cljs new file mode 100644 index 0000000..e75b049 --- /dev/null +++ b/src/com/degel/re_frame_firebase/functions.cljs @@ -0,0 +1,16 @@ +(ns com.degel.re-frame-firebase.functions + (:require + [firebase.functions :as firebase-functions] + [clojure.walk :as w])) + +(defn call-effect [options] + (let [{:keys [cfn-name data on-success on-error]} options + cfn (.httpsCallable (.functions js/firebase) cfn-name)] + (.catch + (.then + (cfn (clj->js data)) + #(on-success (-> (.. % -data) + js->clj + w/keywordize-keys))) + #(on-error %)))) + From 0e8544b5afa57e8bad0ed22c0de64640abb331fa Mon Sep 17 00:00:00 2001 From: werner Date: Sat, 11 Jul 2020 13:54:54 +0100 Subject: [PATCH 04/22] Updated readme for functions --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index ed7f99d..adde1ba 100644 --- a/README.md +++ b/README.md @@ -595,6 +595,28 @@ Example FX: ``` +### Functions + +[Functions](https://firebase.google.com/docs/functions) Cloud Functions for Firebase is a serverless framework that lets you automatically run backend code in response to events. +It uses effects for call. + +#### Call +Executes a Callable Firebase Cloud Function +See: https://firebase.google.com/docs/functions/callable + +Required arguments: :cfn-name :data +- :cfn-name Cloud Function name +- :data Map containing request data +- :on-success Will be called with a clojure Map containing the response data +- :on-error + +Example FX: + ```clojure + {:functions/call {:cfn-name "my-function-name" + :data {:foo "bar"} + :on-success #(js/alert (:foobar %)) + :on-error #(js/alert "Error: " %)}} + ``` ## Examples and projects From d1da523266e0540d07be1700e93330cff24a19e5 Mon Sep 17 00:00:00 2001 From: wkok Date: Sat, 21 Nov 2020 16:49:41 +0000 Subject: [PATCH 05/22] Storage on-error will be passed the parsed message --- src/com/degel/re_frame_firebase/storage.cljs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/com/degel/re_frame_firebase/storage.cljs b/src/com/degel/re_frame_firebase/storage.cljs index 4192dc1..b23a627 100644 --- a/src/com/degel/re_frame_firebase/storage.cljs +++ b/src/com/degel/re_frame_firebase/storage.cljs @@ -35,19 +35,25 @@ (promise-wrapper (.getDownloadURL (-> (.ref (get-storage bucket)) (.child path))) on-success - on-error)) + #(on-error (-> % js->clj .-message_)))) (defn put-effect [items _] (doseq [item items] (let [{:keys [path file metadata on-success on-error on-progress bucket]} item] (put path file (clj->js metadata) - on-success on-error on-progress bucket)))) + on-success + #(on-error (-> % js->clj .-message_)) + on-progress + bucket)))) (defn delete-effect [items _] (doseq [item items] (let [{:keys [path on-success on-error bucket]} item] - (delete path on-success on-error bucket)))) + (delete path + on-success + #(on-error (-> % js->clj .-message_)) + bucket)))) From a41b299d7a6af49d3ab6ba0ce95bdbbe5879e987 Mon Sep 17 00:00:00 2001 From: wkok Date: Thu, 26 Nov 2020 15:32:55 +0000 Subject: [PATCH 06/22] Added update-profile & update-email effects --- src/com/degel/re_frame_firebase.cljs | 23 +++++++++++++++++++++++ src/com/degel/re_frame_firebase/auth.cljs | 16 ++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/com/degel/re_frame_firebase.cljs b/src/com/degel/re_frame_firebase.cljs index cccbc54..52fc5b2 100644 --- a/src/com/degel/re_frame_firebase.cljs +++ b/src/com/degel/re_frame_firebase.cljs @@ -143,6 +143,29 @@ (re-frame/reg-fx :firebase/email-create-user auth/email-create-user) +;;; Updates the user's display name and profile photo URL +;;; +;;; Accepts a map with :profile :on-success :on-error +;;; +;;; Example FX: +;;; {:firebase/update-profile {:profile {:displayName "Joe Soap" +;;; :photoURL "http://my.photo.com"} +;;; :on-success #(js/alert "Success!") +;;; :on-error #(js/alert "Error!")}} +;;; +(re-frame/reg-fx :firebase/update-profile auth/update-profile) + +;;; Updates the user's email address +;;; +;;; Accepts a map with :email :on-success :on-error +;;; +;;; Example FX: +;;; {:firebase/update-email {:email "joe@soap.com" +;;; :on-success #(js/alert "Success!") +;;; :on-error #(js/alert "Error!")}} +;;; +(re-frame/reg-fx :firebase/update-email auth/update-email) + ;;; Login to firebase anonymously ;;; ;;; Parameter is not used diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index f459f27..b26a883 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -160,3 +160,19 @@ (-> (js/firebase.auth) (.signOut) (.catch (core/default-error-handler)))) + +(defn update-profile + [{:keys [profile on-success on-error]}] + (-> (js/firebase.auth) + (.-currentUser) + (.updateProfile (clj->js profile)) + (.then on-success) + (.catch on-error))) + +(defn update-email + [{:keys [email on-success on-error]}] + (-> (js/firebase.auth) + (.-currentUser) + (.updateEmail email) + (.then on-success) + (.catch on-error))) \ No newline at end of file From 9437cb0e02b756efc23ce1fd66af84303f395464 Mon Sep 17 00:00:00 2001 From: wkok Date: Thu, 26 Nov 2020 17:47:20 +0000 Subject: [PATCH 07/22] Added send-email-verification --- src/com/degel/re_frame_firebase.cljs | 10 ++++++++++ src/com/degel/re_frame_firebase/auth.cljs | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/com/degel/re_frame_firebase.cljs b/src/com/degel/re_frame_firebase.cljs index 52fc5b2..6371a74 100644 --- a/src/com/degel/re_frame_firebase.cljs +++ b/src/com/degel/re_frame_firebase.cljs @@ -166,6 +166,16 @@ ;;; (re-frame/reg-fx :firebase/update-email auth/update-email) +;;; Send a user a verification email +;;; +;;; Accepts a map with :on-success :on-error +;;; +;;; Example FX: +;;; {:firebase/send-email-verification {:on-success #(js/alert "Success!") +;;; :on-error #(js/alert "Error!")}} +;;; +(re-frame/reg-fx :firebase/send-email-verification auth/send-email-verification) + ;;; Login to firebase anonymously ;;; ;;; Parameter is not used diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index b26a883..d0dcd19 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -175,4 +175,12 @@ (.-currentUser) (.updateEmail email) (.then on-success) + (.catch on-error))) + +(defn send-email-verification + [{:keys [on-success on-error]}] + (-> (js/firebase.auth) + (.-currentUser) + (.sendEmailVerification) + (.then on-success) (.catch on-error))) \ No newline at end of file From 27023d4c8f058ca1b9e35d71da79babfa70e9fb9 Mon Sep 17 00:00:00 2001 From: wkok Date: Fri, 27 Nov 2020 12:09:26 +0000 Subject: [PATCH 08/22] Error message will be parsed from JS object --- src/com/degel/re_frame_firebase/auth.cljs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index d0dcd19..3764c59 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -175,7 +175,7 @@ (.-currentUser) (.updateEmail email) (.then on-success) - (.catch on-error))) + (.catch #(on-error (-> % js->clj .-message_))))) (defn send-email-verification [{:keys [on-success on-error]}] @@ -183,4 +183,4 @@ (.-currentUser) (.sendEmailVerification) (.then on-success) - (.catch on-error))) \ No newline at end of file + (.catch #(on-error (-> % js->clj .-message_))))) \ No newline at end of file From 2a1954992b148c9f57aaba4cd9c4584b604d29e0 Mon Sep 17 00:00:00 2001 From: wkok Date: Fri, 27 Nov 2020 12:09:50 +0000 Subject: [PATCH 09/22] Message from error will be parsed --- src/com/degel/re_frame_firebase/auth.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index 3764c59..03f2594 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -167,7 +167,7 @@ (.-currentUser) (.updateProfile (clj->js profile)) (.then on-success) - (.catch on-error))) + (.catch #(on-error (-> % js->clj .-message_))))) (defn update-email [{:keys [email on-success on-error]}] From 68ecba429f019784ee47b72b680afb98a9e85e85 Mon Sep 17 00:00:00 2001 From: wkok Date: Fri, 27 Nov 2020 12:31:49 +0000 Subject: [PATCH 10/22] Updated error message parsing --- src/com/degel/re_frame_firebase/auth.cljs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index 03f2594..93b2cd4 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -167,7 +167,7 @@ (.-currentUser) (.updateProfile (clj->js profile)) (.then on-success) - (.catch #(on-error (-> % js->clj .-message_))))) + (.catch #(on-error (-> % js->clj .-message))))) (defn update-email [{:keys [email on-success on-error]}] @@ -175,7 +175,7 @@ (.-currentUser) (.updateEmail email) (.then on-success) - (.catch #(on-error (-> % js->clj .-message_))))) + (.catch #(on-error (-> % js->clj .-message))))) (defn send-email-verification [{:keys [on-success on-error]}] @@ -183,4 +183,4 @@ (.-currentUser) (.sendEmailVerification) (.then on-success) - (.catch #(on-error (-> % js->clj .-message_))))) \ No newline at end of file + (.catch #(on-error (-> % js->clj .-message))))) \ No newline at end of file From 538914733f3bf6b0036d839461e1d7d1391f0659 Mon Sep 17 00:00:00 2001 From: wkok Date: Fri, 27 Nov 2020 14:33:53 +0000 Subject: [PATCH 11/22] Added action-code-settings to send-email-verification --- src/com/degel/re_frame_firebase/auth.cljs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index 93b2cd4..e152fe6 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -178,9 +178,9 @@ (.catch #(on-error (-> % js->clj .-message))))) (defn send-email-verification - [{:keys [on-success on-error]}] + [{:keys [action-code-settings on-success on-error]}] (-> (js/firebase.auth) (.-currentUser) - (.sendEmailVerification) + (.sendEmailVerification action-code-settings) (.then on-success) (.catch #(on-error (-> % js->clj .-message))))) \ No newline at end of file From 948a5c688dc77b84f6f9da8f5e63e84de9fb23dd Mon Sep 17 00:00:00 2001 From: wkok Date: Fri, 27 Nov 2020 14:39:42 +0000 Subject: [PATCH 12/22] action-code-settings --- src/com/degel/re_frame_firebase/auth.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index e152fe6..a731db3 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -181,6 +181,6 @@ [{:keys [action-code-settings on-success on-error]}] (-> (js/firebase.auth) (.-currentUser) - (.sendEmailVerification action-code-settings) + (.sendEmailVerification (clj->js action-code-settings)) (.then on-success) (.catch #(on-error (-> % js->clj .-message))))) \ No newline at end of file From f2ff47461236a7da4c92c35cdd5556a6cc2b30c3 Mon Sep 17 00:00:00 2001 From: wkok Date: Sun, 29 Nov 2020 13:34:45 +0000 Subject: [PATCH 13/22] Added effect :firebase/apply-action-code --- src/com/degel/re_frame_firebase.cljs | 11 +++++++++++ src/com/degel/re_frame_firebase/auth.cljs | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/src/com/degel/re_frame_firebase.cljs b/src/com/degel/re_frame_firebase.cljs index 6371a74..248fb06 100644 --- a/src/com/degel/re_frame_firebase.cljs +++ b/src/com/degel/re_frame_firebase.cljs @@ -176,6 +176,17 @@ ;;; (re-frame/reg-fx :firebase/send-email-verification auth/send-email-verification) +;;; Applies a verification code sent to the user by email +;;; +;;; Accepts a map with :action-code :on-success :on-error +;;; +;;; Example FX: +;;; {:firebase/apply-action-code {:action-code "1234567" +;;; :on-success #(js/alert "Success!") +;;; :on-error #(js/alert "Error!")}} +;;; +(re-frame/reg-fx :firebase/apply-action-code auth/apply-action-code) + ;;; Login to firebase anonymously ;;; ;;; Parameter is not used diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index a731db3..3425568 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -183,4 +183,11 @@ (.-currentUser) (.sendEmailVerification (clj->js action-code-settings)) (.then on-success) + (.catch #(on-error (-> % js->clj .-message))))) + +(defn apply-action-code + [{:keys [action-code on-success on-error]}] + (-> (js/firebase.auth) + (.applyActionCode action-code) + (.then on-success) (.catch #(on-error (-> % js->clj .-message))))) \ No newline at end of file From d6f5a17a3b730971fbfce630afe282f3e24e0b0b Mon Sep 17 00:00:00 2001 From: wkok Date: Tue, 1 Dec 2020 16:31:34 +0000 Subject: [PATCH 14/22] Added success & error handlers to the sign-out effect --- src/com/degel/re_frame_firebase/auth.cljs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index 3425568..7028265 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -156,10 +156,11 @@ (.warn js/console "reCaptcha confirmation missing"))) -(defn sign-out [] +(defn sign-out [on-success on-error] (-> (js/firebase.auth) (.signOut) - (.catch (core/default-error-handler)))) + (.then on-success) + (.catch #(on-error (-> % js->clj .-message))))) (defn update-profile [{:keys [profile on-success on-error]}] From b9678208dcc2fbeee25e24590a72082e94a96cb8 Mon Sep 17 00:00:00 2001 From: wkok Date: Tue, 1 Dec 2020 16:34:21 +0000 Subject: [PATCH 15/22] Fixed destructuring in sign-out effect --- src/com/degel/re_frame_firebase/auth.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index 7028265..2325c08 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -156,7 +156,8 @@ (.warn js/console "reCaptcha confirmation missing"))) -(defn sign-out [on-success on-error] +(defn sign-out + [{:keys [on-success on-error]}] (-> (js/firebase.auth) (.signOut) (.then on-success) From 7df92c9bf8f5d25c28e6573c74465fac966d14e3 Mon Sep 17 00:00:00 2001 From: wkok Date: Sun, 3 Jan 2021 16:09:44 +0000 Subject: [PATCH 16/22] Upgraded firebase to 7.9.0-0 --- .gitignore | 2 ++ project.clj | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d4a3ab9..2c4896e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ .lein-deps-sum .lein-plugins/ .lein-repl-history +.clj-kondo +.lsp .repl* /*.iml /.cljs_node_repl/ diff --git a/project.clj b/project.clj index eaae33b..d108758 100644 --- a/project.clj +++ b/project.clj @@ -8,7 +8,7 @@ :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.10.0"] [org.clojure/clojurescript "1.10.439"] - [cljsjs/firebase "5.7.3-1"] + [cljsjs/firebase "7.9.0-0"] [re-frame "0.10.6"] [com.degel/iron "0.4.0"]] :jvm-opts ^:replace ["-Xmx1g" "-server"] From 8f6292abc52c8a446726189de1ed1655049d854c Mon Sep 17 00:00:00 2001 From: wkok Date: Sun, 3 Jan 2021 16:20:11 +0000 Subject: [PATCH 17/22] Undo firebase version bump --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index d108758..eaae33b 100644 --- a/project.clj +++ b/project.clj @@ -8,7 +8,7 @@ :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.10.0"] [org.clojure/clojurescript "1.10.439"] - [cljsjs/firebase "7.9.0-0"] + [cljsjs/firebase "5.7.3-1"] [re-frame "0.10.6"] [com.degel/iron "0.4.0"]] :jvm-opts ^:replace ["-Xmx1g" "-server"] From 08f28af2d8238b2ad7c36230ab190679876e8e46 Mon Sep 17 00:00:00 2001 From: wkok Date: Sun, 17 Jan 2021 16:35:20 +0000 Subject: [PATCH 18/22] snapshot listeners can be registered by the caller --- .../degel/re_frame_firebase/firestore.cljs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/com/degel/re_frame_firebase/firestore.cljs b/src/com/degel/re_frame_firebase/firestore.cljs index c73ddee..5c5a775 100644 --- a/src/com/degel/re_frame_firebase/firestore.cljs +++ b/src/com/degel/re_frame_firebase/firestore.cljs @@ -321,31 +321,34 @@ doc-changes expose-objects) on-failure))) -(defn- on-snapshotter [reference-or-query snapshot-listen-options on-next on-error] - (.onSnapshot reference-or-query - (clj->SnapshotListenOptions snapshot-listen-options) - on-next - (if on-error (event->fn on-error) (core/default-error-handler)))) +(defn- on-snapshotter [reference-or-query snapshot-listen-options on-next on-error register-listener] + (-> (.onSnapshot reference-or-query + (clj->SnapshotListenOptions snapshot-listen-options) + on-next + (if on-error (event->fn on-error) (core/default-error-handler))) + register-listener)) (defn on-snapshot [{:keys [path-document path-collection where order-by limit start-at start-after end-at end-before doc-changes snapshot-listen-options snapshot-options expose-objects - on-next on-error]}] + on-next on-error register-listener]}] {:pre [(utils/validate :re-frame/vec-or-fn on-next) (utils/validate (s/nilable :re-frame/vec-or-fn) on-error)]} (if path-document (on-snapshotter (clj->DocumentReference path-document) snapshot-listen-options (document-parser-wrapper on-next snapshot-options expose-objects) - on-error) + on-error + register-listener) (on-snapshotter (query (clj->CollectionReference path-collection) where order-by limit start-at start-after end-at end-before) snapshot-listen-options (collection-parser-wrapper on-next snapshot-options snapshot-listen-options doc-changes expose-objects) - on-error))) + on-error + register-listener))) (def on-snapshot-effect on-snapshot) From c1d69b23ffe76a2e55bac58397e0a9152a398094 Mon Sep 17 00:00:00 2001 From: Werner Kok Date: Sat, 1 Jan 2022 17:04:05 +0000 Subject: [PATCH 19/22] started work on supporting firebase sdk v9 --- project.clj | 10 ++-- src/com/degel/re_frame_firebase/auth.cljs | 55 +++++++++---------- src/com/degel/re_frame_firebase/core.cljs | 5 +- src/com/degel/re_frame_firebase/database.cljs | 2 - .../degel/re_frame_firebase/firestore.cljs | 31 ++++++----- .../degel/re_frame_firebase/functions.cljs | 11 ++-- src/com/degel/re_frame_firebase/helpers.cljs | 2 +- src/com/degel/re_frame_firebase/storage.cljs | 36 ++++++------ 8 files changed, 76 insertions(+), 76 deletions(-) diff --git a/project.clj b/project.clj index eaae33b..b760358 100644 --- a/project.clj +++ b/project.clj @@ -6,11 +6,11 @@ :url "https://github.com/deg/re-frame-firebase" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[org.clojure/clojure "1.10.0"] - [org.clojure/clojurescript "1.10.439"] - [cljsjs/firebase "5.7.3-1"] - [re-frame "0.10.6"] - [com.degel/iron "0.4.0"]] + ;; :dependencies [[org.clojure/clojure "1.10.0"] + ;; [org.clojure/clojurescript "1.10.439"] + ;; [cljsjs/firebase "5.7.3-1"] + ;; [re-frame "0.10.6"] + ;; [com.degel/iron "0.4.0"]] :jvm-opts ^:replace ["-Xmx1g" "-server"] :cljsbuild {:builds {}} ; prevent https://github.com/emezeske/lein-cljsbuild/issues/413 :plugins [[lein-npm "0.6.2"]] diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index 2325c08..999e010 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -7,9 +7,8 @@ [clojure.spec.alpha :as s] [re-frame.core :as re-frame] [iron.re-utils :refer [>evt]] - [firebase.app :as firebase-app] - [firebase.auth :as firebase-auth] - [com.degel.re-frame-firebase.core :as core])) + [com.degel.re-frame-firebase.core :as core] + ["@firebase/auth" :refer (getAuth onAuthStateChanged getRedirectResult updateProfile)])) (defn- user @@ -31,19 +30,19 @@ (core/set-current-user))) (defn- init-auth [] - (.onAuthStateChanged - (js/firebase.auth) - set-user - (core/default-error-handler)) - (-> (js/firebase.auth) - (.getRedirectResult) + (onAuthStateChanged (getAuth) set-user (core/default-error-handler)) + + (-> (getAuth) + getRedirectResult (.then (fn on-user-credential [user-credential] - (-> user-credential - (.-user) - set-user))) + (when user-credential + (-> user-credential + (.-user) + set-user)))) (.catch (core/default-error-handler)))) + (def ^:private sign-in-fns {:popup (memfn signInWithPopup auth-provider) :redirect (memfn signInWithRedirect auth-provider)}) @@ -62,13 +61,13 @@ :or {sign-in-method :redirect}} opts] (doseq [scope scopes] - (.addScope auth-provider scope)) + (.addScope ^js auth-provider scope)) (when custom-parameters - (.setCustomParameters auth-provider (clj->js custom-parameters))) + (.setCustomParameters ^js auth-provider (clj->js custom-parameters))) (if-let [sign-in (sign-in-fns sign-in-method)] - (-> (js/firebase.auth) + (-> (getAuth) (sign-in auth-provider) (.then (partial maybe-link-with-credential link-with-credential)) (.catch (core/default-error-handler))) @@ -98,28 +97,28 @@ (defn email-sign-in [{:keys [email password]}] - (-> (js/firebase.auth) + (-> (getAuth) (.signInWithEmailAndPassword email password) (.then set-user) (.catch (core/default-error-handler)))) (defn email-create-user [{:keys [email password]}] - (-> (js/firebase.auth) + (-> (getAuth) (.createUserWithEmailAndPassword email password) (.then set-user) (.catch (core/default-error-handler)))) (defn anonymous-sign-in [opts] - (-> (js/firebase.auth) + (-> (getAuth) (.signInAnonymously) (.then set-user) (.catch (core/default-error-handler)))) (defn custom-token-sign-in [{:keys [token]}] - (-> (js/firebase.auth) + (-> (getAuth) (.signInWithCustomToken token) (.then set-user) (.catch (core/default-error-handler)))) @@ -136,7 +135,7 @@ (defn phone-number-sign-in [{:keys [phone-number on-send]}] (if-let [verifier (:recaptcha-verifier @core/firebase-state)] - (-> (js/firebase.auth) + (-> (getAuth) (.signInWithPhoneNumber phone-number verifier) (.then (fn [confirmation] (when on-send @@ -156,24 +155,24 @@ (.warn js/console "reCaptcha confirmation missing"))) -(defn sign-out +(defn sign-out [{:keys [on-success on-error]}] - (-> (js/firebase.auth) + (-> (getAuth) (.signOut) (.then on-success) (.catch #(on-error (-> % js->clj .-message))))) (defn update-profile [{:keys [profile on-success on-error]}] - (-> (js/firebase.auth) + (-> (getAuth) (.-currentUser) - (.updateProfile (clj->js profile)) + (updateProfile (clj->js profile)) (.then on-success) (.catch #(on-error (-> % js->clj .-message))))) (defn update-email [{:keys [email on-success on-error]}] - (-> (js/firebase.auth) + (-> (getAuth) (.-currentUser) (.updateEmail email) (.then on-success) @@ -181,7 +180,7 @@ (defn send-email-verification [{:keys [action-code-settings on-success on-error]}] - (-> (js/firebase.auth) + (-> (getAuth) (.-currentUser) (.sendEmailVerification (clj->js action-code-settings)) (.then on-success) @@ -189,7 +188,7 @@ (defn apply-action-code [{:keys [action-code on-success on-error]}] - (-> (js/firebase.auth) + (-> (getAuth) (.applyActionCode action-code) (.then on-success) - (.catch #(on-error (-> % js->clj .-message))))) \ No newline at end of file + (.catch #(on-error (-> % js->clj .-message))))) diff --git a/src/com/degel/re_frame_firebase/core.cljs b/src/com/degel/re_frame_firebase/core.cljs index 07167c6..6d2a50e 100644 --- a/src/com/degel/re_frame_firebase/core.cljs +++ b/src/com/degel/re_frame_firebase/core.cljs @@ -4,7 +4,7 @@ (ns com.degel.re-frame-firebase.core (:require [iron.re-utils :refer [evt event->fn sub->fn]] - [firebase.app :as firebase-app])) + ["@firebase/app" :refer (initializeApp)])) ;;; Used mostly to register client handlers (defonce firebase-state (atom {})) @@ -16,7 +16,8 @@ :default-error-handler (event->fn (or default-error-handler js/alert)))) (defn initialize-app [firebase-app-info] - (js/firebase.initializeApp (clj->js firebase-app-info))) + (swap! firebase-state assoc + :app (initializeApp (clj->js firebase-app-info)))) ;;; [TODO] Consider adding a default atom to hold the user state when :get-user-fn and ;;; and :set-user-fn are not defined. Need to do this carefully, so as not to cause any diff --git a/src/com/degel/re_frame_firebase/database.cljs b/src/com/degel/re_frame_firebase/database.cljs index 2208695..8c2c547 100644 --- a/src/com/degel/re_frame_firebase/database.cljs +++ b/src/com/degel/re_frame_firebase/database.cljs @@ -10,8 +10,6 @@ [reagent.ratom :as ratom :refer [make-reaction]] [iron.re-utils :refer [evt event->fn sub->fn]] [iron.utils :as utils] - [firebase.app :as firebase-app] - [firebase.database :as firebase-database] [com.degel.re-frame-firebase.helpers :refer [js->clj-tree success-failure-wrapper]] [com.degel.re-frame-firebase.core :as core] [com.degel.re-frame-firebase.specs :as specs])) diff --git a/src/com/degel/re_frame_firebase/firestore.cljs b/src/com/degel/re_frame_firebase/firestore.cljs index 5c5a775..56447ff 100644 --- a/src/com/degel/re_frame_firebase/firestore.cljs +++ b/src/com/degel/re_frame_firebase/firestore.cljs @@ -6,16 +6,17 @@ [reagent.ratom :as ratom :refer [make-reaction]] [iron.re-utils :as re-utils :refer [evt event->fn sub->fn]] [iron.utils :as utils] - [firebase.app :as firebase-app] - [firebase.firestore :as firebase-firestore] [com.degel.re-frame-firebase.core :as core] [com.degel.re-frame-firebase.specs :as specs] - [com.degel.re-frame-firebase.helpers :refer [promise-wrapper]])) + [com.degel.re-frame-firebase.helpers :refer [promise-wrapper]] + ["@firebase/firestore" :refer (initializeFirestore DocumentReference doc getDoc collection CollectionReference getDocs onSnapshot setDoc)])) (defn set-firestore-settings [settings] - (.settings (js/firebase.firestore) (clj->js (or settings {})))) + (swap! core/firebase-state assoc + :firestore (initializeFirestore (:app @core/firebase-state) + (clj->js (or settings {}))))) ;; Extra public functions (defn server-timestamp @@ -51,7 +52,7 @@ {:firestore/get {:path-collection [:my-collection] :where [[(document-id-field-path) :>= \"start\"]]}}" [] - (.documentId firebase.firestore.FieldPath)) + (.documentId js/firebase.firestore.FieldPath)) ;; Type Conversion/Parsing @@ -61,9 +62,9 @@ See https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference" [path] {:pre [(utils/validate ::specs/path-collection path)]} - (if (instance? js/firebase.firestore.CollectionReference path) + (if (instance? CollectionReference path) path - (.collection (js/firebase.firestore) + (collection (:firestore @core/firebase-state) (str/join "/" (clj->js path))))) (defn clj->DocumentReference @@ -72,10 +73,10 @@ See https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentReference" [path] {:pre [(utils/validate ::specs/path-document path)]} - (if (instance? js/firebase.firestore.DocumentReference path) + (if (instance? DocumentReference path) path - (.doc (js/firebase.firestore) - (str/join "/" (clj->js path))))) + (doc (:firestore @core/firebase-state) + (str/join "/" (clj->js path))))) (defn clj->FieldPath "Converts a string/keyword or a seq of string/keywords into a FieldPath. @@ -234,11 +235,11 @@ ;; re-frame Effects/Subscriptions (defn- setter ([path data set-options] - (.set (clj->DocumentReference path) + (setDoc (clj->DocumentReference path) (clj->js data) (clj->SetOptions set-options))) ([instance path data set-options] - (.set instance + (setDoc instance (clj->DocumentReference path) (clj->js data) (clj->SetOptions set-options)))) @@ -297,11 +298,11 @@ (if end-before (.apply (.-endBefore $) $ (clj->js end-before)) $))) (defn- getter-document [path get-options] - (.get (clj->DocumentReference path) (clj->GetOptions get-options))) + (getDoc (clj->DocumentReference path) (clj->GetOptions get-options))) (defn- getter-collection [path get-options where order-by limit start-at start-after end-at end-before] - (.get (query (clj->CollectionReference path) where order-by limit + (getDocs (query (clj->CollectionReference path) where order-by limit start-at start-after end-at end-before) (clj->GetOptions get-options))) @@ -322,7 +323,7 @@ on-failure))) (defn- on-snapshotter [reference-or-query snapshot-listen-options on-next on-error register-listener] - (-> (.onSnapshot reference-or-query + (-> (onSnapshot reference-or-query (clj->SnapshotListenOptions snapshot-listen-options) on-next (if on-error (event->fn on-error) (core/default-error-handler))) diff --git a/src/com/degel/re_frame_firebase/functions.cljs b/src/com/degel/re_frame_firebase/functions.cljs index e75b049..a9b8d5c 100644 --- a/src/com/degel/re_frame_firebase/functions.cljs +++ b/src/com/degel/re_frame_firebase/functions.cljs @@ -1,11 +1,15 @@ (ns com.degel.re-frame-firebase.functions (:require - [firebase.functions :as firebase-functions] - [clojure.walk :as w])) + [clojure.walk :as w] + [com.degel.re-frame-firebase.core :as core] + ["@firebase/functions" :refer (httpsCallable getFunctions)])) (defn call-effect [options] (let [{:keys [cfn-name data on-success on-error]} options - cfn (.httpsCallable (.functions js/firebase) cfn-name)] + cfn (-> @core/firebase-state + :app + getFunctions + (httpsCallable cfn-name))] (.catch (.then (cfn (clj->js data)) @@ -13,4 +17,3 @@ js->clj w/keywordize-keys))) #(on-error %)))) - diff --git a/src/com/degel/re_frame_firebase/helpers.cljs b/src/com/degel/re_frame_firebase/helpers.cljs index de79167..f27b619 100644 --- a/src/com/degel/re_frame_firebase/helpers.cljs +++ b/src/com/degel/re_frame_firebase/helpers.cljs @@ -14,7 +14,7 @@ ;;; with them. -(defn js->clj-tree [x] +(defn js->clj-tree [^js x] (-> (.val x) js->clj clojure.walk/keywordize-keys)) diff --git a/src/com/degel/re_frame_firebase/storage.cljs b/src/com/degel/re_frame_firebase/storage.cljs index b23a627..d5245b7 100644 --- a/src/com/degel/re_frame_firebase/storage.cljs +++ b/src/com/degel/re_frame_firebase/storage.cljs @@ -1,17 +1,21 @@ (ns com.degel.re-frame-firebase.storage (:require - [firebase.storage :as firebase-storage] + ["@firebase/storage" :refer (getStorage uploadBytesResumable ref deleteObject getDownloadURL)] + [com.degel.re-frame-firebase.core :as core] [com.degel.re-frame-firebase.helpers :refer [promise-wrapper]])) (defn- get-storage [bucket] (if bucket - (.storage (.app js/firebase) (str "gs://" bucket)) - (js/firebase.storage))) ;default firebase bucket + (-> @core/firebase-state + :app + (getStorage (str "gs://" bucket))) + (-> @core/firebase-state + :app + getStorage))) ;default firebase bucket (defn- put [path file metadata on-success on-error on-progress bucket] - (let [upload-task (.put (-> (.ref (get-storage bucket)) - (.child path)) - file metadata)] + (let [upload-task (uploadBytesResumable (ref (get-storage bucket) path) + file metadata)] (.on upload-task "state_changed" @@ -26,25 +30,23 @@ (fn []))))) (defn- delete [path on-success on-error bucket] - (promise-wrapper (.delete (-> (.ref (get-storage bucket)) - (.child path))) + (promise-wrapper (deleteObject (ref (get-storage bucket) path)) on-success on-error)) (defn download-url-effect [{:keys [path on-success on-error bucket]}] - (promise-wrapper (.getDownloadURL (-> (.ref (get-storage bucket)) - (.child path))) + (promise-wrapper (getDownloadURL (ref (get-storage bucket) path)) on-success - #(on-error (-> % js->clj .-message_)))) + #(on-error (-> % js->clj .-message)))) (defn put-effect [items _] (doseq [item items] (let [{:keys [path file metadata on-success on-error on-progress bucket]} item] (put path file (clj->js metadata) - on-success - #(on-error (-> % js->clj .-message_)) - on-progress + on-success + #(on-error (-> % js->clj .-message)) + on-progress bucket)))) (defn delete-effect [items _] @@ -52,9 +54,5 @@ (let [{:keys [path on-success on-error bucket]} item] (delete path on-success - #(on-error (-> % js->clj .-message_)) + #(on-error (-> % js->clj .-message)) bucket)))) - - - - From ffb7a3214a35aae3491f66ddffec8648bcb6bbcc Mon Sep 17 00:00:00 2001 From: Werner Kok Date: Sat, 1 Jan 2022 17:52:25 +0000 Subject: [PATCH 20/22] add analytics support --- src/com/degel/re_frame_firebase.cljs | 36 ++++++++++++++----- .../degel/re_frame_firebase/analytics.cljs | 17 +++++++++ 2 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 src/com/degel/re_frame_firebase/analytics.cljs diff --git a/src/com/degel/re_frame_firebase.cljs b/src/com/degel/re_frame_firebase.cljs index 248fb06..22fc16d 100644 --- a/src/com/degel/re_frame_firebase.cljs +++ b/src/com/degel/re_frame_firebase.cljs @@ -13,7 +13,8 @@ [com.degel.re-frame-firebase.database :as database] [com.degel.re-frame-firebase.firestore :as firestore] [com.degel.re-frame-firebase.storage :as storage] - [com.degel.re-frame-firebase.functions :as functions])) + [com.degel.re-frame-firebase.functions :as functions] + [com.degel.re-frame-firebase.analytics :as analytics])) ;;; Write a value to Firebase. ;;; See https://firebase.google.com/docs/reference/js/firebase.database.Reference#set @@ -417,8 +418,8 @@ ;;; - :bucket If not supplied, will assume the default Firebase allocated bucket ;;; - :metadata Map of metadata to set on Storage object ;;; - :on-progress Will be provided with the percentage complete -;;; - :on-success -;;; - :on-error +;;; - :on-success +;;; - :on-error ;;; ;;; Example FX: ;;; {:storage/put [{:path "path/to/object" @@ -438,8 +439,8 @@ ;;; ;;; - :path Path to object in the Storage bucket ;;; - :bucket If not supplied, will assume the default Firebase allocated bucket -;;; - :on-success -;;; - :on-error +;;; - :on-success +;;; - :on-error ;;; ;;; Example FX: ;;; {:storage/delete [{:path "path/to/object" @@ -457,7 +458,7 @@ ;;; - :path Path to object in the Storage bucket ;;; - :bucket If not supplied, will assume the default Firebase allocated bucket ;;; - :on-success Will be provided with the download url -;;; - :on-error +;;; - :on-error ;;; ;;; Example FX: ;;; {:storage/download-url {:path "path/to/object" @@ -475,17 +476,35 @@ ;;; - :cfn-name Cloud Function name ;;; - :data Map containing request data ;;; - :on-success Will be called with a clojure Map containing the response data -;;; - :on-error +;;; - :on-error ;;; ;;; Example FX: ;;; {:functions/call {:cfn-name "my-function-name" -;;; :data {:foo "bar"} +;;; :data {:foo "bar"} ;;; :on-success #(js/alert (:foobar %)) ;;; :on-error #(js/alert "Error: " %)}} ;;; (re-frame/reg-fx :functions/call functions/call-effect) + +;;; Logs an event in Firebase Analytics +;;; See: https://firebase.google.com/docs/analytics/events?authuser=0&platform=web +;;; +;;; Required arguments: :event :props +;;; +;;; - :event Name of the event (as keyword) +;;; - :props Map of key/value pairs of interesting information +;;; +;;; Example FX: +;;; {:analytics/log {:event :purchase-completed +;;; :props {:amount "123.45" +;;; :currency "USD"}}} +;;; +(re-frame/reg-fx :analytics/log analytics/log-effect) + + + ;;; Start library and register callbacks. ;;; ;;; @@ -527,4 +546,5 @@ :default-error-handler default-error-handler) (core/initialize-app firebase-app-info) (firestore/set-firestore-settings firestore-settings) + (analytics/init) (auth/init-auth)) diff --git a/src/com/degel/re_frame_firebase/analytics.cljs b/src/com/degel/re_frame_firebase/analytics.cljs new file mode 100644 index 0000000..94e784b --- /dev/null +++ b/src/com/degel/re_frame_firebase/analytics.cljs @@ -0,0 +1,17 @@ +(ns com.degel.re-frame-firebase.analytics + (:require + ["@firebase/analytics" :refer (getAnalytics logEvent)] + [com.degel.re-frame-firebase.core :as core])) + +(defn init + [] + (swap! core/firebase-state assoc + :analytics (-> @core/firebase-state + :app + getAnalytics))) + +(defn log-effect + [{:keys [event props]} _] + (-> @core/firebase-state + :analytics + (logEvent (name event) (clj->js props)))) From 11baeac68f236cfb37b1385f04ab013c0d79f9d9 Mon Sep 17 00:00:00 2001 From: Werner Kok Date: Sun, 2 Jan 2022 13:40:59 +0000 Subject: [PATCH 21/22] add app-check support --- src/com/degel/re_frame_firebase.cljs | 18 +++++++++++++----- src/com/degel/re_frame_firebase/app_check.cljs | 14 ++++++++++++++ src/com/degel/re_frame_firebase/auth.cljs | 9 +++++---- 3 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 src/com/degel/re_frame_firebase/app_check.cljs diff --git a/src/com/degel/re_frame_firebase.cljs b/src/com/degel/re_frame_firebase.cljs index 22fc16d..45bdece 100644 --- a/src/com/degel/re_frame_firebase.cljs +++ b/src/com/degel/re_frame_firebase.cljs @@ -14,7 +14,8 @@ [com.degel.re-frame-firebase.firestore :as firestore] [com.degel.re-frame-firebase.storage :as storage] [com.degel.re-frame-firebase.functions :as functions] - [com.degel.re-frame-firebase.analytics :as analytics])) + [com.degel.re-frame-firebase.analytics :as analytics] + [com.degel.re-frame-firebase.app-check :as app-check])) ;;; Write a value to Firebase. ;;; See https://firebase.google.com/docs/reference/js/firebase.database.Reference#set @@ -538,13 +539,20 @@ ;;; (defn init [& {:keys [firebase-app-info firestore-settings + app-check-settings get-user-sub set-user-event - default-error-handler]}] + default-error-handler + firebase-products]}] (core/set-firebase-state :get-user-sub get-user-sub :set-user-event set-user-event :default-error-handler default-error-handler) (core/initialize-app firebase-app-info) - (firestore/set-firestore-settings firestore-settings) - (analytics/init) - (auth/init-auth)) + (when (firebase-products :firestore) + (firestore/set-firestore-settings firestore-settings)) + (when (firebase-products :analytics) + (analytics/init)) + (when (firebase-products :auth) + (auth/init-auth)) + (when (firebase-products :app-check) + (app-check/init app-check-settings))) diff --git a/src/com/degel/re_frame_firebase/app_check.cljs b/src/com/degel/re_frame_firebase/app_check.cljs new file mode 100644 index 0000000..742c9f9 --- /dev/null +++ b/src/com/degel/re_frame_firebase/app_check.cljs @@ -0,0 +1,14 @@ +(ns com.degel.re-frame-firebase.app-check + (:require + ["@firebase/app-check" :refer (initializeAppCheck ReCaptchaV3Provider)] + [com.degel.re-frame-firebase.core :as core])) + +(defn init + [settings] + (when (:debug-provider settings) + (set! js/FIREBASE_APPCHECK_DEBUG_TOKEN true)) + (swap! core/firebase-state assoc + :app-check (initializeAppCheck (:app @core/firebase-state) + (clj->js + {:provider (ReCaptchaV3Provider. (:site-key settings)) + :isTokenAutoRefreshEnabled true})))) diff --git a/src/com/degel/re_frame_firebase/auth.cljs b/src/com/degel/re_frame_firebase/auth.cljs index 999e010..8a1e25c 100644 --- a/src/com/degel/re_frame_firebase/auth.cljs +++ b/src/com/degel/re_frame_firebase/auth.cljs @@ -8,7 +8,8 @@ [re-frame.core :as re-frame] [iron.re-utils :refer [>evt]] [com.degel.re-frame-firebase.core :as core] - ["@firebase/auth" :refer (getAuth onAuthStateChanged getRedirectResult updateProfile)])) + ["@firebase/auth" :refer (getAuth onAuthStateChanged getRedirectResult updateProfile + sendEmailVerification applyActionCode updateEmail)])) (defn- user @@ -174,7 +175,7 @@ [{:keys [email on-success on-error]}] (-> (getAuth) (.-currentUser) - (.updateEmail email) + (updateEmail email) (.then on-success) (.catch #(on-error (-> % js->clj .-message))))) @@ -182,13 +183,13 @@ [{:keys [action-code-settings on-success on-error]}] (-> (getAuth) (.-currentUser) - (.sendEmailVerification (clj->js action-code-settings)) + (sendEmailVerification (clj->js action-code-settings)) (.then on-success) (.catch #(on-error (-> % js->clj .-message))))) (defn apply-action-code [{:keys [action-code on-success on-error]}] (-> (getAuth) - (.applyActionCode action-code) + (applyActionCode action-code) (.then on-success) (.catch #(on-error (-> % js->clj .-message))))) From 3371a8506f51b6aaee06bc9ea0e6daa2843ace6e Mon Sep 17 00:00:00 2001 From: Werner Kok Date: Sat, 4 Mar 2023 16:34:16 +0000 Subject: [PATCH 22/22] v9 compat --- src/com/degel/re_frame_firebase/firestore.cljs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/degel/re_frame_firebase/firestore.cljs b/src/com/degel/re_frame_firebase/firestore.cljs index 56447ff..998cc03 100644 --- a/src/com/degel/re_frame_firebase/firestore.cljs +++ b/src/com/degel/re_frame_firebase/firestore.cljs @@ -9,7 +9,7 @@ [com.degel.re-frame-firebase.core :as core] [com.degel.re-frame-firebase.specs :as specs] [com.degel.re-frame-firebase.helpers :refer [promise-wrapper]] - ["@firebase/firestore" :refer (initializeFirestore DocumentReference doc getDoc collection CollectionReference getDocs onSnapshot setDoc)])) + ["@firebase/firestore" :refer (initializeFirestore DocumentReference doc getDoc collection CollectionReference getDocs onSnapshot setDoc FieldPath)])) (defn set-firestore-settings @@ -87,9 +87,9 @@ [field-path] (cond (nil? field-path) nil - (instance? js/firebase.firestore.FieldPath field-path) field-path + (instance? FieldPath field-path) field-path (coll? field-path) (apply js/firebase.firestore.FieldPath. (clj->js field-path)) - :else (js/firebase.firestore.FieldPath. (clj->js field-path)))) + :else (FieldPath. (clj->js field-path)))) (defn clj->SetOptions "Converts a clojure-style map into a SetOptions satisfying one. @@ -281,7 +281,7 @@ (defn- query [ref where order-by limit start-at start-after end-at end-before] (as-> ref $ - (if where + #_(if where (reduce (fn [$$ [field-path op value]] (.where $$ (clj->FieldPath field-path) (clj->js op) (clj->js value))) $ where)