I am building a program where the user can select a crypto currency, enter their email and basically it will remind them with an email when the crypto hits the user's selected price. (A price notifier by email). I have got email working and a crypto api to get the price data, but now i am just wondering how i am going to get the program to save the users data and every time i get the price data how am i going to send email to multiple users who have signed up for reminders. I hope this is making sense, i will post relevant code below.
Getting price data
async function getPriceData() {
try {
const response = await axios.get(
"https://api.coingecko.com/api/v3/coins/bitcoin",
{}
);
const data = response.data;
const price = data.market_data.current_price.usd;
return price;
} catch (error) {
throw error;
}
}
Email function that uses price data to send email. (Currently using setTimeout to keep checking price data but im not sure this is the best way to keep checking api).
I am using nodemailer for sending emails and all working fine.
Client data is posted to server and used in this function, all working fine.
const emailFunction = (price, recieverEmail) => {
getPriceData().then((response) => {
const btcPrice = response;
const selectedPrice = price;
if (btcPrice < selectedPrice) {
const transport = nodemailer.createTransport({
host: "smtp.sendgrid.net",
port: 587,
auth: {
user: "apikey",
pass: sendgridKey,
},
});
const message = {
from: senderEmail,
to: recieverEmail,
subject: `BTC PRICE BELOW ${selectedPrice}!`,
text: `Bitcoin price is below your selected price of ${selectedPrice}, and is currently ${btcPrice}. This presents a good buying opportunity.`,
};
transport.sendMail(message, (err, info) => {
if (err) {
console.log(err);
} else {
console.log(info);
}
});
}
setTimeout(emailFunction, 60000);
});
};
Currently i can only send emails for one user and i use the setTimeout to check the api to get price data every 60000ms. This works for now but the end product i would like the user to input email and price and the back end will continuously check api and if coin price has gone below the users price, the user will be alerted at that point. How does this scale to keep track of price and say email 50 people if needed?
Thanks for any input and help on this, much appreciated i am a Node noob.
Related
This is the database structure i have i want to get logged in user data.
i want to make table of data: Columns: Date,Status
Also i want to make percentage piechart wheel by calculating success and failure rate. but not able to get data from firebase.
I tried this but not working. I'm able to log in log out successfully. I'm also able to add data in firebase only once per date.
I'm just not able to fetch and show in table.
Here's what i tried:
`
// Get the user's attendance records
firebase.database().ref("attendance").once("value", function(snapshot) {
// Get the attendance data
var attendanceData = snapshot.val();
var userId = firebase.auth().currentUser.uid;
// Display the attendance history
for (var email in attendanceData) {
var attendance = attendanceData[email][userId];
if (attendance) {
for (var date in attendance) {
var status = attendance[date].status;
var tr = document.createElement("tr");
tr.innerHTML = `<td>${date}</td><td>${status}</td>`;
attendanceHistoryTable.appendChild(tr);
}
}
}
});
If I understand correctly, you have a data structure like this:
attendance: {
user: {
"$uid": {
"$date": {
Status: "..."
}
}
}
}
And from this you want to show the status per date for the current user.
If that's indeed the use-case, you can do this with:
const userId = firebase.auth().currentUser.uid;
const attendanceRef = firebase.database().ref("attendance");
const userRef = attendanceRef.child("users").child(userId);
userRef.once("value", function(userSnapshot) {
userSnapshot.forEach((dateSnapshot) => {
const status = dateSnapshot.child("Status").val();
console.log(`User: ${userSnapshot.key}, Date: ${dateSnapshot.key}, Status: ${status}`);
... // TODO: add the data to the HTML as you're already doing
});
});
The main changes I made here:
This only loads the data for the current user, instead of for all users.
This code uses the built-in forEach operation of a DataSnapshot.
This code gives more meaningful names to the variables, so that it's easier to parse what is going on.
This code uses "Status" rather then status, since that's the key in your database screenshot too.
My problem is with Stripe's metadata object having a 500 character limit. I have a working checkout flow but my only restriction is the character limit for my cart. My cartItems object has extras and customer notes I want to include for each cart Item. With that being said, the metadata limit gets to 500 characters fast. I have read on another post here, implementing websockets into my app which would let me create the order using after listening to stripes event. How would I go about this? Any other workarounds?
let endpointSecret;
endpointSecret =
"whsec_bd73383ed0fcf9cfb27bd4929af341605ad32577dfd8825e1143425b846bb3c3";
router.post("/webhook", (request, response) => {
const sig = request.headers["stripe-signature"];
let data;
let eventType;
if (endpointSecret) {
let event;
try {
event = stripe.webhooks.constructEvent(
request.rawBody,
sig,
endpointSecret
);
} catch (err) {
response.status(400).send(`Webhook Error: ${err.message}`);
return;
}
data = event.data.object;
eventType = event.type;
} else {
data = request.body.data.object;
eventType = request.body.type;
}
// Handle the event
if (eventType === "checkout.session.completed") {
stripe.customers
.retrieve(data.customer)
.then((customer) => {
console.log("customer:", customer);
console.log("data:", data);
createOrder(customer, data);
})
.catch((err) => console.log(err.message));
}
You don't typically pass all cart information in metadata, you would typically store that information in your own database and then retrieve the necessary information based on a UUID that corresponds with that data and the order ID that you set on the Checkout Session via metadata which then gets returned via the Webhook.
To give an example of what I'm recommending above --
In your database you would have something like:
Order ID
Cart Item1
Cart Item1 Description
Cart Item2...
123456
hat
red
scarf
123457
sock
blue
Then when you create your Checkout Session you just pass your Order ID as metadata. When you receive your checkout.session.completed Webhook, that metadata will indicate the Order ID so now you have all your data necessary for fulfillment and reconciliation (and you can update your database accordingly).
Also, to clear up a misconception, with Stripe's metadata you can have 50 keys each with values up to 500 characters long.
I made a simple POST request to fetch data from a search bar into backend. I am able to console.log it - but I need to be able to store that information (as a variable/const ideally) and IF it fits the criteria, I need to be able to add it into a function in the backend and return data based on that function. Is this possible with a PUT request or should I use query.params ?
app.post("/search", (req, res) => {
const result = req.body;
res.send({
search: result,
});
});
Pull data from search bar into backend
Run a function using the searched keyword
Return new information based around the keyword
for reference - here's the function that I would like to enter the searched keyword into for every instance of searchBarResultHere ( and there's 7 of them )
async function **searchBarResultHere**() {
const html = await request.get(
"https://finance.yahoo.com/quote/**searchBarResultHere**/"
);
const $ = await cheerio.load(html);
const Price = $('[class="Fw(b) Fz(36px) Mb(-4px) D(ib)"]').text();
const Symbol = $('[class="D(ib) Fz(18px)"]').text();
const PercentChange = $('fin-streamer[class="Fw(500) Pstart(8px) Fz(24px)"][data-field="regularMarketChangePercent"]').find('span').text();
await connectToMongoDB();
// fetch stock/crypto data
const listingModel = new **searchBarResultHere**({
price: Price,
symbol: Symbol,
percentChange: PercentChange,
});
// save into MongoDB Modal
await listingModel.save();
// UPDATE stock price if it changed
await Stock.findOneAndUpdate(
{
symbol: **searchBarResultHere**,
},
{
price: Price,
symbol: **searchBarResultHere**,
percentChange: PercentChange,
},
{
upsert: true
}
);
console.log(Price)
setTimeout(**searchBarResultHere**, 1000000); // 60 seconds == 1minute // not needed with node-cron
}
**searchBarResultHere**();
in a nutshell this is a program that goes on yahoo.finance and periodically records some chosen text fields from the yahoo.finance website.. then stores & displays it back into HTML with Stock/Crypto Name, Price and 24 hour change
I want to let people type in a stock name (or symbol), and make the program fetch all the data for them so they can see it without having to go on yahoo finance :)
But I'm struggling to figure out how to make the connection between seaching for a stock name and sending the search result to the backend function to fetch all data from yahoo.finance.
So I'm trying to Create a reset page using restful API. I haven't found much info on the internet and I'm probably no using the best method. What I'm trying to do is send a code in the email of the user and then after the user typing the code will be decided if he can or cannot update the pass. I can't seem to find a way to pass the value of the code generated on the first request to the second to check if its correct. Any help is appreciated. Thanks in advance!
//ForgotPassword?
app.get('/forgotpassword/:username', function (_req, res) {
var seq = (Math.floor(Math.random() * 10000) + 10000).toString().substring(1);
console.log(seq);
mysqlConnection.connect(function () {
mysqlConnection.query('SELECT Email from Customer Where Username = ?', [_req.params.username], (err, results, _fields) => {
if (!err){
console.log(results[0].Email);
var mailOptions = {
from: 'myemail',
to: results[0].Email,
subject: "Password Reset Verification",
text: "If you did not request this, please ignore this email and your password will remain unchanged. CODE: " + seq,
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
//Handle error here
res.send('Please try again!');
} else {
console.log('Email sent: ' + info.response);
res.send('Sent!');
}
})
}
else
console.log(err);
})
})
});
//CodeRandomCodeFromResetPass
app.get('/reset', function (req, res) {
var code;
//if code typed is = to seq sent in the email
res.send("The code is correct");
});```
//then I'll create a post request that updates the password username from the first get request
The code sent in email should be store in a table or collection. So code will be store against the email and an expiry time of the code. So in the next phase when the code will pass with an email you can check that this(entered) email should belong to this(entered) code within this(expiry time of code) time frame, so if condition satisfied then requested user can reset/change the password.
I am trying to update the user account details in firebase but I have noticed that the input value for one of my fields keeps coming up as undefined even when I console.log it. I am working in two files one is a loginjs file in which I am defining the user input.
signUpForm.addEventListener('click', function (e) {
e.preventDefault();
isSigningUp = true;
var email = signUpEmailInput.value;
var password = signUpPasswordInput.value;
var displayNameUser = displayNameInput.value;
var userPrivateKey = signUpPrivateKey.value;
var user = firebase.auth().currentUser;
var photoURL = "https://www.gravatar.com/avatar/" + md5(email);
if (signUpPasswordInput.value !== signUpPasswordConfirmInput.value) {
setSignUpError('Passwords do not match!');
} else if (!displayNameUser) {
setSignUpError("Display Name is required!");
} else if (!userPrivateKey) {
setSignUpError('You need to set a Private Key!');
} else {
auth.createUserWithEmailAndPassword(email, password)
.then(function (user) {
user.updateProfile({
displayName: displayNameUser,
photoURL: photoURL,
privateKey: userPrivateKey
}).then(function () {
// Update successful.
window.location.href = 'chat.html';
}).catch(function (error) {
// An error happened.
window.alert("Some unexpected error happened!");
});
user.sendEmailVerification().then(function () {
// Email sent.
}).catch(function (error) {
// An error happened.
window.alert("Email was not able to send!");
});
})
.catch(function (error) {
// Display error messages
setSignUpError(error.message);
});
}});
The weird thing is that the user input for my displayname and photoURL are working just fine, but when it comes to my private key user input it registers the input when it goes to the chat page and I do a console.log(user.privatekey) It says it is undefined.
In my chatjs file, thats when I am pushing the all the user profile information. The chatjs file basically allows a user to send a message, the message and all the user profile information gets stored onto the firebase database.
messages.push({
displayName: displayName,
userId: userId,
pic: userPic,
text: myString.toString(),
privatekey: user.privatekey,
timestamp: new Date().getTime() // unix timestamp in milliseconds
})
.then(function () {
messageStuff.value = "";
})
.catch(function (error) {
windows.alert("Your message was not sent!");
messageStuff;
});
The thing again is that the privatekey does not get stored at all, which is what I am not understanding, since it is registering user input in the loginjs file but when I go to the chatjs file it keeps saying the value is undefiend. I have googled everywhere and I still haven't found a solution to it. Any help would be greatly appricated!
It's because the Firebase user object you receive from Firebase is not customizable. When you call the createUserWithEmailAndPassword(email, password) method, it returns a specifically defined user object back to you - check out the docs for the properties of this object.
The properties displayName and photoURL both work because they are already properties of the user returned. privateKey is not an existing property of the Firebase user object, and Firebase doesn't know how to handle an update call for a property that isn't defined. Check out this question & answer where Frank explains that Users in Firebase aren't customizable - you need to store any extra info separately.