import { Hono } from "hono"; import debug from "debug"; import type { FileLibrary, } from "../client/share/types.ts"; import { DeleteStatus, EnableStatus, } from "../client/share/types.ts"; import type { Variables, WithAuth } from "./middlewares.ts"; const log = { api: debug("api:sys"), }; // 创建文件上传路由 export function createFileUploadRoutes(withAuth: WithAuth) { const fileUploadRoutes = new Hono<{ Variables: Variables }>(); // 获取 MinIO 上传策略 fileUploadRoutes.get("/policy", withAuth, async (c) => { try { const prefix = c.req.query("prefix") || "uploads/"; const filename = c.req.query("filename"); const maxSize = Number(c.req.query("maxSize")) || 10 * 1024 * 1024; // 默认10MB if (!filename) { return c.json({ error: "文件名不能为空" }, 400); } const apiClient = c.get('apiClient'); const policy = await apiClient.storage.getUploadPolicy( prefix, filename, maxSize ); return c.json({ message: "获取上传策略成功", data: policy, }); } catch (error) { log.api("获取上传策略失败:", error); return c.json({ error: "获取上传策略失败" }, 500); } }); // 保存文件信息到文件库 fileUploadRoutes.post("/save", withAuth, async (c) => { try { const fileData = (await c.req.json()) as Partial; const user = c.get("user"); // 验证必填字段 if (!fileData.file_name || !fileData.file_path || !fileData.file_type) { return c.json({ error: "文件名、路径和类型不能为空" }, 400); } const apiClient = c.get('apiClient'); // 设置上传者信息 if (user) { fileData.uploader_id = user.id; fileData.uploader_name = user.nickname || user.username; } // 插入文件库记录 const [id] = await apiClient.database.table("file_library").insert({ ...fileData, download_count: 0, is_disabled: EnableStatus.ENABLED, is_deleted: DeleteStatus.NOT_DELETED, created_at: apiClient.database.fn.now(), updated_at: apiClient.database.fn.now(), }); // 获取插入的数据 const [insertedFile] = await apiClient.database .table("file_library") .where("id", id); return c.json({ message: "文件信息保存成功", data: insertedFile, }); } catch (error) { log.api("保存文件信息失败:", error); return c.json({ error: "保存文件信息失败" }, 500); } }); // 获取文件列表 fileUploadRoutes.get("/list", withAuth, async (c) => { try { const page = Number(c.req.query("page")) || 1; const pageSize = Number(c.req.query("pageSize")) || 10; const category_id = c.req.query("category_id"); const fileType = c.req.query("fileType"); const keyword = c.req.query("keyword"); const apiClient = c.get('apiClient'); let query = apiClient.database .table("file_library") .where("is_deleted", DeleteStatus.NOT_DELETED) .orderBy("created_at", "desc"); // 应用过滤条件 if (category_id) { query = query.where("category_id", category_id); } if (fileType) { query = query.where("file_type", fileType); } if (keyword) { query = query.where((builder) => { builder .where("file_name", "like", `%${keyword}%`) .orWhere("description", "like", `%${keyword}%`) .orWhere("tags", "like", `%${keyword}%`); }); } // 获取总数 const total = await query.clone().count(); // 分页查询 const files = await query.limit(pageSize).offset((page - 1) * pageSize); return c.json({ message: "获取文件列表成功", data: { list: files, pagination: { current: page, pageSize, total: Number(total), }, }, }); } catch (error) { log.api("获取文件列表失败:", error); return c.json({ error: "获取文件列表失败" }, 500); } }); // 获取单个文件信息 fileUploadRoutes.get("/:id", withAuth, async (c) => { try { const id = Number(c.req.param("id")); if (!id || isNaN(id)) { return c.json({ error: "无效的文件ID" }, 400); } const apiClient = c.get('apiClient'); const file = await apiClient.database .table("file_library") .where("id", id) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (!file) { return c.json({ error: "文件不存在" }, 404); } return c.json({ message: "获取文件信息成功", data: file, }); } catch (error) { log.api("获取文件信息失败:", error); return c.json({ error: "获取文件信息失败" }, 500); } }); // 增加文件下载计数 fileUploadRoutes.post("/:id/download", withAuth, async (c) => { try { const id = Number(c.req.param("id")); if (!id || isNaN(id)) { return c.json({ error: "无效的文件ID" }, 400); } const apiClient = c.get('apiClient'); // 查询文件是否存在 const file = await apiClient.database .table("file_library") .where("id", id) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (!file) { return c.json({ error: "文件不存在" }, 404); } // 增加下载计数 await apiClient.database .table("file_library") .where("id", id) .update({ download_count: apiClient.database.raw("download_count + 1"), updated_at: apiClient.database.fn.now(), }); return c.json({ message: "更新下载计数成功", }); } catch (error) { log.api("更新下载计数失败:", error); return c.json({ error: "更新下载计数失败" }, 500); } }); // 删除文件 fileUploadRoutes.delete("/:id", withAuth, async (c) => { try { const id = Number(c.req.param("id")); if (!id || isNaN(id)) { return c.json({ error: "无效的文件ID" }, 400); } const apiClient = c.get('apiClient'); // 查询文件是否存在 const file = await apiClient.database .table("file_library") .where("id", id) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (!file) { return c.json({ error: "文件不存在" }, 404); } // 软删除文件 await apiClient.database.table("file_library").where("id", id).update({ is_deleted: DeleteStatus.DELETED, updated_at: apiClient.database.fn.now(), }); return c.json({ message: "文件删除成功", }); } catch (error) { log.api("删除文件失败:", error); return c.json({ error: "删除文件失败" }, 500); } }); return fileUploadRoutes; }