Skip to content

Commit 5d43b97

Browse files
authored
Merge pull request #7 from CrazyMrYan/feat/full/1.2.0
feat: #5 Feature - File details
2 parents 5b3428e + ea5f0c5 commit 5d43b97

2 files changed

Lines changed: 108 additions & 5 deletions

File tree

public/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
formData.append('file', file);
9090

9191
try {
92-
const response = await fetch(`${PUBLIC_NETWORK_DOMAIN}/upload?type=md&compress=false&isThumb=true&isPublic=true`, {
92+
const response = await fetch(`${PUBLIC_NETWORK_DOMAIN}/files?type=md&compress=false&isThumb=true&isPublic=true`, {
9393
method: 'POST',
9494
body: formData,
9595
});

routers/files.js

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const getDefaultThumbPath = (mime) => {
4444
};
4545

4646
// 处理文件上传
47-
router.post("/upload", async (ctx) => {
47+
router.post("/files", async (ctx) => {
4848
try {
4949
const files = ctx.request.files.file;
5050
const fileList = Array.isArray(files) ? files : [files];
@@ -83,7 +83,7 @@ router.post("/upload", async (ctx) => {
8383
}
8484
}
8585

86-
const fileUrl = `${process.env.PUBLIC_NETWORK_DOMAIN}/files/${fileId}`;
86+
const fileUrl = `${process.env.PUBLIC_NETWORK_DOMAIN}/files/${fileId}/preview`;
8787
const thumbUrl = shouldGenerateThumb ? `${fileUrl}?type=thumb` : null;
8888

8989
await File.create({
@@ -118,7 +118,7 @@ router.post("/upload", async (ctx) => {
118118
await fsp.unlink(file.filepath);
119119
}
120120
}
121-
121+
ctx.status(201);
122122
ctx.body = fileList.length > 1 ? responses : responses[0];
123123
} catch (error) {
124124
ctx.status = 500;
@@ -198,6 +198,56 @@ router.get("/files", async (ctx) => {
198198
// 获取单个文件信息
199199
router.get("/files/:id", async (ctx) => {
200200
const { id } = ctx.params;
201+
202+
try {
203+
const file = await File.findOne({
204+
where: {
205+
id,
206+
is_delete: false,
207+
is_public: true,
208+
[Op.or]: [
209+
{ public_expiration: null },
210+
{ public_expiration: { [Op.gt]: new Date() } },
211+
],
212+
},
213+
attributes: [
214+
"id",
215+
"filename",
216+
"is_delete",
217+
"is_public",
218+
"public_expiration",
219+
"is_thumb",
220+
"filesize",
221+
"filelocation",
222+
"thumb_location",
223+
"mime",
224+
"ext",
225+
"created_at",
226+
"created_by",
227+
"updated_at",
228+
"updated_by",
229+
],
230+
});
231+
232+
if (!file) {
233+
ctx.status = 404;
234+
ctx.body = { message: "File not found or not accessible" };
235+
return;
236+
}
237+
238+
ctx.body = file;
239+
240+
// 返回文件流
241+
} catch (error) {
242+
ctx.status = 500;
243+
ctx.body = { message: "Internal server error", error: error.message };
244+
console.error("Get file error:", error);
245+
}
246+
});
247+
248+
// 文件预览
249+
router.get("/files/:id/preview", async (ctx) => {
250+
const { id } = ctx.params;
201251
const { type } = ctx.query; // 获取查询参数 'type',可以是 'thumb' 或 'original'
202252

203253
try {
@@ -259,7 +309,60 @@ router.get("/files/:id", async (ctx) => {
259309
}
260310
});
261311

262-
router.get("/files:export", async (ctx) => {
312+
// 单文件下载
313+
router.get("/files/:id/export", async (ctx) => {
314+
const { id } = ctx.params;
315+
316+
try {
317+
const file = await File.findOne({
318+
where: {
319+
id: id,
320+
is_delete: false,
321+
[Op.or]: [
322+
{ public_expiration: null },
323+
{ public_expiration: { [Op.gt]: new Date() } },
324+
],
325+
},
326+
attributes: ["filename", "real_file_location", "ext"],
327+
});
328+
329+
if (!file) {
330+
ctx.status = 404;
331+
ctx.body = { message: "No valid files found for the provided id" };
332+
return;
333+
}
334+
// 单文件下载
335+
const filePath = file.real_file_location;
336+
const fileName = file.filename;
337+
338+
// 检查文件是否存在
339+
try {
340+
await fsp.access(filePath);
341+
} catch (err) {
342+
ctx.status = 404;
343+
ctx.body = { message: "File not found" };
344+
return;
345+
}
346+
const { mime } = await detectFileType(filePath);
347+
348+
// 设置响应头
349+
ctx.set("Content-Type", mime);
350+
ctx.set("Content-Disposition", `attachment; filename="${fileName}"`);
351+
352+
// 返回文件流
353+
ctx.body = fs.createReadStream(filePath);
354+
} catch (error) {
355+
ctx.status = 500;
356+
ctx.body = {
357+
message: "Error processing your download request",
358+
error: error.message,
359+
};
360+
console.error("Download error:", error);
361+
}
362+
});
363+
364+
// 批量下载
365+
router.get("/files/export", async (ctx) => {
263366
const fileIds = ctx.query.ids ? ctx.query.ids.split(",") : [];
264367

265368
if (fileIds.length === 0) {

0 commit comments

Comments
 (0)