I have this upload function. It works well, except that it uploads the files twice.
startUpload(event: HTMLInputEvent) {
console.log(event) // logs once
this.tasks$ = from([Array.from(event.target.files)]).pipe(
map(files => files.map((file, index) => {
console.log(file) // logs twice
const path = `test/${index}_${file.name}`
const customMetadata = { app: 'Angular!' }
return this.afstorage.upload(path, file, { customMetadata });
})
)
)
this.snapshots$ = this.tasks$.pipe(
map(files =>
files.map(file =>
file.snapshotChanges(),
),
)
)
this.progresses$ = this.tasks$.pipe(
map(files =>
files.map(file =>
file.percentageChanges()
),
)
)
}
How do I prevent it from uploading more than once?
I think the problem is here
files.map((file, index) => {
console.log(file) // logs twice
const path = `test/${index}_${file.name}`
const customMetadata = { app: 'Angular!' }
return this.afstorage.upload(path, file, { customMetadata });
})
The arrow function provided as an argument to .map will be called once for each file in the files array.
So my guess is that this is some kind of file uploader, and you've specified 2 files to be uploaded, or possibly the same file twice.
Update
In response to your comment, if you only want to call this once, e.g. with the first file, you could replace the code above with
const index = 0;
const file = files[0];
console.log(file) // logs twice
const path = `test/${index}_${file.name}`
const customMetadata = { app: 'Angular!' }
return this.afstorage.upload(path, file, { customMetadata });
This will only upload the first file, but skipping the rest of the files doesn't seem like a good idea.
I think there's a problem with your question. You've said you only want this code to execute once, but if multiple files are chosen, how in that case will the other files be uploaded?
Related
I am new to Typescript and node.
I have this function
sftp.connect(config) //CONNECT TO STFP
.then(() => {
sftp.list(remoteFilePath) //LIST THE FILES IN THE FILEPATH
.then((list) => {
list.forEach((index) => { //FOR EVERY FILE IN THE FOLDER, DOWNLOAD IT
const fileName = remoteFilePath + index.name;
console.log(fileName);
sftp.fastGet(fileName, "/Users/Bob/" + index.name)
.then((value) => {
console.log(value);
sftp.end();
})
})
})
})
// .then(() => {
// // sftp.end();
// })
.catch(err => {
console.error(err.message);
});
and using the ssh2-sftp-client library. My question is that is it possible for this library to get the contents of the file as opposed to downloading it? I plan on making this function into a lambda function.
At the moment, the variable value contains a text telling me that the file has been downloaded to my designated path.
If you want to get the contents of the file you can read it using the fs module after downloading it
// using the ES6 module syntax
import { readFileSync } from "fs"
const data = readFileSync("./file.txt")
If you want to get the contents of the file without downloading them to the disk you have to pass a different destination. Use the ssh2-sftp-client get method instead, it accepts a Stream or a Buffer as the destination. You can use a Stream but you have to pipe it somewhere. Here's an example using process.stdout which is a writable stream:
// ...
stfp.get(
fileName, "/Users/Bob/" + index.name,
process.stdout
)
I am trying to make an image organizer app , which searches images using tag's ,
So I want the user to select the image they want, so far I have done this by the following code
// renderer process
$("#uploadImage).on("click", (e) => {
ipcRenderer.send('dialoguploadImage')
});
this is the main process
ipcMain.on('dialoguploadImage', (e) => {
dialog.showOpenDialog({
properties: ['openFile']
}).then(result => {
sendBackimagePathFromMain(result.filePaths[0])
}).
catch(err => {
console.log(err)
})
});
function sendBackimagePathFromMain(result) {
mainWindow.webContents.send('imagePathFromMain',result)
}
so I have the image path, and the only thing I want to know is
how can I duplicate this image, rename it, cerate a new folder and save the image in that folder
like for example to this folder
('./currentDirectory/imageBackup/dognothapppy.jpg')
You can use fs.mkdirSync() to make the folder and fs.copyFileSync() to 'duplicate and rename' the file (in a file system, you don't need to duplicate and rename a file in two different steps, you do both at once, which is copying a file), or their async functions.
const { mkdirSync, copyFileSync } = require('fs')
const { join } = require('path')
const folderToCreate = 'folder'
const fileToCopy = 'selectedFile.txt'
const newFileName = 'newFile.txt'
const dest = join(folderToCreate, newFileName)
mkdirSync(folderToCreate)
copyFileSync(fileToCopy, dest)
I am trying to use cypress functions in files different from the main one (which is the test file). I am wondering if it is possible.
Actually, I did this: this is the code in my test.js file; note that the first function is what I'm trying to do; the second function works normally and I have no problem with that. The reason why I am trying to do that is that I could need to reuse the same function multiple times.
my tree folders:
static_copied
pages
cities
Rome
New York
Bombay
Tokyo
London
Moscow
test.js file:
const pathCities = 'static_copied/pages/cities'
it('Retrieve cities from static and divide links', () => {
let cities1 = misc.retrieveCities()
console.log(cities1)
// this works
cy.task('readFolder', pathCities).then(cities => {
console.log('cities ', cities, typeof cities) // prints an array of cities, and 'object'
})
})
})
my misc.help.js file:
const pathCities = 'static_copied/pages/cities'
module.exports = {
retrieveCities,
[...]
}
[...]
function retrieveCities() {
cy.task('readFolder', pathCities).then(res => {
console.log('here', res, typeof res)
return res
})
}
and finally my cypress/plugins/index.js file:
const fs = require('fs')
// opens devTools by default
module.exports = (on, config) => {
[...]
// reads a folder, both folder and file names
on('task', {
readFolder(path) {
let foldersAnFiles = fs.readdirSync(path, 'utf8')
console.log('--->', foldersAnFiles, typeof foldersAnFiles)
let folders = []
// if its a file, exclude from result
foldersAnFiles.filter(function (folder) {
if (folder.indexOf('.') === -1) {
folders.push(folder)
}
})
return folders
},
})
}
What happens is that in misc.help.js file, print is correct: in retrieveCities() function, this console log console.log('here', res, typeof res) correctly prints an array.
But when i return it in the main test file, console.log(cities1) prints undefined.
Is there a way to pass to the main file my result?
Add this to your commands file and it then call cy.retrieveCities() in any test file and it will work.
Cypress.Commands.add('retrieveCities', () => {
return cy.task('readFolder', pathCities).then(res => {
return res
})
})
I have an application that persists its state on disk, when any state change occur it reads from file the old state, it changes the state on memory and persists on disk again. But, the problem is that store function is writing on disk only after close program. I don't know why?
const load = (filePath) => {
const fileBuffer = fs.readFileSync(
filePath, "utf8"
);
return JSON.parse(fileBuffer);
}
const store = (filePath, data) => {
const contentString = JSON.stringify(data);
fs.writeFileSync(filePath, contentString);
}
To create a complete example, let's use load-dataset command, in the file "src/interpreter/index.js".
while(this.isRunning) {
readLineSync.promptCL({
"load-dataset": async (type, name, from) => {
await loadDataset({type, name, from});
},
...
}, {
limit: null,
});
}
In general, this calls loadDatasets, which reads json ou csv files.
export const loadDataset = async (options) => {
switch(options.type) {
case "csv":
await readCSVFile(options.from)
.then(data => {
app.createDataset(options.name, data);
});
break;
case "json":
const data = readJSONFile(options.from);
app.createDataset(options.name, data);
break;
}
}
The method createDataset() read the file on disk, update it and write again.
createDataset(name, data) {
const state = loadState();
state.datasets = [
...state.datasets,
{name, size: data.length}
];
storeState(state);
const file = loadDataset();
file.datasets = [
...file.datasets,
{name, data}
];
storeDataset(file);
}
Where methods loadState(), storeState(), loadDataset(), storeDataset() uses initial methods.
const loadState = () =>
load(stateFilePath);
const storeState = state =>
store(stateFilePath, state);
...
const loadDataset = () =>
load(datasetFilePath);
const storeDataset = dataset =>
store(datasetFilePath, dataset);
I'm using a package from npm called readline-sync to create a simple "terminal", I don't know if it causes some conflicts.
The source code is in the Github: Git repo. In the file "index.js", the method createDataset() calls loadState() and storeState(), which both uses the methods showed above.
The package readline-sync is used in the interpreter, here Interpreter file, which basic loops until exit command.
Just as note, I'm using Ubuntu 18.04.2 and Node.js 10.15.0. To make this code I saw an example, in the YouTube Video. This guy is using a MAC OS X, I really hope that the system won't be problem.
I am using Cypress to use my application and encounter a problem by sending an uploaded file to the backend. It sends an empty FormData.
I am using the code found here https://github.com/cypress-io/cypress/issues/170 to handle file upload which is:
return cy.get('input[type=file]').then(subject => {
return cy
.fixture('blueprint.xlsx', 'base64')
.then(Cypress.Blob.base64StringToBlob)
.then(blob => {
const el = <HTMLInputElement>subject[0]
if (el != null) {
const testFile = new File([blob], 'blueprint.xlsx')
const dataTransfer = new DataTransfer()
dataTransfer.items.add(testFile)
el.files = dataTransfer.files
}
return subject
})
})
When I debug the API call, the file is set, it is in the fixtures folder and everything seems fine but the call doesn't have any formdata (which should be the file) and ends in a 400 Bad request error.
Why is the formdata empty? Is this a Cypress problem? Is there a way to send my fixture file to the backend?
Your code seems to run ok on the ng-file-upload demo page.
I also tested with an 'xlsx' file, no problem found.
describe('Angular file upload Demo', () => {
/*
To run these tests, add a file 'logo.png' to /cypress/fixtures
*/
it('uploads the fixture file', () => {
cy.visit('https://angular-file-upload.appspot.com/')
cy.get('[name=userName]').type('myLogo')
cy.get('[name=file]').then(subject => {
return cy.fixture('logo.png', 'base64')
.then(Cypress.Blob.base64StringToBlob)
.then(blob => {
console.log('blob', blob)
const el = subject[0]
if (el != null) {
const testFile = new File([blob], 'logo.png')
const dataTransfer = new DataTransfer()
dataTransfer.items.add(testFile)
el.files = dataTransfer.files
}
return subject
})
})
cy.contains('button', 'Submit').click()
cy.contains('.progress', '100%')
cy.contains('body', 'Upload Successful')
})
Cypress.Commands.add('uploadFile', { prevSubject: 'element' }, (subject, fileName) => {
console.log('subject', subject)
return cy.fixture(fileName, 'base64')
.then(Cypress.Blob.base64StringToBlob)
.then(blob => {
console.log('blob', blob)
const el = subject[0]
if (el != null) {
const testFile = new File([blob], fileName)
const dataTransfer = new DataTransfer()
dataTransfer.items.add(testFile)
el.files = dataTransfer.files
}
return subject
})
}
)
it('uploads the file via custom command', () => {
cy.visit('https://angular-file-upload.appspot.com/')
cy.get('[name=userName]').type('myLogo')
cy.get('[name=file]').uploadFile('logo.png')
cy.contains('button', 'Submit').click()
cy.contains('.progress', '100%')
cy.contains('body', 'Upload Successful')
})
})
I use "cypress": "3.3.1"
The following codes work for me,
const fixturePath = 'test.png';
const mimeType = 'application/png';
const filename = 'test.png';
cy.getTestElement('testUploadFrontID')
.get('input[type=file')
.eq(0)
.then(subject => {
cy.fixture(fixturePath, 'base64').then(front => {
Cypress.Blob.base64StringToBlob(front, mimeType).then(function(blob) {
var testfile = new File([blob], filename, { type: mimeType });
var dataTransfer = new DataTransfer();
var fileInput = subject[0];
dataTransfer.items.add(testfile);
fileInput.files = dataTransfer.files;
cy.wrap(subject).trigger('change', { force: true });
});
});
});
getTestElement is a command added by myself,
Cypress.Commands.add(`getTestElement`, selector =>
cy.get(`[data-testid="${selector}"]`)
);
after many hours of trying, i figured out a workaround to make ng-file-upload works.
At least my problem was about the File that was not passed as an instance of Blob, i guess.
I've used the same snippet as Jonas one on cypress side.
The workaround is to add a check into the upload function that manages changes in select and drop directives.
function upload() {
if (!Upload.isFile(file)) {
file = new File([file], file.name, { type: file.type })
}
Upload.upload({
url: "/api/upload",
data: {
file: file
}
})
.then(/* ... */)
/* ... */
}
This is just a workaround and i don't really like it.
I don't know why this happens, it happens for me only when i test it using cypress, so i don't like to add that in my production code.
Could someone please help me understanding why this happens?
Does anyone know why the file instance passed into the upload function seems to be a File instance but then it's not?