From c1a54375329ed4fe7e8fa5f45a5e5f7d69c2e851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E9=91=AB?= <7176466@qq.com> Date: Fri, 26 Aug 2022 23:45:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=9E=E7=8E=B0=E4=BA=86?= =?UTF-8?q?=E9=A6=96=E9=A1=B5=E6=96=87=E4=BB=B6=E5=88=97=E8=A1=A8=EF=BC=8C?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BA=86=E4=B8=8A=E4=BC=A0=E5=92=8C=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +++- config.js | 8 ++++---- public/style.css | 6 ++++++ server.js | 50 +++++++++++++++++++++++++++------------------- views/download.pug | 15 ++++++++------ views/index.pug | 23 +++++++++++++++++++++ views/upload.pug | 9 +++++---- 7 files changed, 79 insertions(+), 36 deletions(-) create mode 100644 views/index.pug diff --git a/README.md b/README.md index 4c33dc2..a62607f 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ -# 文件分享服务器 +# 文件分享 + +一个文件分享服务应用 diff --git a/config.js b/config.js index 5aebbda..67ea21b 100644 --- a/config.js +++ b/config.js @@ -2,8 +2,8 @@ require('dotenv').config() module.exports = { SERVER_HOST: process.env.HOST || 'localhost', SERVER_PORT: process.env.PORT || '3000', - MONGODB_URL: process.env.MONGDB || 'mongodb://localhost/data', - TEMP_PATH: '/tmp', - SAVE_PATH: 'upload', - UPLOAD_SIZE_LIMIT: 1024, + MONGODB_URL: process.env.MONGDB || 'mongodb://localhost/filesharing', + UPLOAD_SIZE_LIMIT: process.env.UPLOAD_SIZE_LIMIT || 102400, + UPLOAD_TEMP_PATH: process.env.UPLOAD_TEMP_PATH || '/tmp', + UPLOAD_SAVE_PATH: process.env.UPLOAD_SAVE_PATH || 'upload', } diff --git a/public/style.css b/public/style.css index 1f96e2e..5405986 100644 --- a/public/style.css +++ b/public/style.css @@ -12,6 +12,7 @@ body { p, h1, +li, form { margin: 1rem auto; } @@ -26,3 +27,8 @@ form button { grid-column: span 2; cursor: pointer; } + +.small { + color: gray; + font-size: small; +} diff --git a/server.js b/server.js index 25b8537..feb8c8c 100644 --- a/server.js +++ b/server.js @@ -1,4 +1,4 @@ -const { SERVER_HOST, SERVER_PORT, MONGODB_URL, TEMP_PATH, SAVE_PATH, UPLOAD_SIZE_LIMIT } = require('./config') +const { SERVER_HOST, SERVER_PORT, MONGODB_URL, UPLOAD_TEMP_PATH, UPLOAD_SAVE_PATH, UPLOAD_SIZE_LIMIT } = require('./config') const fs = require('fs') const path = require('path') const multer = require('multer') @@ -6,7 +6,7 @@ const bcrypt = require('bcrypt') const md5file = require('md5-file') const express = require('express') const mongoose = require('mongoose') -const File = require('./models/File') +const Filesharing = require('./models/Filesharing') mongoose.connect(MONGODB_URL, (error) => { if (error) { console.error(error) @@ -19,19 +19,26 @@ app.set('view engine', 'pug') app.use(express.static('public')) app.use(express.urlencoded({ extended: true })) app.use(express.json()) -app.get('/', (req, res) => { +app.locals.moment = require('moment') +app.locals.moment.locale('zh-cn') +app.get('/', async (req, res) => { + const filesharing = await Filesharing.find().sort({ createdAt: -1 }) + res.render('index', { filesharing }) +}) +app.get('/upload', async (req, res) => { res.render('upload') }) -const upload = multer({ dest: TEMP_PATH, limits: { fileSize: UPLOAD_SIZE_LIMIT } }) +const upload = multer({ dest: UPLOAD_TEMP_PATH, limits: { fileSize: UPLOAD_SIZE_LIMIT } }) app.post('/upload', upload.single('file'), async (req, res) => { - const file_temp_path = path.join(TEMP_PATH, req.file.filename) + const file_temp_path = path.join(UPLOAD_TEMP_PATH, req.file.filename) const md5 = await md5file(file_temp_path) - const file_save_path = path.join(__dirname, SAVE_PATH, md5) + const file_save_path = path.join(__dirname, UPLOAD_SAVE_PATH, md5) if (!fs.existsSync(file_save_path)) { fs.cpSync(file_temp_path, file_save_path) // 复制临时文件到UPLOAD_PATH } fs.unlinkSync(file_temp_path) // 删除临时文件 - let file = { + // 写入数据库 + const filesharing = new Filesharing({ md5, size: req.file.size, encoding: req.file.encoding, @@ -39,33 +46,34 @@ app.post('/upload', upload.single('file'), async (req, res) => { // 解决了multer将中文文件名错误编码的问题 filename: Buffer.from(req.file.originalname, 'latin1').toString('utf8'), password: req.body.password ? await bcrypt.hash(req.body.password, 16) : '', - } - // 写入数据库 - console.log(req.file) - console.log(file) - const fileshare = new File(file) - file = await fileshare.save() - console.log(file) + }) + const file = await filesharing.save() res.status(201).render('upload', { file }) }) app.get('/file/:id', async (req, res) => { - const file = await File.findById(req.params.id) - if (file) { + try { + if (!req.params.id.match(/^[0-9a-fA-F]{24}$/)) throw '格式错误的ObjectId' + const file = await Filesharing.findById(req.params.id) + if (!file) throw '试图下载不存在的文件' res.render('download', { file }) - } else { + } catch (error) { + console.error(error) res.sendStatus(404) } }) app.post('/file/:id', async (req, res) => { - const file = await File.findById(req.params.id) - if (file) { + try { + if (!req.params.id.match(/^[0-9a-fA-F]{24}$/)) throw '格式错误的ObjectId' + const file = await Filesharing.findById(req.params.id) + if (!file) throw '试图下载不存在的文件' if (file.password == '' || (await bcrypt.compare(req.body.password, file.password)) == true) { await file.update({ $inc: { downloads: 1 } }) - res.status(200).download(path.join(SAVE_PATH, file.md5), file.filename) + res.status(200).download(path.join(UPLOAD_SAVE_PATH, file.md5), file.filename) } else { res.sendStatus(401) } - } else { + } catch (error) { + console.error(error) res.sendStatus(404) } }) diff --git a/views/download.pug b/views/download.pug index 01a9537..d05249f 100644 --- a/views/download.pug +++ b/views/download.pug @@ -6,22 +6,25 @@ html(lang='zh') meta(name='viewport' content='width=device-width, initial-scale=1.0') link(rel='icon' href='/favicon.ico' type='image/x-icon') link(rel='stylesheet' href='/style.css') - title 文件下载 + title #{file.filename} | 文件下载 body h1 文件下载 + p + a(href='/') 返回首页 form(method='POST') label 文件 label= file.filename + label 类型 + label= file.mimetype label 大小 label= file.size |   字节 - label 类型 - label= file.mimetype - label 下载 + label 上传 + label= moment(file.createdAt).fromNow() + label 热度 label= file.downloads - |   次 + |   次下载 if file.password label(for='password_input') 密码 input(id='password_input' name='password' type='password' autocomplete='off' required) button(id='download_button' type='submit') 下载 - script(src='/client.js') diff --git a/views/index.pug b/views/index.pug new file mode 100644 index 0000000..a523fe4 --- /dev/null +++ b/views/index.pug @@ -0,0 +1,23 @@ +doctype html +html(lang='zh') + head + meta(charset='UTF-8') + meta(http-equiv='X-UA-Compatible' content='IE=edge') + meta(name='viewport' content='width=device-width, initial-scale=1.0') + link(rel='icon' href='/favicon.ico' type='image/x-icon') + link(rel='stylesheet' href='/style.css') + title 文件分享 + body + h1 文件分享 + p + a(href='/upload') 我要上传 + ul + if filesharing.length==0 + li 暂无文件 + else + for file in filesharing + li + a(href=`/file/${file.id}` target='_blank')= file.filename + if file.password + span   ㊙️ + span.small   ( #{moment(file.createdAt).fromNow()}, #{file.downloads} 次下载 ) diff --git a/views/upload.pug b/views/upload.pug index bf4fa85..635e05b 100644 --- a/views/upload.pug +++ b/views/upload.pug @@ -6,9 +6,11 @@ html(lang='zh') meta(name='viewport' content='width=device-width, initial-scale=1.0') link(rel='icon' href='/favicon.ico' type='image/x-icon') link(rel='stylesheet' href='/style.css') - title 文件分享 + title 文件上传 body - h1 文件分享 + h1 文件上传 + p + a(href='/') 返回首页 if file section p @@ -16,7 +18,7 @@ html(lang='zh') var #{file.filename}   | 分享成功! p 链接   - -const url = '/file/' + file.id + - const url = '/file/' + file.id a(href=url)= url form(method='POST' action='/upload' enctype='multipart/form-data') label(for='file_input') 文件 @@ -24,4 +26,3 @@ html(lang='zh') label(for='password_input') 密码 input(id='password_input' name='password' type='password' autocomplete='off') button(id='share_button' type='submit') 分享 - script(src='/client.js')