Getting firebase getDownloadURL returning - javascript

According to the documentation I've read ref.getDownloadURL(); should return a link I could use in an img src.
Here is my code:
This is how I fire up firebase:
this.storage = app.storage();
storageRef = img => this.storage.ref(img);
I then call it like so:
const householdPics = (data, props) => {
const ref = props.firebase.storageRef(`images/${data.profilePic}`);
const img = ref.getDownloadURL();
console.log(img);
}
data.profilePic is equal to something.jpg.
I can confirm it's in storage in firebase in a directory called
images/
The error I get in my console is:
"Firebase Storage: Object 'images/NULL' does not exist."
From firebase I can copy the path:
gs://urlstuff.com/images
Then all my images are listed.
What am I doing wrong?

To get result of async method, you have to use then to get final url with access code attached to it.
ex.
storageRef
.getDownloadURL().then(url => { console.log(url) });
Here, your url will be printed at console.

Two things are wrong here.
First of all, the error message is suggesting that your value of data.profilePic is null. That's not valid - be sure to validate your data.
Second of all, as you can see from the API documentation, getDownloadURL() doesn't return the URL directly. It's asynchronous and returns a promise that resolves when the URL is available. This means you have to await it or use then to capture its final value, after the async work is done.

Related

How do I run both getDownloadURL and getMetaData at once and get the results into the same object? Firebase Storage

So I have this component where it renders out medias (images or videos) to show what are the uploaded medias (to Firebase Storage). Currently I have a useEffect hook that pulls the data from Firebase Storage and stores the data into a state. How it looks like currently:
const [uploadedMedia, setUploadedMedia] = useState([]);
useEffect(() => {
const uploadedMediaRef = ref(storage, "appTutorials/" + data.id + "/");
const getMedia = async () => {
setUploadedMedia([]);
listAll(uploadedMediaRef).then((resp) => {
resp.items.forEach((item) => {
getDownloadURL(item).then((url) => {
setUploadedMedia((prev) => [...prev, url]);
});
});
});
};
getMedia();
}, []);
What's happening is that on initial render, the app will list all the data that are present in the storage, then we loop through the data to get the download URL through getDownloadURL method that is provided by Firebase. I then put the URL into the uploadedMedia state which is then a list which later I will map through to render the images/videos.
However, what I want to do is to get the metadata through getMetaData method, so that I can know what type of media is it rendering. This is so that I can do conditional rendering on images and videos where images should be rendered using <img> tag and and videos on <iframe> or <video> tag. I want to pull both URL and metadata at once so that I can store both response in an object as such:
[
{
url: "https://link-to-media-here",
type: "png",
}
]
How can I achieve this? I imagined it should be easy as we can just do array manipulation (?) but I just can't seem to get it so far.
The API does not provide a way to combine the results of getDownloadURL and getMetaData. getDownloadURL is a bit special in that it potentially makes a change to object metadata to add a token string that provides access to the object via the returned URL. getMetaData simply fetches what's there and makes no changes. So you will have to call both in order to get everything you need. You could certainly invoke them both asynchronously and use their returned promises along with Promise.all to wait until they both complete.

How do i pass a function from remix loader function?

I am trying to send a function as one of the value from a remix route loader function
export const loader: LoaderFunction = async ({ request }) => {
const userId = await requireUserId(request)
const user = await getUserById(userId)
const canUserPerformAction = getUserPermissions(user)
const organisations = await Organisation.find({}).exec()
return {
organisations,
canUserPerformAction
}
}
getUserPermissions(user) returns a function with the current user context, which needs to be used in the frontend.
this function always ends up being undefined when I fetch it using useLoaderData() in the default component/ frontend. Is there a better way to do this?
Your loader can either be called during the whole page generation, or using an XHR when navigating in your app.
Your loader have to return a valid Response object, which will usually be a JSON response : https://remix.run/docs/en/v1/api/conventions#returning-response-instances
In your code sample, the returned object is automatically converted to a JSON string, and since functions aren't valid json, it gets stripped.
You will need to call your canUserPerformAction and return its actual result as JSON.

How can I correctly format this JSON data from a backpack.tf API request?

I'm attempting to use the backpack.tf API for a Discord Bot I'm developing. I'm currently attempting the UserInfo portion of it. Using my own Steam ID within the API URL results in this output
Essentially, having users, then the ID, and finally the actual information I'm trying to use. My code is as follows:
const Discord = require("discord.js");
const superagent = require("superagent");
const { apiKey } = require("../db/config.json");
module.exports = {
run: async(client, message, args) => {
if (!args[0]) return message.channel.send("Enter in a steam ID!")
let id = args[0]
console.log(id)
let { body } = await superagent
.get(`https://backpack.tf/api/users/info/v1?steamids=${id}&key=${apiKey}`);
message.channel.send(
new Discord.MessageEmbed()
.setImage(body.users.id.avatar)
);
if (!{ body }) return message.channel.send("Check that ID again!");
},
aliases: ["bp"]
}
Most of this is just framework, but it's basically making a call to the API through superagent. When it returns, I attempt to use body.users.id.avatar to get the avatar of a a user. Instead of doing this, it outputs a UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'avatar' of undefined error. The API seems to give no errors when it's simply body.users.id, but adding another layer to it prompts it to break.
I'd want it to simply give me the result I'm asking for. Thanks.
It looks like you are trying to use a dynamic property name, body.users is an object with key values of actual ids with numbers, there won't be a direct .id property, as such body.users.id is undefined
the reason body.users.id doesn't give any errors is because its only undefined but you aren't trying to call a property on it, like you do when you call body.users.id.avatar
body.users.id.avatar => undefined.avatar
This should fix it:
body.users[id].avatar
An example of how this looks:
const id = "2324389";
const obj = {
"2324389": 23,
"1234678": 22,
"id": 21
};
obj.id
// => 21
obj[id]
// => 23
/* obj[id] is the same as below */
obj["2324389"]
// => 23
Also: if (!{ body })
this line might give errors, either way it will never be false since its evaluating if the object is truthy which it is, regardless of the properties
If you were trying to error handle with this, it needs to be earlier in the code, and you need to use .catch instead, unless the API doesn't throw an error even if ID is invalid

Cypress - Visit a URL obtained from a 3rd party(email)

In my test, I want to visit a URL that is sent in an email. I can successfully save the URL in a variable, but am unable to get cypress to go to that URL. I keep getting the below error. I don't fully understand cypress being "promise-like", so I'm not sure how to resolve the issue
Uncaught (in promise) CypressError: Cypress detected that you returned
a promise from a command while also invoking one or more cy commands
in that promise.
The command that returned the promise was:
cy.get()
The cy command you invoked inside the promise was:
cy.request()
Because Cypress commands are already promise-like, you don't need to
wrap them or return your own promise.
Cypress will resolve your command with whatever the final Cypress
command yields.
Cypress.Commands.add("clickForgotPwdLink", (emailaddress) => {
const MailosaurClient = require('mailosaur');
const client = new MailosaurClient('1234');
let latestEmail;
var emailLower = emailaddress.toLowerCase();
client.messages.search('abc', {
sentTo: emailLower
}).then((results) => {
latestEmail = results.items[0];
let email = latestEmail.id;
client.messages.get(email)
.then((newlink) => {
var forgotpwd = newlink.html.links[0].href;
console.log(forgotpwd)
cy.request(''+forgotpwd+'');
})
})
});
I have to face this today.
If you are getting a raw body response (string) you have to get the link in this way:
const links = body.split("href=http://my.url.com");
var activation_link = links[0].match(/\bhttp?:\/\/\S+/);
activation_link= activation_link[0].replace('"','')
cy.visit(activation_link)
Isn't it just as simple as removing all the quotes and plusses from the cy.request? That is how we use a stored url and that works. But that stored url doesn't come from an email but from an element on the page
I also tried like you but Cypress doens't allowed.
You have to do it via cy.request() to Mailosaur API.
Try something like this:
cy.request({
method: 'POST',
url: 'https://mailosaur.com/api/messages/search',
auth: {
username: 'API_key',
},
body: {
sentTo: 'yourEmail',
},
qs: {
server: 'yourServer',
page: 0,
itemsPerPage: 50,
},
});
The easiest way to do this is using Cypress recorder which email testing embedded in it. I like how Preflight generates cypress code and lets you test emails.
I'd recommend checking out https://cypress.preflight.com/
I've dealt with cy.request before. It's a little cumbersome to get the emails

NodeJS, Firestore get field

I have firestore set up on my nodejs chatbot.
And its successfully copying the Facebook users ID to .doc Name,
and setting there username and other info under there user ID in firestore
How do i go about retrieving this "field" name
to display back to user.
what i have so far is this
const givename = db.collection('users').doc(''+ sender_id).get("name");
How ever firebase is returning nothing.
Iv looked alot online on how to return a field. but with little luck.
Any suggestions?
Calling get() doesn't return the data immediately, since the data is loaded asynchronously. It instead returns a promise, which resolves once the data is loaded. This means that you can use await (as in Francisco's answer) or (if await is not available) implement the then() method:
db.collection('users').doc(''+ sender_id).get().then(function(doc) {
console.log(doc.data().name);
});
A common pitfall to be aware of: the doc.data() is only available inside the callback,
Haven't worked with Firestore yet, but from reading https://firebase.google.com/docs/firestore/query-data/get-data
something like below should work (untested):
const userRef = db.collection("users").doc("1234")
const userDoc = await userRef.get()
const {name} = userDoc.data()
console.log(name)
Another way is:
const givename = await db.collection("users").doc("YOUR DOCUMENT NAME").get();
console.log(givename.data().name);
Remember to put this code in an async function since we are using await here

Categories