I am building an analytics dashboard using the MERN stack (Express, Node) are the Important things to highlight.
As part of a dash view, I was trying to find if it's possible to trigger a PhantomJS call to create a pdf report using a button on the page itself.
Given you need to be logged in to see your own analytics, I can not just run phantom from the command line and pass it in the URL of one of the dashboard pages since it requires a login and queries to be made.
Is it possible to do this with phantomJS?
If I correctly understood your question.
Example:
[main.js]
const dashboardToPdfCtrl = require("./controllers/phantom/pdf");
router.route("/api/dashboard/phantom").post(dashboardToPdfCtrl.createPdf);
router.route("/api/dashboard/phantom/html")
.post(dashboardToPdfCtrl.createDashboard);
When the user clicks on the "button" you can validate the USER according to the architecture of your application.
[pdf.js]
exports.createPdf= async (req, res) => {
if (!req.user || !req.user.sub) {
return res
.status(401)
.send({ message: 'No authorization token was found' });
}
const instance = await phantom.create();
const page = await instance.createPage();
const settings = {
operation: "POST",
encoding: "utf8",
headers: {
"Content-Type": "application/json"
},
data: JSON.stringify({
user: req.body.userId,
anyDataYouNeedToRender: req.body.anyDataYouNeedToRender
})
};
//POST request to /api/dashboard/phantom/html
await page.open(
`${process.env.HOST}:${
process.env.PORT
}/api/dashboard/phantom/html`,
settings
);
//Save the content of /public/dashboard/dashboard.html with received data to pdf
const pageSaved = await page.render(
path.resolve(`./public/dashboard/file.pdf`)
);
if (pageSaved) await instance.exit();
}
exports.createDashboard = (req, res) => {
res.render(
path.resolve("./public/dashboard/dashboard.html"),
{ user: req.body.user,
anyDataYouNeedToRender: req.body:anyDataYouNeedToRender
}
);
};
Is that what you were looking for? I want to help you, feel free to ask detalization.
P.S. As friends told before in comments, it will be great if you give us more information to understend you goal.
Related
I have a typical web app with a client and a node.js server. When a user selects an option on the client, I want to export (create) a google doc in their drive.
I am half way there following this tutorial https://developers.google.com/identity/protocols/oauth2/web-server
With my current set up, after the user authenticates, the authentication token is sent to a web hook (server side), but I don't have any of the data for creating the google doc there.
If I did, I could create the doc from there. Otherwise, I need to send the token itself back to the client so I can create the doc with the necessary payload from there.
In that case, I don't know how to signal to the client that the user has been authenticated. Should I use a web socket?
Something tells me that my general set up might not be correct, and that I should be doing it a different way in my use case.
This is my client side code that brings the user to the google auth page after getting the auth url (not sure if this really needs to be done server side, but since I have some user credentials I thought it might be better).
export async function exportToGoogleDoc() {
const response = await POST(`${API_URL}export/gdoc`, {
'hello': 'world'
});
if (response.status == 200){
window.location.href = response.authUrl;
}
}
And then the endpoint (just returns the autheticationUrl)
api.post('/export/gdoc', express.raw({ type: 'application/json' }), async (req, res, next) => {
try {
const scopes = [
'https://www.googleapis.com/auth/drive'
];
const oauth2Client = new google.auth.OAuth2(
credentials.web.client_id,
credentials.web.client_secret,
credentials.web.redirect_uris[0]
);
const authorizationUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
include_granted_scopes: true
});
res.json({ 'status': 200, authUrl : authorizationUrl } );
} catch (err){
next(err);
}
});
But then after the user agrees and authenticates with their google account, the auth token is sent to this web hook. At the bottom I am able to write an empty google doc to the authenticated google drive, but I don't have the data I need to create the real doc.
api.get('/auth/google', express.raw({ type: 'application/json' }), async (req, res, next) => {
const q = url.parse(req.url, true).query;
const oauth2Client = new google.auth.OAuth2(
credentials.web.client_id,
credentials.web.client_secret,
credentials.web.redirect_uris[0]
);
if (q.error) {
console.log('Error:' + q.error);
} else {
const { tokens } = await oauth2Client.getToken(q.code.toString());
oauth2Client.setCredentials(tokens);
const drive = google.drive('v3');
const requestBody = {
'name': 'Dabble',
'mimeType': 'application/vnd.google-apps.document',
};
drive.files.create({
requestBody: requestBody,
fields: 'id',
auth: oauth2Client
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file);
}
});
}
Somehow I either need to get the data for the google doc inside this web hook, or to listen for this web hook from the client.
OR I need an entirely different set up. I realize I also should be probably storing this token somewhere (local storage on client side?) and only making this call if they do not have a token.
Can anyone help me modify my set up? Thanks!
I'm wanting to allow users of my site that use Discord to be able to "automatically" join my guild.
I have everything done except I always get a 401: Unauthorized from Discord's API using the following;
router.get("/cb", passport.authenticate("discord", { failureRedirect: "/" }), async function(req, res) {
const data = { access_token: req.user.accessToken };
axios.put(`https://discordapp.com/api/v8/guilds/${config.CyberCDN.server_id}/members/${req.user.id}`, {
headers: {
"Content-Type": "application/json",
"Authorization": `Bot ${config.CyberCDN.bot_token}`
},
body: JSON.stringify(data)
}).then((success) => {
console.log(`[DASHBOARD] ${req.user.username}#${req.user.discriminator} - Logging in...`);
console.log(success.config.data)
console.log(success.response.status)
return res.status(200).redirect("/");
}).catch((error) => {
console.log(`[DASHBOARD] ${req.user.username}#${req.user.discriminator} - Failed Logging in...`);
console.log(error.config.data.replace(config.CyberCDN.bot_token,"TOKEN"))
console.log(error.response.status)
return res.status(403).redirect("/");
});
});
I don't understand how when everything I have done is correct;
I have even asked in the Discord-API server regarding this matter with the same issue,
I did however have it working ONE TIME and now it's broke again, I have 0 clue how it broke.
My scopes are as follow "oauth_scopes": ["guilds.join"]
I found a better solution to this problem I had:
const DiscordOauth2 = require("discord-oauth2");
const discord = new DiscordOauth2();
/**
* Other required stuff for express.js goes here...
*/
router.get("/login", passport.authenticate("discord"));
router.get("/cb", passport.authenticate("discord", { failureRedirect: "/forbidden" }), async function(req, res) {
req.session.user = req.user;
res.redirect('/');
});
router.get("/support", authOnly, async function(req, res) {
discord.addMember({
accessToken: req.session.user.accessToken,
botToken: config.CyberCDN.bot_token,
guildId: config.CyberCDN.server_id,
userId: req.session.user.id,
roles: [config.CyberCDN.site_role]
}).then((r) => {
if(r) {
let date = new Date(r.joined_at);
res.status(200).json({ status: "Joined Server" });
const embed = new Embed()
.title(`New User Joined Via Site\n${r.user.username}#${r.user.discriminator}`)
.colour(16763904)
.thumbnail(`https://cdn.discordapp.com/avatars/${r.user.id}/${r.user.avatar}.webp?size=128`)
.footer(`User joined at: ${date.toLocaleDateString()}`)
.timestamp();
dhooker.send(embed);
console.log(r)
}else{
res.status(401).json({ status: "Already In There?" });
}
});
});
Basically through browsing my initial 401: Unauthorized error stumbled across a nice little OAuth2 NPM For Discord called discord-oauth2 developed by reboxer and numerous other people, which can be found here.
The helpful part was documented further down the README.md of that repo, in relation to my problem. Relation found here
I have also contributed that they add the removeMember feature also.
I have a shopify store mystore and I have an nodejs app myapp. I need to do is when something happens on mystore a webhook will be created/registered in my nodejs app. I have tried https://www.npmjs.com/package/#shopify/koa-shopify-webhooks this package but it is not working for me and I don't think that it is the same thing that I want. I just want that when let suppose order is created in store a webhook is registered.
if you just have to register a webhook you can use this code.
You just have to change the webhook topic and the endpoint.
This is for orders/create webhook registration
add shopify-api-node and request-promise packages and require them
const ShopifyAPIClient = require("shopify-api-node");
const request = require("request-promise");
then
const createOrderWebhook = await registerWebhook(yourShopDomain, yourShopAccessToken, {
topic: "orders/create",
address: "Your node app end point" //www.example.com/webhooks/createOrder,
format: "json",
});
add your registerWebhook function
const registerWebhook = async function (shopDomain, accessToken, webhook) {
const shopify = new ShopifyAPIClient({
shopName: shopDomain,
accessToken: accessToken,
});
const isCreated = await checkWebhookStatus(shopDomain, accessToken, webhook);
if (!isCreated) {
shopify.webhook.create(webhook).then(
(response) => console.log(`webhook '${webhook.topic}' created`),
(err) =>
console.log(
`Error creating webhook '${webhook.topic}'. ${JSON.stringify(
err.response.body
)}`
)
);
}
};
for checking the webhook already not created at Shopify you can use following code
const checkWebhookStatus = async function (shopDomain, accessToken, webhook) {
try {
const shopifyWebhookUrl =
"https://" + shopDomain + "/admin/api/2020-07/webhooks.json";
const webhookListData = {
method: "GET",
url: shopifyWebhookUrl,
json: true,
headers: {
"X-Shopify-Access-Token": accessToken,
"content-type": "application/json",
},
};
let response = await request.get(webhookListData);
if (response) {
let webhookTopics = response.webhooks.map((webhook) => {
return webhook.topic;
});
return webhookTopics.includes(webhook.topic);
} else {
return false;
}
} catch (error) {
console.log("This is the error", error);
return false;
}
};
Happy coding :)
You can not create/register a new webhook when the order created.
Webhooks are a tool for retrieving and storing data from a certain event. They allow you to register an https:// URL where the event data can be stored in JSON or XML formats. Webhooks are commonly used for:
Placing an order
Changing a product's price
Notifying your IM client or your pager when you are offline
Collecting data for data-warehousing
Integrating your accounting software
Filtering the order items and informing various shippers about the order
Removing customer data from your database when they uninstall your app
My aim is sending email for sign up users using Firebase function and authentication.
I followed Firebase example.
But it tells below error message.
The provided dynamic link domain is not configured or authorized for
the current project
My code is at below.
const actionCodeSettings = {
url: 'https://www.example.com/finishSignUp?cartId=1234',
handleCodeInApp: true,
iOS: {
bundleId: 'com.example.ios'
},
android: {
packageName: 'com.example.android',
installApp: true,
minimumVersion: '12'
},
dynamicLinkDomain: 'example.page.link'
};
exports.sendmail = functions.https.onRequest((req, res) => {
return cors(req, res, () => {
firebase.auth().sendSignInLinkToEmail("sungyong#humminglab.io", actionCodeSettings)
.then((userCredential) => {
res.status(200).send(userCredential);
res.status(200).send(userCredential);
return;
})
.catch(error => {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(error)
// ...
res.status(400).send(error);
});
});
});
Here are my configuration at my console.
example.page.link is not configured as a dynamic link domain for your project.
You need to use one you own. You can get that from "Dynamic Links" under "Grow" in the left menu of the Firebase Console.
If you don't need to use dynamic links with mobile flows, just change to:
const actionCodeSettings = {
// Replace this URL with the URL where the user will complete sign-in.
url: 'https://www.example.com/finishSignUp?cartId=1234',
handleCodeInApp: true
};
Add "example.page.link" in the Authorised domain instead of www.example.com.
Because example.page.link is your domain id.
I got this error when I make subsequent request using mwbot on node.
response:
{ login:
{ result: 'Aborted',
reason: 'Cannot log in when using MediaWiki\\Session\\BotPasswordSessionProvider sessions' } } }
I am reading pages from mediawiki by providing a title. I thought that every request would need to login to read, but it seemed that I was wrong because this error seemed to complain that I already have logged in. But I don't know how the session can be read or how to find out that I already logged in or not.
the route:
router.get('/wikipage/:title', function(req, res, next) {
let title = req.params.title;
const MWBot = require('mwbot');
const wikiHost = "https://wiki.domain.com";
let bot = new MWBot();
let pageContent = "wiki page not created yet, please create";
bot.login({
apiUrl: wikiHost + "/api.php",
username: "xxx#apiuser",
password: "xxxxx"
}).then((response) => {
console.log("logged in");
return bot.read(title);
}).then((response) => {
for(let prop in response.query.pages) {
pageContent = response.query.pages[prop]['revisions'][0]['*'];
console.log("pageContent:", pageContent);
break;
}
res.json({
data: pageContent
});
}).catch((err) => {
// Could not login
console.log("error", err);
});
});
module.exports = router;
I presume you are running this in a browser, in which case the browser takes care of session cookie handling. You can check it the usual way via document.cookie.