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.
Related
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¤cy=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¤cy=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.
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¤cy=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}!`));
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"
I've developed my web app using ReactJS and I'm using as a server ExpressJS. Everithing was working fine until I implemented a /contactme endpoint which just must work as restful POST to send an email. I mean, my aim is just publishing an endpoint to send mails.
I'm using express-mailer for the job, but when I try to send an email using send method I'm getting this error:
message:"No default engine was specified and no extension was provided."
stack:"Error: No default engine was specified and no extension was provided.\n at new View (c:\React\web.facundolarocca.com\node_modules\express\lib\view.js:62:11)\n at EventEmitter.render (c:\React\web.facundolarocca.com\node_modules\express\lib\application.js:569:12)\n at sendMail (c:\React\web.facundolarocca.com\node_modules\express-mailer\lib\express-mailer.js:55:5)\n at Object.exports.extend.createSend [as send] (c:\React\web.facundolarocca.com\node_modules\express-mailer\lib\express-mailer.js:98:7)\n at c:\React\web.facundolarocca.com\server.js:28:16\n at Layer.handle [as handle_request] (c:\React\web.facundolarocca.com\node_modules\express\lib\router\layer.js:95:5)\n at next (c:\React\web.facundolarocca.com\node_modules\express\lib\router\route.js:131:13)\n at Route.dispatch (c:\React\web.facundolarocca.com\node_modules\express\lib\router\route.js:112:3)\n at Layer.handle [as handle_request] (c:\React\web.facundolarocca.com\node_modules\express\lib\router\layer.js:95:5)\n at c:\React\web....
I understand that ExpressJS needs some view engine to return html files, but in my case I'm going to respond a simpli JSON.
Below is my code:
var path = require('path');
var express = require('express');
var app = express();
var mailer = require('express-mailer');
var PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, '/build')));
mailer.extend(app, {
from: 'no-reply#gmail.com',
host: 'smtp.gmail.com',
secureConnection: true,
port: 465,
transportMethod: 'SMTP',
auth: {
user: '*********#gmail.com',
pass: '**********'
}
});
app.get('/', function (req, res) {
//this is working fine
res.sendFile(__dirname + '/build/index.html')
});
app.get('/contactme', function (req, res) {
try {
app.mailer.send('test', {
to: 'myemaila#myemail.com.ar',
subject: 'some subject'
}, function (err) {
if (err) {
console.log(err);
res.status(400).json('There was an error sending the email');
} else {
res.status(200).json('Email Sent');
}
});
} catch (error) {
//Error is raised here
res.status(500).json(error);
}
});
app.listen(PORT, function (error) {
if (error) {
console.error(error);
} else {
console.info("==> 🌎 Listening on port %s. Visit http://localhost:%s/ in your browser.", PORT, PORT);
}
});
So I have two problems, on one hand is how to avoid this error , but in the other hand is why do I need an egine view .
I just expect, from the client side, to read the status code to show some message. I thought I could be able to implement in the same way as I was using restify.
My solution was to move to nodemailer. Here is the whole code:
package.json
{
"dependencies": {
"express": "^4.14.0",
"nodemailer": "^2.7.0",
"nodemailer-smtp-transport": "^2.7.2"
}
}
Code
server.post('/contactme', (req, res) => {
try{
let mailer = require('nodemailer')
let smtpTransport = require('nodemailer-smtp-transport')
let options = {
service: config.mailService.service,
secure: true,
auth: {
user: config.mailService.user,
pass: config.mailService.password
}
}
let transport = mailer.createTransport(smtpTransport(options))
let mail = {
from: 'from',
to: 'to',
subject: 'subject',
html: 'body'
}
transport.sendMail(mail, (error, response) => {
transport.close()
if (error) {
res.json(400, {error});
} else {
res.json(200, {response: 'Mail sent.'});
}
})
} catch(error) {
res.json(400, {error});
}
})
I isolated the problem, as far as I could, but still cannot solve it.
I created an empty server with loopback, added express-session and body-parser
middlewares
"session": {
"express-session": {
"params": {
"name": "id",
"secret": "potato with eyes",
"httpOnly": "false"
}
}
},
"auth": {},
"parse": {
"body-parser": {},
"body-parser#json": {},
"body-parser#urlencoded": {"params": { "extended": true }}
}
Then, I added a pair of methods to root.js.. The first sets session.id to a variable. The second logs it on next request:
module.exports = function (app)
{
var cookieParser = require("cookie-parser")
var router = app.loopback.Router()
router.post("/login", function (req, res)
{
req.session.id = req.body.id
console.log("Set id to " + req.body.id)
res.end()
})
router.post("/addLead", function (req, res)
{
console.log("session", req.session)
console.log("got id: ", req.session.id)
console.log("decrypting single id:", cookieParser.signedCookie(req.session.id, "potato with eyes"))
console.log("cookie! ", req.cookie)
console.log("cookie parsed:", cookieParser.JSONCookie(req.cookie, "potato with eyes"))
console.log("cookie parsed:", cookieParser.signedCookie(req.cookie, "potato with eyes"))
res.status(403).send("You must login first")
})
app.use(router)
}
Decryption of cookies fails. Decryption of id does not change it.
Web server listening at: http://localhost:3000
Browse your REST API at http://localhost:3000/explorer
Set id to 15
session Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true } }
got id: XifrUZXLhKcDHYqQwxESQlLQQ6N1j49d
decrypting single id: XifrUZXLhKcDHYqQwxESQlLQQ6N1j49d
cookie! undefined
cookie parsed: undefined
cookie parsed: undefined
Here is the html I used for testing:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"
integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s="
crossorigin="anonymous"></script>
<script>
function log(data)
{
console.log(JSON.stringify(data))
}
$.post("http://localhost:3000/login", { name: "John Smit", id: 15 }, function (data)
{
log(data)
$.post("http://localhost:3000/addLead", {
name: "Anton Berezin", phone: "337225", model: "1234",
mark: "Toyota", yearFrom: "2014", yearTo: "2017"
}, function (data)
{
log(data)
alert(JSON.stringify(data))
})
.fail(function (error)
{
log(error)
})
})
.fail(function(error)
{
alert(JSON.stringify(error))
})
</script>
</head>
<body>
</body>
</html>
And the archive with a project:
http://www.filedropper.com/cookietest
I'll appreciate any help
Edit:
tested with req.cookie instead of req.session.cookie. Didn't change output.
You don't need to use cookie-parser with express-session anymore.
Since you registered express-session, I would modify your code in this way
module.exports = function (app)
{
var router = app.loopback.Router()
// serialize the session
router.post("/login", function (req, res)
{
req.session = {
userId: 123,
accessToken: 'eadeadaew'
// or whatever data you want to store in the session
};
console.log("Set session");
res.end();
});
// deserialize the session
router.post("/addLead", function (req, res)
{
if(req.session) {
console.log("session", req.session);
console.log("user id: ", req.session.userId);
console.log("token ", req.session.accessToken);
res.end();
} else {
res.status(403).send("You must login first");
}
})
app.use(router);
}