Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions backend/src/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
2 changes: 2 additions & 0 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"));

Expand Down
53 changes: 53 additions & 0 deletions backend/src/user.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;