How can I process Apple pay in react native - javascript

It's my first time to use apple pay. I'm using react-native-payments library and I could get paymentToken but I cant understand how I can perform a payment process.
The payment provider companey hyperpay provided me entity Id and Access token but I don't know how to use them, which information I'll send, for any link I will send information and which response I'll get. This is the function does Payment process as documentation mentioned
paymentRequest.show()
.then(paymentResponse => {
const { paymentToken } = paymentResponse.details;
return fetch('...', {
method: 'POST',
body: {
paymentToken
}
})
.then(res => res.json())
.then(successHandler)
.catch(errorHandler);
});

Related

NMI gateway Updating Subscription

So I'm implementing a payment system with NMI gateway api. I've got everything working except for my update subscription function. To give a break down of how the NMI api works, you put in the required variables for the process you want done, in my case it's updating a subscription on a plan. So I've put the variables and used the POST directly to NMI to update the subscription with the variables that were passed in. I'm getting a response of ok and says it went through and updated subscription, however when I go to my merchant portal to make sure it worked, nothing has changed. To have recurring payments you first set up a plans and then users subscribe to the plans. I've got three different plans that the users should be able to Upgrade or Downgrade to.
Here is my utility function that will update the subscription on a plan
export const updateSubNmi = async ({
subscription_id,
plan_amount,
plan_payments,
day_frequency,
}) => {
const data = {
recurring: 'update_subscription',
subscription_id: subscription_id,
plan_amount: plan_amount,
plan_payments: plan_payments,
day_frequency: day_frequency,
//These are the required variables to read and react with NMI gateway
merchant_id: process.env.NMI_MERCHANT_ID,
merchant_password: process.env.NMI_MERCHANT_PASSWORD,
tokenization_key: process.env.NMI_TOKENIZATION_KEY,
security_key: process.env.NMI_API_KEY,
}
console.log('data to pass in: ', data)
const options = {
method: 'POST',
url: 'https://secure.nmi.com/api/transact.php',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
form: data,
}
return new Promise((resolve, reject) => {
request(options, (err, response, body) => {
if (err) {
reject(err)
} else {
resolve(body, response)
console.log(body)
// console.log(response.body)
}
})
})
}
export default updateSubNmi
Then I've set up a controller that awaits the above function then runs.
import expressAsyncHandler from 'express-async-handler'
import updateSubNmi from '../../Utils/nmiGatewayFunctions/nmiSubUpdate.js'
import Subscription from '../../models/Subscription.js'
export const updateNmiSub = expressAsyncHandler(async (req, res) => {
try {
const { subscription } = req.body
const sub = await Subscription.findById(subscription._id)
if (!sub) {
return res.status(400).json({
message: 'Subscription not found',
})
}
try {
if (sub.plan_id === '') {
console.log(`Free Subscription: ${sub.plan_id}`)
}
} catch (error) {
console.log(error)
return res.status(500).json({
success: false,
message: err.message,
})
}
await updateSubNmi(req.body)
res.status(200).json({ message: `process finished` })
} catch (error) {
console.error(error)
res.status(500).json({ message: `Server Error: ${error.message}` })
}
})
export default updateNmiSub
This is my Postman request to send the body to the gateway. It responds with 200 OK and gives my my custom message I've set up as "process finished"
{
"subscription": {
"_id": "6256f0ab7417d91f8e080aec"
},
"subscription_id": "7146266977",
"plan_amount": "49.99",
"plan_payments": "0",
"day_frequency": "30"
}
Once my route hits it gives me a response from gateway of Subscription Updated as you see below, however when I go the my merchant portal to ensure the subscription was updated to a different plan it's not showing changes.
response=1&responsetext=Subscription Updated&authcode=&transactionid=7146266977&avsresponse=&cvvresponse=&orderid=&type=&response_code=100&subscription_id=7146266977
There is obviously something I'm missing and have been stuck on this for a few days. Any help would be greatly appreciated.
Once a subscription is on a defined plan, the subscription’s plan cannot be updated. You’ll notice that documentation describes the plan_amount, plan_payments, day_frequency variables under the header titled:
Update a Custom Subscription's Plan Details
If the subscription you're attempting to edit uses a plan that's been saved in your account then these values are being ignored. Custom subscriptions are subscriptions that have their own plan that isn’t shared with other subscriptions.
To accommodate your use case, I’d suggest one of two approaches:
When a customer wants to switch plans, you cancel the existing subscription and create a new subscription on the new plan.
Or:
Use custom subscriptions instead of subscriptions on a named plan. To do this in the merchant portal, leave the “Save plan for future use” unchecked when creating subscriptions. If you’re using the Payments API to create subscriptions, use variables described under the “Adding a Custom Subscription” header in the documentation to create subscriptions.

How to use one update function for all fields of a specific model in REST API?

I am using Django REST Framework and React for a project. I have a API route called /api/account/user/ which accepts both GET and POST requests (RetrieveUpdateAPIView). Now, in my React front end, I have this function in my actions file that I would like to use to update user data:
export const updateUser = (email, name, company, phoneVerified, idVerified) => {
return (dispatch, getState) => {
const token = getState().auth.token
let headers = {
'Content-Type': 'application/json'
}
if (token) {
headers['Authorization'] = `Token ${token}`
}
let body = JSON.stringify({email, name, company, phoneVerified, idVerified})
return fetch('//localhost:8000/api/account/user/', {headers, body, method: 'POST'})
.then(res => {
if (res.status < 500) {
return res.json().then(data => {
return {status: res.status, data}
})
}
else {
console.log('Server error.')
}
})
.then(res => {
console.log(res)
if (res.status === 200) {
dispatch({type: 'USER_UPDATE_SUCCESSFUL', data: res.data})
return res.data
}
else if (res.status === 403 || res.status === 401) {
dispatch({type: 'USER_UPDATE_FAILED', data: res.data})
return res.data
}
else {
dispatch({type: 'USER_UPDATE_FAILED', data: res.data})
return res.data
}
})
}
}
This function works if I pass all parameters (email, name, company, phoneVerified, idVerified), but for example, if I want to only update phoneVerified on a button click event, how do I pass only that parameter? Currently I am doing this:
updateUser: (phoneVerified) => dispatch(auth.updateUser(phoneVerified))
But the server response is This field may not be null. Any help with this will be very much appreciated.
It is not the problem of React, it is how you handle in backend code.
You use HTTP POST method in rest API, by default it uses to create one record
You should implement other HTTP method handling for your endpoint, it is PUT method, but with PUT, you still need to send whole object with updated property to update it (Generally, PUT should use to update the record entirely)
Another HTTP method fit your case much better, it is PATCH method, just like PUT but you can just send the updated property to server with the record id (PATCH should use to update the record partially).
For both case, just SHOULD, not MUST because it is the standard convention of HTTP, it is not restricted. Even you still can use GET method to create record.
It depends on your backend code as well. But the line JSON.stringify({name, ...}) will render {name: null, ...} if name is null. So you're sending null values for all the attributes you're not updating. I would change that code to exclude those attributes altogether.

How to automatically join conversation in Microsoft web chat (bot framework)

I'm using https://github.com/Microsoft/BotFramework-WebChat/blob/master/README.md
I want the bot to receive a "join" message whenever the web-chat widget is displayed on the site.
The idea is that the human does not have to initiate the conversation. The bot can respond to somebody joining the conversation with a welcome message.
How is this possible?
This "Welcome feature" has been a long term discussion and topic since Webchat v3. It looks like it has been fixed 2 days ago with this pull request: https://github.com/Microsoft/BotFramework-WebChat/pull/1286
There is now a sample on how to do that, located here:
https://github.com/Microsoft/BotFramework-WebChat/blob/master/samples/15.d.backchannel-send-welcome-event/index.html
In a few words, the demo is the following:
(async function () {
// In this demo, we are using Direct Line token from MockBot.
// To talk to your bot, you should use the token exchanged using your Direct Line secret.
// You should never put the Direct Line secret in the browser or client app.
// https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-authentication
const res = await fetch('https://webchat-mockbot.azurewebsites.net/directline/token', { method: 'POST' });
const { token } = await res.json();
// We are using a customized store to add hooks to connect event
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
// When we receive DIRECT_LINE/CONNECT_FULFILLED action, we will send an event activity using WEB_CHAT/SEND_EVENT
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
}
return next(action);
});
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
Please note that due to the fact that this PR is quite new, it's not embedded in the latest release so you have to point to the master version of webchat.js file, not latest:
<script src="https://cdn.botframework.com/botframework-webchat/master/webchat.js"></script>
And it's working: your bot side is notified of an activity of type Event, where you will be able to reply to your user, before he typed anything:

How to integrate Dialogflow v2 with javascript frontend (Vue.js)

I'm trying to integrate Dialogflow with Vue.js (and axios) according to the documentation's sample HTTP request: https://dialogflow.com/docs/reference/v2-auth-setup and detectIntent: https://dialogflow.com/docs/reference/api-v2/rest/v2beta1/projects.agent.sessions/detectIntent.
I have a service account set up with sufficient permissions, and given it the path parameters and request body as shown in the documentation, but I keep getting 'Error: Request failed with status code 400' when calling the detectIntent API.
There are a few things I'm not sure of, though:
How do I get a sessionId? Currently I just copy the sessionId from Firebase Function logs which shows up when entering a query through the Dialogflow console directly.
How do I actually implement $(gcloud auth print-access-token) in javascript code? Currently I'm running the command in the terminal and pasting the token in the code, just to test if the API works, but I have no clue how it should be implemented.
(Perhaps useful, I have fulfillment set up in a functions folder, and that is working nicely.)
Thanks in advance!
<script>
import axios from 'axios'
export default {
name: 'myChatBot',
mounted () {
// Authorization: Bearer $(gcloud auth print-access-token)
const session = 'projects/mychatbot/agent/sessions/some-session-id'
const token = 'xxxxxxxxxxxx'
axios.defaults.baseURL = 'https://dialogflow.googleapis.com'
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`
axios.defaults.headers.post['Content-Type'] = 'application/json'
axios
.post(`/v2beta1/${session}:detectIntent`, {
"queryInput": {
"text": "add buy milk to inbox",
"languageCode": "en-US"
}
})
.then(response => console.log(response))
.catch(error => console.log(error))
}
}
</script>
You can use JWT authorization to handle your #2 question. You just need to put your JSON file someplace safe. https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth
The reason you are getting the code 400 is because your params are a little off. Here is how your post should look (I've also added some extra code to handle token generation):
<script>
import axios from 'axios'
import { KJUR } from 'jsrsasign'
const creds = require('./YOUR_JSON_FILE')
export default {
name: 'myChatBot',
data() {
return {
token: undefined,
tokenInterval: undefined
}
},
created() {
// update the tokens every hour
this.tokenInterval = setInterval(this.generateToken, 3600000)
this.generateToken()
},
mounted () {
this.detectIntent('add buy milk to inbox')
},
beforeDestroy() {
clearInterval(this.tokenInterval)
},
methods: {
generateToken() {
// Header
const header = {
alg: 'RS256',
typ: 'JWT',
kid: creds.private_key_id
}
// Payload
const payload = {
iss: creds.client_email,
sub: creds.client_email,
iat: KJUR.jws.IntDate.get('now'),
exp: KJUR.jws.IntDate.get('now + 1hour'),
aud: 'https://dialogflow.googleapis.com/google.cloud.dialogflow.v2.Sessions'
}
const stringHeader = JSON.stringify(header)
const stringPayload = JSON.stringify(payload)
this.token = KJUR.jws.JWS.sign('RS256', stringHeader, stringPayload, creds.private_key)
},
detectIntent(text, languageCode = 'en-US') {
if (!this.token) {
// try again
setTimeout(this.detectIntent, 300, text, languageCode)
return
}
// error check for no text, etc.
const session = 'projects/mychatbot/agent/sessions/some-session-id'
axios.defaults.baseURL = 'https://dialogflow.googleapis.com'
axios.defaults.headers.common['Authorization'] = `Bearer ${this.token}`
axios.defaults.headers.post['Content-Type'] = 'application/json'
axios
.post(`/v2beta1/${session}:detectIntent`, {
queryInput: {
text: {
text,
languageCode
}
}
})
.then(response => console.log(response))
.catch(error => console.log(error))
}
}
}
</script>
You can see that in QueryInput it's taking 1 of 3 different types of objects ("text" being one of those).
In the link, it's stated under the HTTP request session path parameters that "It's up to the API caller to choose an appropriate session id.
It can be a random number or some type of user identifier (preferably hashed).
For integration with Dialogflow V2, here's an example for doing with third-party tools that are easy to integrate and start using.
The sessionId is an identifier you can provide that will indicate to Dialogflow whether subsequent requests belong to the same "session" of user interaction (see docs).
For a client's first request to the API, you could just generate a random number to use as a session ID. For subsequent requests from the same client (e.g. if a user is continuing to converse with your agent) you can reuse the same number.
Your implementation of the token management looks fine, as long as the service account you are using has appropriately limited access (since this token could potentially allow anyone to make requests to Google Cloud APIs). For additional security, you could consider proxying the request to Dialogflow through your own server rather than making the call from the client.

preserving user authentication for customAPI calls of azure mobile services

I'm using AzureMobileServices custom API in my hybrid app. The customAPI name is lets say 'userUtils'.
The login and authentication part works good, I am able to authenticate user using facebook/google oAuth.
After login, in its done function , I call a customAPI function - insert (a http POST) - that basically adds the user in docDB if not already added. and returns back user details to my js client.
(I've 'POST' permission set to 'users with application key' for this customAPI ( btw, is this permission setting right or should it be 'only authenticated users'?)).
//below code is part of a typescript file
this._zumoClient = new WindowsAzure.MobileServiceClient( "https://abcdefExample.azure-mobile.net/", "someExampleApplicationKey");
...
....
....
public authenicateUser(p_oAuthProvider: string) {
var p: Promise<any> = new Promise(
(resolve: (result: any) => void, reject: (err: any) => void) =>
this._zumoClient.login(p_oAuthProvider, null).done(
(loginResult) => {
console.log("login returned with result : " + loginResult.userId);
var theUserAuthId = loginResult.userId;
this._zumoClient.invokeApi('UserUtils/insert', {
method: 'POST',
body: { userAuthId: theUserAuthId }
})
.done(
(loginResult: any) => {
resolve(loginResult)
},
(loginErr: any) => {
reject(loginErr);
}
);
},
(loginErr: any) => {
reject(loginErr);
}
)
);
return p;
}
this first 'invokeAPI' call to my customAPI works good.
However, at a later point, I try to call another customAPI 'usersSocialContacts' (a http GET), I get 401 - 'unauthorized request' ( I've 'get' permission set to 'only authenticated users' for this customAPI).
public getUserSocialContacts() {
var p: Promise<any> = new Promise(
(resolve: (result: any) => void, reject: (err: any) => void) =>
this._zumoClient.invokeApi('UserUtils/userSocialContacts', {
method: 'GET'
})
.done(
(contactsResult: any) => {
console.log("got contacts -" + JSON.stringify(contactsResult));
resolve(contactsResult);
},
(contatcsErr: any) => {
reject(contatcsErr);
}
)
);
return p;
}
And if I set the GET permission for this customAPI to 'allow users with the Application key', then the api function gets called but the request.user is undefined.
How does this work, how do I let the customAPI let know that this user has been authenticated and pass the user in every request, from js client. I read some suggestions in some SO questions or otherwise in google search, to cache the user's auth token and pass it in every request to zumo services using an optional filter object in login call, found some examples for C#/.net, but didn't find any clear example or documentation for javascript client, maybe I missed. Azure documentation gives a js example of calling a customAPI from js client, but that doesn't show caching part and sending authenticated user in subsequent requests.
Would appreciate any knowledge sharing or any pointers to right documentation in this regard.
If you would like only logged in users to access the custom api, then you need to set the permission to 'only authenticated users'.
Once the user is logged in, if you are using the same instance of MobileServiceClient (without logging out) then any requests made to zumo service should contain zumo auth token.

Categories