* added upload, download, and delete functionality
* added error handling * added CSS stylesheet * bumped version to 0.3
This commit is contained in:
parent
7179d3cc89
commit
bffe457e13
13
css/updown.css
Normal file
13
css/updown.css
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.table {
|
||||||
|
display: table;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tr {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td {
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "updown",
|
"name": "updown",
|
||||||
"version": "0.2.0",
|
"version": "0.3.0",
|
||||||
"description": "a simple file uploader/downloader",
|
"description": "a simple file uploader/downloader",
|
||||||
"main": "updown.js",
|
"main": "updown.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -21,6 +21,7 @@
|
|||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
|
"express-fileupload": "^1.4.1",
|
||||||
"parcel": "^2.9.3",
|
"parcel": "^2.9.3",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
|
|||||||
102
updown.js
102
updown.js
@ -1,35 +1,115 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const fileupload = require('express-fileupload');
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 3000;
|
const port = 3000;
|
||||||
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const staticPath = "public/";
|
const staticPath = "public/";
|
||||||
|
|
||||||
app.set("view engine", "pug");
|
app.set("view engine", "pug");
|
||||||
|
app.use(fileupload());
|
||||||
|
// serve static css files
|
||||||
|
app.use(express.static(path.join(__dirname, 'css')));
|
||||||
|
|
||||||
function getFilesAndSizes(path) {
|
// Return all files and their sizes
|
||||||
|
function getFilesAndSizes(dir) {
|
||||||
|
// check if dir exists
|
||||||
|
try {
|
||||||
|
fs.accessSync(dir, fs.constants.F_OK);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("exist-check: " + error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// check if dir is readable
|
||||||
|
try {
|
||||||
|
fs.accessSync(dir, fs.constants.R_OK);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("read-check: " + error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// get files and their sizes from path
|
||||||
let files = [];
|
let files = [];
|
||||||
fs.readdirSync(path).forEach(filename => {
|
fs.readdirSync(dir).forEach(filename => {
|
||||||
files.push({ name: filename, size: fs.statSync(path + filename, (e, s) => s).size });
|
files.push({ name: filename, size: fs.statSync(dir + filename, (e, s) => s).size });
|
||||||
})
|
})
|
||||||
console.log(files);
|
console.log(files);//DEBUG
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle main page request
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
console.log(req.query);
|
//TODO: handle sorting
|
||||||
res.render("updown", {
|
//TODO: keep sort parameter in variable or something
|
||||||
message: "method: get",
|
return res.render("updown", {
|
||||||
|
message: req.query.msg,
|
||||||
files: getFilesAndSizes(staticPath)
|
files: getFilesAndSizes(staticPath)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
app.post("/", (req, res) => {
|
// Handle download request
|
||||||
res.render("updown", {
|
app.get('/download/:file', (req, res) => {
|
||||||
message: "method: post",
|
console.log('route /download/: params are ' + req.params);//DEBUG
|
||||||
files: getFilesAndSizes(staticPath)
|
res.download(staticPath + req.params['file'], error => {
|
||||||
|
if (!error)
|
||||||
|
return;
|
||||||
|
if (error.status === 404)
|
||||||
|
return res.redirect('/?msg=Download failed: file not found');
|
||||||
|
else
|
||||||
|
return res.redirect('/?msg=Download failed: Internal server error');
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Handle delete request
|
||||||
|
app.get('/delete/:file', (req, res) => {
|
||||||
|
console.log('route /delete/: params are ' + req.params);//DEBUG
|
||||||
|
// check if path is writable
|
||||||
|
fs.access(staticPath, fs.constants.w_OK, (error) => {
|
||||||
|
if (error) {
|
||||||
|
console.log("Deletion error: " + error.message);
|
||||||
|
return res.redirect("/?msg=Deletion failed: Path is not writable");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// delete file
|
||||||
|
try {
|
||||||
|
fs.rmSync(staticPath + req.params['file']);
|
||||||
|
return res.redirect("/?msg=File deleted");
|
||||||
|
} catch (error) {
|
||||||
|
if (error.message.startsWith("ENOENT")) {
|
||||||
|
return res.redirect("/?msg=Deletion failed: File doesn't exist");
|
||||||
|
} else {
|
||||||
|
console.log("Deletion error: " + error.message);
|
||||||
|
return res.redirect("/?msg=Deletion failed: Internal server error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Handle upload request
|
||||||
|
app.post("/upload/", (req, res) => {
|
||||||
|
// check if request contains a file
|
||||||
|
if (!req.files || Object.keys(req.files).length === 0) {
|
||||||
|
console.log("Upload error: " + error.message);
|
||||||
|
return res.redirect("/?msg=Upload failed: no file selected");
|
||||||
|
}
|
||||||
|
// check if path is writable
|
||||||
|
fs.access(staticPath, fs.constants.w_OK, (error) => {
|
||||||
|
if (error) {
|
||||||
|
console.log("Upload error: " + error.message);
|
||||||
|
return res.redirect("/?msg=Upload failed: Path is not writable");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// upload file
|
||||||
|
let upFile = req.files.up;
|
||||||
|
upFile.mv(staticPath + upFile.name, (error) => {
|
||||||
|
if (!error)
|
||||||
|
return res.redirect("/?msg=File uploaded");
|
||||||
|
else {
|
||||||
|
console.log("Upload error: " + error.message);
|
||||||
|
return res.redirect("/?msg=Upload failed: Internal server error");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`updown listening on port ${port}`)
|
console.log(`updown listening on port ${port}`)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,23 +2,26 @@ doctype html
|
|||||||
html
|
html
|
||||||
head(lang="en")
|
head(lang="en")
|
||||||
title Updown
|
title Updown
|
||||||
|
link(rel='stylesheet', href='/updown.css', type='text/css')
|
||||||
body
|
body
|
||||||
div(align='center')
|
div#message.table
|
||||||
p= message
|
div= message
|
||||||
table(align='center')
|
div#f-upload.table
|
||||||
form(method='get', action='')
|
form#upload-form(method='post', enctype='multipart/form-data', action='/upload/')
|
||||||
tr
|
label(for='up') Upload File
|
||||||
th
|
input#up(type='file', name='up')
|
||||||
a(href='?sort=name') Uploaded File(s)
|
button(type='submit') Submit
|
||||||
th
|
div#flist.table
|
||||||
a(href='?sort=size') Size
|
div.tr#flist-heading
|
||||||
th
|
div.td
|
||||||
th
|
a(href='?sort=name') Uploaded File(s)
|
||||||
|
div.td
|
||||||
|
a(href='?sort=size') Size
|
||||||
each file in files
|
each file in files
|
||||||
tr
|
div.tr
|
||||||
td= file.name
|
div.td= file.name
|
||||||
td= file.size
|
div.td= file.size
|
||||||
td
|
div.td
|
||||||
a(href='?download='+file.name alt="download") 🠳
|
a(href='/download/'+file.name alt="download file") 🠳
|
||||||
td
|
div.td
|
||||||
a(href='?delete='+file.name alt="delete") 🞬
|
a(href='/delete/'+file.name alt="delete file") 🞬
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user