mirror of
https://git.sr.ht/~coasteen/webui
synced 2025-11-04 11:37:34 +01:00
Compare commits
5 commits
e363f780d7
...
243ba4d1c7
| Author | SHA1 | Date | |
|---|---|---|---|
| 243ba4d1c7 | |||
| 13feee7b17 | |||
| a74b0624ca | |||
| 7edf9a3571 | |||
| 8ce7ae12b1 |
6 changed files with 416 additions and 174 deletions
|
|
@ -1,10 +1,11 @@
|
|||
# WebUI - A Simple File Management Tool
|
||||
|
||||
WebUI is a lightweight and easy-to-use web application for managing files on your server.
|
||||
WebUI is a (not very) lightweight and easy-to-use web application for managing files on your server.
|
||||
|
||||
## Screenshot
|
||||
|
||||

|
||||

|
||||
|
||||
## Getting Started
|
||||
|
||||
|
|
|
|||
1
config.conf
Normal file
1
config.conf
Normal file
|
|
@ -0,0 +1 @@
|
|||
logs = enable
|
||||
72
index.html
72
index.html
|
|
@ -7,6 +7,7 @@
|
|||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
#file-tree {
|
||||
margin-top: 20px;
|
||||
|
|
@ -14,6 +15,18 @@
|
|||
ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
li {
|
||||
padding: 5px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
li button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.file-info {
|
||||
flex-grow: 1;
|
||||
padding-left: 5px;
|
||||
}
|
||||
.preview-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
|
@ -22,36 +35,87 @@
|
|||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.preview-content {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
max-height: 90vh;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 400px;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.upload-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.progress-bar {
|
||||
width: 200px;
|
||||
height: 20px;
|
||||
border: 1px solid #ccc;
|
||||
margin-left: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.progress-bar-fill {
|
||||
height: 100%;
|
||||
width: 0;
|
||||
background-color: #4CAF50;
|
||||
transition: width 0.1s;
|
||||
}
|
||||
#batch-actions button {
|
||||
margin-right: 10px;
|
||||
padding: 8px 15px;
|
||||
}
|
||||
.preview-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
max-width: 90%;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.preview-controls button {
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Upload Files</h1>
|
||||
<form id="upload-form" action="/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="files" multiple required>
|
||||
<button type="submit">Upload</button>
|
||||
<input type="file" name="files" multiple required id="file-input">
|
||||
<button type="submit" id="upload-button">Upload</button>
|
||||
</form>
|
||||
|
||||
<h2>Files to Upload</h2>
|
||||
<ul id="upload-list">
|
||||
</ul>
|
||||
|
||||
<h2>Directory Structure</h2>
|
||||
<div id="batch-actions">
|
||||
<button id="select-all">Select All</button>
|
||||
<button id="batch-download">Download Selected</button>
|
||||
<button id="batch-delete">Delete Selected</button>
|
||||
<button id="batch-preview">Preview Selected (Text/Image)</button>
|
||||
</div>
|
||||
<div id="file-tree">
|
||||
<ul id="file-list"></ul>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
BIN
preview2.png
Normal file
BIN
preview2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 961 KiB |
358
script.js
358
script.js
|
|
@ -1,115 +1,265 @@
|
|||
document.addEventListener('DOMContentLoaded', () => {
|
||||
fetchFiles();
|
||||
fetchFiles();
|
||||
|
||||
document.getElementById('upload-form').addEventListener('submit', handleFileUpload);
|
||||
document.getElementById('upload-form').addEventListener('submit', handleFileUpload);
|
||||
document.getElementById('file-input').addEventListener('change', updateUploadList);
|
||||
|
||||
document.getElementById('select-all').addEventListener('click', handleSelectAll);
|
||||
document.getElementById('batch-delete').addEventListener('click', handleBatchDelete);
|
||||
document.getElementById('batch-download').addEventListener('click', handleBatchDownload);
|
||||
document.getElementById('batch-preview').addEventListener('click', handleBatchPreview);
|
||||
});
|
||||
|
||||
function fetchFiles() {
|
||||
fetch('/files')
|
||||
.then(response => response.json())
|
||||
.then(files => {
|
||||
const fileList = document.getElementById('file-list');
|
||||
fileList.innerHTML = '';
|
||||
files.forEach(file => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = `${file.name} (Size: ${file.size} bytes, Date: ${new Date(file.date).toLocaleString()})`;
|
||||
|
||||
const downloadButton = document.createElement('button');
|
||||
downloadButton.textContent = 'Download';
|
||||
downloadButton.onclick = () => {
|
||||
window.location.href = `/download/${file.name}`;
|
||||
};
|
||||
|
||||
const deleteButton = document.createElement('button');
|
||||
deleteButton.textContent = 'Delete';
|
||||
deleteButton.onclick = () => {
|
||||
fetch(`/delete/${file.name}`, { method: 'DELETE' })
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
li.remove();
|
||||
alert('File deleted successfully!');
|
||||
} else {
|
||||
alert('Error deleting file');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const previewButton = document.createElement('button');
|
||||
previewButton.textContent = 'Preview';
|
||||
previewButton.onclick = () => {
|
||||
showPreview(file);
|
||||
};
|
||||
|
||||
li.appendChild(downloadButton);
|
||||
li.appendChild(deleteButton);
|
||||
li.appendChild(previewButton);
|
||||
fileList.appendChild(li);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching file list:', error);
|
||||
});
|
||||
fetch('/files')
|
||||
.then(response => response.json())
|
||||
.then(files => {
|
||||
const fileList = document.getElementById('file-list');
|
||||
fileList.innerHTML = '';
|
||||
files.forEach(file => {
|
||||
const li = document.createElement('li');
|
||||
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.value = file.name;
|
||||
checkbox.dataset.path = `/uploads/${file.name}`;
|
||||
const extension = file.name.split('.').pop().toLowerCase();
|
||||
checkbox.dataset.fileType = extension;
|
||||
|
||||
const fileInfo = document.createElement('span');
|
||||
fileInfo.className = 'file-info';
|
||||
fileInfo.textContent = `${file.name} (Size: ${file.size} bytes, Date: ${new Date(file.date).toLocaleString()})`;
|
||||
|
||||
li.appendChild(checkbox);
|
||||
li.appendChild(fileInfo);
|
||||
fileList.appendChild(li);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching file list:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function updateUploadList(event) {
|
||||
const fileInput = event.target;
|
||||
const uploadList = document.getElementById('upload-list');
|
||||
uploadList.innerHTML = '';
|
||||
|
||||
if (fileInput.files.length === 0) return;
|
||||
|
||||
for (const file of fileInput.files) {
|
||||
const li = document.createElement('li');
|
||||
li.className = 'upload-item';
|
||||
li.innerHTML = `
|
||||
<span>${file.name} (Size: ${Math.round(file.size / 1024)} KB)</span>
|
||||
<div id="progress-${file.name.replace(/[^a-zA-Z0-9]/g, '-')}" class="progress-bar">
|
||||
<div class="progress-bar-fill" style="width: 0;"></div>
|
||||
</div>
|
||||
`;
|
||||
uploadList.appendChild(li);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFileUpload(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const form = event.target;
|
||||
const formData = new FormData(form);
|
||||
|
||||
fetch('/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(message => {
|
||||
alert(message);
|
||||
form.reset();
|
||||
fetchFiles();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error uploading file:', error);
|
||||
alert('File upload failed!');
|
||||
});
|
||||
event.preventDefault();
|
||||
|
||||
const form = event.target;
|
||||
const formData = new FormData(form);
|
||||
const fileInput = document.getElementById('file-input');
|
||||
|
||||
if (fileInput.files.length === 0) {
|
||||
alert('Please select files to upload.');
|
||||
return;
|
||||
}
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.upload.addEventListener('progress', (e) => {
|
||||
if (e.lengthComputable) {
|
||||
const percentComplete = (e.loaded / e.total) * 100;
|
||||
const progressBars = document.querySelectorAll('.progress-bar-fill');
|
||||
|
||||
progressBars.forEach(bar => {
|
||||
bar.style.width = percentComplete.toFixed(2) + '%';
|
||||
});
|
||||
}
|
||||
}, false);
|
||||
|
||||
xhr.addEventListener('load', () => {
|
||||
if (xhr.status === 200) {
|
||||
alert(xhr.responseText);
|
||||
form.reset();
|
||||
document.getElementById('upload-list').innerHTML = '';
|
||||
fetchFiles();
|
||||
} else {
|
||||
alert('File upload failed! Server responded with status ' + xhr.status);
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('error', () => {
|
||||
console.error('Error uploading file:', xhr.statusText);
|
||||
alert('File upload failed!');
|
||||
});
|
||||
|
||||
xhr.open('POST', '/upload');
|
||||
xhr.send(formData);
|
||||
}
|
||||
|
||||
function getSelectedFiles() {
|
||||
const selectedCheckboxes = document.querySelectorAll('#file-list input[type="checkbox"]:checked');
|
||||
return Array.from(selectedCheckboxes).map(checkbox => ({
|
||||
name: checkbox.value,
|
||||
path: checkbox.dataset.path,
|
||||
type: checkbox.dataset.fileType
|
||||
}));
|
||||
}
|
||||
|
||||
function showPreview(file) {
|
||||
const previewContainer = document.createElement('div');
|
||||
previewContainer.className = 'preview-modal';
|
||||
|
||||
const closeButton = document.createElement('button');
|
||||
closeButton.textContent = 'Close';
|
||||
closeButton.onclick = () => {
|
||||
document.body.removeChild(previewContainer);
|
||||
};
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.className = 'preview-content';
|
||||
|
||||
if (file.name.endsWith('.txt')) {
|
||||
const textPreview = document.createElement('iframe');
|
||||
textPreview.src = file.path;
|
||||
textPreview.style.width = '100%';
|
||||
textPreview.style.height = '200px';
|
||||
content.appendChild(textPreview);
|
||||
} else if (file.name.match(/\.(jpg|jpeg|png|gif)$/)) {
|
||||
const imgPreview = document.createElement('img');
|
||||
imgPreview.src = file.path;
|
||||
imgPreview.onload = () => {
|
||||
document.body.appendChild(previewContainer);
|
||||
};
|
||||
imgPreview.onerror = () => {
|
||||
alert('Error loading image preview');
|
||||
document.body.removeChild(previewContainer);
|
||||
};
|
||||
content.appendChild(imgPreview);
|
||||
} else {
|
||||
content.textContent = 'Preview not available for this file type.';
|
||||
}
|
||||
|
||||
previewContainer.appendChild(closeButton);
|
||||
previewContainer.appendChild(content);
|
||||
if (!file.name.match(/\.(jpg|jpeg|png|gif)$/)) {
|
||||
document.body.appendChild(previewContainer);
|
||||
}
|
||||
function handleSelectAll() {
|
||||
const checkboxes = document.querySelectorAll('#file-list input[type="checkbox"]');
|
||||
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
|
||||
|
||||
checkboxes.forEach(cb => {
|
||||
cb.checked = !allChecked;
|
||||
});
|
||||
}
|
||||
|
||||
function handleBatchDelete() {
|
||||
const filesToDelete = getSelectedFiles();
|
||||
if (filesToDelete.length === 0) {
|
||||
alert('No files selected for deletion.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm(`Are you sure you want to delete ${filesToDelete.length} file(s)?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const deletePromises = filesToDelete.map(file =>
|
||||
fetch(`/delete/${file.name}`, { method: 'DELETE' })
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return { name: file.name, status: 'Success' };
|
||||
} else {
|
||||
return { name: file.name, status: 'Failed' };
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
Promise.all(deletePromises)
|
||||
.then(results => {
|
||||
const successfulDeletes = results.filter(r => r.status === 'Success');
|
||||
const failedDeletes = results.filter(r => r.status === 'Failed');
|
||||
|
||||
if (successfulDeletes.length > 0) {
|
||||
alert(`Successfully deleted ${successfulDeletes.length} file(s).`);
|
||||
}
|
||||
if (failedDeletes.length > 0) {
|
||||
alert(`Failed to delete ${failedDeletes.length} file(s). Check console for errors.`);
|
||||
}
|
||||
fetchFiles();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during batch deletion:', error);
|
||||
alert('An error occurred during batch deletion.');
|
||||
});
|
||||
}
|
||||
|
||||
function handleBatchDownload() {
|
||||
const filesToDownload = getSelectedFiles();
|
||||
if (filesToDownload.length === 0) {
|
||||
alert('No files selected for download.');
|
||||
return;
|
||||
}
|
||||
|
||||
filesToDownload.forEach(file => {
|
||||
window.location.href = `/download/${file.name}`;
|
||||
});
|
||||
|
||||
alert(`Initiating download for ${filesToDownload.length} file(s). Check your browser's download manager.`);
|
||||
}
|
||||
|
||||
function handleBatchPreview() {
|
||||
const selectedFiles = getSelectedFiles();
|
||||
const previewableFiles = selectedFiles.filter(file =>
|
||||
file.type === 'txt' || file.type.match(/^(jpg|jpeg|png|gif)$/)
|
||||
);
|
||||
|
||||
if (previewableFiles.length === 0) {
|
||||
alert('No previewable files (.txt, .jpg, .png, .gif) selected.');
|
||||
return;
|
||||
}
|
||||
|
||||
showMultiPreview(previewableFiles);
|
||||
}
|
||||
|
||||
function showMultiPreview(files) {
|
||||
let currentIndex = 0;
|
||||
const previewContainer = document.createElement('div');
|
||||
previewContainer.className = 'preview-modal';
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.className = 'preview-content';
|
||||
|
||||
const controls = document.createElement('div');
|
||||
controls.className = 'preview-controls';
|
||||
|
||||
const prevButton = document.createElement('button');
|
||||
prevButton.textContent = 'Previous';
|
||||
prevButton.onclick = () => {
|
||||
if (currentIndex > 0) {
|
||||
currentIndex--;
|
||||
updatePreviewContent();
|
||||
}
|
||||
};
|
||||
|
||||
const nextButton = document.createElement('button');
|
||||
nextButton.textContent = 'Next';
|
||||
nextButton.onclick = () => {
|
||||
if (currentIndex < files.length - 1) {
|
||||
currentIndex++;
|
||||
updatePreviewContent();
|
||||
}
|
||||
};
|
||||
|
||||
const closeButton = document.createElement('button');
|
||||
closeButton.textContent = 'Close Preview';
|
||||
closeButton.onclick = () => {
|
||||
document.body.removeChild(previewContainer);
|
||||
};
|
||||
|
||||
controls.appendChild(prevButton);
|
||||
controls.appendChild(closeButton);
|
||||
controls.appendChild(nextButton);
|
||||
|
||||
const updatePreviewContent = () => {
|
||||
content.innerHTML = '';
|
||||
const file = files[currentIndex];
|
||||
|
||||
prevButton.disabled = currentIndex === 0;
|
||||
nextButton.disabled = currentIndex === files.length - 1;
|
||||
|
||||
const counter = document.createElement('p');
|
||||
counter.textContent = `File ${currentIndex + 1} of ${files.length}: ${file.name}`;
|
||||
content.appendChild(counter);
|
||||
|
||||
if (file.type === 'txt') {
|
||||
const textPreview = document.createElement('iframe');
|
||||
textPreview.src = file.path;
|
||||
textPreview.style.width = '100%';
|
||||
textPreview.style.height = '400px';
|
||||
content.appendChild(textPreview);
|
||||
} else if (file.type.match(/^(jpg|jpeg|png|gif)$/)) {
|
||||
const imgPreview = document.createElement('img');
|
||||
imgPreview.src = file.path;
|
||||
content.appendChild(imgPreview);
|
||||
} else {
|
||||
content.textContent = `Preview not available for this file type: ${file.name}.`;
|
||||
}
|
||||
};
|
||||
|
||||
previewContainer.appendChild(controls);
|
||||
previewContainer.appendChild(content);
|
||||
document.body.appendChild(previewContainer);
|
||||
|
||||
updatePreviewContent();
|
||||
}
|
||||
|
|
|
|||
156
server.js
156
server.js
|
|
@ -5,92 +5,118 @@ const fs = require('fs');
|
|||
|
||||
const app = express();
|
||||
|
||||
// configure storage for uploaded files
|
||||
function loadConfig() {
|
||||
try {
|
||||
const configPath = path.join(__dirname, 'config.conf');
|
||||
const content = fs.readFileSync(configPath, 'utf8');
|
||||
const match = content.match(/^logs\s*=\s*(.*)$/m);
|
||||
if (match && match[1].trim().toLowerCase() === 'disable') {
|
||||
return { loggingEnabled: false };
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
return { loggingEnabled: true };
|
||||
}
|
||||
|
||||
const config = loadConfig();
|
||||
|
||||
function logAction(message) {
|
||||
if (config.loggingEnabled) {
|
||||
console.log(`[ACTION] ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
cb(null, 'uploads/');
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
||||
cb(null, uniqueSuffix + '-' + file.originalname);
|
||||
}
|
||||
destination: (req, file, cb) => {
|
||||
cb(null, 'uploads/');
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
||||
cb(null, uniqueSuffix + '-' + file.originalname);
|
||||
}
|
||||
});
|
||||
|
||||
const upload = multer({ storage: storage });
|
||||
|
||||
// serve static files
|
||||
app.use(express.static(__dirname));
|
||||
|
||||
// upload files
|
||||
app.post('/upload', upload.array('files'), (req, res) => {
|
||||
if (!req.files || req.files.length === 0) {
|
||||
return res.status(400).send('No files were uploaded.');
|
||||
}
|
||||
res.send(`Successfully uploaded ${req.files.length} file(s)!`);
|
||||
if (!req.files || req.files.length === 0) {
|
||||
logAction(`FAILED upload attempt: No files received.`);
|
||||
return res.status(400).send('No files were uploaded.');
|
||||
}
|
||||
const uploadedNames = req.files.map(f => f.filename).join(', ');
|
||||
logAction(`UPLOADED ${req.files.length} file(s): ${uploadedNames}`);
|
||||
res.send(`Successfully uploaded ${req.files.length} file(s)!`);
|
||||
});
|
||||
|
||||
// get list of uploaded files
|
||||
app.get('/files', (req, res) => {
|
||||
const directoryPath = path.join(__dirname, 'uploads');
|
||||
fs.readdir(directoryPath, (err, files) => {
|
||||
if (err) {
|
||||
return res.status(500).send('Unable to scan directory: ' + err);
|
||||
}
|
||||
const fileListPromises = files.map(file => {
|
||||
return new Promise((resolve) => {
|
||||
const filePath = path.join(directoryPath, file);
|
||||
fs.stat(filePath, (err, stats) => {
|
||||
if (err) {
|
||||
return resolve(null);
|
||||
}
|
||||
resolve({
|
||||
name: file,
|
||||
path: `/uploads/${file}`,
|
||||
size: stats.size,
|
||||
date: stats.mtime
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
logAction(`LIST files requested.`);
|
||||
const directoryPath = path.join(__dirname, 'uploads');
|
||||
fs.readdir(directoryPath, (err, files) => {
|
||||
if (err) {
|
||||
return res.status(500).send('Unable to scan directory: ' + err);
|
||||
}
|
||||
const fileListPromises = files.map(file => {
|
||||
return new Promise((resolve) => {
|
||||
const filePath = path.join(directoryPath, file);
|
||||
fs.stat(filePath, (err, stats) => {
|
||||
if (err) {
|
||||
return resolve(null);
|
||||
}
|
||||
resolve({
|
||||
name: file,
|
||||
path: `/uploads/${file}`,
|
||||
size: stats.size,
|
||||
date: stats.mtime
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Promise.all(fileListPromises).then(fileList => {
|
||||
res.json(fileList.filter(file => file !== null));
|
||||
});
|
||||
});
|
||||
Promise.all(fileListPromises).then(fileList => {
|
||||
res.json(fileList.filter(file => file !== null));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// serve a specific file
|
||||
app.get('/uploads/:filename', (req, res) => {
|
||||
const filePath = path.join(__dirname, 'uploads', req.params.filename);
|
||||
res.sendFile(filePath, err => {
|
||||
if (err) {
|
||||
res.status(404).send('File not found');
|
||||
}
|
||||
});
|
||||
const filename = req.params.filename;
|
||||
logAction(`PREVIEW/ACCESS file: ${filename}`);
|
||||
const filePath = path.join(__dirname, 'uploads', filename);
|
||||
res.sendFile(filePath, err => {
|
||||
if (err) {
|
||||
res.status(404).send(`File not found: ${filename}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// download a specific file
|
||||
app.get('/download/:filename', (req, res) => {
|
||||
const filePath = path.join(__dirname, 'uploads', req.params.filename);
|
||||
res.download(filePath, err => {
|
||||
if (err) {
|
||||
res.status(404).send('File not found');
|
||||
}
|
||||
});
|
||||
const filename = req.params.filename;
|
||||
logAction(`DOWNLOAD file: ${filename}`);
|
||||
const filePath = path.join(__dirname, 'uploads', filename);
|
||||
res.download(filePath, err => {
|
||||
if (err) {
|
||||
res.status(404).send(`File not found for download: ${filename}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// delete a specific file
|
||||
app.delete('/delete/:filename', (req, res) => {
|
||||
const filePath = path.join(__dirname, 'uploads', req.params.filename);
|
||||
fs.unlink(filePath, err => {
|
||||
if (err) {
|
||||
return res.status(404).send('File not found');
|
||||
}
|
||||
res.send('File deleted successfully');
|
||||
});
|
||||
const filename = req.params.filename;
|
||||
const filePath = path.join(__dirname, 'uploads', filename);
|
||||
fs.unlink(filePath, err => {
|
||||
if (err) {
|
||||
logAction(`FAILED deletion of file: ${filename}`);
|
||||
return res.status(404).send('File not found');
|
||||
}
|
||||
logAction(`DELETED file: ${filename}`);
|
||||
res.send('File deleted successfully');
|
||||
});
|
||||
});
|
||||
|
||||
// start the server
|
||||
app.listen(3000, () => {
|
||||
console.log('Server is running on http://localhost:3000');
|
||||
});
|
||||
if (config.loggingEnabled) {
|
||||
console.log('[*] Server is running on http://localhost:3000');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue