This commit is contained in:
satori 2021-07-26 11:22:48 +08:00
parent 52ed0c87e6
commit e58fd0a27b
3 changed files with 166 additions and 55 deletions

189
index.js
View File

@ -2,14 +2,23 @@ import nedb from 'nedb'
import express from 'express'
import expressWs from 'express-ws'
import session from 'express-session'
//import random from 'string-random'
import connect from 'connect-nedb-session'
import random from 'string-random'
import formidable from 'formidable'
import md5 from 'md5-node'
import { resolve } from 'path/posix'
process.on('SIGINT', function() {
console.log('Got SIGINT. Press Control-D/Control-C to exit.');
process.exit(0);
});
const app = expressWs(express()).app
//const NedbStore = connect(session)
const NedbStore = connect(session)
// 自动载入所有库
// 自动构建 db 列表
// 数据: 自动构建 db 列表 或自动载入所有库
const databases = new Map()
const db = (name) => (databases.get(name) || function(){
let database = new nedb({filename:`./data/db/${name}.db`,autoload:true,timestampData:true})
@ -17,75 +26,149 @@ const db = (name) => (databases.get(name) || function(){
return database
}())
// 缓存: 自动构建 ws 列表
const wsstores = new Map()
const wsstore = name => (wsstores.get(name) || function() {
let list = new Map()
wsstores.set(name, list)
return list
}())
// 组件: 要求登录
const online = function(req, res, next) {
req.session.account ? next() : res.status(401).send('未登录')
}
// 组件: 管理权限
const admin = function(req, res, next) {
req.session.account.gid === 1 ? next() : res.status(403).send('没有权限')
}
// 组件: 移除输入非法信息
const remove = function(req, res, next) {
delete req.body._id
delete req.body.uid
delete req.body.createdAt
delete req.body.updatedAt
delete req.body.views
delete req.body.posts
delete req.body.likes
next()
}
// 组件: 从缓存载入数据
// 组件: 操作权限
//const authority = function(req, res, next) {
// (req.method === 'GET') ? next() : res.status(200).send
//}
// 组件: 移除输出敏感信息
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(session({
secret: 'keyboard cat',
name:'sid',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 180 * 24 * 3600000 },
store: new NedbStore({filename: './data/db/session.db'}),
}))
// 只允许管理权限访问
app.use('/session', online, admin)
app.use('/account', online, admin)
app.use('/message', online, admin)
app.use('/attach', online, admin)
app.use('/like', online, admin)
// 操作对象必须要登录
//app.use('/:name', )
// 对象列表
// 对象实体
// 对象附件
// 对象评论
// 对象收藏
// 对象点赞
app.get('/', function(req, res, next) {
res.send('index')
})
app.get('/test', function(req, res, next) {
res.send(`
<DOCTYPE html>
<title>test</title>
<p> 2333 <p>
<div id="div"></div>
<form id="form">
<input type="file" name="files" multiple accept=".jpg,">
<input id="btn" type="button" value="确认上传">
</form>
<script>
const btn = document.getElementById("btn");
const form = document.getElementById("form");
btn.onclick = function () {
console.log(1);
const formData = new FormData(form);
// 获取数组第一个文件
//files = formDate.get("files");
// 返回数组 获取所有文件
// files = formData.getAll("files");
// console.log(files);
const xhr = new XMLHttpRequest();
xhr.open('post', '/demo/FmnKXZ8lxwGjf4GE/file');
xhr.send(formData);
xhr.onload = function () {
alert(xhr.responseText);
}
}
</script>
`)
})
// 无论在哪一级别的对象, 都是泛型对象, 因此不必二级restful
// 列表也是对象
//app.use('/:name', function(req, res, next) {
// log
//})
const count_load = async function(name, query) {
await new Promise(resolve => db(name).count(query, function(err, count) {
resolve(count)
}))
}
const list_load = async function(name, query) {
await new Promise(resolve => db(name).find(query, function(err, docs) {
let list = []
for (let doc of docs) list.push({_id: doc.id})
resolve(list)
}))
}
app.get('/:name', function(req, res, next) {
db(req.params.name).find({}, function(err, docs) {
if (req.query.tid) req.query.tid = Number(req.query.tid) // 某些查询参数需要转换类型(暂时)
if (req.query.top) req.query.top = Number(req.query.top) // 某些查询参数需要转换类型(暂时)
if (req.query.uid || req.query.uid !== req.session?.account?.uid) {
req.query.public = true // 如果查询条件限定为自己的, 则不用限制范围到公开的
}
let { pagesize, page, like, ...query } = req.query
pagesize = Number(pagesize) || 20
let skip = ((Number(page) || 1) - 1) * pagesize
// 基于登录状态的查询, 查询点赞过的, 查询评论过的
if (req.session?.account?.uid) {
if (like) query.$or = list_load('like',{name:req.params.name, uid:req.session.account.uid})
if (post) query.$or = list_load('post',{name:req.params.name, uid:req.session.account.uid})
}
db(req.params.name).find(query).skip(skip).limit(pagesize).sort({createdAt: -1}).exec(async function(err, docs) {
for (let item of docs) {
item.posts = await count_load('post', {name:req.params.name, id:item._id}) // 附加评论数量
item.likes = await count_load('like', {name:req.params.name, id:item._id}) // 附加点赞数量
if (user) item.user = await user_load(item.uid) // 附加用户信息
}
res.json(docs)
})
})
app.put('/:name', function(req, res, next) {})
app.post('/:name', function(req, res, next) {
db(req.params.name).insert({name:'2333'}, function(err, doc) {
res.json(doc)
app.post('/:name', online, remove, function(req, res, next) {
req.body.uid = req.session.account.uid // 默认发布者uid
req.body.public = true // 默认发表即公开
db(req.params.name).insert(req.body, function(err, doc) {
doc ? res.json(doc) : res.status(500).send('内部错误')
})
})
//app.put('/:name', online, function(req, res, next) {})
//app.patch('/:name', online, function(req, res, next) {})
//app.head('/:name', function(req, res, next) {})
//app.options('/:name', function(req, res, next) {})
app.get('/:name/:id', function(req, res, next) {
db(req.params.name).findOne({_id: req.params.id}, async function(err, doc) {
if (err || !doc) return res.status(404).send('目标资源不存在')
if (!doc.public && doc.uid !== req.session?.account?.uid) {
return res.status(403).send('没有权限读取')
}
// 附加用户信息
if (req.query.user) doc.user = await user_load(doc.uid)
})
})
app.patch('/:name', function(req, res, next) {})
app.head('/:name', function(req, res, next) {})
app.options('/:name', function(req, res, next) {})
app.get('/:name/:id', function(req, res, next) {})
app.put('/:name/:id', function(req, res, next) {})
app.post('/:name/:id', function(req, res, next) {})
//app.post('/:name/:id', function(req, res, next) {})
app.patch('/:name/:id', function(req, res, next) {})
app.options('/:name/:id', function(req, res, next) {})
app.head('/:name/:id', function(req, res, next) {})
//app.options('/:name/:id', function(req, res, next) {})
//app.head('/:name/:id', function(req, res, next) {})
app.get('/:name/:id/post', function(req, res, next) {
// 获得此对象的所有post记录

View File

@ -7,10 +7,13 @@
"author": "satori <huan0016@gmail.com>",
"license": "MIT",
"dependencies": {
"connect-nedb-session": "^0.0.3",
"express": "^4.17.1",
"express-session": "^1.17.2",
"express-ws": "^5.0.2",
"formidable": "^1.2.2",
"nedb": "^1.8.0"
"md5-node": "^1.0.1",
"nedb": "^1.8.0",
"string-random": "^0.1.3"
}
}

View File

@ -15,7 +15,7 @@ array-flatten@1.1.1:
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
async@0.2.10:
async@0.2.10, async@~0.2.8:
version "0.2.10"
resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E=
@ -48,6 +48,13 @@ bytes@3.1.0:
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
connect-nedb-session@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/connect-nedb-session/-/connect-nedb-session-0.0.3.tgz#e10f642d3d604f609bb23a450021dd1f0579c5ac"
integrity sha1-4Q9kLT1gT2CbsjpFACHdHwV5xaw=
dependencies:
nedb "0.0.6"
content-disposition@0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
@ -265,6 +272,11 @@ localforage@^1.3.0:
dependencies:
lie "3.1.1"
md5-node@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/md5-node/-/md5-node-1.0.1.tgz#0e22d009d46bdc95b1d3c5e8c8feddc1a5c3aa88"
integrity sha1-DiLQCdRr3JWx08XoyP7dwaXDqog=
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -319,6 +331,14 @@ ms@2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
nedb@0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/nedb/-/nedb-0.0.6.tgz#a2e6c02cb2fcacf91245b02431f44cf1664aa85f"
integrity sha1-oubALLL8rPkSRbAkMfRM8WZKqF8=
dependencies:
async "~0.2.8"
underscore "~1.4.4"
nedb@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/nedb/-/nedb-1.8.0.tgz#0e3502cd82c004d5355a43c9e55577bd7bd91d88"
@ -444,6 +464,11 @@ setprototypeof@1.1.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
string-random@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/string-random/-/string-random-0.1.3.tgz#083f39835c2430fe0be76b9e72f0736e2e0f7b74"
integrity sha512-g+UsIwzKhNi+9/+Q3Q7hP8R4HkQxiIkQlttnxw6GRdk9pnnkGIv53C6H8dvh8wxAVDhkqpnWeauaPXS1b2sBJg==
toidentifier@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"