Download PDF from node API via FTP - node.js

I have PDF on a remote server. I have API with node and I want, from my website, download the PDF.
I'm using jsftp to upload and read PDF. It works fine :
let str = '';
FTP.get('path/to/my/file', (err, socket) => {
socket.on("data", d => {
str += d.toString();
});
socket.on("close", err => {
if (err) {
console.error("There was an error retrieving the file.", err);
}
// HERE I HAVE THE FILE IN STRING
});
socket.resume();
});
On the close event I have the file in String, but I don't succeed to send it to the browser. I've tried things like :
let s = new Readable();
s.push(str);
s.push(null);
s.pipe(res);
OR
res.end(str);
But nothing happen in browser
I'm using Polymer for my ajax request
<iron-ajax
id="openPdf"
content-type="application/json"
method="POST"
url="/api/karaweb/pdf"
on-response="handleOpenPdfResponse"
on-error="errorMessage"></webservice-request>
Any solutions ?
Thanks

I have a mixin called PdfDownloaderMixin; here is the whole code:
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<dom-template id="pdf-downloader-mixin">
<script>
/* #polymerMixin */
const PdfDownloaderMixin = (superClass) => class extends superClass {
constructor() {
super();
}
downloadPdf(blobData) {
let fileObjectUrl = window.URL.createObjectURL(blobData);
window.open(fileObjectUrl);
}
}
</script>
</dom-template>
Then you use like this in your element:
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html" />
<link rel="import" href="pdf-downloader-mixin.html" />
<dom-module id="attachment-handler">
<template>
<iron-ajax id="getAttachmentAjax"
url="[[rootPath]]api/session/getattachment"
debounce-duration="300"
handle-as="blob"></iron-ajax>
</template>
<script>
class AttachmentHandler extends PdfDownloaderMixin(Polymer.Element) {
static get is() { return 'attachment-handler'; }
getAttachment() {
this.$.getAttachmentAjax.generateRequest().completes.then((req) => {
req.succeeded && this.downloadPdf(req.response);
});
}
}
customElements.define(AttachmentHandler.is, AttachmentHandler);
</script>
</dom-module>

Related

How to FTP upload a buffer (pdf buffer) using NodeJS?

I converted a HTML to pdf using html-pdf-node, but I am not find a way to store this PDF in my server using FTP.
My Code:
const html_to_pdf = require('html-pdf-node');
const generatePDF = () => {
// The test HTML file
let content = `
<html>
<head>
<title>Test Application</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2>Just a Test</h2>
</div>
</body>
</html>
`;
// generating the PDF
let options = {
format: 'letter',
margin: {
right: '40px',
left: '40px'
}
};
let file = { content };
html_to_pdf.generatePdf(file, options).then((pdfBuffer) => {
console.log(pdfBuffer); // This is the pdfBuffer. It works because if I send this buffer to my email as an attachment, I can open the PDF
// How can I create and store a test.pdf file inside my server using FTP connection?
});
}
Thank you
Using ftp should do it - https://www.npmjs.com/package/ftp
Installation: npm i ftp and usage something like:
const Client = require("ftp");
// snip snip some code here
html_to_pdf.generatePdf(file, options).then((pdfBuffer) => {
const c = new Client();
c.on("ready", function () {
c.put(pdfBuffer, "foo.pdf", function (err) {
if (err) throw err;
c.end();
});
});
const secureOptions = {
host: "localhost",
port: 21,
user: "TheGreatPotatoKingOfEurope",
password: "5uper_5eekrit!"
};
c.connect(secureOptions);
});

Create image NextJS + NodeJS - 404 This page could not be found

I'm creating images using this library https://github.com/frinyvonnick/node-html-to-image
The output folder is public (https://nextjs.org/docs/basic-features/static-file-serving)
Everything works well on Dev, but when I build the app and run in production mode, I can't have access to the image (the image is created) but I receive the message 404 This page could not be found.
const nodeHtmlToImage = require('node-html-to-image')
async function generateImage({ htmlContent }) {
const htmlFile = `<html>
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Roboto+Slab:400,700|Material+Icons"/>
<style>
body {
width: 600px;
height: auto;
}
</style>
</head>
${htmlContent}
</html>`
const image_name = crypto.randomBytes(20).toString('hex')
const relativePath = `output/${image_name}.png`
const output = `${process.env.SERVER_STATIC_URL}/${relativePath}`
return await nodeHtmlToImage({
output: `./public/${relativePath}`,
html: htmlFile,
}).then(() => {
return { image_src: output }
})
.catch((err) => {
console.log('err')
return err
})
}
export { generateImage }
How can I solve it?
Thanks!

Next.js intercept response

Here is snippet of what my server looks like
nextApp.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url!, true);
handleNextRequest(req, res, parsedUrl);
}).listen(port);
});
Once I get the response for the request, how can I append html comment or any tag basically?
What I wanted to do is, before and after body tag, I want to add some comments.
Current structure
<body></body>
What I want
<!--someContext-->
<body> some content </body>
<!--someMoreContext-->
You can do it by editing the _document special file of Next that used as a base template to the page.
// ./pages/_document.js
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument

How To Send a Message From Popup.js to Content Script in Chrome Extension on Active Tab?

When I click on the toolbar icon from my chrome extension, it brings up the default popup.html along with popup.js. From that popup.js, I want to send a message to the current active tab. I can't figure out how to get the active tab.
My code in the popup.js looks like this:
window.onload = function() {
console.log(`popup.js:window.onload`);
const timeNow = document.getElementById("timeNowId");
timeNow.innerText = new Date().toLocaleTimeString();
var resultsButton = document.getElementById("buttonId");
resultsButton.onclick = () => {
chrome.runtime.sendMessage(
"FromPopupToBackgroundToContent:" + timeNow.innerText,
function(response) {
response === undefined
? alert("popup.js:return from sendMessage:undefined")
: alert("popup.js:return from sendMessage:", response);
}
);
};
};
The full, non-working example is in this github repo at this branch linked to.
https://github.com/pkellner/chrome-extension-message-popup-to-content/tree/feature-popup-to-content-directly-getcurrent
Example:
popup.js
function popup() {
chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
var activeTab = tabs[0];
chrome.tabs.sendMessage(activeTab.id, {"message": "start"});
});
}
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("button1").addEventListener("click", popup);
});
content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "start" ) {
start();
}
}
);
function start(){
alert("started");
}
popup.html
<!DOCTYPE html>
<html>
<head></head>
<script src="popup.js"></script>
<body>
<input id="button1" type=button value=clickme>
</body>
</html>

Trying to figure a way to read all the files in a directory, re-create and write files programmatically

I'm trying to use node built in file structure module/package in trying to read and write files. I'm looking for a way on how I can read all the files in specific directory, re-create the files and write for any changes.
Basically if I have a file called templates/_template-1.html it would re-create it to a different directory called pages/template-1.html. Instead of having to declare each file manually within the gulpfile.js. The code below is currently a work in progress.
It basically prints tpl files written then re-writes them to basic html.
/*------------------ INDEX -------------------*/
/* Build index file for the final HTML form
*/
gulp.task("build:index", function() {
let templateFiles = glob.sync("templates/**/*.tpl"),
templates = {},
RESPONSIVE_HTML = fs.readFileSync("_responsive.html", "utf8"),
THE_HTML = fs.readFileSync("_design-system.html", "utf8"),
THE_VISUAL_LIBRARY = fs.readFileSync("_visual-library.html", "utf8");
// Discover all templates
for (let file in templateFiles) {
file = templateFiles[file];
let template = /templates\/(.+?)\.tpl/gi.exec(file)[1],
text = fs.readFileSync(file, "utf8");
template = path.basename(file, '.tpl');
templates[template] = text;
}
// --------------------------------------------------------
// Visible templates:
_.each(templates, (partial, name) => {
interpolateTemplate(partial, name, templates);
});
// replace the main HTML file
for (let template in templates) {
RESPONSIVE_HTML = RESPONSIVE_HTML.replace(new RegExp(`{[#$]${template}}`, "g"), templates[template]);
THE_HTML = THE_HTML.replace(new RegExp(`{[#$]${template}}`, "g"), templates[template]);
THE_VISUAL_LIBRARY = THE_VISUAL_LIBRARY.replace(new RegExp(`{[#$]${template}}`, "g"), templates[template]);
}
fs.writeFileSync("design-system.html", beautify(THE_HTML), "utf8");
fs.writeFileSync("responsive.html", beautify(RESPONSIVE_HTML), "utf8");
fs.writeFileSync("visual-library.html", beautify(THE_VISUAL_LIBRARY), "utf8");
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BDO Components</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-css.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-html.js"></script>
<script src="assets/js/libs.js" type="text/javascript"></script>
<link rel="stylesheet" href="assets/css/assets-page.css" />
<link rel="stylesheet" href="assets/css/component-guide.css" />
</head>
<body>
<div class="display-panels">
{$control-bar}
<div class="preview-pane -hide-code">
{$globals}
{$design-references}
{$component-modifiers}
<div class="section-block element-group --show-code --components -component"
data-name="Typesetting">
{$typesetting}
</div>
<div class="section-block element-group --show-code --components -component"
data-name="Elements">
{$elements}
</div>
<div class="section-block element-group --show-code --components -component"
data-name="Low Level Components">
{$low-level-components}
</div>
<div class="section-block element-group --show-code --components -component"
data-name="High Level Components">
{$high-level-components}
</div>
</div>
<div class="index-group">
</div>
</div>
<script src="assets/js/app.js" type="text/javascript"></script>
</body>
</html>
You can use the function called readdir on fs. It will return a list of filenames which you can traverse and do whatever you need to do.
Basically, this will read all files inside dirname, read content of each filename returned, modify it, write it back.
(I wrapped fs functions with promises for better flow)
function readFiles(dirname) {
let fileNames = [];
let fileContents = [];
const results = [];
return readdir(dirname)
.then((_fileNames) => {
fileNames = _fileNames;
// map filenames to array of readFile promises
return Promise.all(fileNames.map((filename) => readFile(filename)))
})
.then((allFilesContent) => {
fileContents = allFilesContent;
// for each file, push an object with name + content to a new array
fileNames.forEach((fileName, index) => {
results.push({
name: fileName, // <-- you can also change the file paths here if needed
content: beautify(fileContents[index]) // <-- modify the content here as you please
});
});
})
// map that array to a writeFile promise array
.then(() => results.map((file) => writeFile(file.name, file.content)))
.then(() => console.log('all files written successfully'))
.catch((err) => console.error(err));
}
// FS FUNCTIONS AS PROMISES:
function readFile(filepath) {
return new Promise((resolve, reject) => {
fs.readFile(filepath, 'utf-8', function(err, content) {
if (err) { return reject(err); }
resolve(content);
});
});
}
function readdir(dirname) {
return new Promise((resolve, reject) => {
fs.readdir(dirname, function(err, filenames) {
if (err) { return reject(err); }
resolve(filenames);
});
});
}
function writeFile(filename, content) {
return new Promise((resolve, reject) => {
fs.writeFile(filename, content, function(err) {
if (err) { return reject(err); }
resolve();
});
});
}
I have a series of modules around slurping whole directories (recursively), and then doing stuff, like making a web page, with the results.
https://github.com/AWinterman/node-fsj and https://github.com/AWinterman/fsj-render
it should be pretty easy for you to add what you want.

Resources