How to get PayPal client-side info to Django? - django

I am using PayPal standard IPN payment solution in client side in my Django web app.
<body>
<!-- Set up a container element for the button -->
<div id="paypal-button-container"></div>
<!-- Include the PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=test&currency=USD"></script>
<script>
// Render the PayPal button into #paypal-button-container
paypal.Buttons({
// Set up the transaction
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '88.44'
}
}]
});
},
// Finalize the transaction
onApprove: function(data, actions) {
return actions.order.capture().then(function(orderData) {
// Successful capture! For demo purposes:
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
});
}
}).render('#paypal-button-container');
</script>
</body>
everything works fine and I can access all the data through the details variable in the js code.
Now, i need to insert the details into django db, no api, simple model.
Tried many things, none worked.
I prefer not to use django-paypal because it doesn't have smart buttons (as far as i saw) and there is only option for "buy now button" and no credit / debit card.
how can it be done? or is there smart buttons for django-paypal package?
Thanks for the help!

How to get PayPal client-side info to Django?
Don't.
An integration that creates and captures payments with client-side JS functions is for very simple use cases. It should never be used if you need to do anything automated with the result, such as writing transaction results to a database.
Instead, API-based integrations exist for precisely this use case. Use the v2/checkout/orders API and make two routes (url paths) on your server, one for 'Create Order' and one for 'Capture Order'. You could use the Checkout-PHP-SDK for the routes' API calls to PayPal, or your own HTTPS implementation of first getting an access token and then doing the call. Both of these routes should return/output only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should verify the amount was correct and store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id, which is the PayPal transaction ID) and perform any necessary business logic (such as reserving product or sending an email) immediately before forwarding return JSON to the frontend caller. In the event of an error forward the JSON details of it as well, since the frontend must handle such cases.
Pair those 2 routes with this frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server . (If you need to send any additional data from the client to the server, such as an items array or selected options, add a body parameter to the fetch with a value that is a JSON string or object)

Related

What is the best approach of using django and ajax?

I'm now working on my first big project and can't understand how to use Django with ajax.
On my website there are several services which works separately and are written on javascript, but soemtimes I have to send some information to the server.
Also I have custom admin interface which contains of different changing database operations. All these actions should be done without reloading the page (using ajax post and get requests).
So, I think I have two ways of doing it:
Using ajax and classic Django views for each operation.
Using ajax and integrated into my website Django REST Framework API methods.
The stumbling block is that I wouldn't use this API methods from any other types of clients, just call them from users' browsers via ajax. What is the best approach in my situation? It seems to me that the second way is more "serious", but I don't have much experience of making projects like this and can't speak directly.
You don't need to integrate REST. You can do ajax call to normal view like you do with user interaction. The view can return http response or JSON or whatever you need. If you would like to change somethink in DOM without refreshing page I can sugest HTMX (https://htmx.org/)
standard ajax call to get some json:
let datas = {id: $(this).val(),};
$.ajax({
url: "{% url 'to_your_view' %}",
type: "POST",
data: datas,
success: function (json) {
console.log(json);
},
error: function (xhr, errmsg, err) {
console.log(xhr.status + ": " + xhr.responseText);
}
});
and in view:
def to_your_view(request):
if request.method == "POST":
id = request.POST.get('id', 0)
if id != 0:
return HttpResponse(json.dumps(100), content_type="application/json")

Change the edit url, dynamically using the Datatable Editor

I'm looking on how to update the ajax configuration dynamically using data from a resource when updating a record. Django REST expects the id at the end of the url and the request method must be type PUT
I've spent some time figuring out how to update the ajax request made by the Datatable Editor plugin. I'm using Django Rest as the backend. This might be useful for some people looking for a similar answer.
Technically you can update the ajax options if the editor object before it sends the request by using the preSubmit Event.
editor.on('preSubmit', (e, request,) =>{
let _url = new URL(window.location.origin + "/" + editor.ajax().url)
if(request.action == 'edit'){
editor.ajax().url = `${_url.protocol}//${_url.host}/api/v1/some-endpoint/${Object.keys(request.data)[0]}/${_url.search}`;
editor.ajax().type = 'PUT'
}
editor.ajax().data = request.data[Object.keys(request.data)]
})
This will update the ajax configuration of the edit request right before it get sent. Django Rest expects a PUT request and the id of the record to be added at the end of the URL. As you can see we grab the id from the data object (Its the first key of the request.data object), and we can also change the type of request to PUT.

paypal sandbox not working after adding the client id

I'm sorry if this is a silly question, it's my first time trying to integrate the PayPal payment button into my Django website
I was following a tutorial and everything works fine when I used the HTML script from the PayPal developer website: https://developer.paypal.com/demo/checkout/#/pattern/client
I tested the payments and they went through successfully.
this is the working script
<!-- Set up a container element for the button -->
<div id="paypal-button-container"></div>
<!-- Include the PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=test&currency=USD"></script>
<script>
// Render the PayPal button into #paypal-button-container
paypal.Buttons({
// Set up the transaction
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '88.44'
}
}]
});
},
// Finalize the transaction
onApprove: function(data, actions) {
return actions.order.capture().then(function(orderData) {
// Successful capture! For demo purposes:
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
var transaction = orderData.purchase_units[0].payments.captures[0];
alert('Transaction '+ transaction.status + ': ' + transaction.id + '\n\nSee console for all available details');
// Replace the above to show a success message within this page, e.g.
// const element = document.getElementById('paypal-button-container');
// element.innerHTML = '';
// element.innerHTML = '<h3>Thank you for your payment!</h3>';
// Or go to another URL: actions.redirect('thank_you.html');
});
}
}).render('#paypal-button-container');
</script>
on the final step i should add the id where the payments go, i added the client id from my sandbox app as i followed on the tutorial.
then the payment process failed with a bunch of warnings and errors on the console log.
those are the warnings, i'm not sure if they are relevant
rest_api_v2_checkout_orders_capture_error
capture_order_call_rest_api_error
smart_api_order_capture_status_500_error
and the error
Error: Api: /smart/api/order/2CE30645TN292790N/capture returned status code: 500 (Corr ID: 6059f74d7d86c)
{"ack":"error","message":"Unhandled api error","meta":{"calc":"6059f74d7d86c","rlog":"rZJvnqaaQhLn%2FnmWT8cSUueWscmrtUHe5Y1Bd%2FeqyvyOTq66rSXAciiXRg7dClMl1o2iporwJbYz7mI0k8X%2B5vvp6t7dnU%2B%2B_17b646b9bfe"},"server":"BW5u5z-ag5VIFXCeo-FvfHOppMovQjbfurKdnROZjue_puvEq8w7pr9g-JTUa_N93X-G1W0ItCQpDtpWzP0fjVwpK7fYmKtRr_M6AiZCc9I8jT1o-HkaNIQVCchIVE2wBsEFPkUDKrguIXjpL9HKQHXFhio_DKQgF46f__hfehX6OcSyf8EqFzCq0v_aKUbo2cn6qm-ns-fO2ozMUq0o7RWyqIHd0mDJoV8auE6OUquFw6fW65nkyx9HcNmBdsVrYFstFxkpY2W"}
at https://www.sandbox.paypal.com/smart/buttons?style.label=pay&style.layout=vertical&style.color=blue&style.shape=pill&style.tagline=false&style.height=40&components.0=buttons&locale.country=US&locale.lang=en&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jbGllbnQtaWQ9QVZIT2J5VTZ3VFpncG81bndtNDc2ZU9uZ3dsYjBCWmVmazhxRFpIUFpBU0J0dVNjbk5RMUVXWHF6LV9rV0tySEdPM1JHTWZLaF9ydzl0ZWcmY3VycmVuY3k9VVNEIiwiYXR0cnMiOnsiZGF0YS11aWQiOiJ1aWRfcmhyZnFrcmRqcnJibnJ5aXNlamxqZnJkY2NscHpmIn19&clientID=AVHObyU6wTZgpo5nwm476eOngwlb0BZefk8qDZHPZASBtuScnNQ1EWXqz-_kWKrHGO3RGMfKh_rw9teg&sdkCorrelationID=af48b1f23061a&storageID=uid_59c1216f0c_mtm6mzc6mjq&sessionID=uid_ff296ed2ff_mty6mzm6ntg&buttonSessionID=uid_2b0be9f5d9_mty6mzu6ntu&env=sandbox&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwicHJvZHVjdHMiOnsicGF5SW40Ijp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH19fSwiY2FyZCI6eyJlbGlnaWJsZSI6dHJ1ZSwiYnJhbmRlZCI6dHJ1ZSwiaW5zdGFsbG1lbnRzIjpmYWxzZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJtYXN0ZXJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJhbWV4Ijp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImhpcGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjpmYWxzZX0sImVsbyI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImpjYiI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX19fSwidmVubW8iOnsiZWxpZ2libGUiOmZhbHNlfSwiaXRhdSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJjcmVkaXQiOnsiZWxpZ2libGUiOmZhbHNlfSwiYXBwbGVwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwic2VwYSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpZGVhbCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJiYW5jb250YWN0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImdpcm9wYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwiZXBzIjp7ImVsaWdpYmxlIjpmYWxzZX0sInNvZm9ydCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJteWJhbmsiOnsiZWxpZ2libGUiOmZhbHNlfSwicDI0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInppbXBsZXIiOnsiZWxpZ2libGUiOmZhbHNlfSwid2VjaGF0cGF5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInBheXUiOnsiZWxpZ2libGUiOmZhbHNlfSwiYmxpayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ0cnVzdGx5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm94eG8iOnsiZWxpZ2libGUiOmZhbHNlfSwibWF4aW1hIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJvbGV0byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtZXJjYWRvcGFnbyI6eyJlbGlnaWJsZSI6ZmFsc2V9fQ&platform=desktop&experiment.enableVenmo=true&flow=purchase&currency=USD&intent=capture&commit=true&vault=false&renderedButtons.0=paypal&renderedButtons.1=card&debug=false&applePaySupport=false&supportsPopups=true&supportedNativeBrowser=false:1317:84630
at e.n.dispatch (https://www.sandbox.paypal.com/smart/buttons?style.label=pay&style.layout=vertical&style.color=blue&style.shape=pill&style.tagline=false&style.height=40&components.0=buttons&locale.country=US&locale.lang=en&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jbGllbnQtaWQ9QVZIT2J5VTZ3VFpncG81bndtNDc2ZU9uZ3dsYjBCWmVmazhxRFpIUFpBU0J0dVNjbk5RMUVXWHF6LV9rV0tySEdPM1JHTWZLaF9ydzl0ZWcmY3VycmVuY3k9VVNEIiwiYXR0cnMiOnsiZGF0YS11aWQiOiJ1aWRfcmhyZnFrcmRqcnJibnJ5aXNlamxqZnJkY2NscHpmIn19&clientID=AVHObyU6wTZgpo5nwm476eOngwlb0BZefk8qDZHPZASBtuScnNQ1EWXqz-_kWKrHGO3RGMfKh_rw9teg&sdkCorrelationID=af48b1f23061a&storageID=uid_59c1216f0c_mtm6mzc6mjq&sessionID=uid_ff296ed2ff_mty6mzm6ntg&buttonSessionID=uid_2b0be9f5d9_mty6mzu6ntu&env=sandbox&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwicHJvZHVjdHMiOnsicGF5SW40Ijp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH19fSwiY2FyZCI6eyJlbGlnaWJsZSI6dHJ1ZSwiYnJhbmRlZCI6dHJ1ZSwiaW5zdGFsbG1lbnRzIjpmYWxzZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJtYXN0ZXJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJhbWV4Ijp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImhpcGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjpmYWxzZX0sImVsbyI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImpjYiI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX19fSwidmVubW8iOnsiZWxpZ2libGUiOmZhbHNlfSwiaXRhdSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJjcmVkaXQiOnsiZWxpZ2libGUiOmZhbHNlfSwiYXBwbGVwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwic2VwYSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpZGVhbCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJiYW5jb250YWN0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImdpcm9wYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwiZXBzIjp7ImVsaWdpYmxlIjpmYWxzZX0sInNvZm9ydCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJteWJhbmsiOnsiZWxpZ2libGUiOmZhbHNlfSwicDI0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInppbXBsZXIiOnsiZWxpZ2libGUiOmZhbHNlfSwid2VjaGF0cGF5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInBheXUiOnsiZWxpZ2libGUiOmZhbHNlfSwiYmxpayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ0cnVzdGx5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm94eG8iOnsiZWxpZ2libGUiOmZhbHNlfSwibWF4aW1hIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJvbGV0byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtZXJjYWRvcGFnbyI6eyJlbGlnaWJsZSI6ZmFsc2V9fQ&platform=desktop&experiment.enableVenmo=true&flow=purchase&currency=USD&intent=capture&commit=true&vault=false&renderedButtons.0=paypal&renderedButtons.1=card&debug=false&applePaySupport=false&supportsPopups=true&supportedNativeBrowser=false:1317:19688)
at e.n.resolve (https://www.sandbox.paypal.com/smart/buttons?style.label=pay&style.layout=vertical&style.color=blue&style.shape=pill&style.tagline=false&style.height=40&components.0=buttons&locale.country=US&locale.lang=en&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jbGllbnQtaWQ9QVZIT2J5VTZ3VFpncG81bndtNDc2ZU9uZ3dsYjBCWmVmazhxRFpIUFpBU0J0dVNjbk5RMUVXWHF6LV9rV0tySEdPM1JHTWZLaF9ydzl0ZWcmY3VycmVuY3k9VVNEIiwiYXR0cnMiOnsiZGF0YS11aWQiOiJ1aWRfcmhyZnFrcmRqcnJibnJ5aXNlamxqZnJkY2NscHpmIn19&clientID=AVHObyU6wTZgpo5nwm476eOngwlb0BZefk8qDZHPZASBtuScnNQ1EWXqz-_kWKrHGO3RGMfKh_rw9teg&sdkCorrelationID=af48b1f23061a&storageID=uid_59c1216f0c_mtm6mzc6mjq&sessionID=uid_ff296ed2ff_mty6mzm6ntg&buttonSessionID=uid_2b0be9f5d9_mty6mzu6ntu&env=sandbox&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwicHJvZHVjdHMiOnsicGF5SW40Ijp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH19fSwiY2FyZCI6eyJlbGlnaWJsZSI6dHJ1ZSwiYnJhbmRlZCI6dHJ1ZSwiaW5zdGFsbG1lbnRzIjpmYWxzZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJtYXN0ZXJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJhbWV4Ijp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImhpcGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjpmYWxzZX0sImVsbyI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImpjYiI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX19fSwidmVubW8iOnsiZWxpZ2libGUiOmZhbHNlfSwiaXRhdSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJjcmVkaXQiOnsiZWxpZ2libGUiOmZhbHNlfSwiYXBwbGVwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwic2VwYSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpZGVhbCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJiYW5jb250YWN0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImdpcm9wYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwiZXBzIjp7ImVsaWdpYmxlIjpmYWxzZX0sInNvZm9ydCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJteWJhbmsiOnsiZWxpZ2libGUiOmZhbHNlfSwicDI0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInppbXBsZXIiOnsiZWxpZ2libGUiOmZhbHNlfSwid2VjaGF0cGF5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInBheXUiOnsiZWxpZ2libGUiOmZhbHNlfSwiYmxpayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ0cnVzdGx5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm94eG8iOnsiZWxpZ2libGUiOmZhbHNlfSwibWF4aW1hIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJvbGV0byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtZXJjYWRvcGFnbyI6eyJlbGlnaWJsZSI6ZmFsc2V9fQ&platform=desktop&experiment.enableVenmo=true&flow=purchase&currency=USD&intent=capture&commit=true&vault=false&renderedButtons.0=paypal&renderedButtons.1=card&debug=false&applePaySupport=false&supportsPopups=true&supportedNativeBrowser=false:1317:18745)
at https://www.sandbox.paypal.com/smart/buttons?style.label=pay&style.layout=vertical&style.color=blue&style.shape=pill&style.tagline=false&style.height=40&components.0=buttons&locale.country=US&locale.lang=en&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jbGllbnQtaWQ9QVZIT2J5VTZ3VFpncG81bndtNDc2ZU9uZ3dsYjBCWmVmazhxRFpIUFpBU0J0dVNjbk5RMUVXWHF6LV9rV0tySEdPM1JHTWZLaF9ydzl0ZWcmY3VycmVuY3k9VVNEIiwiYXR0cnMiOnsiZGF0YS11aWQiOiJ1aWRfcmhyZnFrcmRqcnJibnJ5aXNlamxqZnJkY2NscHpmIn19&clientID=AVHObyU6wTZgpo5nwm476eOngwlb0BZefk8qDZHPZASBtuScnNQ1EWXqz-_kWKrHGO3RGMfKh_rw9teg&sdkCorrelationID=af48b1f23061a&storageID=uid_59c1216f0c_mtm6mzc6mjq&sessionID=uid_ff296ed2ff_mty6mzm6ntg&buttonSessionID=uid_2b0be9f5d9_mty6mzu6ntu&env=sandbox&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwicHJvZHVjdHMiOnsicGF5SW40Ijp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH19fSwiY2FyZCI6eyJlbGlnaWJsZSI6dHJ1ZSwiYnJhbmRlZCI6dHJ1ZSwiaW5zdGFsbG1lbnRzIjpmYWxzZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJtYXN0ZXJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJhbWV4Ijp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImhpcGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjpmYWxzZX0sImVsbyI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImpjYiI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX19fSwidmVubW8iOnsiZWxpZ2libGUiOmZhbHNlfSwiaXRhdSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJjcmVkaXQiOnsiZWxpZ2libGUiOmZhbHNlfSwiYXBwbGVwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwic2VwYSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpZGVhbCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJiYW5jb250YWN0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImdpcm9wYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwiZXBzIjp7ImVsaWdpYmxlIjpmYWxzZX0sInNvZm9ydCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJteWJhbmsiOnsiZWxpZ2libGUiOmZhbHNlfSwicDI0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInppbXBsZXIiOnsiZWxpZ2libGUiOmZhbHNlfSwid2VjaGF0cGF5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInBheXUiOnsiZWxpZ2libGUiOmZhbHNlfSwiYmxpayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ0cnVzdGx5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm94eG8iOnsiZWxpZ2libGUiOmZhbHNlfSwibWF4aW1hIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJvbGV0byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtZXJjYWRvcGFnbyI6eyJlbGlnaWJsZSI6ZmFsc2V9fQ&platform=desktop&experiment.enableVenmo=true&flow=purchase&currency=USD&intent=capture&commit=true&vault=false&renderedButtons.0=paypal&renderedButtons.1=card&debug=false&applePaySupport=false&supportsPopups=true&supportedNativeBrowser=false:1317:18389
at XMLHttpRequest.<anonymous> (https://www.sandbox.paypal.com/smart/buttons?style.label=pay&style.layout=vertical&style.color=blue&style.shape=pill&style.tagline=false&style.height=40&components.0=buttons&locale.country=US&locale.lang=en&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jbGllbnQtaWQ9QVZIT2J5VTZ3VFpncG81bndtNDc2ZU9uZ3dsYjBCWmVmazhxRFpIUFpBU0J0dVNjbk5RMUVXWHF6LV9rV0tySEdPM1JHTWZLaF9ydzl0ZWcmY3VycmVuY3k9VVNEIiwiYXR0cnMiOnsiZGF0YS11aWQiOiJ1aWRfcmhyZnFrcmRqcnJibnJ5aXNlamxqZnJkY2NscHpmIn19&clientID=AVHObyU6wTZgpo5nwm476eOngwlb0BZefk8qDZHPZASBtuScnNQ1EWXqz-_kWKrHGO3RGMfKh_rw9teg&sdkCorrelationID=af48b1f23061a&storageID=uid_59c1216f0c_mtm6mzc6mjq&sessionID=uid_ff296ed2ff_mty6mzm6ntg&buttonSessionID=uid_2b0be9f5d9_mty6mzu6ntu&env=sandbox&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwicHJvZHVjdHMiOnsicGF5SW40Ijp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH19fSwiY2FyZCI6eyJlbGlnaWJsZSI6dHJ1ZSwiYnJhbmRlZCI6dHJ1ZSwiaW5zdGFsbG1lbnRzIjpmYWxzZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJtYXN0ZXJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJhbWV4Ijp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImhpcGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjpmYWxzZX0sImVsbyI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX0sImpjYiI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhdWx0YWJsZSI6dHJ1ZX19fSwidmVubW8iOnsiZWxpZ2libGUiOmZhbHNlfSwiaXRhdSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJjcmVkaXQiOnsiZWxpZ2libGUiOmZhbHNlfSwiYXBwbGVwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwic2VwYSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpZGVhbCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJiYW5jb250YWN0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImdpcm9wYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwiZXBzIjp7ImVsaWdpYmxlIjpmYWxzZX0sInNvZm9ydCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJteWJhbmsiOnsiZWxpZ2libGUiOmZhbHNlfSwicDI0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInppbXBsZXIiOnsiZWxpZ2libGUiOmZhbHNlfSwid2VjaGF0cGF5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sInBheXUiOnsiZWxpZ2libGUiOmZhbHNlfSwiYmxpayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ0cnVzdGx5Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm94eG8iOnsiZWxpZ2libGUiOmZhbHNlfSwibWF4aW1hIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJvbGV0byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtZXJjYWRvcGFnbyI6eyJlbGlnaWJsZSI6ZmFsc2V9fQ&platform=desktop&experiment.enableVenmo=true&flow=purchase&currency=USD&intent=capture&commit=true&vault=false&renderedButtons.0=paypal&renderedButtons.1=card&debug=false&applePaySupport=false&supportsPopups=true&supportedNativeBrowser=false:1317:38897)
is there an additional step or any solutions to make this work, thank you
For testing in sandbox, create a new Sandbox business account for a new sandbox country, such as US, and then make a new sandbox REST app for that business account with a new client ID.
For later going live, if the receiving business account is in one of the countries listed here, ensure there is a bank or visa card on the account that is capable of withdrawing funds automatically, in order for that account to be able to receive payments. This seems to be a special regulatory requirement in those countries, but have the account owner contact PayPal's general business or customer support if they need more information

Load protected image from API

I am using EmberJS along with ember-simple-auth and ember-data to authenticate and retrieve data from my API. One of my models contains properties that point to image URLs. I'd like to display these images in my app. I can do this using
<img class="thumbnail" src="{{user.thumbnail}}" />
The problem is that the images are protected and need an "Authorization" header to be set without which the API returns a 401. I thought about adding the token to the URL as a query parameter and modifying the API to accept it but it seems like a bad idea because the auth tokens will be present in the logs. Is there an EmberJS way of retrieving an image from a secured API?
EDIT based on your comment:
This is a server side solution so it would leave your ember code the way it is.
The approach is to never send the actual token with the images but use the token on the server to generate session specific image urls.
This way you never expose the absolute paths to your images but rather create relative urls that resolve to the absolute ones. You can use the session token as a key to an encryption algorithm like md5 and create the relative urls which would hide the sensitive information (such as the token) from the client, thus you would never send the token as the query parameter.
Note that this does mean that if the user is logged in and shares those image links, the images would be visible to anybody using the link until the user logs out (and his session is destroyed).
Previous suggestion
You could make a small component that does this for you where you pass in the url and either also pass the token or get it through an auth service. Then you use a computed property to combine the two. Here's a rough example:
// components/auth-img.js
export default Ember.Component.extend({
// passed in
class: '',
url: '',
token: '',
// local
tagName: 'img',
classNameBindings: ['class'],
attributeBindings: ['src'],
src: Ember.computed('url', 'token', function() {
let { url, token } = this.getProperties('url', 'token');
// combine your url and token and return
return // ...
})
});
And usage:
{{auth-img class="thumbnail" url=user.thumbnail}}

In Ember.js, how do you make requests to an API that are outside of the REST convention?

I would like to request a 'reset password' endpoint e.g GET -> user/password/reset on an API. What is the best way to map this request in ember.js? It doesn't seem appropriate to setup a full ember.js model for this kind of request, as it doesn't have a proper ID and is not really a request for a record, but a triggered event with a success/fail response. Am I incorrectly implementing the REST convention or is there another way to do this?
You can use a simple ember-object to represent password reset and then basic ajax. Something like this:
App.User.reopenClass({
resetPassword: function(subreddit) {
return $.getJSON("user/password/reset").then(
function(response) {
console.log('it worked');
return true;
},
function(response) {
console.log('fail');
return false;
}
);
}
});
See http://eviltrout.com/2013/03/23/ember-without-data.html
That said, this could be a sign that the API endpoint should change. Ideally GET requests should not have side effects, so a GET that resets a password is not recommended. If you think of reset as a password reset request, the reset password endpoint that makes the most sense is POST -> user/password/reset to create a new request.