Accessing specific file structure firebase storage - javascript

I have a specific folder structure in firebase storage that looks something like:
'gs://example.appspot.com/folderA/folderB/documentName'.
I am using a document viewer on my website that takes a URL. My question is, how do I reference the above location as a URL?

With the JS Client SDK, one solution is to call the getDownloadURL() method on the Cloud Storage reference. Something along the following lines:
import { getStorage, ref, getDownloadURL } from "firebase/storage";
const storage = getStorage();
getDownloadURL(ref(storage, 'folderA/folderB/documentName'))
.then((url) => {
console.log(url)
});

Related

Upload files to firebase storage via function

I am trying to allow ability for user to select file and pass to firebase function to store in storage.
I am uploading file in react client like following:
const formData = new FormData();
formData.append("myFile", aFile);
const aRequesObject= {
method: "POST",
body: formData,
};
const response = await fetch(aUrl, aRequesObject);
Then I have a serverless function like following where i want to save this file to cloud storage.
import firebase from "firebase";
import "firebase/storage";
import { config } from "./Config";
firebase.initializeApp(config);
const file = request.body.myFile;
const ref = firebase.storage().ref().child(file.name);
ref.put(file).then(() => {
console.log("Uploaded file", file.name);
}); */
I have tried several variations from firebase documentation. All the examples i have found are uploading directly to storage from client as opposed to passing file to function and extracting from the request and then saving to storage. I am looking for a simple example of this or a link to where someone has done this scenario.

firebase storage: storage.ref is not a function

I would like to use storage service from Firebase with a nodeJS api (hosted on "firebase functions") to allow the users to upload his avatars.
So I read the doc from https://firebase.google.com/docs/storage/web/start
and I do:
admin.js
const admin = require('firebase-admin');
const config = require('./config.js');
admin.initializeApp(config);
const db = admin.firestore();
const storage = admin.storage();
module.exports = { admin, db, storage };
user.js
const { admin, db, storage } = require('../util/admin');
exports.postAvatar = async (request, response) => {
const storageRef = storage.ref();
}
but I have the following error: storage.ref is not a function
Is something is missing from the documentation ?
The console.log of storage const is:
Storage {
INTERNAL: StorageInternals {},
storageClient: Storage {...},
appInternal: FirebaseApp {...}
}
admin.storage() returns a Storage object. If you want to use it to refer to a file in your default storage bucket, you should use its bucket() method with no parameters, and it will give you a Bucket object from the Google Cloud nodejs SDK.
There are no methods called ref() anywhere in that SDK. It's not much like the JavaScript web client SDK. You will have to learn a different but similar API to work with content in using the Cloud Storage node SDK. The Admin SDK just essentially wraps this API.
const file = storage.bucket().file('/path/to/file');
Try below code.
const storage = storage.bucket() // you can also put your bucket-id from config
const storageRef = storage.ref()
Also check this answer. TypeError: firebase.storage is not a function

List all files using firebase storage gives me 404 when trying to use getDownloadUrl

I'm trying to list files under a folder in a web app like the following:
listRef.listAll().then((res) => {
// I get the list of items here
res.items.forEach((imgRef) => {
// 404 error
imgRef.getDownloadURL().then((url) => {
console.log(url);
mapFile(url, imgRef.metadata);
});
});
});
I successfully list res.items but when I try to use getDownloadURL() I get a 404 reference, I did notice that I get folder/image in the reference of the item and when I browse the file using the firebase storage console it browses the slash "/" encoded as %2F
my references are the following:
const storageRef = firebase.app().storage('gs://some-name').ref();
const listRef = storageRef.child(`${Id1}`);
when I save the image I use the following reference:
const imageRef = storageRef.child(`${Id1}/${this.file.name}`);
Edit:
I'm getting the default bucket as a response however I'm setting up the correct storage bucket endpoint in the storage reference, which is not the default.
I solved it somehow a little bit hacky
since the method listAll() were returning the default bucket name I replaced the bucket name (without the gs//) with the name I needed.
imgRef.location.bucket = 'non-default-bucket-name';
imgRef.getDownloadURL().then(url => url); //<- worked

How to get firebase userID from inside a firebase cloud function

My user is directed from my app to a website which eventually returns a response to a redirect uri. I have a cloud function in firebase which listen for that link and get the response. Now I would like to save that information along with the details of the firebase user who triggered the process? For example I would like to save the response in Firestore in a document names as the userID. How can I achieve it??
I have added a picture of my process flow
Here is my function
exports.connectStripeStandardAccount = functions.https.onRequest((req, res) => {
let authCode = req.query.code;
//here I would like to get the uid of the user who triggered the website
return res.send(authCode);
});
});
Here is the code for step nr 1 (my app is written in flutter)
link is in this format
link = https://connect.stripe.com/oauth/authorize?response_type=code&client_id=xxxxxxxxxxxx&scope=read_write
_launchURLWebsite(String link) async {
if (await canLaunch(link)) {
await launch(link);
} else {
throw 'Could not launch $link';
}
}
Thanks
From the different comments to your question, it appears that you are using the Stripe Connect OAuth Reference .
The documentation (link above) explains that you can add a state parameter to your request, which is "an arbitrary string value we will pass back to you".
So, by adding a state parameter to your URL, as follows
https://connect.stripe.com/oauth/authorize?response_type=code&client_id=xxxxxxxxxxxx&scope=read_write&state=theuidofyouruser
you will receive the value of state as a query string parameter in your Cloud Function, as explained here: https://stripe.com/docs/connect/oauth-reference#get-authorize-response
In the Cloud Function, you can get the value of state by doing req.query.state, see the Cloud Functions documentation on this point.
I think this should work for you. By using this method you will be able to call the user's uid from anywhere
Install the provider package (https://pub.dev/packages/provider#-installing-tab-) by adding it to you pubspec.yaml dependencies.
pubspec.yaml
dependencies:
provider: ^3.1.0+1
Next, create a new dart file called auth.dart (you can name it anything you want..
Inside that file create a new class called Auth, like this:
import 'package:firebase_auth/firebase_auth.dart';
class Auth {
String userId;
final FirebaseAuth _auth = FirebaseAuth.instance;
String get userId {
return _userId;
}
void getUserID() async{
FirebaseUser user = await _auth.currentUser();
_userId = user.uid;
}
}
Then in your main.dart file
import the Provider package by adding this import:
import 'package:provider/provider.dart';
and also in the main.dart file, right before your MaterialApp is returned (return MaterialApp...)
Wrap it with a new widget like this:
Consumer<Auth>(
builder: (ctx, auth, _) => MaterialApp(...),),
Now, inside any widget where you want to call the user's Id you can do this..
#override
Widget build(BuildContext context) {
final auth = Provider.of<Auth>(context);
return Container(
child: Text(auth.uid);
);
}

How to access multiple Realtime Database instances in Cloud Functions for Firebase

I'm using multiple databases in a Firebase project. Cloud functions for the main (default) database work great, however, I cannot make them work for a secondary database. For example I want to make a read request on a node with admin privileges:
//this works
admin.database().ref(nodePath).once('value')...
This works in the main database, however, if I want to execute the command on another database, it doesn't work:
//this doesn't work
admin.database(secondaryDatabaseUrl).ref(nodePath).once('value')...
Although the functions are deployed, I get an error on the console when trying to execute the cloud function.
Here's the code for the cloud function with an https trigger:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const secureCompare = require('secure-compare');
exports.testFunction= functions.https.onRequest((req, res) => {
const key = req.query.key;
// Exit if the keys don't match
if (!secureCompare(key, functions.config().cron.key)) {
console.error('keys do not match');
res.status(403).send('error1');
return;
}
//test read request
//the line below crashes the function
return admin.database('https://secondary_db_url.firebaseio.com').ref(`/testNode`).once('value').then(dataSnapshot=> {
console.log('value', dataSnapshot.val());
return;
}).catch(er => {
console.error('error', er);
res.status(403).send('error2');
});
});
Below is the error log in the Firebase console:
TypeError: ns.ensureApp(...).database is not a function
at FirebaseNamespace.fn (/user_code/node_modules/firebase-admin/lib/firebase-namespace.js:251:42)
at exports.testFunction.functions.https.onRequest (/user_code/index.js:16:16)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:26:41)
at /var/tmp/worker/worker.js:671:7
at /var/tmp/worker/worker.js:655:9
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
If I don't specify the secondary database URL, the function will make the read request on my main database which works great:
//this works
return admin.database().ref(`/testNode`).once('value').then(dataSnapshot=> {
...
I'm using the latest SDK versions: "firebase-admin": "^5.5.1" and "firebase-functions": "^0.7.3"
So, how do I get an instance of a secondary database in cloud functions using admin privileges?
Here's how to access database by URL using Admin SDK:
let app = admin.app();
let ref = app.database('https://secondary_db_url.firebaseio.com').ref();
Here's an example from Admin SDK integration tests: https://github.com/firebase/firebase-admin-node/blob/master/test/integration/database.js#L52
With cloud functions > 1.1 now, here is the documentation link that saved my life on this issue.
https://firebase.google.com/docs/database/usage/sharding#connect_your_app_to_multiple_database_instances
So, it looks like this at the top of my my cloud function index.js :
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const dev = admin.initializeApp({
databaseURL: "https://appdev.firebaseio.com"
}, 'dev');
const v2 = admin.initializeApp({
databaseURL: "https://appv2.firebaseio.com"
}, 'v2');
and then, in my clond functions functions code I can do :
//will change stuff on default database
admin.database().ref().child(`stuff/${stuffId}`).set(myStuff)
//will change stuff on my dev database
admin.database(dev).ref().child(`stuff/${stuffId}`).set(myStuff)
//will change stuff on my v2 database
admin.database(v2).ref().child(`stuff/${stuffId}`).set(myStuff)
So it looks like you are trying to access multiple databases using the javascript web client API. Passing the URL of the database to the API like this doesn't work with the Admin SDK:
admin.database('https://secondary_db_url.firebaseio.com').ref(`/testNode`)
Instead, you have to initialize a second app, give it a name, and pass that app around to the Admin SDK APIs. Here's a complete sample that writes the same data to two different database instances in the same project:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
const otherConfig = Object.assign({}, functions.config().firebase)
otherConfig.databaseURL = 'https://your-other-db.firebaseio.com/'
const otherApp = admin.initializeApp(otherConfig, 'otherAppName')
exports.foo = functions.https.onRequest((req, res) => {
const data = { foo: 'bar' }
const p1 = admin.database().ref('data').set(data)
const p2 = admin.database(otherApp).ref('data').set(data)
Promise.all([p1, p2]).then(() => {
res.send("OK")
})
.catch(error => {
res.status(500).send(error)
})
})
Updating this while on Firebase Functions v3.14.0. None of this answers worked for me so I implemented this solution
instance Registers a function that triggers on events from a specific Firebase Realtime Database instance
functions.database.instance('my-app-db-2').ref('/foo/bar')
Use the name of the database instance and it works, no need for the url. functions.database.ref used without instance watches the default instance for events.
So if both the answers doesn't work.
What happened with me is both the method worked without any error but second instance of database was not getting updated.
I updated npm and firebase CLI it worked.
Also #Dough Stevenson you Passing the URL of the database to the API like this **does** work with the Admin SDK
And this is a good blog from Firebase about the same
Firebase Blog : Easier scaling with multi-database support!

Categories

Resources