Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for Firebase Storage & Firebase Functions #38

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
.lein-deps-sum
.lein-plugins/
.lein-repl-history
.clj-kondo
.lsp
.repl*
/*.iml
/.cljs_node_repl/
Expand Down
91 changes: 91 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,97 @@ 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: " %)}}
```


### 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

There are examples provided in the [examples](examples) folder. It is great to
Expand Down
10 changes: 5 additions & 5 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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"]]
Expand Down
161 changes: 157 additions & 4 deletions src/com/degel/re_frame_firebase.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
[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]
[com.degel.re-frame-firebase.functions :as functions]
[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
Expand Down Expand Up @@ -141,6 +145,50 @@
(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 "[email protected]"
;;; :on-success #(js/alert "Success!")
;;; :on-error #(js/alert "Error!")}}
;;;
(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)

;;; 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
Expand Down Expand Up @@ -361,6 +409,103 @@
(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)


;;; 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)



;;; 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.
;;;
;;;
Expand Down Expand Up @@ -394,12 +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)
(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)))
17 changes: 17 additions & 0 deletions src/com/degel/re_frame_firebase/analytics.cljs
Original file line number Diff line number Diff line change
@@ -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))))
14 changes: 14 additions & 0 deletions src/com/degel/re_frame_firebase/app_check.cljs
Original file line number Diff line number Diff line change
@@ -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}))))
Loading