diff --git a/backend/src/file.ts b/backend/src/file.ts index 7e77582..9a0d63f 100644 --- a/backend/src/file.ts +++ b/backend/src/file.ts @@ -74,4 +74,47 @@ router.get("/download", authenticate, (req, res) => { } }); +// 删除文件接口 +router.delete("/delete/:room/:filename", authenticate, (req, res) => { + // 获取路径参数 + const { room, filename } = req.params; + + // 校验参数 + if (!room || !filename) { + return res.status(422).send("422 Unprocessable Entity: Missing room or filename"); + } + + // 路径安全过滤 + const safeRoom = path.normalize(room).replace(/^(\.\.[\/\\])+/, ''); + const safeFilename = path.normalize(filename).replace(/^(\.\.[\/\\])+/, ''); + + if (safeRoom !== room || safeFilename !== filename) { + return res.status(403).send("403 Forbidden: Invalid file path"); + } + + // 拼接文件在服务器上的真实路径 + const filePath = path.resolve(baseDir, safeRoom, safeFilename); + + // 检查文件是否存在并删除 + try { + if (!fs.existsSync(filePath)) { + return res.status(404).send("404 Not Found: File does not exist"); + } + + // fs.unlinkSync:同步删除文件 + fs.unlinkSync(filePath); + + // 返回删除成功消息 + return res.status(200).json({ + message: "File deleted successfully", + deletedFile: `${room}/${filename}`, + }); + + } catch (err) { + // 如果文件被占用、权限不足等,会进到这里 + console.error(err); + return res.status(500).send("500 Internal Server Error"); + } +}); + export default router; diff --git a/backend/src/index.ts b/backend/src/index.ts index af98f24..93eaafd 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -27,6 +27,8 @@ const client = new GraphQLClient( ); export const sdk = getSdk(client); +export const graphqlClient = client; + // Log all requests to the console, optional. app.use(morgan(process.env.NODE_ENV === "production" ? "combined" : "dev")); diff --git a/backend/src/user.ts b/backend/src/user.ts index a93bd91..04ff242 100644 --- a/backend/src/user.ts +++ b/backend/src/user.ts @@ -1,6 +1,7 @@ import express from "express"; import jwt from "jsonwebtoken"; import { sdk as graphql } from "./index"; +import { graphqlClient } from "./index"; interface userJWTPayload { uuid: string; @@ -71,4 +72,56 @@ router.post("/register", async (req, res) => { } }); +// 删除用户接口 (痕迹抹除) + +router.post("/delete", async (req, res) => { + // 获取参数并校验 + const { uuid } = req.body; + + if (!uuid) { + return res.status(422).send("422 Unprocessable Entity: Missing user uuid"); + } + + // 执行 GraphQL 删除操作 + try { + const mutation = ` + mutation deleteUser($uuid: uuid!) { + delete_user(where: {uuid: {_eq: $uuid}}) { + affected_rows + returning { + uuid + username + } + } + } + `; + + // 调用 graphqlClient.request 发送请求 + const result = await graphqlClient.request<{ + delete_user: { + affected_rows: number; + returning: { uuid: string; username: string }[]; + }; + }>(mutation, { uuid }); + + // 处理结果 + // affected_rows 表示数据库中被影响(删除)的行数 + if (result.delete_user.affected_rows === 0) { + // 如果删除了 0 行,说明 uuid 不存在 + return res.status(404).send("404 Not Found: User does not exist"); + } + + // 删除成功,返回被删除的用户信息 + const deletedUser = result.delete_user.returning[0]; + return res.status(200).json({ + message: "User deleted successfully", + deletedUser: deletedUser, + }); + + } catch (err) { + // 异常捕获 + console.error(err); + return res.status(500).send("500 Internal Server Error"); + } +}); export default router;