I am trying to covert json data into Xlsx file and save it in a folder.
I have been trying to use icg-json-to-xlsx module but till now I have been unable to use it.
My code looks like this:
jsonXlsx = require('icg-json-to-xlsx');
filename = path.join('./files', "output.xlsx");
outputFile = jsonXlsx(filename, result) //result contains json data
console.log(outputFile);
but I got this error
outputFile = jsonXlsx(filename, result)
^
TypeError: Property 'jsonXlsx' of object # is not a function
Getting data from mongodb:
in routes:
router.get('/', function(req, res, next) {
fileController.getAll(function(err, result){
if(err){
res.send(500,err);
}
// res.json(result);
var data = result;
in controller:
FileController.prototype.getAll = function(callback){
File.find( {}, {_id: false, id: true, name: true, status: true}, function(err, file){
if(err) {
return callback(err);
} else {
if (!file) {
return callback('file not found');
}
}
callback(null, file);
}
)};
Try this
outputFile = jsonXlsx.writeFile(filename, result);
jsonXlsx is object, which contains methods like writeFile, writeBuffer, so you can't call jsonXlsx as function... or you need add reference to function like this
jsonXlsxWriteFile = require('icg-json-to-xlsx').writeFile;
outputFile = jsonXlsxWriteFile(filename, result)
Example
var jsonXlsx = require('icg-json-to-xlsx');
var path = require('path');
var filename = path.join('./files', "output.xlsx");
var result = [
{ id: '1', name: 'test', status: '123' },
{ id: '2', name: 'david', status: '323'},
{ id: '3', name: 'ram', status: '2323' }
];
var outputFile = jsonXlsx.writeFile(filename, JSON.stringify(result));
console.log(outputFile);
Update:
File
.find({ })
.select({
_id: false, id: true, name: true, status: true
})
.lean()
.exec(function(err, file) {
//
});
In your case, query returns MongooseDocuments, but jsonXlsx needs plain JavaScript objects, so that's why you should use lean()
You can try Alasql JavaScript SQL library. It includes a module to work with JSON and XLSX files (with support of js-xlsx.js library).
Install these two libraries into your project.
npm install alasql
npm install xlsx
Then call alasql function:
var alasql = require(alasql);
alasql('SELECT * INTO XLSX("mydata.xlsx",{headers:true}) \
FROM JSON("mydata.json")');
var cities = [{City:'London',Population:2500000},{City:"Paris",Population:2000000}];
alasql("SELECT * INTO XLSX("mydata.xlsx",{headers:true}) FROM ?",[cities]);
See more examples in this demo file.
There are a lot of modules that can do it. But if you want to control the formatting of xlsx file, then I suggest you use this below code. Rows contain data in the form of JSON array.
var excel = require('node-excel-export');
var styles = {
headerDark: {
fill: {
fgColor: {
rgb: 'FF000000'
}
},
font: {
color: {
rgb: 'FFFFFFFF'
},
sz: 14,
bold: true,
underline: true
}
},
cellPink: {
fill: {
fgColor: {
rgb: 'FFFFCCFF'
}
}
},
cellGreen: {
fill: {
fgColor: {
rgb: 'FF00FF00'
}
}
}
};
var specification = {
"Col1": {
"displayName": 'Col1Name',
"headerStyle": styles.headerDark,
"width": 250
},
"Col2": {
"displayName": 'Col2Name',
"headerStyle": styles.headerDark,
"width": 215
},
"Col3": {
displayName: 'Col3Name',
headerStyle: styles.headerDark,
width: 150
}
}
var report = excel.buildExport(
[{
name: 'Report.xlsx',
specification: specification,
data: rows
}]
);
Related
I'm using pdfmake nodejs library in google cloud function for generating pdf files.
i'm downloading a image to local temp dir and using that image in pdfmake and also i've deployed a local image with the function itself and also using that image in the pdf as well.
The downloaded image is located on "/tmp/image1.png" and the local image is located on "res/image2.png"
while testing with local emulator, the code doesn't have any issue at all, but when i try to run in cloud function production environment, i'm getting following errors,
Invalid image: Error: Unknown image format.Images dictionary should contain dataURL entries (or local file paths in node.js)
i've deployed close to 14 version to cloud functions iterating image formats,filenames,only using local image ,only using downloaded image on tmp folder, but no luck.
When the same function is working on local emulator without any issue, i believe it must be something do to with the cloud function read and write permission.
Following it the dependency,
"dependencies": {
"electron": "^11.1.1",
"express": "^4.17.1",
"firebase-admin": "^9.2.0",
"firebase-functions": "^3.11.0",
"http": "0.0.1-security",
"moment": "^2.29.1",
"open": "^7.3.1",
"pdfmake": "^0.1.69"
},
following code is to download image from link to temp folder,
var path = require('path');
import http from 'http'
import https from 'https'
import { createWriteStream, unlink } from 'fs'
const tempDir = os.tmpdir()
const tempFileName = path.join(tempDir, 'Pic.png')
var url = "https://someimageurl"
var outFileName = path.join(tempDir, 'out.pdf')
var tradeMark = "res/mark.png"
var imageSize = 75
var downloadPic = ''
const proto = !url.charAt(4).localeCompare('s') ? https : http;
function makePdf(){
var fonts = {
Roboto: {
normal: 'fonts/Roboto-Regular.ttf',
bold: 'fonts/Roboto-Medium.ttf',
italics: 'fonts/Roboto-Italic.ttf',
bolditalics: 'fonts/Roboto-MediumItalic.ttf'
},
Algerian: {
normal: 'fonts/Algerian.ttf',
bold: 'fonts/Algerian.ttf',
italics: 'fonts/Roboto-Italic.ttf',
bolditalics: 'fonts/Roboto-MediumItalic.ttf'
}
};
var pdfMakePrinter = require('./node_modules/pdfmake/src/printer');
var printer = new pdfMakePrinter(fonts);
var docDefinition = {
pageOrientation: 'landscape',
pageMargins: [20, 10, 20, 0],
content: [
{
columns: [
{
image: downloadPic,
fit: [imageSize, imageSize],
width: 'auto'
},
[{
text: "name",
style: { bold: true, fontSize: 30, font: 'Algerian', color: 'green' },
alignment: 'center',
width: '*',
},
{
text: "sub Header",
style: { bold: true, fontSize: 20, font: 'Roboto', color: 'green' },
alignment: 'center',
width: '*',
margin: [0, 5, 0, 10]
},
],
{
image: tradeMark,
fit: [imageSize - 25, imageSize - 25],
width: 'auto',
margin: [0, 12, 0, 0]
},
],
columnGap: 20
}
]
};
var pdfDoc = printer.createPdfKitDocument(docDefinition);
pdfDoc.pipe(createWriteStream(outFileName));
pdfDoc.end();
}
function downloadAndPrepareReport(url, filePath) {
console.log("Going to download image file: url: " + url + " filePath: " + filePath)
const proto = !url.charAt(4).localeCompare('s') ? https : http;
return new Promise((resolve, reject) => {
const file = createWriteStream(filePath);
let fileInfo = null;
const request = proto.get(url, response => {
if (response.statusCode !== 200) {
console.log("Image Download failed")
reject(new Error(`Failed to get '${url}' (${response.statusCode})`));
return;
}
fileInfo = {
mime: response.headers['content-type'],
size: parseInt(response.headers['content-length'], 10),
};
response.pipe(file);
});
file.on('finish', () => {
console.log("Image Download Complete")
downloadPic = filePath
makePdf()
resolve("ok done")
}
);
request.on('error', err => {
unlink(filePath, () => reject(err));
});
file.on('error', err => {
unlink(filePath, () => reject(err));
});
request.end();
});
}
downloadAndPrepareReport(url,tempFileName)
This SO answer correctly explains that since the require Node/JS library is not supported by Google Apps Script, the following code changes must be made to get Stripe to work properly in a GAS project:
from
const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
(async () => {
const product = await stripe.products.create({
name: 'My SaaS Platform',
type: 'service',
});
})();
to
function myFunction() {
var url = "https://api.stripe.com/v1/products";
var params = {
method: "post",
headers: {Authorization: "Basic " + Utilities.base64Encode("sk_test_4eC39HqLyjWDarjtT1zdp7dc:")},
payload: {name: "My SaaS Platform", type: "service"}
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText())
}
Now, I want to convert the following code into the Google Apps Script friendly version.
from https://stripe.com/docs/payments/checkout/accept-a-payment#create-checkout-session
const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card', 'ideal'],
line_items: [{
price_data: {
currency: 'eur',
product_data: {
name: 'T-shirt',
},
unit_amount: 2000,
},
quantity: 1,
}],
mode: 'payment',
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cancel',
});
So, I'm trying the following.
to
function myFunction() {
var url = "https://api.stripe.com/v1/checkout/sessions";
var params = {
method: "post",
headers: {
Authorization:
"Basic " + Utilities.base64Encode("sk_test_4eC39HqLyjWDarjtT1zdp7dc:"),
},
payload: {
payment_method_types: ["card", "ideal"],
line_items: [
{
price_data: {
currency: "eur",
product_data: {
name: "T-shirt",
},
unit_amount: 2000,
},
quantity: 1,
},
],
mode: "payment",
success_url:
"https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "https://example.com/cancel",
},
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText());
}
However, instead of getting the expected response object returned, I get the following error:
Exception: Request failed for https://api.stripe.com returned code 400. Truncated server response:
Log.error
{
error: {
message: "Invalid array",
param: "line_items",
type: "invalid_request_error",
},
}
What am I doing wrong? And how can I generalize the first example? What is the specific documentation I need that I'm not seeing?
Edit:
After stringifying the payload per the suggestion from the comments, now I get the following error:
Exception: Request failed for https://api.stripe.com returned code 400. Truncated server response:
Log.error
{
"error": {
"code": "parameter_unknown",
"doc_url": "https://stripe.com/docs/error-codes/parameter-unknown",
"message": "Received unknown parameter: {\"payment_method_types\":. Did you mean payment_method_types?",
"param": "{\"payment_method_types\":",
"type": "invalid_request_error"
}
}
I modified the script mentioned in the comments and now have a one that works for this purpose.
// [ BEGIN ] utilities library
/**
* Returns encoded form suitable for HTTP POST: x-www-urlformencoded
* #see code: https://gist.github.com/lastguest/1fd181a9c9db0550a847
* #see context: https://stackoverflow.com/a/63024022
* #param { Object } element a data object needing to be encoded
* #param { String } key not necessary for initial call, but used for recursive call
* #param { Object } result recursively populated return object
* #returns { Object } a stringified object
* #example
* `{
"cancel_url": "https://example.com/cancel",
"line_items[0][price_data][currency]": "eur",
"line_items[0][price_data][product_data][name]": "T-shirt",
"line_items[0][price_data][unit_amount]": "2000",
"line_items[0][quantity]": "1",
"mode": "payment",
"payment_method_types[0]": "card",
"payment_method_types[1]": "ideal",
"success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}"
}`
*/
const json2urlEncoded = ( element, key, result={}, ) => {
const OBJECT = 'object';
const typeOfElement = typeof( element );
if( typeOfElement === OBJECT ){
for ( const index in element ) {
const elementParam = element[ index ];
const keyParam = key ? `${ key }[${ index }]` : index;
json2urlEncoded( elementParam, keyParam, result, );
}
} else {
result[ key ] = element.toString();
}
return result;
}
// // test
// const json2urlEncoded_test = () => {
// const data = {
// time : +new Date,
// users : [
// { id: 100 , name: 'Alice' , } ,
// { id: 200 , name: 'Bob' , } ,
// { id: 300 , name: 'Charlie' , } ,
// ],
// };
// const test = json2urlEncoded( data, );
// // Logger.log( 'test\n%s', test, );
// return test;
// // Output:
// // users[0][id]=100&users[0][name]=Stefano&users[1][id]=200&users[1][name]=Lucia&users[2][id]=300&users[2][name]=Franco&time=1405014230183
// }
// // quokka
// const test = json2urlEncoded_test();
// const typeOfTest = typeof test;
// typeOfTest
// test
// [ END ] utilities library
From this question and this sample script, I thought that in this case, the values are required to be sent as the form data. So how about the following modification?
Modified script:
function myFunction() {
var url = "https://httpbin.org/anything";
var params = {
method: "post",
headers: {Authorization: "Basic " + Utilities.base64Encode("sk_test_4eC39HqLyjWDarjtT1zdp7dc:")},
payload: {
"cancel_url": "https://example.com/cancel",
"line_items[0][price_data][currency]": "eur",
"line_items[0][price_data][product_data][name]": "T-shirt",
"line_items[0][price_data][unit_amount]": "2000",
"line_items[0][quantity]": "1",
"mode": "payment",
"payment_method_types[0]": "card",
"payment_method_types[1]": "ideal",
"success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}"
}
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText()); // or console.log(res.getContentText())
}
I think that point might be payment_method_types: ["card", "ideal"] is required to be sent as "payment_method_types[0]": "card" and "payment_method_types[1]": "ideal".
References:
Create a Session of official document
How to integrate Stripe payments with Google Apps Script
When i try to run my code it is generating html report only after 2nd run.
In the first run it is generating the json file and then after the second run, by using the generated json file and creating the HTML report
Please tell me how to generate html report by running only once.
below is code i tried
hook.js
const {defineSupportCode} = require('cucumber');
defineSupportCode(function ({After}) {
After(function(scenario,done)
{
const world = this;
console.log('in after block')
if (scenario.result.status === 'failed') {
console.log('in after block inside')
browser.takeScreenshot().then(function (stream) {
let decodedImage = new Buffer(stream.replace(/^data:image\/(png|gif|jpeg);base64,/, ''), 'base64');
world.attach(decodedImage, 'image/png');
console.log('screenshot successful');
}).then(function () {
done();
});
}else {
done();
}
});
});
index.js
var reporter = require('cucumber-html-reporter');
var options = {
theme: 'bootstrap',
output: 'cucumber-report.html',
reportSuiteAsScenarios: true,
launchReport: true,
screenshotsDirectory: 'screenshots123',
takeScreenShotsOnlyForFailedSpecs: true,
//screenshotsSubfolder: 'images',
storeScreenshots: true,
};
reporter.generate(options);
Index.js
var reporter = require('cucumber-html-reporter');
var options = {
theme: 'bootstrap',
jsonFile: 'C:/Users/pc/ProtractorCucumber/htmlReport/cucumber_html_reporter/report.json',
// jsonFile: 'C:/Users/pc/ProtractorCucumber/htmlReport/cucumber_html_reporter/cucumber-report.json',
output: 'C:/Users/pc/ProtractorCucumber/htmlReport/cucumber_html_reporter/cucumber-report.html',
// output: 'report123.html',
reportSuiteAsScenarios: true,
launchReport: true,
screenshotsDirectory: 'screenshots123',
takeScreenShotsOnlyForFailedSpecs: true,
//screenshotsSubfolder: 'images',
storeScreenshots: true,
};
reporter.generate(options);
Cucumber-html-reporter will require the JSON file created by cucumber after the execution.
Please refer the following snippet which has exception handled before calling generate function of cucumber-html-report.
const Cucumber = require('cucumber');
import { browser } from 'protractor';
import * as fs from 'fs';
import { config } from '../config/config';
import { defineSupportCode } from "cucumber";
import * as reporter from 'cucumber-html-reporter';
import { mkdirp } from 'mkdirp';
defineSupportCode(function ({ registerHandler, registerListener, After, setDefaultTimeout }) {
setDefaultTimeout(10 * 1000);
let jsonReports = process.cwd() + "/reports/json";
let htmlReports = process.cwd() + "/reports/html";
let targetJson = jsonReports + "/cucumber_report.json";
//BeforeFeature
registerHandler('BeforeFeature', function (event, callback) {
browser.get(config.baseUrl);
callback();
});
After(function (scenario) {
let world = this;
if (scenario.isFailed()) {
return browser.takeScreenshot().then(function (screenShot) {
// screenShot is a base-64 encoded PNG
world.attach(screenShot, 'image/png');
});
}
})
let cucumberReporterOptions = {
theme: "bootstrap",
//theme: "foundation",
// theme: "simple",
jsonFile: targetJson,
output: htmlReports + "/cucumber_reporter.html",
reportSuiteAsScenarios: true,
launchReport: false
};
let logFn = string => {
if (!fs.existsSync(jsonReports)) {
mkdirp.sync(jsonReports);
}
try {
fs.writeFileSync(targetJson, string);
reporter.generate(cucumberReporterOptions); // invoke cucumber-html-reporter
} catch (err) {
if (err) {
console.log(`Failed to save cucumber test results to json file.
Failed to create html report.
`);
console.log(err);
}
}
};
let jsonformatter = new Cucumber.JsonFormatter({
log: logFn
});
registerListener(jsonformatter);
})
So I am practising some nodejs and this time I am playing around with steam api and json objects. But I am having some problems.
So, from the Steam api,
http://steamcommunity.com/profiles/<steamid>/inventory/json/730/2
I got the json from this code,
var request = require('request');
var url = "http://steamcommunity.com/profiles/<steamid>/inventory/json/730/2"
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
var json = JSON.parse(body);
console.log(body)
}
});
And the json looks lite this, json-link
From the json I want to take out the classid and instanceid from each of the items, but there comes the problem. I don't know how. I know I need to parse it but nothing more unfortunately.
Would be very helpful if someone could explain how, or link a guide/tutorial so I can learn.
Thanks!
EDIT:
var request = require('request');
var _ = require('lodash');
var url = "http://steamcommunity.com/profiles/76561198007691048/inventory/json/730/2";
request({
url: url,
json: true
}, function jsonParse(error, response, data) {
console.log(data.rgDescriptions);
var item = getItems(data.rgDescriptions);
console.log(item);
}
);
function getItems(data){
var item = data;
if(!item){
return "error";
}
return _(item).keys().map(function(id){
return _.pick([id], "name");}).value();
Console give me this; [ {}, {}, {}, {}, {}, {}, {}, {},
{},.... ]
JSON look like this;
'1293508920_0':
{ appid: '730',
classid: '1293508920',
instanceid: '0',
icon_url: '-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXU5A1PIYQNqhpOSV-fRPasw8rsUFJ5KBFZv668FF4u1qubIW4Su4mzxYHbzqGtZ-KGlz8EuJcg3rnE9NiijVe3_UY-Zzr2JJjVLFEEeiQRtg',
icon_drag_url: '',
name: 'Shadow Case',
market_hash_name: 'Shadow Case',
market_name: 'Shadow Case',
name_color: 'D2D2D2',
background_color: '',
type: 'Base Grade Container',
tradable: 1,
marketable: 1,
commodity: 1,
market_tradable_restriction: '7',
},
'1644880589_236997301':
{ appid: '730',
classid: '1644880589',
instanceid: '236997301',
icon_url: '-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXU5A1PIYQNqhpOSV-fRPasw8rsUFJ4MAlVo6n3e1Y27OPafjBN09izq42ChfbzNvXTlGkD6p0lj7_FpNjx0VDj_UBoZ272cNfBdg48MAyB-VS3xum61Me_ot2XnqkB5QYc',
icon_drag_url: '',
name: 'MLG Columbus 2016 Mirage Souvenir Package',
market_hash_name: 'MLG Columbus 2016 Mirage Souvenir Package',
market_name: 'MLG Columbus 2016 Mirage Souvenir Package',
name_color: 'D2D2D2',
background_color: '',
type: 'Base Grade Container',
tradable: 1,
marketable: 1,
commodity: 0,
market_tradable_restriction: '7',
},
To work with complex objects or collections you can use lodash library.
So, you have json with the following format:
{
"success":true,
"rgInventory": {
"5719625206": {"id":"5719625206","classid":"1651313004","instanceid":"188530139","amount":"1","pos":1},
"5719034454": {"id":"5719034454","classid":"1649582636","instanceid":"188530139","amount":"1","pos":2},
"5718628709": {"id":"5718628709","classid":"1649582636","instanceid":"188530139","amount":"1","pos":3},
...
}
}
To extract array of required items, first of all install lodash library in your project: npm i -S, after that add this code into your file:
var _ = require('lodash');
function extractItems(data) {
var rgInventory = _.get(data, 'rgInventory');
if (!rgInventory) {
return [];
}
return _(rgInventory)
.keys()
.map(function(id) {
return _.pick(rgInventory[id], ['classid', 'instanceid']);
})
.value();
}
If my schema is as follows:
var Configuration = describe('Configuration', function () {
property('name', String);
set('restPath', pathTo.configurations);
});
var Webservice = describe('Webservice', function () {
property('wsid', String);
property('url', String);
});
Configuration.hasMany(Webservice, { as: 'webservices', foreignKey: 'cid'});
and that reflects data like so:
var configurationJson = {
"name": "SafeHouseConfiguration2",
"webServices": [
{"wsid": "mainSectionWs", "url":"/apiAccess/getMainSection" },
{"wsid": "servicesSectionWs", "url":"/apiAccess/getServiceSection" }
]
};
shouldn’t I be able to seed mongoDB with the following:
var configSeed = configurationJson;
Configuration.create(configSeed, function (err, configuration) {
)};
which would create the following tables with data from the json object:
Configuration
Webservice
Since this did not work as I had expected, my seed file ended up as the following:
/db/seeds/development/Configuration.js
var configurationJson = {
"name": "SafeHouseConfiguration2",
"webServices": [
{"wsid": "mainSectionWs", "url":"/apiAccess/getMainSection" },
{"wsid": "servicesSectionWs", "url":"/apiAccess/getServiceSection" }
]
};
Configuration.create(configurationJson, function (err, configuration) {
//Webservices config
var webservicesConfig = configSeed.webServices;
webservicesConfig.forEach(function(wsConfig){
configuration.webservices.create(wsConfig, function(err){
});
});