Transaction not reflecting on the Paypal App Account - node.js

I am successfully making a Platform Transaction on my Platform. All transfers go as expected apart from the Platform Fees. They reflect on the Merchant Seller's side, as well as the Buyer's, but not on the Platform Account.
Transaction details snapshot
The Partner Commission of -$9.33 USD does not show on the Platform account. In fact this transaction does not reflect in any way. There is no way of telling that it ever happened at all from the Paypal Sandbox App Account.
What could it be that I am missing?
Thank you all in advance.
CLIENT SIDE : index.html
<html>
<head>
<meta charset="utf-8"/>
<!-- Optimal rendering on mobile devices. -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Optimal Internet Explorer compatibility -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- Sample CSS styles for demo purposes. You can override these styles to match your web page's branding. -->
<link rel="stylesheet" type="text/css" href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css"/>
<!-- JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?components=buttons,hosted-fields&client-id=Ae4XWCzGDY24rKpazdCnRnT1wUjnQ_2PzLF5aOhviaUfQ7_O34rr8NqrunXe7PxCi-sEt7noZfr1ojbs" data-client-token="eyJicmFpbnRyZWUiOnsiYXV0aG9yaXphdGlvbkZpbmdlcnByaW50IjoiZWNkYWE1MzZjNjQ5Nzg1YjU2ZWQ5NGMyZGU2ZjRjMGQzY2FiMDY0MzkyNTA3YTkxZTU2MjI3MDlhZTMzOWUyNHxtZXJjaGFudF9pZD1yd3dua3FnMnhnNTZobTJuJnB1YmxpY19rZXk9NjNrdm4zN3Z0MjlxYjRkZiZjcmVhdGVkX2F0PTIwMjEtMDMtMjlUMTM6Mjg6MTMuOTQxWiIsInZlcnNpb24iOiIzLXBheXBhbCJ9LCJwYXlwYWwiOnsiaWRUb2tlbiI6ImV5SnJhV1FpT2lJNVpqWmxOalV5T0RGallXWmhORFU1WkRReU9EWmhPRE5pWVdZMVl6aGtPRFUwWVdNNE5XRmtJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUpwYzNNaU9pSm9kSFJ3Y3pvdkwyRndhUzV6WVc1a1ltOTRMbkJoZVhCaGJDNWpiMjBpTENKemRXSWlPaUpvZEhSd2N6b3ZMM2QzZHk1d1lYbHdZV3d1WTI5dEwzZGxZbUZ3Y0hNdllYVjBhQzlwWkdWdWRHbDBlUzkxYzJWeUwwSlhRazEyZVhoclJsWjBkWHBCZUd4RmNGZENiMVJRTkhSNGFHOVRVMnh0YVZWWmNtbDZhM3BrWkdjaUxDSmhZM0lpT2xzaVkyeHBaVzUwSWwwc0ltRjFaQ0k2SWtGbE5GaFhRM3BIUkZreU5ISkxjR0Y2WkVOdVVtNVVNWGRWYW01Ulh6SlFla3hHTldGUGFIWnBZVlZtVVRkZlR6TTBjbkk0VG5GeWRXNVlaVGRRZUVOcExYTkZkRGR1YjFwbWNqRnZhbUp6SWl3aVlYVjBhRjkwYVcxbElqb3hOakUzTURJME5EazBMQ0poYlhJaU9sdGRMQ0poZWlJNkluTmlMbk5zWXlJc0ltVjRjQ0k2TVRZeE56QXlOVE01TkN3aWMyVnpjMmx2Ymw5cGJtUmxlQ0k2SWxoMVNuUnBiMDU0WWs1YU1HOVFUVzVpTWtkNVpXdHRRMWh3UXlJc0ltbGhkQ0k2TVRZeE56QXlORFE1TkN3aWFuUnBJam9pVlRKQlFVbGtiVVZETTJjekxVTkpOelpDYWtSdk56WjNUVFpoZDJ4VWJuWmFNMGhsVW5kWmNXRmxTazUyZW1SWFpWTmlhMUUyVERoUU5qbFdUako0Y21kR1prTkNUVGxHYVdGRGNVNHhSUzFqTVZobVEzSndZWFJPTWxGWVltczFZbE4yVlZveVpYTlRTRzU1VG1aaWRWUkxZamxQUjB0cWNGRjZSbWR5V0ZFaUxDSmpiR2xsYm5SZmFXUWlPaUpCWlRSWVYwTjZSMFJaTWpSeVMzQmhlbVJEYmxKdVZERjNWV3B1VVY4eVVIcE1SalZoVDJoMmFXRlZabEUzWDA4ek5ISnlPRTV4Y25WdVdHVTNVSGhEYVMxelJYUTNibTlhWm5JeGIycGljeUo5LkhObzlndU5SQVktSDZTR2tUR0xxRUFtbDNWRkJwNHRwNjdSSVJPN1NMbm5PRUtkWGFHSjhfYkJfR3N5dWxZeGQ4Slhnd3duTWV4ejZYaElEUnVtVzVkaDloQm9CbFctTGtNUEZ6cmVDZnk3SnVnbmZPYk9PaWRhV19Wd1IyRXpLSTZ1UzZWaFhKbEFvaWI1U3dfYjNXYlVHR2tudUM5cjZDZ0xlWnNTaDVQZDRuaFc1M0pplatformlHQTZkOVc3ZU5VZXBKNUJwd1FJWkRVYmJyY2JXelFDMzRFN0tQbndjOENIQWh3UGNSZWpWaktWWVlLSE9lUF9KeWpEbFZDWXM4NU5YVEExYV9ldDdFUHZmcmN1NzF0S3FhR0hNV21XWE9KS245UGZ2Zk10b2ZfRWN3SmhVd2RBU1ZqZmU4VjlzM3ZidzRJRGZHMFRjYzY1d2hIaFp4Sl94dyIsImFjY2Vzc1Rva2VuIjoiQTIxQUFJNTNiLVl0Qk1neFlmb1NQZHJKUUsxZTBCYVZSZm01X3BPNlg4bnktZ292S1l3dy11YU1fWm8wM0YxQXdzenZfYjF4RmZJTkE1YkNfUEZya3A0bkxxMzljdWdndyJ9fQ=="></script>
<!-- Include the PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=Ae4XWCzGDY24rKpazdCnRnT1wUjnQ_2PzLF5aOhviaUfQ7_O34rr8NqrunXe7PxCi-sEt7noZfr1ojbs&currency=USD" data-namespace="paypal_sdk"></script>
</head>
<body>
<!-- JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?components=hosted-fields&client-id=Ae4XWCzGDY24rKpazdCnRnT1wUjnQ_2PzLF5aOhviaUfQ7_O34rr8NqrunXe7PxCi-sEt7noZfr1ojbs&merchant-id=H82BJAGD75E6C&currency=USD&intent=capture" data-partner-attribution-id="FLAVORsb-z1ivv5077605_MP" data-client-token="eyJicmFpbnRyZWUiOnsiYXV0aG9yaXphdGlvbkZpbmdlcnByaW50IjoiZWNkYWE1MzZjNjQ5Nzg1YjU2ZWQ5NGMyZGU2ZjRjMGQzY2FiMDY0MzkyNTA3YTkxZTU2MjI3MDlhZTMzOWUyNHxtZXJjaGFudF9pZD1yd3dua3FnMnhnNTZobTJuJnB1YmxpY19rZXk9NjNrdm4zN3Z0MjlxYjRkZiZjcmVhdGVkX2F0PTIwMjEtMDMtMjlUMTM6Mjg6MTMuOTQxWiIsInZlcnNpb24iOiIzLXBheXBhbCJ9LCJwYXlwYWwiOnsiaWRUb2tlbiI6ImV5SnJhV1FpT2lJNVpqWmxOalV5T0RGallXWmhORFU1WkRReU9EWmhPRE5pWVdZMVl6aGtPRFUwWVdNNE5XRmtJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUpwYzNNaU9pSm9kSFJ3Y3pvdkwyRndhUzV6WVc1a1ltOTRMbkJoZVhCaGJDNWpiMjBpTENKemRXSWlPaUpvZEhSd2N6b3ZMM2QzZHk1d1lYbHdZV3d1WTI5dEwzZGxZbUZ3Y0hNdllYVjBhQzlwWkdWdWRHbDBlUzkxYzJWeUwwSlhRazEyZVhoclJsWjBkWHBCZUd4RmNGZENiMVJRTkhSNGFHOVRVMnh0YVZWWmNtbDZhM3BrWkdjaUxDSmhZM0lpT2xzaVkyeHBaVzUwSWwwc0ltRjFaQ0k2SWtGbE5GaFhRM3BIUkZreU5ISkxjR0Y2WkVOdVVtNVVNWGRWYW01Ulh6SlFla3hHTldGUGFIWnBZVlZtVVRkZlR6TTBjbkk0VG5GeWRXNVlaVGRRZUVOcExYTkZkRGR1YjFwbWNqRnZhbUp6SWl3aVlYVjBhRjkwYVcxbElqb3hOakUzTURJME5EazBMQ0poYlhJaU9sdGRMQ0poZWlJNkluTmlMbk5zWXlJc0ltVjRjQ0k2TVRZeE56QXlOVE01TkN3aWMyVnpjMmx2Ymw5cGJtUmxlQ0k2SWxoMVNuUnBiMDU0WWs1YU1HOVFUVzVpTWtkNVpXdHRRMWh3UXlJc0ltbGhkQ0k2TVRZeE56QXlORFE1TkN3aWFuUnBJam9pVlRKQlFVbGtiVVZETTJjekxVTkpOelpDYWtSdk56WjNUVFpoZDJ4VWJuWmFNMGhsVW5kWmNXRmxTazUyZW1SWFpWTmlhMUUyVERoUU5qbFdUako0Y21kR1prTkNUVGxHYVdGRGNVNHhSUzFqTVZobVEzSndZWFJPTWxGWVltczFZbE4yVlZveVpYTlRTRzU1VG1aaWRWUkxZamxQUjB0cWNGRjZSbWR5V0ZFaUxDSmpiR2xsYm5SZmFXUWlPaUpCWlRSWVYwTjZSMFJaTWpSeVMzQmhlbVJEYmxKdVZERjNWV3B1VVY4eVVIcE1SalZoVDJoMmFXRlZabEUzWDA4ek5ISnlPRTV4Y25WdVdHVTNVSGhEYVMxelJYUTNibTlhWm5JeGIycGljeUo5LkhObzlndU5SQVktSDZTR2tUR0xxRUFtbDNWRkJwNHRwNjdSSVJPN1NMbm5PRUtkWGFHSjhfYkJfR3N5dWxZeGQ4Slhnd3duTWV4ejZYaElEUnVtVzVkaDloQm9CbFctTGtNUEZ6cmVDZnk3SnVnbmZPYk9PaWRhV19Wd1IyRXpLSTZ1UzZWaFhKbEFvaWI1U3dfYjNXYlVHR2tudUM5cjZDZ0xlWnNTaDVQZDRuaFc1M0pplatformlHQTZkOVc3ZU5VZXBKNUJwd1FJWkRVYmJyY2JXelFDMzRFN0tQbndjOENIQWh3UGNSZWpWaktWWVlLSE9lUF9KeWpEbFZDWXM4NU5YVEExYV9ldDdFUHZmcmN1NzF0S3FhR0hNV21XWE9KS245UGZ2Zk10b2ZfRWN3SmhVd2RBU1ZqZmU4VjlzM3ZidzRJRGZHMFRjYzY1d2hIaFp4Sl94dyIsImFjY2Vzc1Rva2VuIjoiQTIxQUFJNTNiLVl0Qk1neFlmb1NQZHJKUUsxZTBCYVZSZm01X3BPNlg4bnktZ292S1l3dy11YU1fWm8wM0YxQXdzenZfYjF4RmZJTkE1YkNfUEZya3A0bkxxMzljdWdndyJ9fQ=="></script>
<!-- Buttons container -->
<div id="paypal-button-container"></div>
<!-- Implementation -->
<script>
let orderId;
// Displays PayPal buttons
paypal_sdk.Buttons({
style: {
layout: 'horizontal'
},
// Call your server to set up the transaction
createOrder: function(data, actions) {
return fetch('/demo/checkout/api/paypal/platform_store_order/create/', {
method: 'post'
}).catch(error => {
console.error('ERR -> fetch : ' + error.message);
}).then(function(res) {
return res.json();
}).catch(error => {
console.error('ERR -> res : ' + error.message);
}).then(function(orderData) {
return orderData.id;
}).catch(error => {
console.error('ERR -> orderData : ' + error.message);
});
},
// Call your server to finalize the transaction
onApprove: function(data, actions) {
return fetch('/demo/checkout/api/paypal/order_platform_store/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({'orderID': data.orderID, 'payerID': data.payerID})
}).then(function(res) {
return res.json();
}).then(function(orderData) {
// Three cases to handle:
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
// (2) Other non-recoverable errors -> Show a failure message
// (3) Successful transaction -> Show confirmation or thank you
// This example reads a v2/checkout/orders capture response, propagated from the server
// You could use a different API or structure for your 'orderData'
var errorDetail = Array.isArray(orderData.details) && orderData.details[0];
if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
return actions.restart(); // Recoverable state, per:
// https://developer.paypal.com/docs/checkout/integration-features/funding-failure/
}
if (errorDetail) {
var msg = 'Sorry, your transaction could not be processed.';
if (errorDetail.description) {
msg += '\n\n' + errorDetail.description;
}
if (orderData.debug_id){
msg += ' (' + orderData.debug_id + ')'
};
return alert(msg); // Show a failure message
}
// Show a success message
alert('Transaction : ' + JSON.stringify(orderData));
});
}
}).render("#paypal-button-container");
</script>
</body>
</html>
NODE app.js
const path = require("path");
var express = require("express");
var cors = require("cors");
var app = express();
var request = require("request");
const port = process.env.PORT || 3000;
app.use(cors());
var bodyParser = require("body-parser");
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(bodyParser.json());
// Add your credentials:
// Add your client ID and secret
var CLIENT = "Ae4XWCzGDY24rKpazdCnRnT1wUjnQ_2PzLF5aOhviaUfQ7_O34rr8NqrunXe7PxCi-sEt7noZfr1ojbs";
var SECRET = "EMmNF1LZSOooLUAxEt5csF-rMyIseuV5D6qOoKMzbyUEDaQEhO_DjLarbVsF_vLiXnGHi8qFL13gebg_";
var PAYPAL_API = "https://api-m.sandbox.paypal.com";
const paypal = require("#paypal/checkout-server-sdk");
let environment = new paypal.core.SandboxEnvironment(CLIENT, SECRET);
let client = new paypal.core.PayPalHttpClient(environment);
app.get("/", function (req, res) {
res.sendFile(path.join(__dirname + "/index.html"));
});
// Set up the payment:
// 1. Set up a URL to handle requests from the PayPal button
app.post("/demo/checkout/api/paypal/order/create/", async function (req, res) {
let ordersCreateRequest = new paypal.orders.OrdersCreateRequest();
ordersCreateRequest.requestBody({
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "9.88",
},
},
],
});
// Call API with your client and get a response for your call
let createOrder = async function () {
let response = await client.execute(ordersCreateRequest);
return response;
};
let platformOrder = await createOrder();
let orderId = platformOrder.result.id;
// 2. Call /v2/checkout/orders to set up the Order
res.json({
id: orderId,
});
});
// Set up the payment:
// 1. Set up a URL to handle requests from the PayPal button
app.post("/demo/checkout/api/paypal/platform_store_order/create/", async function (req, res) {
let ordersCreateRequest = new paypal.orders.OrdersCreateRequest();
ordersCreateRequest.requestBody({
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "31.13",
},
"payee": {
"email_address": "platform#business.example.com",
},
"payment_instruction": {
"disbursement_mode": "INSTANT",
"platform_fees": [
{
"amount": {
"currency_code": "USD",
"value": "9.33",
},
},
],
},
},
],
});
// Call API with your client and get a response for your call
let createOrder = async function () {
let response = await client.execute(ordersCreateRequest);
return response;
};
let platformOrder = await createOrder();
let orderId = platformOrder.result.id;
res.json({
id: orderId,
});
});
// 1. Set up a URL to handle requests from the PayPal button.
app.post("/demo/checkout/api/paypal/order_platform_store/", async function (req, res) {
// 2. Get the payment ID and the payer ID from the request query.
var orderID = req.body.orderID;
request.post(
PAYPAL_API + "/v2/checkout/orders/" + orderID + "/capture",
{
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer A21AAJ8sH_Uq73w8XonQYB9rc1STsZpoK_Q14PkHbRgxtbYUN6FvCg-FbOKYIDlt0Zzo8xVQMvSuCAaRgjSfGoEPYRbxk62xQ",
"PayPal-Partner-Attribution-Id": "FLAVORsb-z1ivv5077605_MP",
},
},
function (err, response, body) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
res.json(response);
}
);
});
app.listen(port, () => console.log(`Listening on port ${port}!`));

Are you a PayPal partner? It's required to use this in the live environment: https://developer.paypal.com/docs/platforms/test-go-live/#2-go-live
If you are, PayPal will guide you in testing this in both sandbox and live modes.
If you are not, you can't use this anyway.

Related

How to make use the Paypal Payouts API to make payments to nultiple people

I am trying to execute a PayPal Payout on a Node.Js environment, but I can't seem to wrap my head around it. The payment doesn't get made.
I think that I am not getting the parameters right, and, or maybe my code needs re-organizing.
Please help me wrap my head around it, and eventually start heading in the right direction?
Thank you all in advance.
LOCALLY ON THE CLIENT BROWSER:
<script>
paypal.Button.render({
env: 'sandbox', // Or 'production'
// Set up the payment:
// 1. Add a payment callback
payment: function(data, actions) {
// 2. Make a request to your server
return actions.request.post('/my-api/create-payment/')
.then(function(res) {
// 3. Return res.id from the response
return res.id;
});
},
// Execute the payment:
// 1. Add an onAuthorize callback
onAuthorize: function(data, actions) {
// 2. Make a request to your server
return actions.request.post('/my-api/execute-payment/', {
paymentID: data.paymentID,
payerID: data.payerID
})
.then(function(res) {
// 3. Show the buyer a confirmation message.
});
}
}, '#paypal-button');
</script>
ON THE NODE ENVIRONMENT
const path = require("path");
var express = require("express");
var cors = require("cors");
var app = express();
var request = require("request");
const port = process.env.PORT || 3000;
app.use(cors());
var bodyParser = require("body-parser");
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(bodyParser.json());
app.get("/", function (req, res) {
res.sendFile(path.join(__dirname + "/index.html"));
});
/** - - - - - - - */
var requestBody = {
"sender_batch_header": {
"sender_batch_id": "Payouts_2018_100007",
"email_subject": "You have a payout!",
"email_message": "You have received a payout! Thanks for using our service!",
},
"items": [
{
"note": "Your 1$ Payout!",
"amount": {
"currency": "USD",
"value": "100.00",
},
"receiver": "john-doe#personal.example.com",
"sender_item_id": "Test_txn_1",
},
{
"note": "Your 1$ Payout!",
"amount": {
"currency": "USD",
"value": "200.00",
},
"receiver": "business.example.com",
"sender_item_id": "Test_txn_2",
},
],
};
// Add your credentials:
// Add your client ID and secret
var CLIENT = "abc-def-ZAFupw-kq6-ghi";
var SECRET = "xyz-ns0xjKT0dkbpJrkvnkMG4ZUZEHd-mnop567";
var PAYPAL_API = "https://api-m.sandbox.paypal.com";
var PAYOUTS_URL = "https://api-m.sandbox.paypal.com/v1/payments/payouts?";
// Set up the payment:
// 1. Set up a URL to handle requests from the PayPal button
app.post("/my-api/create-payment/", function (req, res) {
// 2. Call /v1/payments/payment to set up the payment
request.post(
PAYPAL_API + "/v1/payments/payment",
{
auth: {
user: CLIENT,
pass: SECRET,
},
body: {
intent: "sale",
payer: {
payment_method: "paypal",
},
transactions: [
{
amount: {
total: "300.00",
currency: "USD",
},
},
],
redirect_urls: {
return_url: "https://mighty-oasis-92039.herokuapp.com/",
cancel_url: "https://mighty-oasis-92039.herokuapp.com/",
},
},
json: true,
},
function (err, response) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
// 3. Return the payment ID to the client
res.json({
id: response.body.id,
});
}
);
});
/** START PAYOUTS */
app.post("/my-api/execute-payment/", function (req, res) {
// 2. Get the payment ID and the payer ID from the request body.
var paymentID = req.body.paymentID;
var payerID = req.body.payerID;
// 3. Call /v1/payments/payment/PAY-XXX/execute to finalize the payment.
request.post(
`${PAYOUTS_URL}paymentID`,
{
auth: {
user: CLIENT,
pass: SECRET,
},
requestBody,
},
function (err, response) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
// 4. Return a success response to the client
res.json({
status: "success",
});
}
);
});
/** END PAYOUTS */
app.listen(port, () => console.log(`listening on port ${port}!`));
The button code in your question is for checkout.js and v1/payments, both of which are deprecated integrations, and which are for receiving payments.
Your server side code is for Payouts, which is for sending payments from your own account. These are entirely separate things.
If you want buyers to be able to directly pay another account, first integrate the current version of PayPal Checkout.
Server side 'Create Order' and 'Capture Order' are documented here: https://developer.paypal.com/docs/business/checkout/server-side-api-calls/#server-side-api-calls
Pair those two routes that return JSON data with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
And in the create call, configure the payee who will receive the payment: https://developer.paypal.com/docs/checkout/integration-features/pay-another-account/

How to make Make and Pay for an Order on Paypal

I am trying to make an order and payment on a Node.js Environment to a user user#email.example.com but no funds get transferred. No errors are thrown.
What could it be that I am missing?
Thank you all in advance.
THE CLIENT SIDE
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Add meta tags for mobile and IE -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title> PayPal Smart Payment Buttons Integration | Server Demo </title>
</head>
<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=abc-50mQSYBJpg_OWguVkwn0qCDB-ZAFupw-kq6-k_O1havNEFGH&currency=USD"></script>
<script>
// Render the PayPal button into #paypal-button-container
paypal.Buttons({
// Call your server to set up the transaction
createOrder: function(data, actions) {
return fetch('/demo/checkout/api/paypal/order/create/', {
method: 'post'
}).catch(error => {
console.error('ERR -> fetch : ' + error.message);
}).then(function(res) {
return res.json();
}).catch(error => {
console.error('ERR -> res : ' + error.message);
}).then(function(orderData) {
return orderData.id;
}).catch(error => {
console.error('ERR -> orderData : ' + error.message);
});
},
// Call your server to finalize the transaction
onApprove: function(data, actions) {
return fetch('/demo/checkout/api/paypal/order?orderID=' + data.orderID, {
method: 'get'
}).then(function(res) {
return res.json();
}).then(function(orderData) {
// Three cases to handle:
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
// (2) Other non-recoverable errors -> Show a failure message
// (3) Successful transaction -> Show confirmation or thank you
// This example reads a v2/checkout/orders capture response, propagated from the server
// You could use a different API or structure for your 'orderData'
var errorDetail = Array.isArray(orderData.details) && orderData.details[0];
if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
return actions.restart(); // Recoverable state, per:
// https://developer.paypal.com/docs/checkout/integration-features/funding-failure/
}
if (errorDetail) {
var msg = 'Sorry, your transaction could not be processed.';
if (errorDetail.description) msg += '\n\n' + errorDetail.description;
if (orderData.debug_id) msg += ' (' + orderData.debug_id + ')';
return alert(msg); // Show a failure message
}
// Show a success message
alert('Transaction completed by ' + JSON.stringify(orderData));
});
}
}).render('#paypal-button-container');
</script>
</body>
</html>
THE NODE SERVER
const path = require("path");
var express = require("express");
var cors = require("cors");
var app = express();
var request = require("request");
const port = process.env.PORT || 3000;
app.use(cors());
var bodyParser = require("body-parser");
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(bodyParser.json());
app.get("/", function (req, res) {
res.sendFile(path.join(__dirname + "/index.html"));
});
// Add your credentials:
// Add your client ID and secret
var CLIENT = "abc-50mQSYBJpg_OWguVkwn0qCDB-ZAFupw-kq6-k_O1havNEFGH";
var SECRET = "1234upB-ns0xj5678bpJrkvnkMG4ZUZEHd-0GbPrTe991045673Th1RrqYBqIjhl9Tdm";
var PAYPAL_API = "https://api-m.sandbox.paypal.com";
// Set up the payment:
// 1. Set up a URL to handle requests from the PayPal button
app.post("/demo/checkout/api/paypal/order/create/", function (req, res) {
// 2. Call /v2/checkout/orders to set up the Order
request.post(
PAYPAL_API + "/v2/checkout/orders",
{
auth: {
user: CLIENT,
pass: SECRET,
},
body: {
intent: "CAPTURE",
payer: {
payment_method: "paypal",
},
purchase_units: [
{
amount: {
currency_code: "USD",
value: "10.00",
},
payee: {
email_address: "user#email.example.com",
},
},
],
redirect_urls: {
return_url: "https://mighty-oasis-92039.herokuapp.com/",
cancel_url: "https://mighty-oasis-92039.herokuapp.com/",
},
},
json: true,
},
function (err, response) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
// 3. Return the payment ID to the client
res.json({
id: response.body.id,
});
}
);
});
/** START EXECUTE PAYMENT */
// 1. Set up a URL to handle requests from the PayPal button.
app.get("/demo/checkout/api/paypal/order/", function (req, res) {
// 2. Get the payment ID and the payer ID from the request query.
var orderID = req.query.orderID;
// 3. Call /v2/checkout/orders/{id}/capture to Capture payment for order.
request.post(
PAYPAL_API + "/v2/checkout/orders/" + orderID + "/capture",
{
auth: {
user: CLIENT,
pass: SECRET,
},
json: true,
},
function (err, response) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
// 4. Return a success response to the client
res.json({
status: "success",
});
}
);
});
/** END EXECUTE PAYMENT */
app.listen(port, () => console.log(`url-shortener listening on port ${port}!`));

ADSK Forge Viewer displays my 3D DWG as only 2D

I am create a web app and using the Forge viewer to display my models, but when I upload and translate a 3D DWG model to svf for viewing I am only seeing 2D. It is a 3D DWG model, but the viewer is only displaying it as a 2D model instead. Is there something I'm missing within the viewer.html code? I can't seem to find where the mistake is.
viewer.html (Used from a sample project on github)
<!DOCTYPE html>
<html>
<head>
<title>Autodesk Forge: 3D Viewer App Sample</title>
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
<!-- Third Party package -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<!-- Autodesk Forge Viewer files (IMPORTANT) -->
<link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css"
type="text/css" />
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>
<style>
/** Just simple CSS styling to make this page a little nicer **/
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<!-- The Viewer will be instantiated here -->
<div id="MyViewerDiv"></div>
<!-- Custom script -->
<script>
var viewer;
var options = {
env: "AutodeskProduction",
api: "derivativeV2", // TODO: for models uploaded to EMEA change this option to 'derivativeV2_EU'
getAccessToken: getForgeToken
};
var documentId = "urn:" + getUrlParameter("urn");
console.log(documentId);
// Run this when the page is loaded
Autodesk.Viewing.Initializer(options, function onInitialized() {
// Find the element where the 3d viewer will live.
var htmlElement = document.getElementById("MyViewerDiv");
if (htmlElement) {
// Create and start the viewer in that element
viewer = new Autodesk.Viewing.GuiViewer3D(htmlElement);
viewer.start();
// Load the document into the viewer.
Autodesk.Viewing.Document.load(
documentId,
onDocumentLoadSuccess,
onDocumentLoadFailure
);
}
});
/**
* Autodesk.Viewing.Document.load() success callback.
* Proceeds with model initialization.
*/
function onDocumentLoadSuccess(doc) {
// Load the default viewable geometry into the viewer.
// Using the doc, we have access to the root BubbleNode,
// which references the root node of a graph that wraps each object from the Manifest JSON.
var viewable = doc.getRoot().getDefaultGeometry();
if (viewable) {
viewer
.loadDocumentNode(doc, viewable)
.then(function (result) {
console.log("Viewable Loaded!");
})
.catch(function (err) {
console.log("Viewable failed to load.");
console.log(err);
});
}
}
/**
* Autodesk.Viewing.Document.load() failure callback.
*/
function onDocumentLoadFailure(viewerErrorCode) {
console.error(
"onDocumentLoadFailure() - errorCode: " + viewerErrorCode
);
jQuery("#MyViewerDiv").html(
"<p>Translation in progress... Please try refreshing the page.</p>"
);
}
// Get Query string from URL,
// we will use this to get the value of 'urn' from URL
function getUrlParameter(name) {
console.log("Made it here 2");
console.log(name);
name = name.replace(/[[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
var results = regex.exec(location.search);
return results === null
? ""
: decodeURIComponent(results[1].replace(/\+/g, " "));
}
// Get public access token for read only,
// using ajax to access route /api/forge/oauth/public in the background
function getForgeToken(callback) {
console.log("Made it here");
jQuery.ajax({
url: "/api/forge/oauth2/public",
success: function (res) {
callback(res.access_token, res.expires_in);
}
});
}
</script>
</body>
</html>
Node JS Code to translate and send to viewer
const express = require("express");
const Axios = require("axios");
const bodyParser = require("body-parser");
const cors = require("cors");
let config = require("./config");
let mainFunc = require("./BP-s3oss");
//Express Server
let app = express();
// let router = express.Router();
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(__dirname + "/www"));
app.get("/api/s3Data/:bucket", async (req, res) => {
let bucket = req.params.bucket;
let object = decodeURIComponent(req.query.object);
//Log to console
console.log(config.forge.forge_bucket + " " + object);
//Comment KWard: Add in Error check if unsuccessful
try {
//Main Function
let main = await mainFunc(bucket, object);
//Initialize Process
res.redirect("/api/forge/s3toOSS/" + config.forge.forge_bucket + "/" + encodeURIComponent(object));
} catch (error) {
res.status(500).send('Something bad Happened!');
}
});
//Start Express Server on Port 3000
app.set("port", 3000);
var server = app.listen(app.get("port"), function () {
console.log("Server listening on port " + server.address().port);
});
//-------------------------------------------------------------------
// Configuration for your Forge account
// Initialize the 2-legged OAuth2 client, and
// set specific scopes
//-------------------------------------------------------------------
var FORGE_CLIENT_ID = config.forgecredentials.client_id;
var FORGE_CLIENT_SECRET = config.forgecredentials.client_secret;
var access_token = "";
var scopes = "data:read data:write data:create bucket:create bucket:read";
const querystring = require("querystring");
//Route /AWStoFORGE/OSS
app.get("/api/forge/s3toOSS/:bucket/:object", async (req, res) => {
let bucket = req.params.bucket;
let object = req.params.object;
console.log(bucket + " " + object);
res.redirect("/api/forge/oauth" + "/" + encodeURIComponent(object));
});
// Route /api/forge/oauth
app.get("/api/forge/oauth/:object", function (req, res) {
let objectKey = req.params.object;
Axios({
method: "POST",
url: "https://developer.api.autodesk.com/authentication/v1/authenticate",
headers: {
"content-type": "application/x-www-form-urlencoded"
},
data: querystring.stringify({
client_id: FORGE_CLIENT_ID,
client_secret: FORGE_CLIENT_SECRET,
grant_type: "client_credentials",
scope: scopes
})
})
.then(function (response) {
// Success
access_token = response.data.access_token;
console.log("Successful Authentication");
res.redirect(
"/api/forge/datamanagement/bucket/getobject" + "/" + encodeURIComponent(objectKey)
);
})
.catch(function (error) {
// Failed
console.log(error);
res.send("Failed to authenticate");
});
});
// Route /api/forge/oauth2/public
app.get("/api/forge/oauth2/public", function (req, res) {
// Limit public token to Viewer read only
Axios({
method: "POST",
url: "https://developer.api.autodesk.com/authentication/v1/authenticate",
headers: {
"content-type": "application/x-www-form-urlencoded"
},
data: querystring.stringify({
client_id: FORGE_CLIENT_ID,
client_secret: FORGE_CLIENT_SECRET,
grant_type: "client_credentials",
scope: "viewables:read"
})
})
.then(function (response) {
// Successs
res.json({
access_token: response.data.access_token,
expires_in: response.data.expires_in
});
})
.catch(function (error) {
// Failed
console.log(error);
res.status(500).json(error);
});
});
const bucketKey = config.forge.forge_bucket;
const policyKey = "persistent"; // Never Expires
// For converting the source into a Base64-Encoded string
var Buffer = require("buffer").Buffer;
String.prototype.toBase64 = function () {
// Buffer is part of Node.js to enable interaction with octet streams in TCP streams,
// file system operations, and other contexts.
return new Buffer(this).toString("base64");
};
app.get("/api/forge/datamanagement/bucket/getobject/:objectKey", function (
req,
res
) {
let objectVal = req.params.objectKey;
console.log(bucketKey);
console.log(objectVal);
Axios({
method: "GET",
url:
"https://developer.api.autodesk.com/oss/v2/buckets/" +
encodeURIComponent(bucketKey) +
"/objects/" +
encodeURIComponent(objectVal) +
"/details",
maxContentLength: 104857780,
headers: {
Authorization: "Bearer " + access_token,
"content-type": "application/json"
}
})
.then(function (response) {
//Success
console.log("Object Retrieved from Forge OSS");
var urn = response.data.objectId.toBase64();
res.redirect("/api/forge/modelderivative/" + encodeURIComponent(urn));
})
.catch(function (error) {
//Failed
console.log(error);
res.send("Failed to get objectId from OSS.");
});
});
// Route /api/forge/modelderivative
app.get("/api/forge/modelderivative/:urn", function (req, res) {
var decodeURN = decodeURIComponent(req.params.urn)
var urn = decodeURN;
var format_type = "svf";
var format_views = ["2d", "3d"];
// console.log(urn);
Axios({
method: "POST",
url: "https://developer.api.autodesk.com/modelderivative/v2/designdata/job",
headers: {
"content-type": "application/json",
Authorization: "Bearer " + access_token
},
data: JSON.stringify({
input: {
urn: urn
},
output: {
formats: [
{
type: format_type,
views: format_views
}
]
}
})
})
.then(function (response) {
// Success
console.log("Redirected to Viewer HTML");
res.redirect("/viewer.html?urn=" + urn);
// res.send(urn);
})
.catch(function (error) {
// Failed
console.log(error);
res.send("Error at Model Derivative job.");
});
});
Check if the default view of your model is the 2D one that you are seeing as you are loading the default view with:
var viewable = doc.getRoot().getDefaultGeometry();
You can either load a specific view through the DocumentBrowser extension:
const viewer = new Autodesk.Viewing.GuiViewer3D(document.body.children[0],{extensions:['Autodesk.DocumentBrowser']})
Autodesk.Viewing.Document.load('urn:urn', doc=> {
viewer.start()
viewer.loadDocumentNode(doc,doc.getRoot().getDefaultGeometry())
//…
Or specify query to look up a viewable (such as a 3D one) in the document and load it:
Autodesk.Viewing.Document.load('urn:urn', doc=> {
const viewable = doc.getRoot().search({'role':'3d'})[0] //name of viewable for instance
viewer.start()
viewer.loadDocumentNode(doc,viewable)
//...
Adding a little more info to this...
If you want to retrieve the list of views in the document browser extension, here are two ways...
Using DOC object
let myViews = viewer.model.getDocumentNode().search({'role':'3d', type:'view'});
// returns, 5 views in an array
// change the camera view to view #2
viewer.setView(myViews[1]);
// print out the name of the view
console.log( myViews[1].name() );
> "3D_RF_AC1"
Using Extension
let ext = viewer.getExtension("Autodesk.DocumentBrowser");
let myViews = ext.geometries[0].children.filter( i => {
return(i.data.camera)
})
// change the camera view to view #2
viewer.setView( myViews[1] );
// print out the name of the view
console.log( myViews[1].name() );
> "3D_RF_AC1"

Cross-Origin Request Blocked when requesting Paypal sandbox but a different localhost port works fine

I'm having trouble understanding why I'm getting a Cross-Origin Request Blocked error when trying to send a user in my app to a sandbox.paypal.com payment page when ordering a product. The frontend of my app (with React) uses localhost port 3000 while the backend uses localhost port 4000. The communication between the two ports when performing CRUD operations works as intended. But now that I'm introducing paypal into the mix the app doesn't go to the sandbox paypal page when trying to order a product. This is the error message in the console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-0Y510528E2479935T. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
I'm confused because communication already works between the two localhosts. Doesn't Access-Control-Allow-Origin default to "*"? I'm using "paypal-rest-sdk" in Node.js
Frontend logic:
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { useID, useAdmin } from "../../context/auth";
import { Button, Accordion, Card, ListGroup, Form } from "react-bootstrap";
import axios from "axios";
function ProductDetails(props) {
const [isError, setIsError] = useState(false);
const [id, setID] = useState("");
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [price, setPrice] = useState(0);
const [stock, setStock] = useState(0);
const [messages, setMessages] = useState([]);
const { IDTokens } = useID();
const { adminTokens } = useAdmin();
const Message = props => (
<Card>
<Card.Body>
<Card.Title>
{props.message.owner.username === "(User removed)" ? (
<span>{props.message.owner.username}</span>
) : (
<Link to={`/users/${props.message.owner.id}`}>{props.message.owner.username}</Link>
)}
</Card.Title>
<Card.Text>
{props.message.content}
</Card.Text>
{IDTokens === props.message.owner.id || adminTokens ? (
<span>
<Link to={`/products/list/${id}/messages/${props.message._id}/edit/`} style={{ marginRight: 10, marginLeft: 10 }}>
Edit
</Link>
<Link to={`/products/list/${id}/messages/${props.message._id}/delete/`}>Delete</Link>
</span>
) : (
<span></span>
)}
</Card.Body>
</Card>
)
useEffect(() => {
axios.get(`http://localhost:4000/products/${props.match.params.id}`)
.then(res => {
setID(res.data.product._id);
setName(res.data.product.name);
setDescription(res.data.product.description);
setPrice(res.data.product.price);
setStock(res.data.product.stock);
setMessages(res.data.messages);
}).catch(function(err) {
setIsError(true);
})
}, [props, IDTokens]);
function messageList() {
return messages.map(function(currentMessage, i){
return <Message message={currentMessage} key={i} />;
})
}
function postOrder() {
if(stock > 0) {
let productInfo = {
name,
description,
price
};
axios.post("http://localhost:4000/orders/pay",
productInfo
).then(res => {
if(res.status === 200) {
console.log(res.data);
} else {
setIsError(true);
}
}).catch(err => {
setIsError(true);
});
}
}
return (
<div className="text-center">
<h2>Products Details</h2>
<Accordion>
<Card>
<Card.Header>
<Accordion.Toggle as={Button} variant="link" eventKey="0">
Product Info
</Accordion.Toggle>
</Card.Header>
<Accordion.Collapse eventKey="0">
<Card.Body>
<ListGroup>
<ListGroup.Item>Name: {name}</ListGroup.Item>
<ListGroup.Item>Description: {description}</ListGroup.Item>
<ListGroup.Item>Price: ${price.toFixed(2)}</ListGroup.Item>
<ListGroup.Item>Stock: {stock}</ListGroup.Item>
</ListGroup>
{stock > 0 ? (
<Form>
<Button onClick={postOrder} variant="success">Order Now</Button>
{ isError &&<p>Something went wrong with making the order!</p> }
</Form>
) : (
"Cannot order, currently out of stock"
)}
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
<Link to={`/products/list/${id}/messages/new`}>Questions or Comments Regarding this Product? Leave a Message.</Link>
<h3>Messages: </h3>
{messages.length > 0 ? (
messageList()
) : (
<p>(No messages)</p>
)}
{ isError &&<p>Something went wrong with getting the product!</p> }
</div>
)
}
export default ProductDetails;
Backend logic:
const express = require("express"),
router = express.Router(),
paypal = require("paypal-rest-sdk"),
Order = require("../database/models/order");
router.post("/pay", function(req, res) {
console.log("req.body: ", req.body);
const create_payment_json = {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
"return_url": "http://localhost:3000/orders/success",
"cancel_url": "http://localhost:3000/orders/cancel"
},
"transactions": [{
"item_list": {
"items": [{
"name": req.body.name,
"sku": "001",
"price": req.body.price,
"currency": "USD",
"quantity": 1
}]
},
"amount": {
"currency": "USD",
"total": req.body.price
},
"description": req.body.description
}]
};
paypal.payment.create(create_payment_json, function (err, payment) {
if(err) {
console.log(err.message);
} else {
for(let i = 0; i < payment.links.length; i++){
if(payment.links[i].rel === 'approval_url'){
res.redirect(payment.links[i].href);
}
}
}
});
});
router.get('/success', (req, res) => {
console.log("req.query: ", req.query)
const payerId = req.query.PayerID;
const paymentId = req.query.paymentId;
const execute_payment_json = {
"payer_id": payerId,
"transactions": [{
"amount": {
"currency": "USD",
"total": req.query.total
}
}]
};
paypal.payment.execute(paymentId, execute_payment_json, function (error, payment) {
if(err) {
console.log(err.message);
} else {
let order = new Order(JSON.stringify(payment));
order.save().then(order => {
res.status(200).json(`Order added successfully! Created order details: ${order}`);
}).catch(err => {
console.log("Order create error: ", err.message);
});
}
});
});
server.js (client_id and client_secret are changed for stackoverflow):
const express = require("express"),
app = express(),
bodyParser = require("body-parser"),
mongoose = require("mongoose"),
session = require("express-session"),
passport = require("passport"),
localStrategy = require("passport-local"),
paypal = require("paypal-rest-sdk"),
cors = require("cors"),
PORT = 4000,
// Require models
User = require("./database/models/user"),
// Require routes
productRoutes = require("./routes/products"),
messageRoutes = require("./routes/messages"),
orderRoutes = require("./routes/orders"),
userRoutes = require("./routes/users");
app.use(bodyParser.json());
app.use(cors());
// Paypal config
paypal.configure({
"mode": "sandbox", //sandbox or live
"client_id": "...",
"client_secret": "..."
});
// Mongoose config
mongoose.set('useUnifiedTopology', true);
mongoose.set('useFindAndModify', false);
mongoose.connect("mongodb://localhost/barnwood", {
useNewUrlParser: true,
useCreateIndex: true
});
// Sessions
app.use(
session({
secret: "Birdhouses are cool.", // Secret can be any string
resave: false,
saveUninitialized: false
})
);
app.use(passport.initialize());
app.use(passport.session());
passport.use(new localStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
// Routes config
app.use("/products", productRoutes);
app.use("/messages", messageRoutes);
app.use("/orders", orderRoutes);
app.use("/users", userRoutes);
// Start server
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
You're asking your backend server to process the payment and upon success your backend server is doing res.redirect(payment.links[i].href); your browser (axios which has maxRedirects set to 5 by default) is going to follow the redirect and then read the response which is on a different domain than yours, which PayPal refuses you to read in a cross origin way. Reason why you get CORS being blocked.
You have two solutions to this problem:
Instead of doing a res.redirect(payment.links[i].href); you should reply the link and let the browser redirect.
For example:
// replace res.redirect(payment.links[i].href); by
res.json({forwardLink: payment.links[i].href});
Then in your React app, you should read the response and do a window.location = response.forwardLink
axios
.post('http://localhost:4000/orders/pay', productInfo)
.then((res) => {
if (res.status === 200) {
console.log(res.data)
} else {
setIsError(true)
}
})
.catch((err) => {
setIsError(true)
})
becomes
axios
.post('http://localhost:4000/orders/pay', productInfo)
.then((res) => {
if (res.status === 200) {
console.log(res.data)
window.location = res.data.forwardLink
} else {
setIsError(true)
}
})
.catch((err) => {
setIsError(true)
})
You could also prohibit Axios from following redirect (some param tweak with maxRedirects: 0 I think), in which case your response code would be 302 (instead of 200) and you could read the headers.location param with which you can then do window.location = headers.location
Your code would become something like:
axios({
maxRedirects: 0,
method: 'post',
url: 'http://localhost:4000/orders/pay',
data: productInfo,
})
.then((res) => {
if (res.status === 302) {
console.log(res.headers)
window.location = res.headers.location
} else {
setIsError(true)
}
})
.catch((err) => {
setIsError(true)
})

Heroku default node.js application

i have a problem on running the heroku sample application online , it works perfectly locally , but on heroku it shows this error :
TypeError: /app/views/index.ejs:7
5| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2.0, user-scalable=yes" />
6|
>> 7| <title><%= app.name %></title>
8| <link rel="stylesheet" href="stylesheets/screen.css" media="Screen" type="text/css" />
9| <link rel="stylesheet" href="stylesheets/mobile.css" media="handheld, only screen and (max-width: 480px), only screen and (max-device-width: 480px)" type="text/css" />
10|
Cannot read property 'name' of undefined
at Object.<anonymous> (eval at <anonymous> (/app/node_modules/ejs/lib/ejs.js:198:12))
at Object.<anonymous> (/app/node_modules/ejs/lib/ejs.js:200:15)
at ServerResponse._render (/app/node_modules/express/lib/view.js:422:21)
at ServerResponse.render (/app/node_modules/express/lib/view.js:315:17)
at /app/web.js:49:11
at [object Object].me (/app/node_modules/faceplate/index.js:114:7)
at /app/web.js:48:18
at /app/node_modules/faceplate/index.js:104:7
at EventEmitter.<anonymous> (/app/node_modules/faceplate/index.js:131:11)
at EventEmitter.emit (events.js:70:17)
I read somewhere that may be a problem with dependencies in package.json so here is my package.json file :
{
"name": "facebook-template-node",
"version": "0.0.1",
"description": "Template app for Heroku / Facebook integration, Node.js language",
"dependencies": {
"async": "0.1.18",
"ejs": "0.4.3",
"express": "2.4.6",
"faceplate": "0.6.x"
},
"engines": {
"node": "0.6.x"
}
}
and here's the code of web.js :
var async = require('async');
var express = require('express');
var util = require('util');
// create an express webserver
var app = express.createServer(
express.logger(),
express.static(__dirname + '/public'),
express.bodyParser(),
express.cookieParser(),
// set this to a secret value to encrypt session cookies
express.session({ secret: process.env.SESSION_SECRET || 'secret123' }),
require('faceplate').middleware({
app_id: process.env.FACEBOOK_APP_ID,
secret: process.env.FACEBOOK_SECRET,
scope: 'user_likes,user_photos,user_photo_video_tags'
})
);
// listen to the PORT given to us in the environment
var port = process.env.PORT || 3000;
app.listen(port, function() {
console.log("Listening on " + port);
});
app.dynamicHelpers({
'host': function(req, res) {
return req.headers['host'];
},
'scheme': function(req, res) {
return req.headers['x-forwarded-proto'] || 'http';
},
'url': function(req, res) {
return function(path) {
return app.dynamicViewHelpers.scheme(req, res) + app.dynamicViewHelpers.url_no_scheme(req, res)(path);
}
},
'url_no_scheme': function(req, res) {
return function(path) {
return '://' + app.dynamicViewHelpers.host(req, res) + (path || '');
}
},
});
function render_page(req, res) {
req.facebook.app(function(err, app) {
req.facebook.me(function(user) {
res.render('index.ejs', {
layout: false,
req: req,
app: app,
user: user
});
});
});
}
function handle_facebook_request(req, res) {
// if the user is logged in
if (req.facebook.token) {
async.parallel([
function(cb) {
// query 4 friends and send them to the socket for this socket id
req.facebook.get('/me/friends', { limit: 4 }, function(friends) {
req.friends = friends;
cb();
});
},
function(cb) {
// query 16 photos and send them to the socket for this socket id
req.facebook.get('/me/photos', { limit: 16 }, function(photos) {
req.photos = photos;
cb();
});
},
function(cb) {
// query 4 likes and send them to the socket for this socket id
req.facebook.get('/me/likes', { limit: 4 }, function(likes) {
req.likes = likes;
cb();
});
},
function(cb) {
// use fql to get a list of my friends that are using this app
req.facebook.fql('SELECT uid, name, is_app_user, pic_square FROM user WHERE uid in (SELECT uid2 FROM friend WHERE uid1 = me()) AND is_app_user = 1', function(result) {
req.friends_using_app = result;
cb();
});
}
], function() {
render_page(req, res);
});
} else {
render_page(req, res);
}
}
app.get('/', handle_facebook_request);
app.post('/', handle_facebook_request);
You seem to be using the res.render function, however don't seem to be passing it the app object. I believe (unless I'm missing something) that you need to pass the app object to the render function. For example:
res.render('view_name', { app: { name: 'Site_Name' } } );
The other option, if you are using app in a large number of your views, is to add the app object too app.locals, which will make it available in all views (rendered from the current app). This can be done as:
app.locals({
app: {
name: 'Site_Name'
}
});
and then you do not need to pass app to each render call, and
res.render('view_name', {} );
should work.
This is an issue with Facebook's application security and is addressed here:
Heroku - Created a facebook app with Node.js which gives type error
I got it working by disabling sandbox mode on my app.

Resources