post.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
  2. import { FileService } from '../../../modules/files/file.service';
  3. import { FileSchema, CreateFileDto } from '../../../modules/files/file.schema';
  4. import { ErrorSchema } from '../../../utils/errorHandler';
  5. import { AppDataSource } from '../../../data-source';
  6. import { AuthContext } from '../../../types/context';
  7. import { authMiddleware } from '../../../middleware/auth.middleware';
  8. import { parseWithAwait } from '../../../utils/parseWithAwait';
  9. // 创建文件上传策略响应Schema,不包含关联的uploadUser字段
  10. const CreateFileResponseSchema = z.object({
  11. file: z.object({
  12. id: z.number().int().positive().openapi({
  13. description: '文件ID',
  14. example: 1
  15. }),
  16. name: z.string().max(255).openapi({
  17. description: '文件名称',
  18. example: '项目计划书.pdf'
  19. }),
  20. type: z.string().max(50).nullable().openapi({
  21. description: '文件类型',
  22. example: 'application/pdf'
  23. }),
  24. size: z.number().int().positive().nullable().openapi({
  25. description: '文件大小,单位字节',
  26. example: 102400
  27. }),
  28. path: z.string().max(512).openapi({
  29. description: '文件存储路径',
  30. example: '/uploads/documents/2023/project-plan.pdf'
  31. }),
  32. description: z.string().nullable().openapi({
  33. description: '文件描述',
  34. example: '2023年度项目计划书'
  35. }),
  36. uploadUserId: z.number().int().positive().openapi({
  37. description: '上传用户ID',
  38. example: 1
  39. }),
  40. uploadTime: z.coerce.date().openapi({
  41. description: '上传时间',
  42. example: '2023-01-15T10:30:00Z'
  43. }),
  44. lastUpdated: z.date().nullable().openapi({
  45. description: '最后更新时间',
  46. example: '2023-01-16T14:20:00Z'
  47. }),
  48. createdAt: z.coerce.date().openapi({
  49. description: '创建时间',
  50. example: '2023-01-15T10:30:00Z'
  51. }),
  52. updatedAt: z.coerce.date().openapi({
  53. description: '更新时间',
  54. example: '2023-01-16T14:20:00Z'
  55. })
  56. }),
  57. uploadPolicy: z.object({
  58. 'x-amz-algorithm': z.string(),
  59. 'x-amz-credential': z.string(),
  60. 'x-amz-date': z.string(),
  61. 'x-amz-security-token': z.string().optional(),
  62. policy: z.string(),
  63. 'x-amz-signature': z.string(),
  64. host: z.string(),
  65. key: z.string(),
  66. bucket: z.string()
  67. })
  68. });
  69. // 创建文件上传策略路由
  70. const createUploadPolicyRoute = createRoute({
  71. method: 'post',
  72. path: '/',
  73. middleware: [authMiddleware],
  74. request: {
  75. body: {
  76. content: {
  77. 'application/json': { schema: CreateFileDto }
  78. }
  79. }
  80. },
  81. responses: {
  82. 200: {
  83. description: '生成文件上传策略成功',
  84. content: {
  85. 'application/json': {
  86. schema: CreateFileResponseSchema
  87. }
  88. }
  89. },
  90. 400: {
  91. description: '请求参数错误',
  92. content: { 'application/json': { schema: ErrorSchema } }
  93. },
  94. 500: {
  95. description: '服务器错误',
  96. content: { 'application/json': { schema: ErrorSchema } }
  97. }
  98. }
  99. });
  100. // 创建路由实例
  101. const app = new OpenAPIHono<AuthContext>().openapi(createUploadPolicyRoute, async (c) => {
  102. try {
  103. const data = await c.req.json();
  104. const user = c.get('user');
  105. // 创建文件服务实例
  106. const fileService = new FileService(AppDataSource);
  107. // 添加用户ID到文件数据
  108. const fileData = {
  109. ...data,
  110. uploadUserId: user.id,
  111. uploadTime: new Date()
  112. };
  113. const result = await fileService.createFile(fileData);
  114. const typedResult = await parseWithAwait(CreateFileResponseSchema, result);
  115. return c.json(typedResult, 200);
  116. } catch (error) {
  117. if (error instanceof z.ZodError) {
  118. return c.json({
  119. code: 400,
  120. message: '参数错误',
  121. errors: error.issues
  122. }, 400);
  123. }
  124. const message = error instanceof Error ? error.message : '生成上传策略失败';
  125. return c.json({ code: 500, message }, 500);
  126. }
  127. });
  128. export default app;