Create folder structure in SharePoint library using JavaScript - javascript

Requirement is to create folder structure from an array in a SharePoint library using JavaScript. Below is the desired structure:
var ary = [A,B,C]
A -> Fldr1 -> Fldr2 -> File
B -> Fldr1 -> Fldr2 -> File
C -> Fldr1 -> Fldr2 -> File
But currently its creating folder A,B and C in library but inside structure is being created for C only.
So result am getting is :
A
B
C -> Fldr1 -> Fldr2 -> File
Below code works perfect when only one item in array, but fails when multiple items.
Here I check if folder exists, then check for 2nd level, if doesn't exist create first and so on for remaining structure.
async function processArray(selectedCountries) {
await selectedCountries.map(async (item) => {
let promiseCntry = await checkCntryFolder(item);
if(flag){ //if cntry exists
let promiseChckfolder = await checkFolder(tdmrkNm);
if(flagFldr)//if folder exists
{
let promiseChkSubFolder = await checkSubFolder(appStatus);
if(flagSub)//if sub -folder exists
{
let createFile = await CreateFileInSideFolder();
}
else
{
let promiseCreateSub = await createSubFolder(appStatus);
let createFile = await CreateFileInSideFolder();
}
}
}
});
}
}

Stop using deferreds and stop using the done method. Use proper promises with then instead.
Assuming this is jQuery, where those objects with done methods also have then methods, you can (and should) just use async/await directly:
async function callAry(array) {
return Promise.all(array.map(async (item) => {
const flag = await checkCntryFolder(item);
if (flag) {
const folderFlag = await checkFolder(nm);
if (folderFlag) {
const subFlag = await checkSubFolder(Status);
if (subFlag) {
await CreateFileInSideFolder();
console.log('file done');
}
}
}
}));
}

ok, so finally I have got it working:
I was not passing proper arguments to the methods.
Below is the working code:
async function processArray(selectedCountries) {
return Promise.all(selectedCountries.map(async (item) => {
//await selectedCountries.map(async (item) => {
let promiseCntry = await checkCntryFolder(item);
if(flag){ //if cntry exists
let promiseChckfolder = await checkFolder(tdmrkNm,item);
if(flagFldr)//if folder exists
{
let promiseChkSubFolder = await checkSubFolder(appStatus,tdmrkNm,item);
if(flagSub)//if sub -folder exists
{
let createFile = await CreateFileInSideFolder(appStatus,tdmrkNm,item);
}
else
{
let promiseCreateSub = await createSubFolder(appStatus,tdmrkNm,item);
let createFile = await CreateFileInSideFolder(appStatus,tdmrkNm,item);
}
}
else//if folder doesn't exist
{
let createFldr = await createFolder(tdmrkNm,item);
let promiseChkSubFolder = await checkSubFolder(appStatus,tdmrkNm,item);
if(flagSub)
{
let createFile = await CreateFileInSideFolder(appStatus,tdmrkNm,item);
}
else
{
let promiseCreateSub = await createSubFolder(appStatus,tdmrkNm,item);
let createFile = await CreateFileInSideFolder(appStatus,tdmrkNm,item);
}
}
}
else//if cntry doesn't exist
{
let createCntry = await createCntryFolder(item);
let promiseChckfolder = await checkFolder(tdmrkNm,item);
if(flagFldr)//if folder exists
{
let promiseChkSubFolder = await checkSubFolder(appStatus,tdmrkNm,item);
if(flagSub) //if sub-folder exists
{
let createFile = await CreateFileInSideFolder(appStatus,tdmrkNm,item);
}
else //if sub-folder doesn't exist
{
let promiseCreateSub = await createSubFolder(appStatus,tdmrkNm,item);
let createFile = await CreateFileInSideFolder(appStatus,tdmrkNm,item);
}
}
else //if folder doesn't exist
{
let createFldr = await createFolder(tdmrkNm,item);
let promiseChkSubFolder = await checkSubFolder(appStatus,tdmrkNm,item);
if(flagSub)//if sub-folder exists
{
let createFile = await CreateFileInSideFolder(appStatus,tdmrkNm,item);
}
else//if sub-folder doesn't exist
{
let promiseCreateSub = await createSubFolder(appStatus,tdmrkNm,item);
let createFile = await CreateFileInSideFolder(appStatus,tdmrkNm,item);
}
}
}
},Promise.resolve()));

Related

How to wait till I get the secret values from Keyvault in Node JS?

I am fairly new to Javascript and I understand that it executes asynchronously. I tried using the callback method to fetch the secret values and then execute next block of code. But it is not waiting.
This is the function that fetches the keyvault secret values
function getsecret_values(client,secret_name,callback) {
let val = []
for (let i =0;i<secret_name.length;i++){
client.getSecret(secret_name[i]).then((latestSecret) => {
val[i] = latestSecret.value;
})
}
callback(val)
}
I am calling getsecret_values function from main block
let vaultName = result.database;
const url = `https://${vaultName}.vault.azure.net`;
const credential = new ClientSecretCredential(result.host, result.user, result.password);
const client = new SecretClient(url, credential);
let secret_values = []
getsecret_values(client, secrets, function(result) {
secret_values = result
console.log(secret_values)
});
console.log(secret_values)
\\next code block
Both the console.log returns empty array.
I want my code to wait till the secret values are fetched and put into secret_values array and then proceed to next block of code. How do I achieve this?
the easiest way is to use Async Await pattern, which uses promises in the background. Trying not to change your code much:
async function getsecret_values(client,secret_name) {
let val = []
for (let i =0;i<secret_name.length;i++){
const latestSecret = await client.getSecret(secret_name[i])
val[i] = latestSecret.value;
}
return val
}
in your main block:
getsecret_values(client, secrets).then(function(result) {
secret_values = result
console.log(secret_values)
});
console.log(secret_values) // will still be an empty array as the then function has not been executed yet....
my approach would be:
async function getsecret_values(client,secret_name) {
let val = []
for (let i =0;i<secret_name.length;i++){
const latestSecret = await client.getSecret(secret_name[i])
val[i] = latestSecret.value;
}
return val
}
// main:
async function main() {
let vaultName = result.database;
const url = `https://${vaultName}.vault.azure.net`;
const credential = new ClientSecretCredential(result.host, result.user, result.password);
const client = new SecretClient(url, credential);
const secret_values = await getsecret_values(client, secrets)
console.log(secret_values)
}
main()

read CAR file using js-car

I have a CAR file object in javascript and want to read it using js-car github. But I keep getting unexpected end of the file error. Here is my code I am trying
let arrayBuffer = await files[0].arrayBuffer();
let bytes=new Uint8Array(carFile);
const reader = await CarReader.fromBytes(bytes) //throws error here
const indexer = await CarIndexer.fromBytes(bytes) //throws error here
I also tired this
let str = await files[0].stream()
const reader = await CarReader.fromIterable(files[0].stream()) //throws error here
and none of them work. However with the same file this code works
const inStream = fs.createReadStream('test.car')
const reader = await CarReader.fromIterable(inStream)
I checked and I know that CarReader.fromBytes needs a Unit8Arrey and I am sure files[0] is not null. Does anyone knows what I am missing here?
for the people might face similar issue in future this is my solution:
I used res.body directly and converted it to an async stream and read it using fromIterable
async function* streamAsyncIterator(stream) {
// Get a lock on the stream
const reader = stream.getReader();
try {
while (true) {
// Read from the stream
const { done, value } = await reader.read();
// Exit if we're done
if (done) return;
// Else yield the chunk
yield value;
}
}
finally {
reader.releaseLock();
}
}
const info = await w3StorageClient.status(response)
if (info) {
// Fetch and verify files from web3.storage
const res = await w3StorageClient.get(response);
const reader = await CarReader.fromIterable(streamAsyncIterator(res.body))
// read the list of roots from the header
const roots = await reader.getRoots()
// retrieve a block, as a { cid:CID, bytes:UInt8Array } pair from the archive
const got = await reader.get(roots[0])
// also possible: for await (const { cid, bytes } of CarIterator.fromIterable(inStream)) { ... }
let decoded = cbor.decode(got.bytes)
console.log('Retrieved [%s] from example.car with CID [%s]',
decoded,
roots[0].toString())
}

How to use date.js through Puppeteer exposeFunction?

I am using puppeteer 1.19.0 and date.js 0.3.3 for this example
const puppeteer = require('puppeteer');
const date = require('date.js');
let scrape = async () => {
const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();
await page.exposeFunction('formatDate', (text) =>
date(text));
await page.goto('https://www.daraz.com.bd/products/the-vip-suction-mobile-phone-stand-pocket-size-i113492895-s1030756115.html');
await page.waitFor(1000);
const result = await page.evaluate(() => {
let elements = document.querySelectorAll('#module_product_qna > div.pdp-mod-qna > div:nth-child(2) > ul > li')
for (var element of elements)
{
let question = element.querySelector('div:first-of-type > div.qna-content').innerText;
let qtime = element.querySelector('div:first-of-type > div.qna-meta').innerText;
let q = qtime.match(/- (.+)/);
qtime = formatDate(q[1]);
return {
question,
qtime
}
}});
browser.close();
return result;
};
scrape().then((value) => {
console.log(value);
});
You can see I am trying to use date function of date.js library to parse relative date through puppeteer exposeFunction but date function is not working inside page context. Any suggestions what I am doing wrong?
I appreciate your replies!
From puppeteer docs:
The method adds a function called name on the page's window object.
When called, the function executes puppeteerFunction in node.js and
returns a Promise which resolves to the return value of
puppeteerFunction.
Try this:
const result = await page.evaluate(async() => {
let elements = document.querySelectorAll('#module_product_qna > div.pdp-mod-qna > div:nth-child(2) > ul > li')
for (var element of elements)
{
let question = element.querySelector('div:first-of-type > div.qna-content').innerText;
let qtime = element.querySelector('div:first-of-type > div.qna-meta').innerText;
let q = qtime.match(/- (.+)/);
qtime = await window.formatDate(q[1]);
return {
question,
qtime
}
}});

How to execute something similar to a goto statement in node js or how to create and call a function within an asynchronous function?

I am running an automated test through puppeteer that fills up a form and checks for captcha as well. If the captcha is incorrect, it refreshes to a new image but then I need to process the whole image again and reach the function which was used earlier to process it.
(async function example() {
const browser = await puppeteer.launch({headless: false})
const page = await browser.newPage()
/*-----------NEED TO COME BACK HERE-----------*/
const tessProcess = utils.promisify(tesseract.process);
await page.setViewport(viewPort)
await page.goto('http://www.example.com')
await page.screenshot(options)
const text = await tessProcess('new.png');
console.log(text.trim());
await page.$eval('input[id=userEnteredCaptcha]', (el, value) => el.value = value, text.trim())
await page.$eval('input[id=companyID]', el => el.value = 'val');
const submitBtn = await page.$('[id="data"]');
await submitBtn.click();
try {
var x = await page.waitFor("#msgboxclose");
console.log("Captcha error")
}
catch (e) {
console.error('No Error');
}
if(x){
await page.keyboard.press('Escape');
/*---------GO FROM HERE--------*/
}
})()
I want to sort of create a loop so that the image can be processed again whenever the captcha is wrong
Declare a boolean variable that indicates whether you need to try again or not, and put the repeated functionality inside a while loop that checks that variable. If the x condition at the end of the loop is not fulfilled, set tryAgain to false, so that no further iterations occur:
(async function example() {
const browser = await puppeteer.launch({headless: false})
const page = await browser.newPage()
let tryAgain = true; // <--------------------------
while (tryAgain) { // <--------------------------
/*-----------NEED TO COME BACK HERE-----------*/
const tessProcess = utils.promisify(tesseract.process);
await page.setViewport(viewPort)
await page.goto('http://www.example.com')
await page.screenshot(options)
const text = await tessProcess('new.png');
console.log(text.trim());
await page.$eval('input[id=userEnteredCaptcha]', (el, value) => el.value = value, text.trim())
await page.$eval('input[id=companyID]', el => el.value = 'val');
const submitBtn = await page.$('[id="data"]');
await submitBtn.click();
try {
var x = await page.waitFor("#msgboxclose");
console.log("Captcha error")
}
catch (e) {
console.error('No Error');
}
if(x){
await page.keyboard.press('Escape');
/*---------GO FROM HERE--------*/
} else {
tryAgain = false; // <--------------------------
}
}
})()

How to correctly transfer DOM elements across files?

I have a function which takes in a tag name and text as input and returns all the elements made of the given tag containing the given text as output (I get an array of all the elements having the matching text).
I will be using this function across multiple functions so I thought I could save it in another file and import the function into all the other files that I may need but I am unable to transfer the element. I am using puppeteer to open the browser and get my required documents.
The code I am importing:
commonFunctions.js:
module.exports = {
matchTagAndTextContents: async function matchTagAndTextContents(page, selector, text) {
const ele = await page.evaluate((selector,text) => {
function matchTagAndText(sel, txt) {
var elements = document.querySelectorAll(selector);
return Array.prototype.filter.call(elements, function(element){
return RegExp(text).test(element.textContent);
});
}
const matchedElements = matchTagAndText(selector,text);
return matchedElements;
},selector,text);
return ele;
}
}
Another file where I try to use the imported function:
foo.js:
const commonFunctions = require('./commonFunctions');
const puppeteer = require('puppeteer');
let browser = null;
browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
(async () => {
let page = await browser.newPage();
await page.goto("https://www.google.com");
let elem = null;
await commonFunctions.matchTagAndTextContents(page,'h1','Google').then( res => {
elem = res;
});
await page.evaluate((elem) => {
elem.forEach( el => {
el.click();
})
},elem);
})();
Here inside foo.js I keep getting el.click() is not a function, but if I implement the forEach inside the commonFunctions.js like:
matchedElements.forEach( el => {
el.click();
});
It works and the element gets clicked. What am I doing wrong?
Thats beacause elem is null in your execution and res its assigned to elem in the evaluated scope.
try changing
let elem = null;
await commonFunctions.matchTagAndTextContents(page,'h1','Google').then( res => {
elem = res;
});
await page.evaluate((elem) => {
elem.forEach( el => {
el.click();
})
},elem);
whith
var elem = null;
elem = await commonFunctions.matchTagAndTextContents(page,'h1','Google');
await page.evaluate((elem) => {
elem.forEach( el => {
el.click();
})
},elem);

Categories

Resources