Browse Source

✨ feat: 新增部分接口

Pchen. 3 months ago
parent
commit
fffb1770b4

+ 1 - 0
.gitignore

@@ -1,4 +1,5 @@
 node_modules/
 *.log
+config.json
 uploads/*
 !uploads/.gitkeep

+ 3 - 1
apis/Captcha/SendEmail.js

@@ -62,7 +62,6 @@ class SendEmail extends API {
             await Redis.set(`email:${email}`, code, {
                 EX: 600
             });
-            await sendEmail(email, '验证码', `${content}您的验证码为:${code}。此验证码10分钟内有效,请妥善保管您的验证码,非本人操作请忽略。`);
         } catch (err) {
             this.logger.error(`发送邮箱验证码失败!${err.stack}`);
             return res.json({
@@ -74,6 +73,9 @@ class SendEmail extends API {
         res.json({
             ...BaseStdResponse.OK
         })
+
+        // 先返回后发送
+        await sendEmail(email, '验证码', `${content}您的验证码为:${code}。此验证码10分钟内有效,请妥善保管您的验证码,非本人操作请忽略。`);
     }
 }
 

+ 55 - 0
apis/Repos/AddRepo.js

@@ -0,0 +1,55 @@
+const API = require("../../lib/API")
+const AccessControl = require("../../lib/AccessControl")
+const { BaseStdResponse } = require("../../BaseStdResponse")
+const db = require("../../plugin/DataBase/db")
+
+// 添加仓库
+class AddRepo extends API {
+    constructor() {
+        super()
+
+        this.setMethod("POST")
+        this.setPath("/Repos")
+    }
+
+    checkName(name) {
+        const regex = /^(?!\.)(?!.*\/{2,})(?!.*\.git$)[\u4E00-\u9FA5A-Za-z0-9._-]+(?<!\/)$/
+        return regex.test(name)
+    }
+
+    async onRequest(req, res) {
+        let { uuid, session, name, url } = req.body
+
+        if ([uuid, session, name, url].some(value => value === '' || value === null || value === undefined))
+            return res.json({
+                ...BaseStdResponse.MISSING_PARAMETER
+            })
+
+        if (!this.checkUsername(username))
+            return res.json({
+                ...BaseStdResponse.ERR,
+                msg: '仓库名称不合法!'
+            })
+
+        // 检查 session
+        if (!await AccessControl.checkSession(uuid, session))
+            return res.status(401).json({
+                ...BaseStdResponse.ACCESS_DENIED
+            })
+
+        const time = new Date().getTime()
+        let sql = 'INSERT INTO repos (name, url, create_user, create_time) VALUES (?, ?, ?, ?)'
+
+        let result = await db.query(sql, [name, url, uuid, time])
+
+        if (result && result.affectedRows > 0) {
+            res.json({
+                ...BaseStdResponse.OK
+            })
+        } else {
+            res.json({ ...BaseStdResponse.ERR, endpoint: 7894378, msg: '添加仓库失败!' })
+        }
+    }
+}
+
+module.exports.AddRepo = AddRepo

+ 47 - 0
apis/Repos/GetRepoList.js

@@ -0,0 +1,47 @@
+const API = require("../../lib/API");
+const db = require("../../plugin/DataBase/db");
+const AccessControl = require("../../lib/AccessControl");
+const { BaseStdResponse } = require("../../BaseStdResponse");
+
+class GetRepoList extends API {
+    constructor() {
+        super();
+
+        this.setPath('/Repos/List')
+        this.setMethod('GET')
+    }
+
+    async onRequest(req, res) {
+        let {
+            uuid,
+            session
+        } = req.query
+
+        if ([uuid, session].some(value => value === '' || value === null || value === undefined))
+            return res.json({
+                ...BaseStdResponse.MISSING_PARAMETER
+            })
+
+        // 检查 session
+        if (!await AccessControl.checkSession(uuid, session))
+            return res.status(401).json({
+                ...BaseStdResponse.ACCESS_DENIED
+            })
+
+        let sql = 'SELECT * FROM repos WHERE create_user = ?'
+        let rows = await db.query(sql, [uuid])
+
+        if (!rows)
+            return res.json({
+                ...BaseStdResponse.MISSING_FILE,
+                msg: '获取仓库列表失败!'
+            })
+
+        res.json({
+            ...BaseStdResponse.OK,
+            data: rows
+        })
+    }
+}
+
+module.exports.GetRepoList = GetRepoList;

+ 106 - 0
apis/Upload/UploadAvatar.js

@@ -0,0 +1,106 @@
+const API = require("../../lib/API");
+const { v4: uuidv4 } = require('uuid');
+const { BaseStdResponse } = require("../../BaseStdResponse");
+const db = require("../../plugin/DataBase/db");
+const AccessControl = require("../../lib/AccessControl");
+const multer = require('multer');
+const path = require('path');
+
+const { url } = require("../../config.json")
+
+// 配置Multer的存储选项
+const storage = multer.diskStorage({
+    destination: (req, file, cb) => {
+        cb(null, 'uploads/');
+    },
+    filename: (req, file, cb) => {
+        const fileName = uuidv4();
+        const fileExtension = path.extname(file.originalname);
+        cb(null, `${fileName}${fileExtension}`);
+    }
+});
+
+// 限制文件类型
+const fileFilter = (req, file, cb) => {
+    // 只接受以下扩展名的图片文件
+    const allowedTypes = /jpeg|jpg|png|gif/;
+    const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
+    const mimetype = allowedTypes.test(file.mimetype);
+
+    if (extname && mimetype) {
+        return cb(null, true);
+    } else {
+        cb(new Error('只允许上传图片文件 (jpeg, jpg, png, gif)'));
+    }
+};
+
+// 初始化Multer中间件
+const upload = multer({
+    storage: storage,
+    fileFilter: fileFilter,
+    limits: { fileSize: 3 * 1024 * 1024 } // 限制文件大小为3MB
+}).single('upload');
+
+class UploadAvatar extends API {
+    constructor() {
+        super();
+
+        this.setMethod("POST");
+        this.setPath("/UploadAvatar");
+    }
+
+    async onRequest(req, res) {
+        // 使用Multer中间件处理文件上传
+        upload(req, res, async (err) => {
+            if (err) {
+                this.logger.error(`图片上传失败!${err.stack || ''}`)
+                return res.json({
+                    ...BaseStdResponse.ERR,
+                    msg: '图片上传失败!'
+                });
+            }
+
+            let { uuid, session } = req.body
+
+            if ([uuid, session].some(value => value === '' || value === null || value === undefined)) {
+                return res.json({
+                    ...BaseStdResponse.MISSING_PARAMETER,
+                    endpoint: 1513126
+                });
+            }
+
+            if (!await AccessControl.checkSession(uuid, session)) {
+                return res.status(401).json({
+                    ...BaseStdResponse.ACCESS_DENIED,
+                    endpoint: 481545
+                });
+            }
+
+            if (!req.file) {
+                return res.json({
+                    ...BaseStdResponse.MISSING_PARAMETER,
+                    msg: '请上传图片文件'
+                });
+            }
+
+            const picturePath = url + req.file.filename; // 获取文件路径
+
+            let sql = 'UPDATE users SET avatar = ? WHERE uuid = ?'
+            let r = await db.query(sql, [picturePath, uuid])
+            if (r && r.affectedRows > 0)
+                return res.json({
+                    ...BaseStdResponse.OK,
+                    data: {
+                        picturePath
+                    }
+                });
+
+            res.json({
+                ...BaseStdResponse.ERR,
+                msg: '上传头像失败!'
+            })
+        });
+    }
+}
+
+module.exports.UploadAvatar = UploadAvatar;

+ 65 - 0
apis/User/BindEmail.js

@@ -0,0 +1,65 @@
+const API = require("../../lib/API");
+const db = require("../../plugin/DataBase/db");
+const { BaseStdResponse } = require("../../BaseStdResponse");
+const Redis = require('../../plugin/DataBase/Redis');
+const sendEmail = require('../../plugin/Email/Email');
+const AccessControl = require("../../lib/AccessControl");
+
+class BindEmail extends API {
+    constructor() {
+        super();
+
+        this.setMethod("POST");
+        this.setPath("/User/BindEmail");
+    }
+
+    async onRequest(req, res) {
+        let { uuid, session, email, code } = req.body;
+
+        if ([uuid, session, email, code].some(value => value === '' || value === null || value === undefined)) {
+            return res.json({
+                ...BaseStdResponse.MISSING_PARAMETER,
+                endpoint: 1513126
+            });
+        }
+
+        // 检查 session
+        if (!await AccessControl.checkSession(uuid, session))
+            return res.status(401).json({
+                ...BaseStdResponse.ACCESS_DENIED
+            })
+
+
+        const VerifyCode = await Redis.get(`email:${email}`);
+        if (!VerifyCode || VerifyCode != code)
+            return res.json({
+                ...BaseStdResponse.SMS_CHECK_FAIL,
+                msg: '邮箱验证码输入错误或已过期'
+            })
+
+        let sql = 'SELECT email FROM users WHERE email = ?';
+        let EmailRows = await db.query(sql, [email]);
+        if (EmailRows.length > 0)
+            return res.json({
+                ...BaseStdResponse.USER_ALREADY_EXISTS,
+                msg: '该邮箱已被注册!'
+            })
+
+        sql = 'UPDATE users SET email = ? WHERE uuid = ?';
+        let result = await db.query(sql, [email, uuid]);
+
+        if (result && result.affectedRows > 0) {
+            // 注册成功后删除邮箱对应的验证码 避免注册失败后重复获取
+            await Redis.del(`email:${email}`);
+
+            res.json({
+                ...BaseStdResponse.OK
+            });
+            await sendEmail(email, '换绑邮箱成功', `您的GitNexus账号换绑邮箱成功,操作时间:${new Date().toLocaleString()}`);
+        } else {
+            res.json({ ...BaseStdResponse.ERR, endpoint: 7894378, msg: '操作失败!' });
+        }
+    }
+}
+
+module.exports.BindEmail = BindEmail;

+ 47 - 0
apis/User/GetUserInfo.js

@@ -0,0 +1,47 @@
+const API = require("../../lib/API");
+const db = require("../../plugin/DataBase/db");
+const AccessControl = require("../../lib/AccessControl");
+const { BaseStdResponse } = require("../../BaseStdResponse");
+
+class GetRepoList extends API {
+    constructor() {
+        super();
+
+        this.setPath('/User/Info')
+        this.setMethod('GET')
+    }
+
+    async onRequest(req, res) {
+        let {
+            uuid,
+            session
+        } = req.query
+
+        if ([uuid, session].some(value => value === '' || value === null || value === undefined))
+            return res.json({
+                ...BaseStdResponse.MISSING_PARAMETER
+            })
+
+        // 检查 session
+        if (!await AccessControl.checkSession(uuid, session))
+            return res.status(401).json({
+                ...BaseStdResponse.ACCESS_DENIED
+            })
+
+        let sql = 'SELECT uuid, session, password, username, permission AS roles, avatar, email FROM users WHERE uuid = ?'
+        let rows = await db.query(sql, [uuid])
+
+        if (!rows || rows.length === 0)
+            return res.json({
+                ...BaseStdResponse.MISSING_FILE,
+                msg: '获取用户信息失败!'
+            })
+
+        res.json({
+            ...BaseStdResponse.OK,
+            data: rows[0]
+        })
+    }
+}
+
+module.exports.GetRepoList = GetRepoList;

+ 23 - 0
config-example.json

@@ -0,0 +1,23 @@
+{
+    "port": 30000,
+    "database": {
+        "host": "localhost",
+        "database": "gitnexus",
+        "port": 3306,
+        "user": "gitnexus",
+        "password": ""
+    },
+    "redis": {
+        "host": "localhost",
+        "port": 5173,
+        "password": ""
+    },
+    "email": {
+        "host": "smtp.exmail.qq.com",
+        "port": 465,
+        "secure": true,
+        "user": "",
+        "password": ""
+    },
+    "url": "https://cd1-api.gitnexus.cn/"
+}

+ 1 - 1
config.json

@@ -19,5 +19,5 @@
         "user": "mail@ctbu.top",
         "password": "FPhxUVrt5J9WxgiP"
     },
-    "url": "https://cd1-api.gitnexus.cn/"
+    "url": "http://localhost:30000/"
 }