why twilio is not reading xml from url? - javascript

This is the code and i want twilio to read from a route which is a post route but it doesnt read xlm from there and there i want to get digit from a user and according to that input during call then i want the flow to work based on that input.
.create({
method: 'POST',
url: 'https://stormy-everglades-64562.herokuapp.com/voice',
to: '+923047931504',
from: '+17207344485'
})
.then(call => console.log(call.sid));
app.post('/voice', (request, response) => {
// Create TwiML response
const twiml = new VoiceResponse();
twiml.gather(
{
numDigits: 1,
action: '/gather',
},
gatherNode => {
gatherNode.say('For sales, press 1. For support, press 2.');
}
);
// If the user doesn't enter input, loop
twiml.redirect('/voice');
// Render the response as XML in reply to the webhook request
response.type('text/xml');
response.send(twiml.toString());
});```

Try the below:
app.post('/voice', (request, response) => {
// Create TwiML response
const twiml = new twilio.twiml.VoiceResponse();
const gather = twiml.gather(
{
numDigits: 1,
action: '/gather',
})
gather.say('For sales, press 1. For support, press 2.');
// If the user doesn't enter input, loop
twiml.redirect('/voice');
// res.set('Content-Type','text/xml');
response.type('text/xml');
response.send(twiml.toString());
});

Related

Express.js update/put route does not work

I have a website where I want to add, edit and delete student contact data. The data is stored in a SQLite database. My post, get and delete routes (Express API) work but my update route does not.
I load the data of an existing contact into a html form and my plan is to edit the data in the form to send the updated data via a button. But I get the error message "Cannot GET /api/update/contacts/1" although I've implemented a POST method request.
I guess the request doesn't hit the API endpoint but I don't know why, especially since all the other routes are working. Can anyone help?
I already tried MethodOverride, but it also did not work.
The code in my html page with the form and the button:
<form method="POST" id="myForm">
<button
onclick="update()"
id="aktualisierenButton"
type="submit"
>Aktualisieren
</button>
<script>
function update() {
window.open("/api/update/contacts/" + localStorage.getItem("paraID"),
"_blank",
"toolbar=no,scrollbars=no,width=800,height=800");
window.close();
}
I already tried MethodOverride, but it also did not help.
The code in my start.js file where I handle the routes:
app.put("api/update/contacts/:studentID", async (request, response) => {
const studentID = parseInt(request.params.studentID);
const existingContact = await contactsManager.getContact(studentID);
if (existingContact) {
const contact = request.body;
await contactsManager.updateContact(studentID, contact);
response.status(200).send();
} else {
response.status(400).send({
error: "The contact with the specified studentID does not exist.",
});
}
});
The code in my ContactsManager.js file where I handle the database requests:
async updateContact(studentID, contact) {
return new Promise((resolve, reject) => {
db.run(
"UPDATE contacts SET vorname = ?, nachname = ?, mail = ? WHERE studentID = ?",
[contact.vorname, contact.nachname, contact.mail, studentID],
(error, row) => {
if (error) {
reject(error);
} else {
resolve(row);
}
}
);
});
}
You are getting the error because window.open will make a GET request to the resource and load it into a window. Instead of creating a new window then destroying it just to update your data, try using the Fetch API instead.
Using the fetch api with a PUT request would look something like below. You will need to adapt this to your specific data, and process or display the result if that's what you are trying to achieve by opening a new window, but this should give you a starting point.
try {
let fetchUrl = "https://mysite.url/api/update/contacts/" + localStorage.getItem("paraID")
let fetchOptions = {
method: "PUT",
headers: {
"Content-Type": "application/json" // Update with your data type
},
body: JSON.stringify({
data: myData // Update with your JSON data to PUT
})
}
let response = await fetch(fetchUrl, fetchOptions)
if (response.ok) {
// Convert the response to json and process
let data = await response.json()
console.log(data)
}
} catch (error) {
// Handle network errors here
console.error(error)
}
Your endpoint also does not implement a POST request, it uses a PUT request. If you wanted a POST request you should use app.post instead of app.put, although using a PUT request is fine for what you are trying to achieve.

How to trigger an API call when a message is sent to Azure service bus topic?

I am working on Azure service bus topic. Following the documentation, created a sender and reciever code.
This is the sender code i am having,
const { ServiceBusClient } = require("#azure/service-bus");
const connectionString = "<SERVICE BUS NAMESPACE CONNECTION STRING>"
const topicName = "<TOPIC NAME>";
const messages = [
{ body: "Albert Einstein" },
{ body: "Werner Heisenberg" },
{ body: "Marie Curie" },
{ body: "Steven Hawking" },
{ body: "Isaac Newton" },
{ body: "Niels Bohr" },
{ body: "Michael Faraday" },
{ body: "Galileo Galilei" },
{ body: "Johannes Kepler" },
{ body: "Nikolaus Kopernikus" }
];
async function main() {
// create a Service Bus client using the connection string to the Service Bus namespace
const sbClient = new ServiceBusClient(connectionString);
// createSender() can also be used to create a sender for a queue.
const sender = sbClient.createSender(topicName);
try {
// Tries to send all messages in a single batch.
// Will fail if the messages cannot fit in a batch.
// await sender.sendMessages(messages);
// create a batch object
let batch = await sender.createMessageBatch();
for (let i = 0; i < messages.length; i++) {
// for each message in the arry
// try to add the message to the batch
if (!batch.tryAddMessage(messages[i])) {
// if it fails to add the message to the current batch
// send the current batch as it is full
await sender.sendMessages(batch);
// then, create a new batch
batch = await sender.createMessageBatch();
// now, add the message failed to be added to the previous batch to this batch
if (!batch.tryAddMessage(messages[i])) {
// if it still can't be added to the batch, the message is probably too big to fit in a batch
throw new Error("Message too big to fit in a batch");
}
}
}
// Send the last created batch of messages to the topic
await sender.sendMessages(batch);
console.log(`Sent a batch of messages to the topic: ${topicName}`);
// Close the sender
await sender.close();
} finally {
await sbClient.close();
}
}
// call the main function
main().catch((err) => {
console.log("Error occurred: ", err);
process.exit(1);
});
This code is working fine, but instead of sending a batch of dummy data to the service bus topic i want to implement my use case here.
My use case is I will be using this sender code in a react front end application, where there is a node API call happening at the end of a form submission. So at the end of form submission, i will send that unique form ID to the topic and i need to somehow trigger the api call for that form id.
I am unable to connect the dots. How to do this?
Added reciever side code.
const { delay, ServiceBusClient, ServiceBusMessage } = require("#azure/service-bus");
const axios = require("axios").default;
const connectionString = "<ConnectionString>"
const topicName = "<TopicName>";
const subscriptionName = "<Subscription>";
async function main() {
// create a Service Bus client using the connection string to the Service Bus namespace
const sbClient = new ServiceBusClient(connectionString);
// createReceiver() can also be used to create a receiver for a queue.
const receiver = sbClient.createReceiver(topicName, subscriptionName);
// function to handle messages
const myMessageHandler = async (messageReceived) => {
console.log(`Received message: ${messageReceived.body}`);
const response = axios({
method: 'post',
url: 'http://localhost:8080/gitWrite?userprojectid=63874e2e3981e40a6f4e04a7',
});
console.log(response);
};
// function to handle any errors
const myErrorHandler = async (error) => {
console.log(error);
};
// subscribe and specify the message and error handlers
receiver.subscribe({
processMessage: myMessageHandler,
processError: myErrorHandler
});
// Waiting long enough before closing the sender to send messages
await delay(5000);
await receiver.close();
await sbClient.close();
}
// call the main function
main().catch((err) => {
console.log("Error occurred: ", err);
process.exit(1);
});
While messages are published to a topic, they are recieved by subscriptions under the topic. You'll need to define one or more subscriptions to receive the messages. That's on the broker. For your code, you'll need a receiving code on the server-side/backend. Could be something like a node.js service or Azure Function. But a code that would receive from the subscription(s).
I would review the idea of publishing messages from the client side directly to Azure Service Bus. If the code is a React front end application, make sure the connection string is not embedded in resources or can be revealed.

React + Expressjs URL params returning undefined on get request

so I'm trying to make a web application that stores the user. I want to use this user in the back-end to retrieve information. So right now a button is clicked and that calls the back-end, the onClick function currently looks like this.
const getBackend = () => {
let url = new URL('https://http://localhost:4000/backend');
url.search = new URLSearchParams({
username: user,
});
fetch(`http://localhost:4000/prize`, {
method: "GET",
url:url,
});
}
and my express.js server looks like this:
app.get("/backend", async (req, res) => {
let user = req.query.username;
console.log("user");
res.send(user);
}
What happens is that when I click the button from the front end with the getBackend function the console and browser will log the user as "undefined". However, when I put the link on the browser directly as: http://localhost:4000/prize?username=test3%40something.edu I successfully get "test3#something.edu" working. How can I make the button give me the same as putting it on the browser?
Thank you.
I think you accidently added the https in the url. You should leave off the https and just keep the http
const getBackend = () => {
let url = new URL('http://localhost:4000/backend');
url.search = new URLSearchParams({
username: user,
});
fetch(`http://localhost:4000/prize`, {
method: "GET",
url:url,
});
}

How can I delay a POST request from a user form until AFTER a webhook POST from Stripe is received?

I want users to pay a fee before a POST request from a front end form is processed. I have a Stripe webhook that works fine on the backend, but I'm not sure how to delay the front end posting of the form until after the payment confirmation is received.
In the code below, right now, createTour and createTourPay run at the same time. I would like for createTourPay to execute first, and the createTour only triggers after Stripe posts to my application from the webhook. How can I achieve this?
Controller File (webhook):
exports.webhookCheckout = (req, res, next) => {
const signature = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
signature,
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
return res.status(400).send(`Webhook error: ${err.message}`);
}
if (
event.type === 'checkout.session.completed' &&
event.line_items.name === 'New Job Purchase'
) {
res.status(200).json({ recieved: true });
// Somehow, I want this to trigger the execution of the POST request in my front end JS file.
} else {
if (event.type === 'checkout.session.completed')
createBookingCheckout(event.data.object);
res.status(200).json({ recieved: true });
}
};
Front end JS file:
export const createTourPay = async myForm => {
try {
// 1) Get the checkout session from API response
const session = await axios(`/api/v1/tours/tour-pay`);
const complete = 1;
// console.log(session);
// 2) Create checkout form + charge the credit card
await stripe.redirectToCheckout({
sessionId: session.data.session.id
});
} catch (err) {
// console.log(err);
showAlert('error', err);
}
};
export const createTour = async myForm => {
try {
const startLocation = {
type: 'Point',
coordinates: [-10.185942, 95.774772],
address: '123 Main Street',
description: 'Candy Land'
};
const res = await axios({
method: 'POST',
headers: {
'Content-Type': `multipart/form-data; boundary=${myForm._boundary}`
},
url: '/api/v1/tours',
data: myForm
});
if (res.data.status === 'success') {
showAlert('success', 'NEW TOUR CREATED!');
window.setTimeout(() => {
location.assign('/');
}, 1500);
}
} catch (err) {
showAlert('error', err.response.data.message);
}
};
Broadly: don't do this. Instead, you in fact should create some pending/unpaid version of the "tour" (or any other product/service) in your system, then attach the unique id (eg: tour_123) to the Checkout session when you create it, either using the client_reference_id (doc) or metadata (doc):
const session = await stripe.checkout.sessions.create({
// ... other params
client_reference_id: 'tour_123',
metadata: { tour_id: 'tour_123' },
});
Then you'd use the webhook to inspect those values, and update your own database to indicate the payment has been made and that you can fulfill the order to the customer (ship product, send codes, allow access to service etc).
If you really want to proceed with a more synchronous flow, you can use separate auth and capture to sequence your customer experience and capture the funds later after authorizing and creating your tour entity.
Edit: a note about security
You should never trust client-side logic for restricted operations like creating a "paid" tour. A motivated user could, for example, simply call your /api/v1/tours create endpoint without ever going through your payment flow. Unless you validate a payment and track that state on your server you won't be able to know which of these had actually paid you.

PayPal Server Side integration not passing payment details to the client

Why am I not getting the response with the capture details on the client side?
I am trying to implement a server side integration for PayPal's smart buttons. I have tried a few different methods, and this is the method I have had the most success with.
However, it still doesn't appear to be working 100%. Atm, clicking a button opens the payment window, I can login with the sandbox personal account, go through the checkout flow, and then I get the standard alert, but for some reason I am not getting the desired response from the server.
When I sign into sandbox paypal, on the personal account, I can see the transactions being sent successfully (they are pending, awaiting confirmation from the merchant). When I sign into the sandbox merchant account, there are no transactions available. When I take the order ID from the smart button, and send it to PayPal's api route to get the order details, it comes back as captured and completed.
Has anyone else experienced something similar with the payments not showing up on the merchant sandbox account? If I sign into the developer account, and look at the API log, I can see the orders being created and captured successfully, but they still don't show up on the merchant account.
Here's my server side code:
const express = require("express");
const router = express.Router();
// 1. Set up your server to make calls to PayPal
// 1a. Import the SDK package
const paypal = require("#paypal/checkout-server-sdk");
// 1b. Import the PayPal SDK client that was created in `Set up Server-Side SDK`.
/**
*
* PayPal HTTP client dependency
*/
const payPalClient = require("./PayPalConfig");
// route to set up a transaction
router.post("/orders/create", async (req, res) => {
// 3. Call PayPal to set up a transaction
const request = new paypal.orders.OrdersCreateRequest();
request.prefer("return=representation");
request.requestBody({
intent: "CAPTURE",
purchase_units: [
{
amount: {
currency_code: "USD",
value: "4.20",
},
},
],
});
let order;
try {
order = await payPalClient.client().execute(request);
} catch (err) {
// 4. Handle any errors from the call
console.error(err);
return res.sendStatus(500);
}
// 5. Return a successful response to the client with the order ID
res.json({
orderID: order.result.id,
});
console.log(order.result.id);
});
// route to handle capturing of orders
router.post("/orders/capture", async (req, res) => {
// const captureDetails
let captureDetails = "";
// 2a. Get the order ID from the request body
const orderID = req.body.orderID;
// 3. Call PayPal to capture the order
const request = new paypal.orders.OrdersCaptureRequest(orderID);
request.requestBody({});
try {
const capture = await payPalClient.client().execute(request);
// 4. Save the capture ID to your database. Implement logic to save capture to your database for future reference.
const captureID = capture.result.purchase_units[0].payments.captures[0].id;
captureDetails = capture.result;
// await database.saveCaptureID(captureID);
res.json(captureDetails);
} catch (err) {
// 5. Handle any errors from the call
console.error(err);
return res.sendStatus(500);
}
// 6. Return a successful response to the client
// res.sendStatus(200).json({ details: captureDetails });
res.json({ details: captureDetails });
});
module.exports = router;
Here's my client side code:
// Render the PayPal button into #paypal-button-container
paypal
.Buttons({
// Call your server to set up the transaction
createOrder: function (data, actions) {
return fetch("http://localhost:3000/payment/paypal/orders/create", {
method: "post",
})
.then(function (res) {
return res.json();
})
.then(function (orderData) {
return orderData.orderID;
console.log(orderData.orderID);
});
},
// Call your server to finalize the transaction
onApprove: function (data) {
return fetch("http://localhost:3000/payment/paypal/orders/capture", {
method: "post",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({
orderID: data.orderID,
}),
})
.then(function (res) {
return res;
})
.then(function (details) {
console.log(details);
alert("Transaction funds captured from " + details.payer_given_name);
});
},
})
.render("#paypal-button-container");
Here's the details being logged from the client
Response {type: "cors", url: "http://localhost:3000/payment/paypal/orders/capture", redirected: false, status: 200, ok: true, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: "OK"
type: "cors"
url: "http://localhost:3000/payment/paypal/orders/capture"
__proto__: Response
On the server side, don't specify 'details' as a key.
res.json(captureDetails);
You need to return res.json() on the client side. It hasn't parsed the json object.
When I sign into the sandbox merchant account, there are no
transactions available. When I take the order ID from the smart
button, and send it to PayPal's api route to get the order details, it
comes back as captured and completed.
You are signing in to the wrong sandbox merchant account. The correct one will depend on the sandbox clientId you are using.

Categories