mirror of
https://git.sr.ht/~coasteen/webui
synced 2025-11-04 11:37:34 +01:00
116 lines
3.6 KiB
JavaScript
116 lines
3.6 KiB
JavaScript
const express = require('express')
|
|
const multer = require('multer')
|
|
const path = require('path')
|
|
const fs = require('fs')
|
|
const morgan = require('morgan')
|
|
const chalk = require('chalk').default
|
|
|
|
const app = express()
|
|
const uploadDir = path.join(__dirname, 'uploads')
|
|
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true })
|
|
|
|
function loadConfig() {
|
|
try {
|
|
const content = fs.readFileSync(path.join(__dirname, 'config.conf'), 'utf8')
|
|
const match = content.match(/^logs\s*=\s*(.*)$/m)
|
|
if (match && match[1].trim().toLowerCase() === 'disable') return { loggingEnabled: false }
|
|
} catch {}
|
|
return { loggingEnabled: true }
|
|
}
|
|
|
|
const config = loadConfig()
|
|
|
|
const colors = {
|
|
info: chalk.cyanBright,
|
|
warn: chalk.yellowBright,
|
|
error: chalk.redBright,
|
|
action: chalk.greenBright,
|
|
sys: chalk.magentaBright
|
|
}
|
|
|
|
function log(level, msg) {
|
|
if (!config.loggingEnabled) return
|
|
const time = new Date().toISOString().replace('T', ' ').split('.')[0]
|
|
const colorFn = colors[level.toLowerCase()] || chalk.white
|
|
console.log(`[${time}] [${level.toUpperCase()}] ${colorFn(msg)}`)
|
|
}
|
|
|
|
const storage = multer.diskStorage({
|
|
destination: (req, file, cb) => cb(null, uploadDir),
|
|
filename: (req, file, cb) => cb(null, `${Date.now()}-${Math.round(Math.random() * 1e9)}-${file.originalname}`)
|
|
})
|
|
const upload = multer({ storage }).array('files')
|
|
|
|
app.use(express.static(__dirname))
|
|
if (config.loggingEnabled) app.use(morgan('dev'))
|
|
|
|
app.post('/upload', (req, res) => {
|
|
upload(req, res, err => {
|
|
if (err) {
|
|
log('error', `UPLOAD ERROR: ${err.message}`)
|
|
return res.status(500).send('Upload error')
|
|
}
|
|
if (!req.files?.length) {
|
|
log('warn', `UPLOAD FAILED: No files received`)
|
|
return res.status(400).send('No files uploaded')
|
|
}
|
|
const names = req.files.map(f => f.filename).join(', ')
|
|
log('action', `UPLOADED ${req.files.length} file(s): ${names}`)
|
|
res.send(`Uploaded ${req.files.length} file(s)!`)
|
|
})
|
|
})
|
|
|
|
app.get('/files', (req, res) => {
|
|
log('info', 'Listing all files')
|
|
fs.readdir(uploadDir, (err, files) => {
|
|
if (err) {
|
|
log('error', `Unable to read uploads directory: ${err.message}`)
|
|
return res.status(500).send('Unable to scan directory')
|
|
}
|
|
const fileList = files.map(file => {
|
|
const stat = fs.statSync(path.join(uploadDir, file))
|
|
return { name: file, path: `/uploads/${file}`, size: stat.size, date: stat.mtime }
|
|
})
|
|
res.json(fileList)
|
|
})
|
|
})
|
|
|
|
app.get('/uploads/:filename', (req, res) => {
|
|
const filename = req.params.filename
|
|
const filePath = path.join(uploadDir, filename)
|
|
log('info', `Serving file: ${filename}`)
|
|
res.sendFile(filePath, err => {
|
|
if (err) {
|
|
log('error', `File not found: ${filename}`)
|
|
res.status(404).send('File not found')
|
|
}
|
|
})
|
|
})
|
|
|
|
app.get('/download/:filename', (req, res) => {
|
|
const filename = req.params.filename
|
|
const filePath = path.join(uploadDir, filename)
|
|
log('action', `Downloading file: ${filename}`)
|
|
res.download(filePath, err => {
|
|
if (err) {
|
|
log('error', `Download failed for: ${filename}`)
|
|
res.status(404).send('File not found')
|
|
}
|
|
})
|
|
})
|
|
|
|
app.delete('/delete/:filename', (req, res) => {
|
|
const filename = req.params.filename
|
|
const filePath = path.join(uploadDir, filename)
|
|
fs.unlink(filePath, err => {
|
|
if (err) {
|
|
log('error', `Failed to delete: ${filename}`)
|
|
return res.status(404).send('File not found')
|
|
}
|
|
log('action', `Deleted file: ${filename}`)
|
|
res.send('File deleted successfully')
|
|
})
|
|
})
|
|
|
|
const PORT = 3000
|
|
app.listen(PORT, () => log('sys', `Server running on http://localhost:${PORT}`))
|