Add file upload functionality

This commit is contained in:
aronmal 2022-11-09 21:34:20 +01:00
parent 5e4554710c
commit f3c3f15f3a
Signed by: aronmal
GPG key ID: 816B7707426FC612
6 changed files with 217 additions and 5 deletions

View file

@ -13,6 +13,7 @@
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"formidable": "^2.0.1",
"socket.io": "^4.5.3", "socket.io": "^4.5.3",
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },
@ -21,6 +22,7 @@
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/dotenv": "^8.2.0", "@types/dotenv": "^8.2.0",
"@types/express": "^4.17.13", "@types/express": "^4.17.13",
"@types/formidable": "^2.0.5",
"@types/node": "^17.0.0", "@types/node": "^17.0.0",
"@types/uuid": "^8.3.3", "@types/uuid": "^8.3.3",
"nodemon": "^2.0.15", "nodemon": "^2.0.15",
@ -166,6 +168,15 @@
"@types/range-parser": "*" "@types/range-parser": "*"
} }
}, },
"node_modules/@types/formidable": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-2.0.5.tgz",
"integrity": "sha512-uvMcdn/KK3maPOaVUAc3HEYbCEhjaGFwww4EsX6IJfWIJ1tzHtDHczuImH3GKdusPnAAmzB07St90uabZeCKPA==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/mime": { "node_modules/@types/mime": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
@ -268,6 +279,11 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
}, },
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -472,6 +488,15 @@
"npm": "1.2.8000 || >= 1.4.16" "npm": "1.2.8000 || >= 1.4.16"
} }
}, },
"node_modules/dezalgo": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
"integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==",
"dependencies": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"node_modules/diff": { "node_modules/diff": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
@ -642,6 +667,31 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/formidable": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz",
"integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==",
"dependencies": {
"dezalgo": "1.0.3",
"hexoid": "1.0.0",
"once": "1.4.0",
"qs": "6.9.3"
},
"funding": {
"url": "https://ko-fi.com/tunnckoCore/commissions"
}
},
"node_modules/formidable/node_modules/qs": {
"version": "6.9.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
"integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==",
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/forwarded": { "node_modules/forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -733,6 +783,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==",
"engines": {
"node": ">=8"
}
},
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@ -996,6 +1054,14 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/parseurl": { "node_modules/parseurl": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -1440,6 +1506,11 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/ws": { "node_modules/ws": {
"version": "8.2.3", "version": "8.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
@ -1601,6 +1672,15 @@
"@types/range-parser": "*" "@types/range-parser": "*"
} }
}, },
"@types/formidable": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-2.0.5.tgz",
"integrity": "sha512-uvMcdn/KK3maPOaVUAc3HEYbCEhjaGFwww4EsX6IJfWIJ1tzHtDHczuImH3GKdusPnAAmzB07St90uabZeCKPA==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/mime": { "@types/mime": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
@ -1688,6 +1768,11 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
}, },
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
},
"balanced-match": { "balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -1840,6 +1925,15 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
}, },
"dezalgo": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
"integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==",
"requires": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"diff": { "diff": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
@ -1974,6 +2068,24 @@
"unpipe": "~1.0.0" "unpipe": "~1.0.0"
} }
}, },
"formidable": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz",
"integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==",
"requires": {
"dezalgo": "1.0.3",
"hexoid": "1.0.0",
"once": "1.4.0",
"qs": "6.9.3"
},
"dependencies": {
"qs": {
"version": "6.9.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
"integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw=="
}
}
},
"forwarded": { "forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -2034,6 +2146,11 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
}, },
"hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g=="
},
"http-errors": { "http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@ -2226,6 +2343,14 @@
"ee-first": "1.1.1" "ee-first": "1.1.1"
} }
}, },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"requires": {
"wrappy": "1"
}
},
"parseurl": { "parseurl": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -2538,6 +2663,11 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
}, },
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"ws": { "ws": {
"version": "8.2.3", "version": "8.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",

View file

@ -15,6 +15,7 @@
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"formidable": "^2.0.1",
"socket.io": "^4.5.3", "socket.io": "^4.5.3",
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },
@ -23,6 +24,7 @@
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/dotenv": "^8.2.0", "@types/dotenv": "^8.2.0",
"@types/express": "^4.17.13", "@types/express": "^4.17.13",
"@types/formidable": "^2.0.5",
"@types/node": "^17.0.0", "@types/node": "^17.0.0",
"@types/uuid": "^8.3.3", "@types/uuid": "^8.3.3",
"nodemon": "^2.0.15", "nodemon": "^2.0.15",

View file

@ -1,6 +1,8 @@
import cors from 'cors'; import cors from 'cors';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
import express from 'express'; import express from 'express';
import formidable from 'formidable';
import { mkdir, rename } from 'fs/promises';
const app = express(); const app = express();
dotenv.config(); dotenv.config();
@ -15,8 +17,33 @@ app.listen(+process.env.API_PORT, () => console.log(`Server running on: ${proces
app.use(express.json()); app.use(express.json());
app.use(cors({ origin: process.env.CORS_HOST })); app.use(cors({ origin: process.env.CORS_HOST }));
// Register post route // File upload post route
// app.post('/api/register', () => { }); app.post('/api/upload', (req, res) => {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if (!('filepath' in files.filetoupload) || !files.filetoupload?.filepath) {
res.write('Ups! Missing property "filetoupload" file');
res.end();
return;
}
const filename = files.filetoupload.originalFilename
const oldpath = files.filetoupload.filepath
const newdir = process.cwd() + '/upload/'
const newpath = newdir + filename
mkdir(newdir, { recursive: true })
.then(() => {
return rename(oldpath, newpath)
})
.then(() => {
console.log('New Upload: ' + filename)
res.write('File uploaded and moved!');
res.end();
})
.catch((err) => {
if (err) throw err;
})
});
});
// - - - - - // - - - - -
@ -49,6 +76,6 @@ io.on("connection", (socket) => {
console.log("Got test:", payload) console.log("Got test:", payload)
// ... // ...
}); });
socket.emit('test2', 'lol') socket.emit('test2', 'lol')
}); });

View file

@ -1,7 +1,8 @@
// import Gamefield from './components/Gamefield'; // import Gamefield from './components/Gamefield';
// import Homepage from './components/Homepage'; // import Homepage from './components/Homepage';
// import Homepage2 from './components/Homepage2'; // import Homepage2 from './components/Homepage2';
import SocketIO from './components/SocketIO'; // import SocketIO from './components/SocketIO';
import Upload from './components/Upload';
import './styles/App.scss'; import './styles/App.scss';
function App() { function App() {
@ -13,7 +14,8 @@ function App() {
{/* <Gamefield/> */} {/* <Gamefield/> */}
{/* <Homepage/> */} {/* <Homepage/> */}
{/* <Homepage2/> */} {/* <Homepage2/> */}
<SocketIO/> {/* <SocketIO/> */}
<Upload />
</header> </header>
</div> </div>
); );

View file

@ -0,0 +1,44 @@
import { useState } from 'react';
function Upload() {
const [file, setFile] = useState('');
const [filename, setFilename] = useState('');
// function handleChange
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
console.log(e.target.files);
if (!e.target.files?.length)
return
const file = e.target.files[0]
console.log(URL.createObjectURL(e.target.files[0]))
setFile(URL.createObjectURL(e.target.files[0]));
setFilename(e.target.files[0].name);
const url = 'http://localhost:5000/api/upload';
const formData = new FormData();
formData.append('filetoupload', file);
console.log(file)
const config = {
method: 'POST',
body: formData
};
fetch(url, config)
.then((response) => {
console.log(response.body)
})
.catch(error => console.log(error))
}
return (
<div>
<h2>Add Image:</h2>
<input type="file" className='inputt' onChange={handleChange} />
<img src={file} alt={filename || 'No selection'} />
</div>
)
}
export default Upload

View file

@ -186,4 +186,11 @@
grid-area: 4 / 4 / -4 / -4; grid-area: 4 / 4 / -4 / -4;
} }
} }
}
.inputt {
background-color: #61dafb;
&:hover {
background-color: red;
}
} }