I am new to js/reactjs/nodejs and I am implementing a feature to allow a user to choose a file manually and upload it to a
test local ftp server
(in directory/test)
. The issue i am having is that theftp.upload
function takes aString
for the full path of the file being uploaded, but I am not explicitly giving the path because the file is chosen via a "Browse files" button.It works perfectly if I test without ftp (locally), but I can't seem to upload the file from the request onto a FTP-Server. If I add a full path to the file which I want to upload, it seems to work but that ruins the purpose of
choosing a file to upload and uploading after clicking on Upload
This is the server.js
const express = require("express");
const fileUpload = require("express-fileupload");
const app = express();
var EasyFtp = require("easy-ftp");
var ftp = new EasyFtp();
app.use(fileUpload());
var config = {
host: "127.0.0.1",
type: "FTP",
port: "",
username: "admin",
password: "",
};
ftp.connect(config);
app.post("/upload", (req, res) => {
console.log(req.files);
if (req.files === null) {
return res.status(400).json({ msg: "No file was uploaded" }); //no file uploaded
}
const file = req.files.file;
ftp.upload(file, "/test", function (err) {
if (err) {
console.log(err);
return res.status(500).send(err);
} else {
console.log("finished:", res);
res.json({ fileName: file.name, filePath: `/upload/${file.name}` });
}
});
// res.json({ fileName: file.name, filePath: `/uploads/${file.name}` });
});
ftp.mv(
`/test/(${
(file.tempFilePath.split("/").at(-1),
file.name,
function (err, newPath) {})
})`
);
ftp.close();
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`server started on port ${PORT}`));
This is the FileUpload file
import React, { Fragment, useState } from "react";
import axios from "axios";
import Message from "./Message";
import Progress from "./Progress";
const FileUpload = () => {
//actual file and filename should go into state because the label "Choose File" needs to be replaced with the actual filename
const [files, setFile] = useState("");
const [filename, setFilename] = useState("Choose File...");
const [uploadedFiles, setUploadedFiles] = useState({});
const [message, setMessage] = useState("");
const [uploadPercent, setUploadPercent] = useState(0);
const onChange = (e) => {
setFile(e.target.files[0]);
let x = [];
for (let file of e.target.files) {
x.push(file.name);
}
setFilename(x);
};
const onSubmit = async (e) => {
e.preventDefault();
//add the file to form data
const formData = new FormData();
formData.append("file", files);
try {
const response = await axios.post("/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
//progress bar for upload
onUploadProgress: (progressEvent) => {
setUploadPercent(
parseInt(
//get rid of progress bar after 10 seconds of finished upload
Math.round((progressEvent.loaded * 100) / progressEvent.total)
)
);
setTimeout(() => setUploadPercent(0), 1000);
},
//clear loaded percentage bar
});
const { fileName, filePath } = response.data;
setUploadedFiles({ fileName, filePath });
setMessage("File uploaded successfully");
} catch (error) {
if (error.response.status === 500) {
setMessage("There was a problem with the server, please try again.");
} else {
setMessage(error.response.data.msg);
}
}
};
return (
<Fragment>
{message ? <Message msg={message} /> : null}
<form onSubmit={onSubmit}>
<div className="custom-file">
<input
type="file"
className="custom-file-input"
id="customFile"
onChange={onChange}
multiple
/>
<label className="custom-file-label" htmlFor="customFile">
{filename}
</label>
</div>
<Progress percentage={uploadPercent} />
<input
type="submit"
value="Upload"
className="btn btn-primary btn-block mt-4"
/>
</form>
</Fragment>
);
};
export default FileUpload;
Is there any way to correct this? What am I missing? If more code snippets are required please let me know!
UPDATE!!
ftp.mv not doing anything
app.post("/upload", (req, res) => {
console.log(req.files);
if (req.files === null) {
return res.status(400).json({ msg: "No file was uploaded" }); //error message if no file was uploaded
}
const file = req.files.file;
const tempFileName = file.tempFilePath.split("/").at(-1);
ftp.upload(file.tempFilePath, "/test", function (err) {
if (err) {
console.log(err);
return res.status(500).send(err);
} else {
console.log("finished:", res);
res.json({
fileName: file.name,
filePath: `/uploads/${file.name}`,
});
}
});
ftp.mv(`/test/${tempFileName}`, "abc", function (err, newPath) {});
ftp.close();
});
CodePudding user response:
You are sending a file to the server, you need to save it momentarily and upload it from there, start by changing your fileUpload configuration to this:
app.use(fileUpload({
useTempFiles : true,
tempFileDir : '/tmp/'
}));
Then you can upload the file by accessing its temporary file path:
app.post("/upload", (req, res) => {
console.log(req.files);
if (req.files === null) {
return res.status(400).json({ msg: "No file was uploaded" }); //no file uploaded
}
const file = req.files.file;
// here we access the temporary file path
ftp.upload(file.tempFilePath, "/test", function (err) {
if (err) {
console.log(err);
return res.status(500).send(err);
} else {
console.log("finished:", res);
res.json({ fileName: file.name, filePath: `/upload/${file.name}` });
}
ftp.close();
});
});
});