Initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
.env
|
||||||
|
node_modules
|
||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "sw1",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}/file.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"access_token":"00D0Q0000008ipI!AQEAQMnYks5eNzLDp_OnKVFWoLjIRbH9.l5m1dWrXi9uincFgJLXfp2Xjsq3fUVLME_hWxZLUz6bi3MGn.kRRoS_dfH12yz1",
|
||||||
|
"refresh_token":"5Aep861kbRszIADsvg2SfeYjNbk56Irp0JDnM8BJPqvw6JZavvYBjsOg_Ha2KvaCiqyM6RKdfGpRnsZtRPSVdRB",
|
||||||
|
"signature":"oPM1SwaBGuPyYocnfh3h197bxQ5AzR0hK0+gdHhkJks=",
|
||||||
|
"scope":"refresh_token web api",
|
||||||
|
"instance_url":"https://almascuola--dev2021.sandbox.my.salesforce.com",
|
||||||
|
"id":{
|
||||||
|
"access_token":"00D0Q0000008ipI!AQEAQMnYks5eNzLDp_OnKVFWoLjIRbH9.l5m1dWrXi9uincFgJLXfp2Xjsq3fUVLME_hWxZLUz6bi3MGn.kRRoS_dfH12yz1",
|
||||||
|
"refresh_token":"5Aep861kbRszIADsvg2SfeYjNbk56Irp0JDnM8BJPqvw6JZavvYBjsOg_Ha2KvaCiqyM6RKdfGpRnsZtRPSVdRB",
|
||||||
|
"signature":"oPM1SwaBGuPyYocnfh3h197bxQ5AzR0hK0+gdHhkJks=",
|
||||||
|
"scope":"refresh_token web api",
|
||||||
|
"instance_url":"https://almascuola--dev2021.sandbox.my.salesforce.com",
|
||||||
|
"id":"https://test.salesforce.com/id/00D0Q0000008ipIUAQ/005MA00000AiipLYAR",
|
||||||
|
"token_type":"Bearer","issued_at":"1783859104265"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
const ExcelJS = require('exceljs');
|
||||||
|
const { PDFParse } = require('pdf-parse');
|
||||||
|
const { PDFDocument } = require('pdf-lib');
|
||||||
|
const readline = require('node:readline/promises');
|
||||||
|
const { stdin: input, stdout: output } = require('node:process');
|
||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
const sfdc = require('./sfdc2');
|
||||||
|
require('dotenv').config();
|
||||||
|
let excelFile = process.argv[2];
|
||||||
|
let pdfFile = process.argv[3];
|
||||||
|
// excel1 => /Users/ddatinguinoo/Downloads/Estratto IPP 5 Sic.xlsx
|
||||||
|
// excel2 => /Users/ddatinguinoo/Downloads/Estratto Haccp IPP 5 (1).xlsx
|
||||||
|
// pdf1 => /Users/ddatinguinoo/Downloads/G-S IPP 5.pdf
|
||||||
|
// pdf2 => /Users/ddatinguinoo/Downloads/H IPP 5.pdf
|
||||||
|
const data = []; // contains the info of all the clients
|
||||||
|
const tempFilePath = [];
|
||||||
|
|
||||||
|
const authConfig = {
|
||||||
|
sfdcTokenFile: process.env.SFDC_TOKEN_FILE, // Path to store/retrieve OAuth tokens
|
||||||
|
sfdcClientId: process.env.SFDC_CLIENT_ID,
|
||||||
|
sfdcClientSecret: process.env.SFDC_CLIENT_SECRET
|
||||||
|
};
|
||||||
|
|
||||||
|
async function initializeSalesforceConnection() {
|
||||||
|
// sfdc.setProductionBaseUrl(); // or sfdc.setSandboxBaseUrl();
|
||||||
|
sfdc.setSandboxBaseUrl(); // Example: using sandbox
|
||||||
|
sfdc.setTokenFile(authConfig.sfdcTokenFile);
|
||||||
|
sfdc.setClientId(authConfig.sfdcClientId);
|
||||||
|
sfdc.setClientSecret(authConfig.sfdcClientSecret);
|
||||||
|
|
||||||
|
// Try to load existing token or initiate OAuth flow
|
||||||
|
if (!await sfdc.getSalesforceToken()) {
|
||||||
|
console.log('No token found. Initiating OAuth2 flow...');
|
||||||
|
// For command-line scripts where a browser can be opened:
|
||||||
|
await sfdc.initToken((loginUrl) => {
|
||||||
|
console.log(`Please open this URL to authenticate: ${loginUrl}`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('Token loaded successfully.');
|
||||||
|
}
|
||||||
|
// Ensure the access token is valid and refresh if necessary
|
||||||
|
await sfdc.checkToken();
|
||||||
|
console.log('Salesforce connection is ready.');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function attachPdfToAccount(sfdc) {
|
||||||
|
let parser;
|
||||||
|
try {
|
||||||
|
let contentVersion;
|
||||||
|
for (let i = 0; i < tempFilePath.length; i++) {
|
||||||
|
// 1. Read the local PDF file and convert it to Base64
|
||||||
|
const pdfBuffer = fs.readFileSync(tempFilePath[i]); // pdfFilePath is tempFilePath
|
||||||
|
const base64Pdf = pdfBuffer.toString('base64');
|
||||||
|
parser = new PDFParse({ data: pdfBuffer });
|
||||||
|
try {
|
||||||
|
const result = await parser.getText();
|
||||||
|
let conditions = [];
|
||||||
|
|
||||||
|
const userID = result.text.match(/Codice fiscale:\s*([A-Za-z0-9]+)/i);
|
||||||
|
const codiceFiscale = userID ? userID[1].trim() : null;
|
||||||
|
if (codiceFiscale) {
|
||||||
|
conditions.push(`CF__c='${ codiceFiscale }'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nameMatch = result.text.match(/Il\s+Sig\.\/La\s+Sig\.ra[ \t]+([A-Za-zÀ-ÿ']+(?:[ \t]+[A-Za-zÀ-ÿ']+)+)/i);
|
||||||
|
|
||||||
|
if (nameMatch) {
|
||||||
|
const rawName = nameMatch[1].trim(); // "Kan Jessica Shuk Yi"
|
||||||
|
const parts = rawName.split(/\s+/);
|
||||||
|
|
||||||
|
if (parts.length >= 2) {
|
||||||
|
const fullName = parts.join(' ');
|
||||||
|
const reversedName = [...parts.slice(1), parts[0]].join(' ');
|
||||||
|
|
||||||
|
conditions.push(`Name='${fullName}'`);
|
||||||
|
if (fullName !== reversedName) {
|
||||||
|
conditions.push(`Name='${reversedName}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the soql comand to search in the database
|
||||||
|
const soql = `SELECT Id, Name FROM Account WHERE (${conditions.join(' OR ')}) ORDER BY CreatedDate DESC LIMIT 1`;
|
||||||
|
const result_soql = await sfdc.query(soql);
|
||||||
|
if (result_soql && result_soql.records && result_soql.records.length > 0) { // if we find something
|
||||||
|
contentVersion = await sfdc.create('ContentVersion', {
|
||||||
|
Title: `${ result_soql.records[0].Name }_Document.pdf`,
|
||||||
|
PathOnClient: `${ result_soql.records[0].Name }_Document.pdf`,
|
||||||
|
VersionData: base64Pdf, // Must be Base64 string
|
||||||
|
FirstPublishLocationId: result_soql.records[0].Id// Automatically creates the link to the Account!
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (parser) {
|
||||||
|
await parser.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(`PDFs successfully attached!`);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error uploading PDF: `, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we create an Account for each client and upload their pdf file
|
||||||
|
async function uploadUserAccount() {
|
||||||
|
await initializeSalesforceConnection();
|
||||||
|
|
||||||
|
// now for each client we need to create an Account on Salesforce
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const firstName = (data[i].NOME || '').toString().trim();
|
||||||
|
const lastName = (data[i].COGNOME || '').toString().trim();
|
||||||
|
|
||||||
|
let userData = {
|
||||||
|
Name: `${ firstName } ${ lastName }`.trim(),
|
||||||
|
CF__c: data[i].CODICE_FISCALE || null,
|
||||||
|
};
|
||||||
|
const newAccount = await sfdc.create('Account', userData); // it creates the Account
|
||||||
|
}
|
||||||
|
console.log('Accounts created successfully!');
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log('Something went wrong while creating the accounts: ', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// this is where i need to store each page in a common temporary pdf file
|
||||||
|
async function processPage(pdfDoc, pageIndex) {
|
||||||
|
try {
|
||||||
|
const newDoc = await PDFDocument.create();
|
||||||
|
const [ copiedPage ] = await newDoc.copyPages(pdfDoc, [pageIndex]);
|
||||||
|
newDoc.addPage(copiedPage);
|
||||||
|
const pdfBytes = await newDoc.save();
|
||||||
|
|
||||||
|
const filepath = path.join(os.tmpdir(), `fileTemp_page_${pageIndex}.pdf`);
|
||||||
|
fs.writeFileSync(filepath, pdfBytes);
|
||||||
|
tempFilePath.push(filepath);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('Error in processPage:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function splitExcelFile(inputFile) {
|
||||||
|
let numRows; // this parameter is needed when we need to analyze the pdf file in case it has duplicates
|
||||||
|
const columnNames = []; // contains the names of the columns (header names)
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`Loading excel file: ${ inputFile }\n`);
|
||||||
|
|
||||||
|
const workbook = new ExcelJS.Workbook();
|
||||||
|
await workbook.xlsx.readFile(inputFile);
|
||||||
|
const worksheet = workbook.getWorksheet(1);
|
||||||
|
|
||||||
|
const headerRow = worksheet.getRow(1).actualCellCount; //number of columns of the table
|
||||||
|
numRows = (worksheet.actualRowCount) - 1;
|
||||||
|
|
||||||
|
worksheet.getRow(1) // to convert every title of the first row to upper case
|
||||||
|
.eachCell((col, col_num) => {
|
||||||
|
if (typeof col.value === 'string') {
|
||||||
|
col.value = col.value.toUpperCase().trim();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// convert every letter of CF to uppercase and store the CFs in the array cf
|
||||||
|
if (worksheet.getRow(1).getCell(6).value.trim() === 'CODICE FISCALE') {
|
||||||
|
worksheet.getColumn(6)
|
||||||
|
.eachCell((row, row_num) => {
|
||||||
|
row.value = (row.value).toString().toUpperCase();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet.getColumn(8) // of the first file
|
||||||
|
.eachCell((cell, rownumber) => {
|
||||||
|
if (typeof cell.value === 'string') {
|
||||||
|
cell.value = (cell.value).replace(/\b\w/g, char => char.toUpperCase());
|
||||||
|
/* \b finds the start of a word (the boundary of a word)
|
||||||
|
\w targets the first letter following that boundary
|
||||||
|
/g (global flag) ensures it updates every word
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// to store the names of the columns in columnNames
|
||||||
|
worksheet.getRow(1).eachCell((cell, cell_num) => {
|
||||||
|
columnNames.push(cell.value);
|
||||||
|
})
|
||||||
|
|
||||||
|
// now we need to store the data of each user
|
||||||
|
for (let i = 2; i <= numRows + 1; i++) {
|
||||||
|
let dataUser = {};
|
||||||
|
worksheet.getRow(i)
|
||||||
|
.eachCell((cell, cell_num) => {
|
||||||
|
const rawColumnName = columnNames[cell_num - 1] || `column_${cell_num}`;
|
||||||
|
|
||||||
|
// 1. Trim whitespace and replace spaces with underscores
|
||||||
|
const cleanKey = rawColumnName
|
||||||
|
.toString()
|
||||||
|
.trim()
|
||||||
|
.replace(/\s+/g, '_'); // \s => matches any whitespaces
|
||||||
|
// + => groups multiple consecutive spaces together into a
|
||||||
|
// single match so you don't end up with multiple underscores.
|
||||||
|
|
||||||
|
dataUser[cleanKey] = cell.value;
|
||||||
|
})
|
||||||
|
data.push(dataUser);
|
||||||
|
}
|
||||||
|
return numRows;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('Error processing the excel file: ', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function splitPDF(numRows, inputFile) {
|
||||||
|
console.log(`Loading pdf file: ${ inputFile }...\n`);
|
||||||
|
let parser;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// 1. we use pdfParse to read and extract the content of a pdf file
|
||||||
|
const existingPdfBytes = fs.readFileSync(inputFile);
|
||||||
|
parser = new PDFParse({ data: existingPdfBytes });
|
||||||
|
const result = await parser.getText();
|
||||||
|
const pagesNumber = result.pages.length; //pages number of the pdf file
|
||||||
|
|
||||||
|
// 2. we use pdf-lib to create and edit a pdf file
|
||||||
|
const srcPdf = await PDFDocument.load(existingPdfBytes);
|
||||||
|
|
||||||
|
// if there are duplicates (back to back duplicates), I only have to print one copy
|
||||||
|
if (pagesNumber > numRows) { // comparison between the number of pages of the pdf file and those of the excel file
|
||||||
|
let displayNumPage = 1;
|
||||||
|
let i;
|
||||||
|
for (i = 1; i < pagesNumber && displayNumPage <= numRows; i += 2) {
|
||||||
|
if (result.pages[i].text.trim() === result.pages[i - 1].text.trim()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*console.log(`--- PAGE ${ displayNumPage } ---`);
|
||||||
|
console.log(result.pages[i].text);
|
||||||
|
console.log("\n");*/
|
||||||
|
|
||||||
|
await processPage(srcPdf, i);
|
||||||
|
displayNumPage++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (let i = 0; i < pagesNumber; i++) {
|
||||||
|
/*console.log(`--- PAGE ${i + 1} ---`);
|
||||||
|
console.log(result.pages[i].text);
|
||||||
|
console.log("\n");*/
|
||||||
|
await processPage(srcPdf, i); // Pass 0-based index i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(`Error processing the pdf file: `, error);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (parser) {
|
||||||
|
await parser.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const result = await splitExcelFile(excelFile);
|
||||||
|
await splitPDF(result, pdfFile);
|
||||||
|
const rl = readline.createInterface({ input, output });
|
||||||
|
let reply = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
while(!reply) {
|
||||||
|
const response = await rl.question('Do you want to create accounts or upload pages (accounts/pages)? ');
|
||||||
|
reply = response.trim();
|
||||||
|
|
||||||
|
if (!reply) {
|
||||||
|
console.log('Please try again!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply === 'accounts') {
|
||||||
|
await uploadUserAccount();
|
||||||
|
}
|
||||||
|
else if (reply === 'pages') {
|
||||||
|
await initializeSalesforceConnection();
|
||||||
|
await attachPdfToAccount(sfdc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
rl.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
Generated
+2281
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "project",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "basic node project",
|
||||||
|
"main": "project_node.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "denise",
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "commonjs",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.18.1",
|
||||||
|
"dotenv": "^17.4.2",
|
||||||
|
"exceljs": "^4.4.0",
|
||||||
|
"express": "^5.2.1",
|
||||||
|
"papaparse": "^5.5.4",
|
||||||
|
"pdf-lib": "^1.17.1",
|
||||||
|
"pdf-parse": "^2.4.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,923 @@
|
|||||||
|
var fs = require('fs');
|
||||||
|
var axios = require('axios');
|
||||||
|
var Papa = require('papaparse');
|
||||||
|
|
||||||
|
|
||||||
|
const sfdc = {
|
||||||
|
baseurl:'',
|
||||||
|
apiurl:'/services/data/v58.0',
|
||||||
|
callbackUrl:'http://localhost:3000/auth',
|
||||||
|
credentials: {},
|
||||||
|
afterLoginUrl:undefined,
|
||||||
|
|
||||||
|
app: {},
|
||||||
|
server: undefined,
|
||||||
|
|
||||||
|
logresult: function(resp) { console.log('internal--->'); console.log(JSON.stringify(resp,null,2)); },
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set token filename
|
||||||
|
* @param {string} filename
|
||||||
|
*/
|
||||||
|
sfdc.setTokenFile=function(filename) {
|
||||||
|
this.tokenfile=filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Custom URL
|
||||||
|
* @param {string} customUrl
|
||||||
|
*/
|
||||||
|
sfdc.setCustomBaseUrl=function(customUrl) {
|
||||||
|
this.baseurl=customUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Sandbox URL
|
||||||
|
*/
|
||||||
|
sfdc.setSandboxBaseUrl=function() {
|
||||||
|
this.baseurl='https://test.salesforce.com';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Production URL
|
||||||
|
*/
|
||||||
|
sfdc.setProductionBaseUrl=function() {
|
||||||
|
this.baseurl='https://login.salesforce.com';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set ClientId
|
||||||
|
* @param {string} clientId
|
||||||
|
*/
|
||||||
|
sfdc.setClientId=function(clientId) {
|
||||||
|
this.clientId=clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set ClientSecret
|
||||||
|
* @param {string} clientSecret
|
||||||
|
*/
|
||||||
|
sfdc.setClientSecret=function(clientSecret) {
|
||||||
|
this.clientSecret=clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retrieve Token file
|
||||||
|
* @returns null if not found, token struct if found
|
||||||
|
*/
|
||||||
|
sfdc.getSalesforceToken=async function() {
|
||||||
|
try {
|
||||||
|
let data=fs.readFileSync(this.tokenfile);
|
||||||
|
this.credentials = JSON.parse(data);
|
||||||
|
return this.credentials;
|
||||||
|
} catch(err) {
|
||||||
|
console.log('cannot find files');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* store Token file
|
||||||
|
*/
|
||||||
|
sfdc.storeSalesforceToken=async function() {
|
||||||
|
console.log('save token');
|
||||||
|
try {
|
||||||
|
fs.writeFileSync(this.tokenfile, JSON.stringify(this.credentials));
|
||||||
|
console.log('saved');
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
console.log(this.credentials);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init oauth2 sequence
|
||||||
|
* listen for callback calls and store token when received
|
||||||
|
*/
|
||||||
|
sfdc.initToken=function(callback) {
|
||||||
|
return new Promise( (resolve, reject) => {
|
||||||
|
console.log('initToken');
|
||||||
|
var express = require('express');
|
||||||
|
this.app = express();
|
||||||
|
this.server=this.app.listen(3000);
|
||||||
|
this.app.get('/auth', async (req, res) => {
|
||||||
|
await this.manageSalesforceCallback(req, res);
|
||||||
|
if (this.oauth2phase==2) this.storeSalesforceToken();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
let loginurl=this.requestAuthCode();
|
||||||
|
if (callback) callback(loginurl);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* initTokenExpress
|
||||||
|
* use this when already bind to 3000
|
||||||
|
* @param {express app} app
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
sfdc.initTokenExpress=function(app) {
|
||||||
|
return new Promise( (resolve, reject) => {
|
||||||
|
app.get('/auth', async (req, res) => {
|
||||||
|
await sfdc.manageSalesforceCallback(req, res);
|
||||||
|
if (this.oauth2phase==2) sfdc.storeSalesforceToken();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* manage callback
|
||||||
|
* internal function, receive express get method
|
||||||
|
*/
|
||||||
|
sfdc.manageSalesforceCallback=async function(req, res) {
|
||||||
|
var refresh_token = req.query.refresh_token;
|
||||||
|
var code = req.query.code;
|
||||||
|
console.log('refresh token: ' + refresh_token);
|
||||||
|
console.log('code: ' + code)
|
||||||
|
|
||||||
|
if (!sfdc.afterLoginUrl)
|
||||||
|
res.send('ok');
|
||||||
|
else
|
||||||
|
res.redirect(sfdc.afterLoginUrl);
|
||||||
|
|
||||||
|
if (code != undefined) {
|
||||||
|
this.oauth2phase=1;
|
||||||
|
console.log('code received, get token');
|
||||||
|
this.credentials=await this.getRefreshToken(code);
|
||||||
|
this.storeSalesforceToken();
|
||||||
|
if (this.server) this.server.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refresh_token) {
|
||||||
|
this.oauth2phase=2;
|
||||||
|
console.log('refresh_token received');
|
||||||
|
this.credentials=refresh_token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create initial url for receiving auth code
|
||||||
|
* @returns false if errors, login url if ok
|
||||||
|
*/
|
||||||
|
sfdc.requestAuthCode=async function() {
|
||||||
|
console.log('requestAuthCode');
|
||||||
|
var url = this.baseurl+'/services/oauth2/authorize';
|
||||||
|
url += '?response_type=code';
|
||||||
|
url += '&client_id=' + encodeURIComponent(this.clientId);
|
||||||
|
url += '&redirect_uri=' + this.callbackUrl;
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(url);
|
||||||
|
let response=await axios.get(url);
|
||||||
|
|
||||||
|
if (response.status == 200) {
|
||||||
|
console.log('Please authenticate via this url in the browser:');
|
||||||
|
console.log(response.request.res.responseUrl);
|
||||||
|
return response.request.res.responseUrl;
|
||||||
|
} else {
|
||||||
|
console.log('Error on authenticate:');
|
||||||
|
console.log(response.data.url);
|
||||||
|
console.log(response.data.explanation);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ask for new access token
|
||||||
|
* @returns non lo so
|
||||||
|
*/
|
||||||
|
sfdc.getAccessToken=async function() {
|
||||||
|
console.log('getAccessToken');
|
||||||
|
var url = this.baseurl+'/services/oauth2/token';
|
||||||
|
var body= 'grant_type=refresh_token';
|
||||||
|
body += '&client_id=' + this.clientId;
|
||||||
|
body += '&client_secret=' + this.clientSecret;
|
||||||
|
body += '&refresh_token=' + this.credentials.refresh_token;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.post(url, body);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.log('getAccessToken error:' + error.response.statusText);
|
||||||
|
console.log('error:', error.response.data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ask for refresh token
|
||||||
|
* @param {string} code authcode for this scope
|
||||||
|
* @returns false if error, refresh token structure if ok
|
||||||
|
*/
|
||||||
|
sfdc.getRefreshToken=async function(code) {
|
||||||
|
console.log('getRefreshToken');
|
||||||
|
var url = this.baseurl+'/services/oauth2/token';
|
||||||
|
let body = 'grant_type=authorization_code';
|
||||||
|
body += '&code=' + code;
|
||||||
|
body += '&client_id=' + this.clientId;
|
||||||
|
body += '&client_secret=' + this.clientSecret;
|
||||||
|
body += '&redirect_uri=' + this.callbackUrl;
|
||||||
|
|
||||||
|
let opts = { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(url);
|
||||||
|
let response=await axios.post(url, body, opts);
|
||||||
|
console.log(response.data);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.log('getRefreshToken error:' + error.response.statusText);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check autocode ttl
|
||||||
|
* @returns true if authcode is still valid, false if not
|
||||||
|
*/
|
||||||
|
sfdc.isTokenValid=function() {
|
||||||
|
|
||||||
|
if (!this.credentials.issued_at) {
|
||||||
|
console.log('no credentials available');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var h = 2; // token live in hours
|
||||||
|
var im = h * 60 * 60 * 1000; // token live in milliseconds
|
||||||
|
|
||||||
|
var i1 = parseInt(this.credentials.issued_at)
|
||||||
|
var i2 = new Date().valueOf();
|
||||||
|
|
||||||
|
// console.log('i2 vs i1 vs i1+im',i2,i1,i1+im);
|
||||||
|
if (i2 > (i1 + im)) {
|
||||||
|
console.log('authcode expired');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
console.log('authcode is still valid');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fresh authcode if old is expired
|
||||||
|
* @returns authcode old or new
|
||||||
|
*/
|
||||||
|
sfdc.checkToken=async function() {
|
||||||
|
console.log('checkToken');
|
||||||
|
if (!this.isTokenValid()) {
|
||||||
|
try {
|
||||||
|
let res=await this.getAccessToken();
|
||||||
|
|
||||||
|
this.credentials.issued_at = res.issued_at;
|
||||||
|
this.credentials.access_token = res.access_token;
|
||||||
|
this.credentials.instance_url = res.instance_url;
|
||||||
|
console.log('new access token generated...');
|
||||||
|
return res;
|
||||||
|
} catch(err) {
|
||||||
|
console.log('checkToken: error on getting a new token!');
|
||||||
|
console.log('err',err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.credentials;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// Actions
|
||||||
|
// ======================
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
var soql="selct id from account limit 10",
|
||||||
|
var nextBatch=false;
|
||||||
|
var irow=0;
|
||||||
|
do {
|
||||||
|
let data=await sfdc.query(soql, nextBatch);
|
||||||
|
console.log(`${irow} of ${data.totalSize}`);
|
||||||
|
|
||||||
|
// do what you need
|
||||||
|
for(var a of data.records) {
|
||||||
|
setData(a)
|
||||||
|
}
|
||||||
|
// do what you need
|
||||||
|
|
||||||
|
soql=data.nextRecordsUrl;
|
||||||
|
nextBatch=!data.done;
|
||||||
|
irow+=data.records.length;
|
||||||
|
|
||||||
|
} while (nextBatch);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
sfdc.search=async function(soql, nextRecord=false) {
|
||||||
|
var url = soql; // next batch
|
||||||
|
if(!nextRecord) url = this.credentials.instance_url + this.apiurl + '/search/?q=' + encodeURI(soql);
|
||||||
|
else url = this.credentials.instance_url + soql;
|
||||||
|
|
||||||
|
var config = { headers: { 'Authorization': 'Bearer ' + this.credentials.access_token } };
|
||||||
|
|
||||||
|
var t1=new Date();
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.get(url, config);
|
||||||
|
return response.data;
|
||||||
|
} catch(err) {
|
||||||
|
console.log('search error');
|
||||||
|
console.log(err);
|
||||||
|
console.log(err.response.data);
|
||||||
|
return err.response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.query=async function(soql, nextRecord=false) {
|
||||||
|
var url = soql; // next batch
|
||||||
|
if(!nextRecord) url = this.credentials.instance_url + this.apiurl + '/query/?q=' + encodeURIComponent(soql);
|
||||||
|
else url = this.credentials.instance_url + soql;
|
||||||
|
|
||||||
|
var config = { headers: { 'Authorization': 'Bearer ' + this.credentials.access_token } };
|
||||||
|
|
||||||
|
var t1=new Date();
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.get(url, config);
|
||||||
|
// console.log(soql);
|
||||||
|
// console.log('query ok');
|
||||||
|
|
||||||
|
var t2=new Date();
|
||||||
|
// console.log('duration (ms): '+(t2.valueOf()-t1.valueOf() ));
|
||||||
|
// console.log('records:'+response.data.totalSize);
|
||||||
|
return response.data;
|
||||||
|
} catch(err) {
|
||||||
|
console.log('query error');
|
||||||
|
console.log(err);
|
||||||
|
console.log(err.response.data);
|
||||||
|
return err.response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.retrieve=async function(obj, id, fields) {
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/sobjects/'+obj+'/'+id+'?fields='+fields.join(',');
|
||||||
|
|
||||||
|
var config = { headers: { 'Authorization': 'Bearer ' + this.credentials.access_token } };
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.get(url, config);
|
||||||
|
console.log('retrieve ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('retrieve bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.upsert=async function(obj, key, records) {
|
||||||
|
|
||||||
|
if (!records || !records.length) return {};
|
||||||
|
|
||||||
|
var body={ "allOrNone" : false, records: [] };
|
||||||
|
|
||||||
|
records.forEach(function(r) {
|
||||||
|
var r2=JSON.parse(JSON.stringify(r));
|
||||||
|
r2['attributes']={ type: obj };
|
||||||
|
body.records.push( r2 );
|
||||||
|
});
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/composite/sobjects/'+obj+'/'+key;
|
||||||
|
|
||||||
|
var config = { headers: { 'Authorization': 'Bearer ' + this.credentials.access_token } };
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.patch(url, body, config);
|
||||||
|
console.log('upsert ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('upsert bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.create=async function(obj, record) {
|
||||||
|
|
||||||
|
if (!record) return {};
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/sobjects/'+obj;
|
||||||
|
|
||||||
|
var config = { headers: { 'Authorization': 'Bearer ' + this.credentials.access_token } };
|
||||||
|
|
||||||
|
var body=record;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.post(url, body, config);
|
||||||
|
console.log('create ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('create bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.update=async function(obj, key, record) {
|
||||||
|
|
||||||
|
if (!record) return {};
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/sobjects/'+obj+'/'+key;
|
||||||
|
|
||||||
|
var config = { headers: { 'Authorization': 'Bearer ' + this.credentials.access_token } };
|
||||||
|
|
||||||
|
var body=record;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.patch(url, body, config);
|
||||||
|
console.log('create ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('create bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// bulk api 2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
sfdc.bulkQuery=async function (query) {
|
||||||
|
await this.checkToken();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var body = {
|
||||||
|
"operation" : "query",
|
||||||
|
"query" : query
|
||||||
|
};
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/jobs/query/';
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.post(url, JSON.stringify(body), config)
|
||||||
|
console.log('create ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('createJob bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
sfdc.bulkQueryStatus=async function (jobId) {
|
||||||
|
await this.checkToken();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/jobs/query/' + jobId + '/';
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.get(url, config)
|
||||||
|
console.log('jobStatus ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('jobStatus bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.bulkQueryStatusPolling=async function (jobId, waitTime, waitSteps) {
|
||||||
|
|
||||||
|
let bulkWait={state:''};
|
||||||
|
let count=0;
|
||||||
|
do {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, waitTime?waitTime:1000));
|
||||||
|
bulkWait=await sfdc.bulkQueryStatus(jobId);
|
||||||
|
count++;
|
||||||
|
console.log('status:',bulkWait.state,'count:', count);
|
||||||
|
} while ( (bulkWait.state!='JobComplete' && bulkWait.state!='Failed') || (waitSteps && count<waitSteps) )
|
||||||
|
|
||||||
|
return bulkWait.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sfdc.bulkQueryResultsLoop=async function (jobId, maxRecords) {
|
||||||
|
|
||||||
|
let locator=undefined;
|
||||||
|
let data=[];
|
||||||
|
do {
|
||||||
|
let bulkId3=await sfdc.bulkQueryResults(jobId, locator, maxRecords?maxRecords:50000);
|
||||||
|
console.log('locator:', bulkId3.locator, bulkId3.maxRecords);
|
||||||
|
locator=bulkId3.locator;
|
||||||
|
|
||||||
|
let parsed=Papa.parse(bulkId3.data, {header:true, delimiter: ',', newline: "\n", skipEmptyLines: true});
|
||||||
|
console.log(parsed.data.length);
|
||||||
|
data=data.concat(parsed.data);
|
||||||
|
} while (locator!='null');
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sfdc.bulkQueryResults=async function (jobId, locator, maxRecords) {
|
||||||
|
await this.checkToken();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Accept': 'text/csv',
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/jobs/query/' + jobId + '/results';
|
||||||
|
|
||||||
|
let params=[];
|
||||||
|
if (locator) params.push('locator='+locator);
|
||||||
|
if (maxRecords) params.push('maxRecords='+maxRecords);
|
||||||
|
if (params.length) {
|
||||||
|
url += '?';
|
||||||
|
url += params.join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.get(url, config)
|
||||||
|
console.log('jobStatus ok');
|
||||||
|
let res={
|
||||||
|
"locator": response.headers['sforce-locator'],
|
||||||
|
"maxRecords": response.headers['sforce-numberofrecords'],
|
||||||
|
data: response.data
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
} catch(error) {
|
||||||
|
console.log('jobStatus bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.bulkCreate=async function (operation, obj, key) {
|
||||||
|
await this.checkToken();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var body = {
|
||||||
|
operation: operation,
|
||||||
|
object: obj,
|
||||||
|
contentType: "CSV",
|
||||||
|
columnDelimiter: "COMMA",
|
||||||
|
lineEnding: "LF",
|
||||||
|
};
|
||||||
|
if (key) body.externalIdFieldName=key;
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/jobs/ingest/';
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.post(url, JSON.stringify(body), config)
|
||||||
|
console.log('create ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('createJob bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
sfdc.bulkSendData=async function (jobId, data) {
|
||||||
|
await this.checkToken();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/csv',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token
|
||||||
|
},
|
||||||
|
maxContentLength: Infinity,
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
};
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/jobs/ingest/' + jobId + '/batches/';
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.put(url, data, config)
|
||||||
|
console.log('sendBatch ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('sendBatch bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.bulkClose=async function (jobId) {
|
||||||
|
await this.checkToken();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var body = {
|
||||||
|
state: "UploadComplete"
|
||||||
|
};
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/jobs/ingest/' + jobId + '/';
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.patch(url, JSON.stringify(body), config)
|
||||||
|
console.log('closeJob ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('closeJob bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.bulkStatus=async function (jobId) {
|
||||||
|
await this.checkToken();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/jobs/ingest/' + jobId + '/';
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.get(url, config)
|
||||||
|
console.log('jobStatus ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('jobStatus bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.bulkGetResults=async function (jobId) {
|
||||||
|
await this.checkToken();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Accept': 'text/csv',
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/jobs/ingest/' + jobId + '/successfulResults';
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.get(url, config)
|
||||||
|
console.log('jobStatus ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('jobStatus bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.bulkGetFailed=async function (jobId) {
|
||||||
|
await this.checkToken();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Accept': 'text/csv',
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/jobs/ingest/' + jobId + '/failedResults';
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response=await axios.get(url, config)
|
||||||
|
console.log('jobStatus ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('jobStatus bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.createContentVersion=async function(Title, PathOnClient, VersionData, FirstPublishLocationId) {
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/sobjects/ContentVersion';
|
||||||
|
|
||||||
|
console.log(url);
|
||||||
|
|
||||||
|
var config = { headers: {
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token,
|
||||||
|
// 'Content-Type': 'multipart/form-data; boundary="boundary_string" '
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
} };
|
||||||
|
|
||||||
|
let body = {
|
||||||
|
Title: Title,
|
||||||
|
PathOnClient: PathOnClient,
|
||||||
|
VersionData: VersionData,
|
||||||
|
FirstPublishLocationId: FirstPublishLocationId
|
||||||
|
}
|
||||||
|
|
||||||
|
// let body='--boundary_string\nContent-Disposition: form-data; name="entity_content";\nContent-Type: application/json\n';
|
||||||
|
// body+=JSON.stringify(record);
|
||||||
|
// body+='\n--boundary_string\nContent-Disposition: form-data; name="VersionData"; filename="'+record.PathOnClient+'";\nContent-Type: application/octet-stream\n';
|
||||||
|
// body+=data;
|
||||||
|
// body+='\n--boundary_string\n';
|
||||||
|
|
||||||
|
|
||||||
|
console.log(body);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.post(url, body, config);
|
||||||
|
console.log('createContentVersion ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('createContentVersion bad');
|
||||||
|
if (error.response) console.log(error.response.data);
|
||||||
|
else console.log(error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sfdc.getContentBody=async function(bodyUrl) {
|
||||||
|
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += bodyUrl;
|
||||||
|
|
||||||
|
console.log(url);
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
responseType: 'arraybuffer',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + this.credentials.access_token,
|
||||||
|
} };
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.get(url, config);
|
||||||
|
console.log('getContentBody ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('getContentBody bad');
|
||||||
|
if (error.response) console.log(error.response.data);
|
||||||
|
else console.log(error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sfdc.objectFields = async function(obj) {
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/sobjects/'+obj+'/describe';
|
||||||
|
|
||||||
|
var config = { headers: { 'Authorization': 'Bearer ' + this.credentials.access_token } };
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.get(url, config);
|
||||||
|
console.log('objectFields ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('objectFields bad');
|
||||||
|
console.log(error);
|
||||||
|
// console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdc.object = async function(obj) {
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/sobjects/'+obj;
|
||||||
|
|
||||||
|
var config = { headers: { 'Authorization': 'Bearer ' + this.credentials.access_token } };
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.get(url, config);
|
||||||
|
console.log('object ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('object bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all available objects in Salesforce
|
||||||
|
* @param {string} token - Salesforce access token
|
||||||
|
* @returns {Promise<Array>} List of objects with their metadata
|
||||||
|
*/
|
||||||
|
sfdc.listobjects = async function(token) {
|
||||||
|
var url = this.credentials.instance_url;
|
||||||
|
url += this.apiurl + '/sobjects';
|
||||||
|
|
||||||
|
var config = { headers: { 'Authorization': 'Bearer ' + this.credentials.access_token } };
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.checkToken();
|
||||||
|
let response=await axios.get(url, config);
|
||||||
|
console.log('listobjects ok');
|
||||||
|
return response.data;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('listobjects bad');
|
||||||
|
console.log(error.response.data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// Cache
|
||||||
|
// ======================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example
|
||||||
|
*
|
||||||
|
var cache=sfdc.newCache(5);
|
||||||
|
for (var i=0; i<upd.length; i++) {
|
||||||
|
if (cache.add( upd[i] )) {
|
||||||
|
await sfdc.upsert("Account", "Id", cache.content() );
|
||||||
|
cache.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await sfdc.upsert("Account", "Id", cache.content() );
|
||||||
|
*/
|
||||||
|
|
||||||
|
sfdc.newCache=function(maxrecords=100) {
|
||||||
|
return {
|
||||||
|
records:[],
|
||||||
|
maxrecords:maxrecords,
|
||||||
|
|
||||||
|
add: function(record) {
|
||||||
|
this.records.push(record);
|
||||||
|
if (this.maxrecords>= this.records.length) return false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
isEmpty: function() { return (this.records.length==0); },
|
||||||
|
|
||||||
|
content: function() { return this.records; },
|
||||||
|
|
||||||
|
reset: function() { this.records=[]; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//export default sfdc;
|
||||||
|
|
||||||
|
module.exports = sfdc;
|
||||||
Reference in New Issue
Block a user