From fcfc745d0bd5828613787f743fe489e2c1ad6bb2 Mon Sep 17 00:00:00 2001 From: durunsong Date: Tue, 26 Nov 2024 09:37:38 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=98chore:=E5=8D=87=E7=BA=A7=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=AB=AF=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/.env | 5 +- server/app.js | 83 ++++++++++ server/bin/index.js | 49 ++++++ server/controllers/home.js | 45 ++++++ server/controllers/login.js | 8 - server/index.js | 31 ---- server/package.json | 11 +- server/pnpm-lock.yaml | 229 ++++++++++++++++++++++++++++ server/public/images/404.png | Bin 0 -> 10090 bytes server/public/images/api.png | Bin 0 -> 2638 bytes server/public/stylesheets/style.css | 12 ++ server/routes/userRoutes.js | 26 ++-- server/views/error.ejs | 61 ++++++++ server/views/index.ejs | 11 ++ 14 files changed, 517 insertions(+), 54 deletions(-) create mode 100644 server/app.js create mode 100644 server/bin/index.js create mode 100644 server/controllers/home.js delete mode 100644 server/index.js create mode 100644 server/public/images/404.png create mode 100644 server/public/images/api.png create mode 100644 server/public/stylesheets/style.css create mode 100644 server/views/error.ejs create mode 100644 server/views/index.ejs diff --git a/server/.env b/server/.env index 5e2683c..90ae27f 100644 --- a/server/.env +++ b/server/.env @@ -1,4 +1,5 @@ # 这里放置一些配置信息 -PORT = 4000 -# JWT 刷新令牌KEY +# 端口号 +PORT = '4000' +# JWT_SECRET --- 用于生成和验证JWT的密钥 JWT_SECRET = 'f7d623cd21149c493d7304960edaf2e10ad147528dbaf183520184fc0a0f64cb' \ No newline at end of file diff --git a/server/app.js b/server/app.js new file mode 100644 index 0000000..da6fe9b --- /dev/null +++ b/server/app.js @@ -0,0 +1,83 @@ +/** + * 引入模块依赖 + */ +const app = require("./bin/index"); +const debug = require("debug")("kilyicms_server:server"); +const http = require("http"); + +/** + * 从环境变量中获取端口号,如果未定义则使用默认端口 4000 + */ +const port = normalizePort(process.env.PORT || "4000"); +app.set("port", port); + +/** + * 创建 HTTP 服务器 + */ +const server = http.createServer(app); + +/** + * 监听指定端口,启动服务器 + */ +server.listen(port, () => { + console.log(`Server is running on port ${port}`); +}); +server.on("error", onError); +server.on("listening", onListening); + +/** + * 将端口规范化为数字、字符串或 false + * @param {string|number} val - 输入的端口值 + * @returns {number|string|boolean} - 规范化后的端口 + */ +function normalizePort(val) { + const port = parseInt(val, 10); + // 检查是否为有效端口号 + if (isNaN(port)) { + // 不是数字则返回原始字符串(如命名管道) + return val; + } + if (port >= 0) { + // 有效端口号 + return port; + } + return false; // 无效端口 +} + +/** + * 处理服务器启动过程中的错误 + * @param {Error} error - 错误对象 + */ +function onError(error) { + if (error.syscall !== "listen") { + throw error; + } + const bind = typeof port === "string" ? "Pipe " + port : "Port " + port; + // 用友好信息处理特定的监听错误 + switch (error.code) { + case "EACCES": + console.error(bind + " requires elevated privileges"); + process.exit(1); + break; + case "EADDRINUSE": + console.error(bind + " is already in use"); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * HTTP 服务器 “监听 ”事件的事件监听器。 + */ +function onListening() { + const addr = server.address(); + const bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port; + debug("Listening on " + bind); +} + +/** + * @vercel部署需要这样写 + */ +module.exports = app; diff --git a/server/bin/index.js b/server/bin/index.js new file mode 100644 index 0000000..aa74b71 --- /dev/null +++ b/server/bin/index.js @@ -0,0 +1,49 @@ +// 入口文件 +require("dotenv").config(); +const createError = require("http-errors"); +const express = require("express"); +const bodyParserMiddleware = require("../middleware/bodyParserMiddleware"); +const corsMiddleware = require("../middleware/corsMiddleware"); +const userRoutes = require("../routes/userRoutes"); +const { connectDb } = require("../config/db-connection"); +const path = require("path"); +// const { hashExistingPasswords } = require("./controllers/hashExistingPasswords"); + +// 创建服务器对象 +const app = express(); + +// 在服务器启动时,调用 hashExistingPasswords 函数 +// 备用方案, 如果需要加密所有用户密码,则取消注释 +// hashExistingPasswords(); + +// 加载中间件 +app.use(bodyParserMiddleware.json); // 使用 bodyParser.json() +app.use(bodyParserMiddleware.urlencoded); // 使用 bodyParser.urlencoded() +app.use(corsMiddleware); // 使用 cors() + +// 设置静态资源目录 +app.use(express.static(path.join(__dirname, "../public"))); + +// 设置视图引擎 +app.set("views", path.join(__dirname, "../views")); +app.set("view engine", "ejs"); + +// 数据库连接 +connectDb(); + +// 注册路由 +app.use("/", userRoutes); + +// 处理 404 错误 +app.use((req, res, next) => { + next(createError(404)); +}); + +// 错误处理 +app.use((err, req, res) => { + res.locals.message = err.message; + res.locals.error = req.app.get("env") === "development" ? err : {}; + res.status(err.status || 500).render("error"); +}); + +module.exports = app; diff --git a/server/controllers/home.js b/server/controllers/home.js new file mode 100644 index 0000000..196f482 --- /dev/null +++ b/server/controllers/home.js @@ -0,0 +1,45 @@ +// 默认首页 +const homePage = (req, res) => { + res.send(` + + + + + + + kilyicms-server + + + +

Welcome to the world of kilyicms API!

+ + + `); +}; + +module.exports = { + homePage, +}; diff --git a/server/controllers/login.js b/server/controllers/login.js index 5c701e3..04924fd 100644 --- a/server/controllers/login.js +++ b/server/controllers/login.js @@ -7,38 +7,30 @@ const { connection } = require("../config/db-connection.js"); const loginUser = (req, res) => { const { user_name, password } = req.body; - if (!user_name || !password) { return res .status(400) .json({ status: 400, message: "账号和密码都是必需的" }); } - const findUserQuery = "SELECT * FROM users WHERE user_name = ? AND is_delete = 0"; - connection.query(findUserQuery, [user_name], async (err, results) => { if (err) { console.error(err); return res.status(500).json({ status: 500, message: "查询用户失败" }); } - if (results.length === 0) { return res.status(409).json({ status: 409, message: "用户不存在" }); } - const user = results[0]; const hashFromDb = user.password; - // 验证密码 const passWordMatch = await comparePassword(password, hashFromDb); if (!passWordMatch) { return res.status(409).json({ status: 409, message: "用户名或密码错误" }); } - // 生成 JWT const token = generateToken({ id: user.id, user_name: user.user_name }); - // 登录时间 const login_time = formatTime(); res.status(200).json({ diff --git a/server/index.js b/server/index.js deleted file mode 100644 index 82d88f4..0000000 --- a/server/index.js +++ /dev/null @@ -1,31 +0,0 @@ -// 入口文件 -const express = require("express"); -const bodyParserMiddleware = require("./middleware/bodyParserMiddleware"); -const corsMiddleware = require("./middleware/corsMiddleware"); -const userRoutes = require("./routes/userRoutes"); -const { connectDb } = require("./config/db-connection"); -// const { hashExistingPasswords } = require("./controllers/hashExistingPasswords"); - -// 创建服务器对象 -const app = express(); -const PORT = process.env.PORT || 4000; - -// 在服务器启动时,调用 hashExistingPasswords 函数 -// 备用方案, 如果需要加密所有用户密码,则取消注释 -// hashExistingPasswords(); - -// 中间件 -app.use(bodyParserMiddleware.json); // 使用 bodyParser.json() -app.use(bodyParserMiddleware.urlencoded); // 使用 bodyParser.urlencoded() -app.use(corsMiddleware); // 使用 cors() - -// 数据库连接 -connectDb(); - -// 注册路由 -app.use("/api/users", userRoutes); - -// 启动服务器 -app.listen(PORT, () => { - console.log(`Server is running on port ${PORT}`); -}); diff --git a/server/package.json b/server/package.json index 2a1b01d..3b0149d 100644 --- a/server/package.json +++ b/server/package.json @@ -1,7 +1,7 @@ { "name": "kilyicms_server", "version": "2.0.1", - "main": "index.js", + "main": "app.js", "description": "一个免费开源的多语言中后台管理系统基础解决方案,基于 Vue3、TypeScript、Element Plus、Pinia 和 Vite 等主流技术", "author": { "name": "Jack-DU", @@ -14,16 +14,23 @@ }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "node index.js" + "start": "node app.js" }, "dependencies": { "bcrypt": "^5.1.1", "body-parser": "^1.20.3", + "cookie-parser": "~1.4.7", "cors": "^2.8.5", + "debug": "~2.6.9", + "dotenv": "^16.4.5", + "ejs": "^3.1.10", "express": "^4.21.1", + "http-errors": "~1.6.3", "jsonwebtoken": "^9.0.2", "moment": "^2.30.1", + "morgan": "~1.9.1", "mysql2": "^3.11.3", + "path": "^0.12.7", "uuid": "^10.0.0" }, "devDependencies": { diff --git a/server/pnpm-lock.yaml b/server/pnpm-lock.yaml index 7ece3b5..326b767 100644 --- a/server/pnpm-lock.yaml +++ b/server/pnpm-lock.yaml @@ -14,21 +14,42 @@ importers: body-parser: specifier: ^1.20.3 version: 1.20.3 + cookie-parser: + specifier: ~1.4.7 + version: 1.4.7 cors: specifier: ^2.8.5 version: 2.8.5 + debug: + specifier: ~2.6.9 + version: 2.6.9 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + ejs: + specifier: ^3.1.10 + version: 3.1.10 express: specifier: ^4.21.1 version: 4.21.1 + http-errors: + specifier: ~1.6.3 + version: 1.6.3 jsonwebtoken: specifier: ^9.0.2 version: 9.0.2 moment: specifier: ^2.30.1 version: 2.30.1 + morgan: + specifier: ~1.9.1 + version: 1.9.1 mysql2: specifier: ^3.11.3 version: 3.11.3 + path: + specifier: ^0.12.7 + version: 0.12.7 uuid: specifier: ^10.0.0 version: 10.0.0 @@ -167,6 +188,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + aproba@2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} @@ -192,6 +217,9 @@ packages: async-sema@3.1.1: resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + aws-ssl-profiles@1.1.2: resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} engines: {node: '>= 6.0.0'} @@ -199,6 +227,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + basic-auth@2.0.1: + resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} + engines: {node: '>= 0.8'} + bcrypt@5.1.1: resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} engines: {node: '>= 10.0.0'} @@ -213,6 +245,9 @@ packages: brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -228,6 +263,10 @@ packages: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -238,6 +277,13 @@ packages: code-block-writer@10.1.1: resolution: {integrity: sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==} + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true @@ -260,6 +306,10 @@ packages: resolution: {integrity: sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==} engines: {node: '>=8'} + cookie-parser@1.4.7: + resolution: {integrity: sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==} + engines: {node: '>= 0.8.0'} + cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} @@ -267,6 +317,10 @@ packages: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -302,6 +356,10 @@ packages: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} + depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -318,6 +376,10 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} @@ -329,6 +391,11 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -503,6 +570,9 @@ packages: file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -555,6 +625,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -573,6 +647,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + http-errors@1.6.3: + resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} + engines: {node: '>= 0.6'} + http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -593,6 +671,9 @@ packages: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -619,6 +700,11 @@ packages: is-property@1.0.2: resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + json-schema-to-ts@1.6.4: resolution: {integrity: sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==} @@ -709,6 +795,10 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -729,6 +819,10 @@ packages: moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + morgan@1.9.1: + resolution: {integrity: sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==} + engines: {node: '>= 0.8.0'} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -793,10 +887,18 @@ packages: resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} engines: {node: '>= 0.4'} + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} + on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -821,6 +923,9 @@ packages: path-to-regexp@6.2.1: resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} + path@0.12.7: + resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} + picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -832,6 +937,10 @@ packages: resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} engines: {node: '>=10'} + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -879,6 +988,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -912,6 +1024,9 @@ packages: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} + setprototypeof@1.1.0: + resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -930,6 +1045,10 @@ packages: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -945,6 +1064,10 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} @@ -1007,6 +1130,9 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -1209,6 +1335,10 @@ snapshots: ansi-regex@5.0.1: {} + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + aproba@2.0.0: {} are-we-there-yet@2.0.0: @@ -1226,10 +1356,16 @@ snapshots: async-sema@3.1.1: {} + async@3.2.6: {} + aws-ssl-profiles@1.1.2: {} balanced-match@1.0.2: {} + basic-auth@2.0.1: + dependencies: + safe-buffer: 5.1.2 + bcrypt@5.1.1: dependencies: '@mapbox/node-pre-gyp': 1.0.11 @@ -1264,6 +1400,10 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -1280,12 +1420,23 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.2 + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + chownr@2.0.0: {} cjs-module-lexer@1.2.3: {} code-block-writer@10.1.1: {} + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + color-support@1.1.3: {} concat-map@0.0.1: {} @@ -1300,10 +1451,17 @@ snapshots: convert-hrtime@3.0.0: {} + cookie-parser@1.4.7: + dependencies: + cookie: 0.7.2 + cookie-signature: 1.0.6 + cookie-signature@1.0.6: {} cookie@0.7.1: {} + cookie@0.7.2: {} + cors@2.8.5: dependencies: object-assign: 4.1.1 @@ -1329,6 +1487,8 @@ snapshots: denque@2.1.0: {} + depd@1.1.2: {} + depd@2.0.0: {} destroy@1.2.0: {} @@ -1337,6 +1497,8 @@ snapshots: diff@4.0.2: {} + dotenv@16.4.5: {} + ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 @@ -1355,6 +1517,10 @@ snapshots: ee-first@1.1.1: {} + ejs@3.1.10: + dependencies: + jake: 10.9.2 + emoji-regex@8.0.0: {} encodeurl@1.0.2: {} @@ -1510,6 +1676,10 @@ snapshots: file-uri-to-path@1.0.0: {} + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -1581,6 +1751,8 @@ snapshots: graceful-fs@4.2.11: {} + has-flag@4.0.0: {} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.0 @@ -1595,6 +1767,13 @@ snapshots: dependencies: function-bind: 1.1.2 + http-errors@1.6.3: + dependencies: + depd: 1.1.2 + inherits: 2.0.3 + setprototypeof: 1.1.0 + statuses: 1.5.0 + http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -1623,6 +1802,8 @@ snapshots: once: 1.4.0 wrappy: 1.0.2 + inherits@2.0.3: {} + inherits@2.0.4: {} ipaddr.js@1.9.1: {} @@ -1639,6 +1820,13 @@ snapshots: is-property@1.0.2: {} + jake@10.9.2: + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + json-schema-to-ts@1.6.4: dependencies: '@types/json-schema': 7.0.15 @@ -1721,6 +1909,10 @@ snapshots: dependencies: brace-expansion: 1.1.11 + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + minipass@3.3.6: dependencies: yallist: 4.0.0 @@ -1736,6 +1928,16 @@ snapshots: moment@2.30.1: {} + morgan@1.9.1: + dependencies: + basic-auth: 2.0.1 + debug: 2.6.9 + depd: 1.1.2 + on-finished: 2.3.0 + on-headers: 1.0.2 + transitivePeerDependencies: + - supports-color + mri@1.2.0: {} ms@2.0.0: {} @@ -1787,10 +1989,16 @@ snapshots: object-inspect@1.13.2: {} + on-finished@2.3.0: + dependencies: + ee-first: 1.1.1 + on-finished@2.4.1: dependencies: ee-first: 1.1.1 + on-headers@1.0.2: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -1807,6 +2015,11 @@ snapshots: path-to-regexp@6.2.1: {} + path@0.12.7: + dependencies: + process: 0.11.10 + util: 0.10.4 + picocolors@1.0.0: {} picomatch@2.3.1: {} @@ -1815,6 +2028,8 @@ snapshots: dependencies: parse-ms: 2.1.0 + process@0.11.10: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -1857,6 +2072,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safer-buffer@2.1.2: {} @@ -1905,6 +2122,8 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.2 + setprototypeof@1.1.0: {} + setprototypeof@1.2.0: {} side-channel@1.0.6: @@ -1920,6 +2139,8 @@ snapshots: sqlstring@2.3.3: {} + statuses@1.5.0: {} + statuses@2.0.1: {} string-width@4.2.3: @@ -1936,6 +2157,10 @@ snapshots: dependencies: ansi-regex: 5.0.1 + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + tar@6.2.1: dependencies: chownr: 2.0.0 @@ -2001,6 +2226,10 @@ snapshots: util-deprecate@1.0.2: {} + util@0.10.4: + dependencies: + inherits: 2.0.3 + utils-merge@1.0.1: {} uuid@10.0.0: {} diff --git a/server/public/images/404.png b/server/public/images/404.png new file mode 100644 index 0000000000000000000000000000000000000000..e666697545bfe25a23474ee7927527fcbbf98a49 GIT binary patch literal 10090 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 HT<`w_`9$Ah literal 0 HcmV?d00001 diff --git a/server/public/stylesheets/style.css b/server/public/stylesheets/style.css new file mode 100644 index 0000000..d20a135 --- /dev/null +++ b/server/public/stylesheets/style.css @@ -0,0 +1,12 @@ +body { + padding: 50px; + font: + 14px "Lucida Grande", + Helvetica, + Arial, + sans-serif; +} + +a { + color: #00b7ff; +} diff --git a/server/routes/userRoutes.js b/server/routes/userRoutes.js index 8c2704c..c33ec63 100644 --- a/server/routes/userRoutes.js +++ b/server/routes/userRoutes.js @@ -6,39 +6,43 @@ const login = require("../controllers/login"); const refreshToken = require("../controllers/refreshToken"); const userInfo = require("../controllers/userInfo"); const register = require("../controllers/register"); +const homePage = require("../controllers/home"); const router = express.Router(); +// 首页 +router.get("/", homePage.homePage); + // 添加用户 -router.post("/", userController.createUser); +router.post("/api/users", userController.createUser); // 获取用户列表 -router.get("/", userController.getUsers); +router.get("/api/users", userController.getUsers); // 更新用户 -router.put("/:id", userController.updateUser); +router.put("/api/users/:id", userController.updateUser); // 删除用户(软删除) -router.delete("/:id", userController.deleteUser); +router.delete("/api/users/:id", userController.deleteUser); // 获取删除的用户列表 -router.get("/deleteList", deleteUsers.getDeletedUsers); +router.get("/api/users/deleteList", deleteUsers.getDeletedUsers); // 完全删除用户接口 -router.delete("/deleteList/:id", deleteUsers.permanentDeleteUser); +router.delete("/api/users/deleteList/:id", deleteUsers.permanentDeleteUser); // 还原删除用户接口 -router.put("/restore/:id", deleteUsers.restoreUserApi); +router.put("/api/users/restore/:id", deleteUsers.restoreUserApi); // 登录接口 -router.post("/login", login.loginUser); +router.post("/api/users/login", login.loginUser); // 注册接口 -router.post("/register", register.registerUser); +router.post("/api/users/register", register.registerUser); // 刷新jwt -router.post("/refresh-token", refreshToken.refreshToken); +router.post("/api/users/refresh-token", refreshToken.refreshToken); // 获取用户信息 -router.get("/userInfo", userInfo.getUserDetails); +router.get("/api/users/userInfo", userInfo.getUserDetails); module.exports = router; diff --git a/server/views/error.ejs b/server/views/error.ejs new file mode 100644 index 0000000..fff0c0a --- /dev/null +++ b/server/views/error.ejs @@ -0,0 +1,61 @@ + + + + + + + + 404 - Page Not Found + + + + + 404 Image +

404 - Page Not Found

+

Sorry, the page you are looking for does not exist.

+ Go back to Home + + + \ No newline at end of file diff --git a/server/views/index.ejs b/server/views/index.ejs new file mode 100644 index 0000000..7b7a1d6 --- /dev/null +++ b/server/views/index.ejs @@ -0,0 +1,11 @@ + + + + <%= title %> + + + +

<%= title %>

+

Welcome to <%= title %>

+ +