* added upload, download, and delete functionality

* added error handling
* added CSS stylesheet
* bumped version to 0.3
This commit is contained in:
eclipse 2023-11-11 17:22:10 +01:00
parent 7179d3cc89
commit bffe457e13
4 changed files with 127 additions and 30 deletions

13
css/updown.css Normal file
View File

@ -0,0 +1,13 @@
.table {
display: table;
margin: 0 auto;
}
.tr {
display: table-row;
}
.td {
display: table-cell;
}

View File

@ -1,6 +1,6 @@
{
"name": "updown",
"version": "0.2.0",
"version": "0.3.0",
"description": "a simple file uploader/downloader",
"main": "updown.js",
"scripts": {
@ -21,6 +21,7 @@
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",
"events": "^3.3.0",
"express-fileupload": "^1.4.1",
"parcel": "^2.9.3",
"path-browserify": "^1.0.1",
"process": "^0.11.10",

102
updown.js
View File

@ -1,35 +1,115 @@
const express = require('express');
const fileupload = require('express-fileupload');
const app = express();
const port = 3000;
const path = require('path');
const fs = require('fs');
const staticPath = "public/";
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 = [];
fs.readdirSync(path).forEach(filename => {
files.push({ name: filename, size: fs.statSync(path + filename, (e, s) => s).size });
fs.readdirSync(dir).forEach(filename => {
files.push({ name: filename, size: fs.statSync(dir + filename, (e, s) => s).size });
})
console.log(files);
console.log(files);//DEBUG
return files;
}
// Handle main page request
app.get('/', (req, res) => {
console.log(req.query);
res.render("updown", {
message: "method: get",
//TODO: handle sorting
//TODO: keep sort parameter in variable or something
return res.render("updown", {
message: req.query.msg,
files: getFilesAndSizes(staticPath)
})
})
app.post("/", (req, res) => {
res.render("updown", {
message: "method: post",
files: getFilesAndSizes(staticPath)
// Handle download request
app.get('/download/:file', (req, res) => {
console.log('route /download/: params are ' + req.params);//DEBUG
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, () => {
console.log(`updown listening on port ${port}`)
})

View File

@ -2,23 +2,26 @@ doctype html
html
head(lang="en")
title Updown
link(rel='stylesheet', href='/updown.css', type='text/css')
body
div(align='center')
p= message
table(align='center')
form(method='get', action='')
tr
th
div#message.table
div= message
div#f-upload.table
form#upload-form(method='post', enctype='multipart/form-data', action='/upload/')
label(for='up') Upload File
input#up(type='file', name='up')
button(type='submit') Submit
div#flist.table
div.tr#flist-heading
div.td
a(href='?sort=name') Uploaded File(s)
th
div.td
a(href='?sort=size') Size
th
th
each file in files
tr
td= file.name
td= file.size
td
a(href='?download='+file.name alt="download") 🠳
td
a(href='?delete='+file.name alt="delete") 🞬
div.tr
div.td= file.name
div.td= file.size
div.td
a(href='/download/'+file.name alt="download file") 🠳
div.td
a(href='/delete/'+file.name alt="delete file") 🞬