How to send confirmation order to an email provided through a post request - sendgrid

I have an ecommerce website (no user authentication) which stores some products (localStorage) and creates a post request with the user's mail provided in the form, along with the list of products.
The api path is www.api.site.com/api/orders. I am wondering how to send the order summary to the user's email, provided in the post request it sent.
Here is my Cart.js
var products = JSON.parse(localStorage.getItem("products"));
const onSubmit = (data) => { //on send order button press
var object = {
list: products, //the products list
...data, //email and phone
};
axios
.post(`https://api.*site*.com/api/orders`, {
data: {
email: object.email,
phone: object.phone,
items: object.list,
},
}).then(...)
I have seen that in every documentation, the controllers send the same mail to the same address
example :
// path: ./src/api/{api name}/controllers/{api name}.js or ./src/api/{api name}/services/{api name}.js
await strapi.plugins['email'].services.email.send({
to: 'valid email address',
from: 'your verified email address', //e.g. single sender verification in SendGrid
...
}),
How can I pass the user's email to the 'from' field? Any suggestion would be much appreciated.

Related

Add a new field for already existing resource using PUT

I implemented google auth in my NextJS app. The idea is: user makes some progress working with my web app, I store this progress in local storage as an array. If he decides to register I receive the session back, then I send PUT request to db to update the document by inserting a new field (array) from local storage.
I implemented GET request that returns registered user data by email and it works. The question is, how to insert a new field using PUT method? In my case this field is array and calls progress. I'm not sure if I should use update.
This is the record from my mongodb:
_id: 63cc85641624a77f17ca5f29
name: "John P"
email: "john.p#gmail.com"
image: "https://lh3.googleusercontent.com/a/AEdFTp7xzF4eYtyhTgRxmgP4vYdCqDa6zW…"
emailVerified: null
I want to add a new field: progress: ['some data']
This is my PUT request:
case 'PUT':
const updateData = await fetch(`${baseUrl}/updateOne`, {
...fetchOptions,
body: JSON.stringify({
...fetchBody,
filter: { email: email },
update: {} <---------------!!!!!
}),
})
const updateDataJson = await updateData.json()
res.status(200).json(updateDataJson.documents)
break
If you want to update your document using updateOne, and add a progress key, you can use:
filter: { email: email },
update: {$set: {progress: arr}}

How to attach an ICS (calendar invite) to an email and have it automatically accepted and added to calendar?

It seems when you get an email from a confirmation of a flight booking or an Airbnb reservation, GMail automatically adds an event to your calendar that is already pre-approved. Wondering how that happens? I've looked at all the other answers like this one and was able to get the Calendar invite to show up on the email and Google Calendar but not to have it be automatically approved. This gist was also useful in getting to this point, but now I can't find any information. Even more confusing: if you look at the Flights/Airbnb reservation emails, you won't see any attachments to the emails (no .ics). This is what my event data for the ics library looks like:
const event = {
start: startDate,
end: endDate,
status: 'CONFIRMED',
busyStatus: 'FREE',
organizer: {
name: myName,
email: myEmail,
},
attendees: [
{
name,
email,
rsvp: true,
partstat: 'ACCEPTED',
},
],
url: calUrl,
title: calTitle,
summary: calSummary,
description: calDescription,
location: address,
productId: productId,
method: 'PUBLISH',
};

Firestore cloud functions - can I send emails to users every time an document is added to a different collection (not 'users')?

I'm very new to cloud functions but have set up a couple of firestore cloud functions & got them working sending emails to individuals when their user document is created or updates but I really want to send emails to each user when a document is added to another collection (it's a react app displaying videos - I want to update all subscribed users when a new video is added). I can restructure the db if necessary but it currently has users and videos as the only 2 root level collections.
I've tried using .get() to the users collection to collect all their email addresses to put in the 'to' field of the email, but I just get an error saying 'db.get() is not a function'. After researching I found a couple of things to try but both got the same error:
functions.firestore
.document('users/{uid}').get()
.then((querySnapshot) => {
and
const admin = require('firebase-admin');
var db = admin.firestore();
db.document('users/{uid}').get()
.then((querySnapshot) => {
Can anyone help? Is it possible to do this? It seems that in theory the new Email Trigger Extension might do this but tbh I'd rather code it myself and learn how it works as I go - especially having 'cracked' the first two! But I can't find any way to access the contents of two collections within one function & I've spend days looking in all the usual places for any info so I'm beginning to think maybe cloud functions can only access one collection per function - but I also can't find anything that actually says that...?
Here is the whole function using the format I have working for the other 2 functions (apart from trying to access the users):
const functions = require('firebase-functions');
const nodemailer = require('nodemailer');
const admin = require('firebase-admin');
var db = admin.firestore();
//google account credentials used to send email
var transporter = nodemailer.createTransport({
host: process.env.HOST,
port: 465,
secure: true,
auth: {
user: process.env.USER_EMAIL,
pass: process.env.USER_PASSWORD,
}
});
//Creating a Firebase Cloud Function
exports.sendNewVidEmail = functions.firestore
.document('videos{uid}')
.onCreate(async (snap, context) => {
const newValue = snap.data();
// access title & description
const newVideoTitle = newValue.title;
const newVideoDescription = newValue.description;
//try to access users
db.document('users/{uid}').get()
.then((querySnapshot) => {
let users = [];
querySnapshot.forEach((doc) => {
// check for data
console.log(doc.id, " => ", doc.data());
users.push(doc.data().subscriberEmail)
//check for 'users' array
console.log('users = ', users)
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
// perform desired operations ...
if (newVideoTitle) {
const mailOptions = {
from: process.env.USER_EMAIL,
to: users,
subject: 'new video!',
html: `
<h2> xxx has a new video called ${newVideoTitle}</h2>
<p> xxx says this about ${newVideoTitle}: ${newVideoDescription}.
</p></ br>
<h4>Watch ${newVideoTitle} here.and please tick 'like' if you like it!</h4>
<p>Yours,</p>
<p>xxx :-) </p>`
};
return transporter.sendMail(mailOptions)
.then(() => {
console.log('sent')
})
.catch(error => {
console.log(error)
return
})
}
});
Well, I fixed it!! The code I was using was almost there, and thanks to a great youtube tutorial from Jeff Delaney (fireship) [here][1] I got the code I needed. 2 lines and so simple, and now I'm kicking myself, but in case anyone else gets stuck on this, my error was to try & use .forEach() (from the docs) and .push() to get the users' emails array when just using .map() on the snapshots creates the users array perfectly and then it worked!
const userSnapshots = await admin.firestore().collection('users').get();
const emails = userSnapshots.docs.map(snap => snap.data().subscriberEmail);
Hope it helps someone down the line:
https://www.youtube.com/watch?v=vThujL5-fZQ

I don't understand how to get a token to make API calls

I'm using the Payouts API and to do so I have to specify an access token when calling https://api-m.sandbox.paypal.com/v1/payments/payouts
To get an access token, as specified here I have to send a POST request with Postman to https://developer.paypal.com/docs/api/overview/#get-an-access-token and it returns in the response the token
My problem is that this token has an expiration time, which is an issue because I can't go in my app every 15 minutes to change the token in the Authorization header. How can I get a "permanent" or rather an "auto refreshed" token ?
I tried to make a call from my app instead of Postman but it doesn't seem to work, it says my credentials are invalid
This is my code in case it can be useful (I'm managing everything from the front-end):
window.paypal
.Buttons({
createOrder: (data, actions) => {
return actions.order.create({
purchase_units: [
{
description: this.product.description,
amount: {
value: this.product.price
}
}
]
});
},
onApprove: (data, actions) => {
const timestamp = new Date().getUTCMilliseconds();
const id = timestamp;
return actions.order.capture().then(details => {
axios
.post(
"https://api-m.sandbox.paypal.com/v1/payments/payouts",
{
sender_batch_header: {
sender_batch_id: id,
email_subject: "You have a payout!",
email_message:
"You have received a payout! Thanks for using our service!",
recipient_type: "EMAIL"
},
items: [
{
amount: {
value: this.product.price,
currency: "USD"
},
note: "congrats someone bought your stuff",
sender_item_id: id,
receiver: "john#doe.com"
}
]
},
{
headers: {
Authorization:
"Bearer <my token that I get from postman>"
}
}
)
.then(() => {
alert(
"Transaction completed by " + details.payer.name.given_name
);
})
.catch(err => console.log(err));
});
}
})
.render(".paypal");
}
},
Update
Reading the code a second time and noticing how your Payout is for the same this.product.price as the original payment, that makes no sense. Don't use payouts at all for this use case. The full amount will go to your account normally, but if you want the full amount to go somewhere else instead, set the payee variable for this checkout: https://developer.paypal.com/docs/checkout/integration-features/pay-another-account/
(original answer below)
Using Payouts from the client side is an absolutely terrible idea, anyone with your client credentials will be able to send money from your account to wherever they want
The payouts API must be used from your server only. Your server needs to do an API call to get an access token, similar to what you mention about postman -- except using whatever backend environment you have. You can integrate direct HTTPS calls, or there are also Payouts SDKs available which will handle getting the access token automatically.
As for how to trigger that backend action when capturing a payment, use a proper server integration:
Create two routes, one for 'Create Order' and one for 'Capture Order', documented here. These routes should return JSON data. Before returning JSON data, that last route (the capture one) should record the successful transaction in your database and trigger any Payout logic you want.
Pair those two routes with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server

How to subscribe to certain records in collection with id in meteor

I'm new to meteor,I have two collections named Employee and Visitors.and two templates Home and Print. i can get the id of the record from the button like this.
printVisitor:function(){
return Visitor.findOne({_id:Session.get('UpdateVisitorId')});
}
now when i click button that redirects to another page and i need to print those values say name, phone number using the particular id of record which i could get from the above code.
my route code looks like this
Router.route('/print/:_id', {
name: 'print',
controller: 'PrintController',
action: 'action',
where: 'client'
});
and my print html is this
<template name="Print">
This is: {{VisitorName}}
Visiting:{{EmployeeName}}
Phone:{{PhoneNumber}}
how can i publish and subscribe and print those certain values of that id
Publish and subscribe can take arguments. You also want to use this.params to get the URL parameters. This is the general pattern
Router.route('/foo/:_id', {
name: 'foo',
waitOn: function(){
// this grabs the ID from the URL
var someId = this.params._id;
// this subscribes to myPublication while sending in the ID as a parameter to the publication function
return [
Meteor.subscribe('myPublication', someId)
]
}
});
/server/publications.js
Meteor.publish('myPublication', function(id){
check(id, String);
return MyCollection.findOne({_id: id});
});
You'll now have access to the data you subscribed to on this route.