Commit 5efe1187 by Finley Ge Committed by GitHub

fix(service): set default expiration for invoked file uploads (#7279)

* fix(service): set default expiration for invoked file uploads

Update the invoke file upload logic to ignore the client-provided
expiration time and enforce a fixed 365-day expiry, ensuring consistent
storage cleanup behavior.

* test(service): mock system time in invoke tests

Use fake timers to ensure consistent file expiration time calculation.
parent e2ca301c
...@@ -16,6 +16,7 @@ import { getUserDetail } from '../user/controller'; ...@@ -16,6 +16,7 @@ import { getUserDetail } from '../user/controller';
import { MongoTeam } from '../user/team/teamSchema'; import { MongoTeam } from '../user/team/teamSchema';
import { InvokeFileUploadSchema, InvokeSessionSchema, type InvokeFileUploadType } from './type'; import { InvokeFileUploadSchema, InvokeSessionSchema, type InvokeFileUploadType } from './type';
import type { InvokeSessionType } from './type'; import type { InvokeSessionType } from './type';
import { addHours } from 'date-fns';
const INVOKE_TOKEN_EXPIRES_IN = 60 * 60; const INVOKE_TOKEN_EXPIRES_IN = 60 * 60;
...@@ -72,7 +73,7 @@ export class InvokeProcessor { ...@@ -72,7 +73,7 @@ export class InvokeProcessor {
const { appId, chatId, uId } = InvokeSessionSchema.parse(this._session); const { appId, chatId, uId } = InvokeSessionSchema.parse(this._session);
const { filename, body, contentType, expiredTime } = InvokeFileUploadSchema.parse(params); const { filename, body, contentType } = InvokeFileUploadSchema.parse(params);
const result = await getS3ChatSource().uploadChatFile({ const result = await getS3ChatSource().uploadChatFile({
sourceType: ChatSourceTypeEnum.app, sourceType: ChatSourceTypeEnum.app,
sourceId: appId, sourceId: appId,
...@@ -81,7 +82,7 @@ export class InvokeProcessor { ...@@ -81,7 +82,7 @@ export class InvokeProcessor {
filename, filename,
body, body,
contentType, contentType,
expiredTime expiredTime: addHours(new Date(), 365)
}); });
return { return {
......
...@@ -16,8 +16,7 @@ export type InvokeSessionType = z.infer<typeof InvokeSessionSchema>; ...@@ -16,8 +16,7 @@ export type InvokeSessionType = z.infer<typeof InvokeSessionSchema>;
export const InvokeFileUploadSchema = z.object({ export const InvokeFileUploadSchema = z.object({
filename: UploadFileByBodySchema.shape.filename, filename: UploadFileByBodySchema.shape.filename,
body: UploadFileByBodySchema.shape.body, body: UploadFileByBodySchema.shape.body,
contentType: UploadFileByBodySchema.shape.contentType, contentType: UploadFileByBodySchema.shape.contentType
expiredTime: UploadFileByBodySchema.shape.expiredTime
}); });
export type InvokeFileUploadType = z.infer<typeof InvokeFileUploadSchema>; export type InvokeFileUploadType = z.infer<typeof InvokeFileUploadSchema>;
import { beforeEach, describe, expect, it, vi } from 'vitest'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { PluginPermissionEnum } from '@fastgpt/global/sdk/fastgpt-plugin'; import { PluginPermissionEnum } from '@fastgpt/global/sdk/fastgpt-plugin';
import { ChatSourceTypeEnum } from '@fastgpt/global/core/chat/constants'; import { ChatSourceTypeEnum } from '@fastgpt/global/core/chat/constants';
...@@ -29,6 +29,8 @@ const createProcessor = () => ...@@ -29,6 +29,8 @@ const createProcessor = () =>
describe('InvokeProcessor.handleFileUpload', () => { describe('InvokeProcessor.handleFileUpload', () => {
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-01T00:00:00.000Z'));
mockGetToolFilePrefix.mockReturnValue('chat/app-1/user-1/chat-1'); mockGetToolFilePrefix.mockReturnValue('chat/app-1/user-1/chat-1');
mockUploadChatFile.mockResolvedValue({ mockUploadChatFile.mockResolvedValue({
key: 'chat/app-1/user-1/chat-1/image.png', key: 'chat/app-1/user-1/chat-1/image.png',
...@@ -40,6 +42,10 @@ describe('InvokeProcessor.handleFileUpload', () => { ...@@ -40,6 +42,10 @@ describe('InvokeProcessor.handleFileUpload', () => {
}); });
}); });
afterEach(() => {
vi.useRealTimers();
});
it('上传文件内容并返回最终访问 URL', async () => { it('上传文件内容并返回最终访问 URL', async () => {
const body = Buffer.from('image'); const body = Buffer.from('image');
const result = await createProcessor().handleFileUpload({ const result = await createProcessor().handleFileUpload({
...@@ -56,7 +62,7 @@ describe('InvokeProcessor.handleFileUpload', () => { ...@@ -56,7 +62,7 @@ describe('InvokeProcessor.handleFileUpload', () => {
filename: 'image.png', filename: 'image.png',
body, body,
contentType: 'image/png', contentType: 'image/png',
expiredTime: undefined expiredTime: new Date('2026-01-16T05:00:00.000Z')
}); });
expect(mockCreateUploadChatFileURL).not.toHaveBeenCalled(); expect(mockCreateUploadChatFileURL).not.toHaveBeenCalled();
expect(result).toEqual({ expect(result).toEqual({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment