Send data from script.js to Node.js file (Using Sendgrid API) - javascript

Trying to insert data into a node.js server file from a submit event on another js.file client.
But it wont work could you see if there is any wrong with code? Looks kinda good to me but ofcourse something is wrong.
Client submit event code
`window.onload = function() {
document.getElementById('contact-form').addEventListener('submit', function(event) {
event.preventDefault();
const customMessage = document.getElementById('contact-form');
$.post("/request", {
mes: customMessage
}, function(data, status) {
console.log(data);
});
});
}`
Server node js code
// require necessary modules
`const express = require('express');
const bodyParser = require('body-parser');
const sgMail = require("#sendgrid/mail");
require('dotenv').config({ path: './dist/sendgrid/.env' });`
// set up the express app
`const app = express();
const port = process.env.PORT || 3000;`
// use body-parser middleware to parse request body
`app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());`
// set up the SendGrid API key
`sgMail.setApiKey(process.env.SENDGRID_API_KEY);`
// define route to handle POST request from client
`app.post('/request', async (req, res) =\> {
try {
// extract message from request body
const { mes } = req.body;
`
// send email using SendGrid
` await sgMail.send({
to: 'test#gmail.com',
from: 'test2#gmail.com',
subject: 'test text not working',
text: mes
});
console.log('Email sent successfully');
res.status(200).send('Email sent successfully');`
} catch (error) {
console.error(error);
if (error.response) {
console.error(error.response.body);
}
res.status(500).send('Internal server error');
}
});`
// start the server
`app.listen(port, () =\> {
console.log(`Server started on port ${port}`);
});
`
This is basic code that is working on single execute:
`
require("dotenv").config();
const sgMail = require("#sendgrid/mail");
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const sendMail = async(msg) =\> {
try{
await sgMail.send(msg);
console.log("message sent succes");
} catch (error) {
console.error(error);
if (error.response) {
console.error(error.response.body);
}
}
};
sendMail({
to: 'test#gmail.com',
from: 'test2#gmail.com',
subject: 'test text',
text: "this test works"
});`

Related

Stripe & Node.js - "Cannot POST /create-checkout-session"

I'm trying to follow the Stripe Checkout subscription instructions:
https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=checkout
When I submit the form, over localhost I get "Cannot POST /create-checkout-session" (404 in network tab), and if I run from my production server, it just opens /create-checkout-session as a new (blank) Vue page. I have tried changing the form action to https://mydomain.xyz/create-checkout-session, but it didn't work.
Subscribe.vue
<form action="/create-checkout-session" method="POST">
<input type="hidden" name="priceId" value="[removed for Stack Overflow]" />
<button type="submit">Checkout</button>
</form>
I don't know if something is interfering with the endpoint, so I've copied my entire app.js file:
app.js
let express = require('express'),
cors = require('cors'),
mongoose = require('mongoose'),
database = require('./database'),
bodyParser = require('body-parser');
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
const stripe = require('stripe')('[removed for StackOverflow]');
//connect mongoDB
mongoose.Promise = global.Promise;
mongoose.connect(database.db, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log("Database connected")
},
error => {
console.log("Database couldn't be connected to: " + error);
}
)
const cryptoEndPoint = require('../backend/routes/crypto.route')
const app = express();
app.use(decodeIDToken);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cors())
//API
app.use('/api', cryptoEndPoint)
app.post("/create-checkout-session", async (req, res) => {
console.log("can't even get anything to console log, only get createError is not defined");
const { priceId } = req.body;
// Create new Checkout Session for the order
// Other optional params include:
// [billing_address_collection] - to display billing address details on the page
// [customer] - if you have an existing Stripe Customer ID
// [customer_email] - lets you prefill the email input in the form
// [automatic_tax] - to automatically calculate sales tax, VAT and GST in the checkout page
// For full details see https://stripe.com/docs/api/checkout/sessions/create
try {
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [
{
price: priceId,
// For metered billing, do not pass quantity
quantity: 1,
},
],
// {CHECKOUT_SESSION_ID} is a string literal; do not change it!
// the actual Session ID is returned in the query parameter when your customer
// is redirected to the success page.
success_url: 'https://mydomain.xyz/thankyou?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://mydomain.xyz/thankyou',
});
return res.redirect(303, session.url);
} catch (e) {
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
});
//create port
const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
console.log('Connected to port ' + port);
})
//Find 404
app.use((req, res, next) => {
next(createError(404));
})
//error handler
app.use(function (err, req, res, next) {
console.log(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
})
/**
* Decodes the JSON Web Token sent via the frontend app
* Makes the currentUser (firebase) data available on the body.
*/
async function decodeIDToken(req, res, next) {
if (req.headers?.authorization?.startsWith('Bearer ')) {
const idToken = req.headers.authorization.split('Bearer ')[1];
// console.log(idToken);
try {
const decodedToken = await admin.auth().verifyIdToken(idToken);
// console.log("one");
req['currentUser'] = decodedToken;
// console.log("two");
} catch (err) {
console.log("error: " + err);
}
}
next();
}
app.post("/webhook", async (req, res) => {
let data;
let eventType;
// Check if webhook signing is configured.
const webhookSecret = '[removed for Stack Overflow]'
if (webhookSecret) {
// Retrieve the event by verifying the signature using the raw body and secret.
let event;
let signature = req.headers["stripe-signature"];
try {
event = stripe.webhooks.constructEvent(
req.body,
signature,
webhookSecret
);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`);
return res.sendStatus(400);
}
// Extract the object from the event.
data = event.data;
eventType = event.type;
} else {
// Webhook signing is recommended, but if the secret is not configured in `config.js`,
// retrieve the event data directly from the request body.
data = req.body.data;
eventType = req.body.type;
}
switch (eventType) {
case 'checkout.session.completed':
//...
break;
case 'invoice.paid':
//...
break;
case 'invoice.payment_failed':
//...
break;
default:
// Unhandled event type
}
res.sendStatus(200);
});
Does anyone know what is going wrong?
I added this to my app.js file, and it's working:
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
app.use(allowCrossDomain);

Nodemailer email posting but says pending

I'm trying to use Nodemailer in a React/Express app I'm working on and on the server it says it's posting but in the network tab its showing pending and then it never goes through? Here's my code:
const express = require('express');
const router = express.Router();
const nodemailer = require('nodemailer');
require("dotenv").config();
// router.get('/', () => {
// resizeBy.send('Welcome to my email form')
// });
module.exports = () => {
router.post('/', (req, res) => {
console.log("inside event handler")
let transporter = nodemailer.createTransport({
service: 'Gmail',
port: 465,
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
let mailOptions = {
from: process.env.EMAIL,
to: `${req.body.values.email}`,
subject: `Message from: ${process.env.EMAIL}`,
html: `
<h3>Information</h3>
<ul>
<li>Name: ${req.body.values.name}</li>
<li>Email: ${req.body.values.email}</li>
</ul>
<h3>Message</h3>
<p>${req.body.values.message}</p>
`
}
transporter.sendMail(mailOptions, (err, response) => {
if (err) {
res.send(err)
console.log("Error happened in send email", err)
} else {
res.send('Success! Message sent!')
console.log("Message sent")
}
})
transporter.close();
})
return router;
}
It looks like you don't need to use transporter.close() since you aren't pooling connections. Using it in this context is probably your problem.
transporter.sendMail() is async so you are sending mail and then immediately closing it with transporter.close(). This means the sendMail callback isn't fired, which in turn means res.send() is never sent, which results in your never ending and pending http request to your client.
I suggest removing the transporter.close() line and retrying.

Nodemailer not sending email, displays "Message sent:Undefined"

It was working and then it wasn't. I sent a few mails and after a while it stopped working. I get
"Message sent:Undefined"
(node:9048) UnhandledPromiseRejectionWarning: Error: spawn sendmail ENOENT
at Process.ChildProcess._handle.onexit (internal/child_process.js:269:19)
I have no idea why.
Frontend- Axios console logs the response data therefore the server and the frontend both are working. It is just the issue with the Nodemailer.
Any help is appreciated. Thanks!
const express = require("express");
const app = express();
const cors = require("cors");
const nodemailer = require("nodemailer");
const path = require("path");
const fs = require("fs");
const readData = path.join(__dirname, "../email_take2/data.json");
const { v4: uuidv4 } = require("uuid");
app.use(express.json());
app.use(cors());
const port = process.env.PORT || 5000;
app.listen(5000, () => console.log(`Listening at port ${port}`));
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use(express.static("../client/build"));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "../client", "build", "index.html"));
});
}
function listUserData() {
const data = fs.readFileSync(readData);
return JSON.parse(data);
}
app.post("/sendEmail", function (req, res) {
console.log(req.body);
const emailInfo = {
id: uuidv4(),
email: req.body.email,
cc: req.body.cc,
message:req.body.message,
};
const dataArray = listUserData();
dataArray.push(emailInfo);
fs.writeFileSync(readData, JSON.stringify(dataArray));
res.send(emailInfo);
console.log("SentBody", emailInfo);
let transporter = nodemailer.createTransport({
sendmail:true,
host: "smtp.outlook.com",
port: 587,
secure: false, // true for 465, false for other ports
tls: {
ciphers: "SSLv3",
},
auth: {
user: "memail#outlook.com", // generated ethereal user
pass: "mypw", // generated ethereal passwordAccount.pass,
},
});
// send mail with defined transport object
let info = transporter.sendMail({
from: '"Fred Foo 👻" <foo#example.com>', // sender address
to: "garbageacc7878#outlook.com", // list of receivers
subject: "Hello ✔", // Subject line
text: "Hello world?", // plain text body
html: "<b>Hello world?</b>", // html body
});
console.log("Message sent: %s", info.messageId);
return emailInfo;
});
transporter.sendMail returns a promise, that's why your console log has undefined. So either attach a .then and .catch.
transporter.sendMail(...)
.then((data)=>{console.log('Mail sent', data)})
.catch(err => {console.error('Failure',err)})
Or make your request handler an async function and use async await and use tryCatch.
try{
let data = await transporter.sendMail(...)
console.log('Mail sent', data)
} catch (err) {
console.error('Failure',err)
}

How come fetch only works here when I add an alert to the end of the line? Express + NodeJS + Fetch. What's a good fix here

I'm using NodeJS w/ Express to create a web app that records your audio using the VMSG library and posts the BLOB audio to my file system using HTTP Requests and multer. It also adds that instance of a recording into a MongoDB database.
I'm having an issue with the fetch command. It's not working unless I put an alert right after the fetch. The way I have it set up is that I have my main express app (index.js), and a router to the /recordingsDirectory (recordings.js) which is the endpoint for processing the posts. My main index HTML page uses Handlebars and uses a separate JS script (recorder.js) to 1) use the VMSG library and 2) fetch a POST to the /recordingsDirectory once someone submits the audio file w/ the name and the AudioBlob present. This is where I'm stuck. I can fetch in recorder.js with an alert line after the fetch, but I can't have the fetch on the end of the else if block by itself. I'd like to do it without this since the alert is ugly. A solution I've tried is that I tried to make the onsubmit function async and await fetch since I thought maybe it's waiting for a promise but that didn't work.
Here are the files. I commented CRITICAL and SUPER CRITICAL to the lines of code that you should check out and I think where the issues lie:
index.js
const express = require('express')
const handlebars = require('express-handlebars')
const path = require('path')
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const xhr = new XMLHttpRequest()
const db = require('./db')
const app = express()
const PORT = process.env.PORT || 8000
app.set('view engine', 'hbs')
app.engine('hbs', handlebars({
layoutsDir: path.join(__dirname, 'views', 'layouts'),
extname: 'hbs',
defaultLayout: 'index',
partialsDir: path.join(__dirname, 'views', 'partials'),
}))
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use((err, req, res, next) => {
if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
return res.status(400).send({ status: 404, message: err.message })
}
next()
})
app.get('/', (req, res) => {
res.render('main', {
title: 'Main Page'
})
})
app.get('/recordings', (req, res) => {
var database = db.get().db('AudioJungle')
database.collection('recordings').find().sort({ "date": -1 }).toArray(function(err, docs) {
res.render('recordings', {
title: 'Recordings',
recordings: docs
})
})
})
// CRITICAL
app.use('/recordingsDirectory', require('./recordings/recordings'))
app.use(express.static('public'))
app.use('/scripts', express.static(path.join(__dirname, 'node_modules', 'vmsg')))
db.connect(function(err) {
if (err) {
console.log('Unable to connect to Mongo.')
process.exit(1)
} else {
app.listen(PORT, () => console.log(`Listening on Port: ${PORT}`))
}
})
process.on('SIGINT', function() {
db.close(function () {
console.log('Disconnected on app termination');
process.exit(0);
});
});
app.use((req, res, next) => {
res.status(404).send({
status: 404,
error: 'Not found'
})
})
recordings.js (Aka the /recordingsDirectory endpoint for a fetch POST)
const express = require('express')
const router = express.Router()
const multer = require('multer')
const fs = require('fs-extra')
const db = require('../db')
const { ObjectId } = require('bson')
const moment = require('moment')
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, callback) => {
let path = './public/uploads'
fs.mkdirsSync(path)
callback(null, path)
},
filename: (req, file, callback) => {
createRecording(req).then((id) => {
var file_name = id + '.mp3'
callback(null, file_name)
})
}
})
})
var type = upload.single('audio-file')
// CRITICAL
router.post('/', type, (req, res) => {
console.log('made it')
res.status(200)
res.send('OK')
})
router.delete('/delete', (req, res) => {
deleteRecording(req.body._id).then((dbResponse) => {
if (dbResponse == null || dbResponse == undefined) {
res.status(400).json({ msg: 'ID already deleted' })
} else {
res.status(200)
}
})
})
router.get('/', (req, res) => {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
recordings.findOne({"_id": ObjectId(req.query.id)}, function(err, result) {
if (err) throw err
if (result == null || result == undefined) {
return res.status(400).json({
status: 404,
error: 'Recording no longer in the database'
})
}
res.status(200)
res.json({
name: result.name,
date: result.date
})
})
})
async function createRecording(req) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioObject = {
name: req.body.name,
date: moment().format('MMMM Do YYYY, h:mm:ss a')
}
var dbResponse = await recordings.insertOne(audioObject)
return dbResponse.insertedId
}
async function deleteRecording(id) {
var database = db.get().db('AudioJungle')
var recordings = database.collection('recordings')
var audioToDelete = {
_id: ObjectId(id)
}
var deleteResult = await recordings.deleteOne(audioToDelete)
return deleteResult
}
module.exports = router
And below is the Script the audio and name and tries to Fetch (where I need the alert for it to actually process into the /recordingsdirectory)
recorder.js
import { record } from "/scripts/vmsg.js";
let recordButton = document.getElementById("record");
var blobObj = null
recordButton.onclick = function() {
record({wasmURL: "/scripts/vmsg.wasm"}).then(blob => {
blobObj = blob
var tag = document.createElement("p")
tag.id="finishedRecording"
var text = document.createTextNode("Audio File Recorded")
tag.appendChild(text)
var element = document.getElementById("box")
element.appendChild(tag)
document.getElementById('box').appendChild(a)
})
}
let form = document.getElementById('mp3Form');
form.addEventListener("submit", submitAudio)
function submitAudio() {
var fileName = form.elements[0].value
if (fileName == "") {
alert('Please enter a name for your file')
} else if (blobObj != null) {
// CRITICAL
// SUPER CRITICAL WHERE FETCH DOESN'T WORK UNLESS I PUT AN ALERT AT THE END
const formData = new FormData()
formData.append('name', fileName)
formData.append('audio-file', blobObj)
const options = {
method: 'POST',
body: formData
}
fetch('/recordingsDirectory', options);
// If I comment an alert here, /recordingsDirectory will process the post since it console.logs 'made it'
} else {
alert('Record some Audio to upload')
}
}
Here's my file system.
Also, I'd like to mention that the fetch works properly on my Windows PC without having to add the alert, but it doesn't work without the alert on my macbook. If any one figures out a fix or an error in how I'm doing things to allow this please let me know. I've been stuck on this problem for a day now. Thanks a bunch!

how to integrate dialogflow result to linebot (Node.js)?

I am creating the chatbot(Line) integrate the Google Dialogflow using node.js.
I can create the line chatbot from user input the text and echo some text, only.
And I can create the code from user input send command to Google Dialogflow, and dialogflow using
the NLU tech response text to the user.
But I need user input the text send to the dialogflow and response the text(A) , then send the text(A)(after code add some template button's code) to Line bot create show some template button to user.
How can I integrate two part code achieve user input text and through dialogflow result , using the result send to the line bot server?
user input -> dialogflow ->mycode(add some template button call line) ->linbot ->bot show template button to user
Thank you.
//----------------------------------
My dialogflow code:
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(
bodyParser.urlencoded({
extended: true
})
)
app.use(
bodyParser.json()
)
app.post("/webhook", function(req,res){
console.log(JSON.stringify(req.body, null, 2))
var intent = req.body.queryResult.intent.displayName;
var entityCity = req.body.queryResult.parameters["geo-city"];
if(intent === 'myIntent')
{
// here I need call bot.on method, but I don't known how to do.
// return res.json({
fulfillmentText: `I known your mean.`
});
}
else
{
return res.json({
fulfillmentText: `i am not sure your mean`
});
}
})
app.listen(process.env.PORT || 5566, function(){
console.log('server start ...');
})
//----------------------------------
My Line chatbot code:
var linebot = require('linebot');
var express = require('express');
var app = express();
const bot = linebot({
channelId: 'mychannelId',
channelSecret: 'mychannelSecret',
channelAccessToken: 'mychannelAccessToken'
});
bot.on('message',function(event) {
console.log('bot');
console.log(event);
var msg = event.message.text;
// here can add some template button code and reply to user.
});
const linebotParser = bot.parser();
app.post('/webhook', linebotParser);
var server = app.listen(process.env.PORT || 8080, function() {
var port = server.address().port;
});
//--------------------
My Line chatbot code other version:
const line = require('#line/bot-sdk');
const express = require('express');
const lineConfig = {
channelAccessToken: process.env.HEROKU_LINE_CHANNEL_ACCESS_TOKEN,
channelSecret: process.env.HEROKU_LINE_CHANNEL_SECRET
};
const client = new line.Client(lineConfig);
const app = express();
app.post('/webhook', line.middleware(lineConfig), function(req, res) {
Promise
.all(req.body.events.map(handleEvent))
.then(function(result) {
res.json(result);
});
});
function handleEvent(event) {
switch (event.type) {
case 'join':
case 'follow':
return client.replyMessage(event.replyToken, {
type: 'text',
text: 'hello~'
});
case 'message':
switch (event.message.type) {
case 'text':
return client.replyMessage(event.replyToken, {
type: 'text',
text: (event.message.text+'~yu')
});
}
}
}
app.listen(process.env.PORT || 3000, function(){
console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});
const line = require('#line/bot-sdk');
const express = require('express');
const dialogflow = require('dialogflow');
const uuid = require('uuid');
const lineConfig = {
channelAccessToken: process.env.HEROKU_LINE_CHANNEL_ACCESS_TOKEN,
channelSecret: process.env.HEROKU_LINE_CHANNEL_SECRET
};
const client = new line.Client(lineConfig);
const app = express();
app.post('/webhook', line.middleware(lineConfig), function(req, res) {
Promise
.all(req.body.events.map(handleEvent))
.then(function(result) {
res.json(result);
});
});
async function handleEvent(event) {
switch (event.type) {
case 'join':
case 'follow':
return client.replyMessage(event.replyToken, {
type: 'text',
text: 'hello~'
});
case 'message':
switch (event.message.type) {
case 'text':
const response = await queryDF(event.message.text)
// you will get response from DF here
return client.replyMessage(event.replyToken, {
type: 'text',
text: (event.message.text+'~yu')
});
}
}
}
async function queryDF(message, projectId = 'your-project-id') {
// A unique identifier for the given session
const sessionId = uuid.v4();
// Create a new session
const sessionClient = new dialogflow.SessionsClient();
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: message,
// The language used by the client (en-US)
languageCode: 'en-US',
},
},
};
// Send request and log result
const responses = await sessionClient.detectIntent(request);
return responses[0].queryResult;
}
app.listen(process.env.PORT || 3000, function(){
console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});
You need to user dialogflow npm detect Intent method

Categories