diff --git a/e2e-tests/playwright/package-lock.json b/e2e-tests/playwright/package-lock.json index 4ca2186ae5..ac36d99e15 100644 --- a/e2e-tests/playwright/package-lock.json +++ b/e2e-tests/playwright/package-lock.json @@ -19,7 +19,8 @@ "dotenv": "16.4.5", "form-data-encoder": "4.0.2", "formdata-node": "6.0.3", - "uuid": "11.0.3" + "uuid": "11.0.3", + "zod": "3.24.1" }, "devDependencies": { "@types/uuid": "10.0.0", @@ -2537,6 +2538,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } }, "dependencies": { @@ -4127,6 +4137,11 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true + }, + "zod": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==" } } } diff --git a/e2e-tests/playwright/package.json b/e2e-tests/playwright/package.json index bef58ce05d..a91cdc10b5 100644 --- a/e2e-tests/playwright/package.json +++ b/e2e-tests/playwright/package.json @@ -27,7 +27,8 @@ "dotenv": "16.4.5", "form-data-encoder": "4.0.2", "formdata-node": "6.0.3", - "uuid": "11.0.3" + "uuid": "11.0.3", + "zod": "3.24.1" }, "devDependencies": { "@types/uuid": "10.0.0", diff --git a/e2e-tests/playwright/support/file.ts b/e2e-tests/playwright/support/file.ts new file mode 100644 index 0000000000..c3ed26ebca --- /dev/null +++ b/e2e-tests/playwright/support/file.ts @@ -0,0 +1,65 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import path from 'node:path'; +import fs from 'node:fs'; + +const assetPath = path.resolve(__dirname, 'asset'); + +/** + * Reads file data and creates a File object. + * @param filePath - The path to the file. + * @param mimeType - The MIME type of the file. + * @returns A File object containing the file data. + * @throws If the file does not exist. + */ +export function getFileData(filePath: string, mimeType: string): File { + if (!fs.existsSync(filePath)) { + throw new Error(`File not found at path: ${filePath}`); + } + + const fileName = path.basename(filePath); + const fileBuffer = fs.readFileSync(filePath); + + return new File([fileBuffer], fileName, {type: mimeType}); +} + +/** + * Reads file data from the "asset" directory and creates a File object. + * @param filename - The name of the file in the "asset" directory. + * @param mimeType - The MIME type of the file. + * @returns An object containing a File object and the filename. + */ +export function getFileDataFromAsset(filename: string, mimeType: string) { + const filePath = path.join(assetPath, filename); + + return {file: getFileData(filePath, mimeType), filename: path.basename(filePath)}; +} + +/** + * Reads file data and creates a Blob object. + * @param filePath - The path to the file. + * @param mimeType - The MIME type of the file. + * @returns A Blob object containing the file data. + * @throws If the file does not exist. + */ +export function getBlobData(filePath: string, mimeType: string): Blob { + if (!fs.existsSync(filePath)) { + throw new Error(`File not found at path: ${filePath}`); + } + const fileBuffer = fs.readFileSync(filePath); + + return new Blob([fileBuffer], {type: mimeType}); +} + +/** + * Reads file data from the "asset" directory and creates a Blob object. + * @param filename - The name of the file in the "asset" directory. + * @param mimeType - The MIME type of the file. + * @returns An object containing a Blob object and the filename. + */ +export function getBlobDataFromAsset(filename: string, mimeType: string) { + const filePath = path.join(assetPath, filename); + + return {blob: getBlobData(filePath, mimeType), filename: path.basename(filePath)}; +} diff --git a/e2e-tests/playwright/support/server/init.ts b/e2e-tests/playwright/support/server/init.ts index 982d7cbbb1..aa15dfb2c2 100644 --- a/e2e-tests/playwright/support/server/init.ts +++ b/e2e-tests/playwright/support/server/init.ts @@ -1,11 +1,11 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import path from 'node:path'; import {expect} from '@playwright/test'; import {PreferenceType} from '@mattermost/types/preferences'; import testConfig from '@e2e-test.config'; +import {getFileDataFromAsset} from '@e2e-support/file'; import {makeClient} from '.'; import {getOnPremServerConfig} from './default_config'; @@ -42,9 +42,8 @@ export async function initSetup({ const {client: userClient} = await makeClient(user); if (withDefaultProfileImage) { - // Set user profile image - const fullPath = path.join(path.resolve(__dirname), '../', 'asset/mattermost-icon_128x128.png'); - await userClient.uploadProfileImageX(user.id, fullPath); + const {file} = getFileDataFromAsset('mattermost-icon_128x128.png', 'image/png'); + await userClient.uploadProfileImage(user.id, file); } // Update user preference diff --git a/e2e-tests/playwright/tests/client/schema.ts b/e2e-tests/playwright/tests/client/schema.ts new file mode 100644 index 0000000000..e07ae3d851 --- /dev/null +++ b/e2e-tests/playwright/tests/client/schema.ts @@ -0,0 +1,25 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {z} from 'zod'; + +const FileInfoSchema = z.object({ + id: z.string(), + user_id: z.string(), + channel_id: z.string(), + create_at: z.number().int(), + update_at: z.number().int(), + delete_at: z.number().int(), + name: z.string(), + extension: z.string(), + size: z.number().int(), + mime_type: z.string(), + mini_preview: z.nullable(z.any()), + remote_id: z.string(), + archived: z.boolean(), +}); + +export const FileUploadResponseSchema = z.object({ + file_infos: z.array(FileInfoSchema), + client_ids: z.array(z.string()), +}); diff --git a/e2e-tests/playwright/tests/client/upload_file.spec.ts b/e2e-tests/playwright/tests/client/upload_file.spec.ts new file mode 100644 index 0000000000..15620722f6 --- /dev/null +++ b/e2e-tests/playwright/tests/client/upload_file.spec.ts @@ -0,0 +1,140 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {expect, test} from '@e2e-support/test_fixture'; +import {getBlobDataFromAsset, getFileDataFromAsset} from '@e2e-support/file'; +import {getRandomId} from '@e2e-support/util'; +import {Client} from '@e2e-support/server'; +import {FileUploadResponse} from '@mattermost/types/files'; +import {ServerChannel} from '@mattermost/types/channels'; +import {Team} from '@mattermost/types/teams'; +import {UserProfile} from '@mattermost/types/users'; + +import {FileUploadResponseSchema} from './schema'; + +let userClient: Client; +let user: UserProfile; +let team: Team; +let townSquareChannel: ServerChannel; + +const filename = 'mattermost-icon_128x128.png'; +const mimeType = 'image/png'; +const {file} = getFileDataFromAsset(filename, mimeType); +const {blob} = getBlobDataFromAsset(filename, mimeType); + +test.beforeAll(async ({pw}) => { + ({userClient, user, team} = await pw.initSetup()); + townSquareChannel = await userClient.getChannelByName(team.id, 'town-square'); +}); + +test('should succeed with File', async () => { + // # Prepare data with File + const clientId = getRandomId(); + const formData = new FormData(); + formData.set('channel_id', townSquareChannel.id); + formData.set('client_ids', clientId); + formData.set('files', file, filename); + + // # Do upload then validate the response + const data = await userClient.uploadFile(formData); + validateFileUploadResponse(data, clientId, user.id, townSquareChannel.id); +}); + +test('should succeed with Blob', async () => { + // # Prepare data with Blob + const clientId = getRandomId(); + const formData = new FormData(); + formData.set('channel_id', townSquareChannel.id); + formData.set('client_ids', clientId); + formData.set('files', blob, filename); + + // # Do upload then validate the response + const data = await userClient.uploadFile(formData); + validateFileUploadResponse(data, clientId, user.id, townSquareChannel.id); +}); + +test('should succeed even with channel_id only', async () => { + // # Set without channel ID + const formData = new FormData(); + formData.set('channel_id', townSquareChannel.id); + + // # Do upload then validate the response + const data = await userClient.uploadFile(formData); + + // * Validate that it doe snot throw an error + const validate = () => FileUploadResponseSchema.parse(data); + expect(validate).not.toThrow(); + + // * Validate that file_infos and client_ids are as expected + expect(data.client_ids).toMatchObject([]); + expect(data.file_infos.length).toBe(0); +}); + +test('should fail on invalid channel ID', async () => { + const clientId = getRandomId(); + + // # Set with invalid channel ID + let formData = new FormData(); + formData.set('channel_id', 'invalid.channel.id'); + formData.set('client_ids', clientId); + formData.set('files', file, filename); + + await expect(userClient.uploadFile(formData)).rejects.toThrowError( + 'Invalid or missing channel_id parameter in request URL.', + ); + + // # Set without channel ID + formData = new FormData(); + formData.set('client_ids', clientId); + formData.set('files', file, filename); + + await expect(userClient.uploadFile(formData)).rejects.toThrowError( + 'Invalid or missing channel_id in request body.', + ); +}); + +test('should fail on missing files', async () => { + const clientId = getRandomId(); + + // # Set with invalid channel ID + const formData = new FormData(); + formData.set('channel_id', townSquareChannel.id); + formData.set('client_ids', clientId); + + await expect(userClient.uploadFile(formData)).rejects.toThrowError( + 'Unable to upload file(s). Have 1 client_ids for 0 files.', + ); +}); + +test('should fail on incorrect order setting up FormData', async () => { + const clientId = getRandomId(); + + // # Set with files before client_ids + const formData = new FormData(); + formData.set('channel_id', townSquareChannel.id); + formData.set('files', file, filename); + formData.set('client_ids', clientId); + + await expect(userClient.uploadFile(formData)).rejects.toThrowError( + 'Invalid or missing client_ids in request body.', + ); +}); + +function validateFileUploadResponse(data: FileUploadResponse, clientId: string, userId: string, channelId: string) { + // * Validate the schema + const validate = () => FileUploadResponseSchema.parse(data); + expect(validate).not.toThrow(); + + // * Validate that file_infos and client_ids are as expected + expect(data.client_ids).toMatchObject([clientId]); + expect(data.file_infos.length).toBe(1); + + // * Validate important contents of file_infos + const fileInfo = data.file_infos[0]; + expect(fileInfo.user_id).toBe(userId); + expect(fileInfo.channel_id).toBe(channelId); + expect(fileInfo.delete_at).toBe(0); + expect(fileInfo.extension).toBe('png'); + expect(fileInfo.mime_type).toBe('image/png'); + expect(fileInfo.archived).toBe(false); +} diff --git a/webapp/channels/src/components/__snapshots__/pdf_preview.test.tsx.snap b/webapp/channels/src/components/__snapshots__/pdf_preview.test.tsx.snap index 3ce5fe6b95..8e33644cd3 100644 --- a/webapp/channels/src/components/__snapshots__/pdf_preview.test.tsx.snap +++ b/webapp/channels/src/components/__snapshots__/pdf_preview.test.tsx.snap @@ -13,6 +13,7 @@ exports[`component/PDFPreview should match snapshot, not successful 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, diff --git a/webapp/channels/src/components/audio_video_preview/__snapshots__/audio_video_preview.test.tsx.snap b/webapp/channels/src/components/audio_video_preview/__snapshots__/audio_video_preview.test.tsx.snap index 52ecc99fb5..61d33f8d1d 100644 --- a/webapp/channels/src/components/audio_video_preview/__snapshots__/audio_video_preview.test.tsx.snap +++ b/webapp/channels/src/components/audio_video_preview/__snapshots__/audio_video_preview.test.tsx.snap @@ -19,6 +19,7 @@ exports[`AudioVideoPreview should match snapshot, cannot play 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, diff --git a/webapp/channels/src/components/file_attachment/__snapshots__/file_attachment.test.tsx.snap b/webapp/channels/src/components/file_attachment/__snapshots__/file_attachment.test.tsx.snap index 4c6ea4be71..d04e7d8524 100644 --- a/webapp/channels/src/components/file_attachment/__snapshots__/file_attachment.test.tsx.snap +++ b/webapp/channels/src/components/file_attachment/__snapshots__/file_attachment.test.tsx.snap @@ -18,6 +18,7 @@ exports[`FileAttachment should match snapshot, after change from file to image 1 fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -67,6 +68,7 @@ exports[`FileAttachment should match snapshot, after change from file to image 1 fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -112,6 +114,7 @@ exports[`FileAttachment should match snapshot, regular file 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -161,6 +164,7 @@ exports[`FileAttachment should match snapshot, regular file 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -238,6 +242,7 @@ exports[`FileAttachment should match snapshot, regular image 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -315,6 +320,7 @@ exports[`FileAttachment should match snapshot, small image 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -360,6 +366,7 @@ exports[`FileAttachment should match snapshot, svg image 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -409,6 +416,7 @@ exports[`FileAttachment should match snapshot, svg image 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -486,6 +494,7 @@ exports[`FileAttachment should match snapshot, when file is not loaded 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -530,6 +539,7 @@ exports[`FileAttachment should match snapshot, with compact display 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -575,6 +585,7 @@ exports[`FileAttachment should match snapshot, without compact display and witho fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, diff --git a/webapp/channels/src/components/file_attachment/file_attachment.test.tsx b/webapp/channels/src/components/file_attachment/file_attachment.test.tsx index eeefd89a2e..085b7477ba 100644 --- a/webapp/channels/src/components/file_attachment/file_attachment.test.tsx +++ b/webapp/channels/src/components/file_attachment/file_attachment.test.tsx @@ -41,6 +41,7 @@ describe('FileAttachment', () => { height: 80, has_preview_image: true, user_id: '', + channel_id: 'channel_id', create_at: 0, update_at: 0, delete_at: 0, diff --git a/webapp/channels/src/components/file_attachment/filename_overlay.test.tsx b/webapp/channels/src/components/file_attachment/filename_overlay.test.tsx index 52e9c701a7..fae32d1354 100644 --- a/webapp/channels/src/components/file_attachment/filename_overlay.test.tsx +++ b/webapp/channels/src/components/file_attachment/filename_overlay.test.tsx @@ -17,6 +17,7 @@ describe('components/file_attachment/FilenameOverlay', () => { height: 80, has_preview_image: true, user_id: '', + channel_id: 'channel_id', create_at: 0, update_at: 0, delete_at: 0, diff --git a/webapp/channels/src/components/file_preview/__snapshots__/file_preview.test.tsx.snap b/webapp/channels/src/components/file_preview/__snapshots__/file_preview.test.tsx.snap index 30d7a7f5fc..69e02dfbcc 100644 --- a/webapp/channels/src/components/file_preview/__snapshots__/file_preview.test.tsx.snap +++ b/webapp/channels/src/components/file_preview/__snapshots__/file_preview.test.tsx.snap @@ -36,6 +36,7 @@ exports[`FilePreview should match snapshot 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -82,6 +83,7 @@ exports[`FilePreview should match snapshot 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -140,6 +142,7 @@ exports[`FilePreview should match snapshot when props are changed 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -186,6 +189,7 @@ exports[`FilePreview should match snapshot when props are changed 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -244,6 +248,7 @@ exports[`FilePreview should match snapshot when props are changed 2`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, diff --git a/webapp/channels/src/components/file_preview/__snapshots__/file_progress_preview.test.tsx.snap b/webapp/channels/src/components/file_preview/__snapshots__/file_progress_preview.test.tsx.snap index 917b9d823c..e27dc5a49f 100644 --- a/webapp/channels/src/components/file_preview/__snapshots__/file_progress_preview.test.tsx.snap +++ b/webapp/channels/src/components/file_preview/__snapshots__/file_progress_preview.test.tsx.snap @@ -28,6 +28,7 @@ exports[`component/file_preview/file_progress_preview should match snapshot 1`] fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, @@ -112,6 +113,7 @@ exports[`component/file_preview/file_progress_preview snapshot for percent value fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "", "create_at": 0, "delete_at": 0, diff --git a/webapp/channels/src/components/file_preview/file_preview.test.tsx b/webapp/channels/src/components/file_preview/file_preview.test.tsx index fb0294d99d..404477d1f2 100644 --- a/webapp/channels/src/components/file_preview/file_preview.test.tsx +++ b/webapp/channels/src/components/file_preview/file_preview.test.tsx @@ -20,6 +20,7 @@ describe('FilePreview', () => { extension: 'png', has_preview_image: true, user_id: '', + channel_id: 'channel_id', create_at: 0, update_at: 0, delete_at: 0, @@ -41,6 +42,7 @@ describe('FilePreview', () => { id: 'file_id_1', has_preview_image: true, user_id: '', + channel_id: 'channel_id', create_at: 0, update_at: 0, delete_at: 0, diff --git a/webapp/channels/src/components/file_preview/file_progress_preview.test.tsx b/webapp/channels/src/components/file_preview/file_progress_preview.test.tsx index 953b8d1c10..4ab7c82a7c 100644 --- a/webapp/channels/src/components/file_preview/file_progress_preview.test.tsx +++ b/webapp/channels/src/components/file_preview/file_progress_preview.test.tsx @@ -19,6 +19,7 @@ describe('component/file_preview/file_progress_preview', () => { height: 80, has_preview_image: true, user_id: '', + channel_id: 'channel_id', create_at: 0, update_at: 0, delete_at: 0, diff --git a/webapp/channels/src/components/file_preview_modal/__snapshots__/file_preview_modal.test.tsx.snap b/webapp/channels/src/components/file_preview_modal/__snapshots__/file_preview_modal.test.tsx.snap index 9d023a9efa..6ca46b1d93 100644 --- a/webapp/channels/src/components/file_preview_modal/__snapshots__/file_preview_modal.test.tsx.snap +++ b/webapp/channels/src/components/file_preview_modal/__snapshots__/file_preview_modal.test.tsx.snap @@ -66,6 +66,7 @@ exports[`components/FilePreviewModal should fall back to default preview if plug fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -206,6 +207,7 @@ exports[`components/FilePreviewModal should match snapshot 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -346,6 +348,7 @@ exports[`components/FilePreviewModal should match snapshot for external file 1`] fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -486,6 +489,7 @@ exports[`components/FilePreviewModal should match snapshot when plugin overrides fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -547,6 +551,7 @@ exports[`components/FilePreviewModal should match snapshot when plugin overrides fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -664,6 +669,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -726,6 +732,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -815,6 +822,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded and showing f fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -877,6 +885,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded and showing f fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -966,6 +975,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with .js file fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1028,6 +1038,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with .js file fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1119,6 +1130,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with .m4a fil fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1180,6 +1192,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with .m4a fil fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1270,6 +1283,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with .mov fil fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1331,6 +1345,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with .mov fil fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1421,6 +1436,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with footer 1 fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1483,6 +1499,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with footer 1 fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1572,6 +1589,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with image 1` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1634,6 +1652,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with image 1` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1723,6 +1742,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with other fi fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -1784,6 +1804,7 @@ exports[`components/FilePreviewModal should match snapshot, loaded with other fi fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, diff --git a/webapp/channels/src/components/file_preview_modal/file_preview_modal_footer/__snapshots__/file_preview_modal_footer.test.tsx.snap b/webapp/channels/src/components/file_preview_modal/file_preview_modal_footer/__snapshots__/file_preview_modal_footer.test.tsx.snap index cce0a9b93c..77aca6f324 100644 --- a/webapp/channels/src/components/file_preview_modal/file_preview_modal_footer/__snapshots__/file_preview_modal_footer.test.tsx.snap +++ b/webapp/channels/src/components/file_preview_modal/file_preview_modal_footer/__snapshots__/file_preview_modal_footer.test.tsx.snap @@ -44,6 +44,7 @@ exports[`components/file_preview_modal/file_preview_modal_footer/FilePreviewModa fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -117,6 +118,7 @@ exports[`components/file_preview_modal/file_preview_modal_footer/FilePreviewModa fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, diff --git a/webapp/channels/src/components/file_preview_modal/file_preview_modal_header/__snapshots__/file_preview_modal_header.test.tsx.snap b/webapp/channels/src/components/file_preview_modal/file_preview_modal_header/__snapshots__/file_preview_modal_header.test.tsx.snap index 23ca45c7e9..f621980ddc 100644 --- a/webapp/channels/src/components/file_preview_modal/file_preview_modal_header/__snapshots__/file_preview_modal_header.test.tsx.snap +++ b/webapp/channels/src/components/file_preview_modal/file_preview_modal_header/__snapshots__/file_preview_modal_header.test.tsx.snap @@ -23,6 +23,7 @@ exports[`components/file_preview_modal/file_preview_modal_header/FilePreviewModa fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -64,6 +65,7 @@ exports[`components/file_preview_modal/file_preview_modal_header/FilePreviewModa fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, diff --git a/webapp/channels/src/components/file_search_results/__snapshots__/file_search_result_item.test.tsx.snap b/webapp/channels/src/components/file_search_results/__snapshots__/file_search_result_item.test.tsx.snap index a9266c1026..6690980a47 100644 --- a/webapp/channels/src/components/file_search_results/__snapshots__/file_search_result_item.test.tsx.snap +++ b/webapp/channels/src/components/file_search_results/__snapshots__/file_search_result_item.test.tsx.snap @@ -13,6 +13,7 @@ exports[`components/file_search_result/FileSearchResultItem should match snapsho fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -110,6 +111,7 @@ exports[`components/file_search_result/FileSearchResultItem should match snapsho fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -216,6 +218,7 @@ exports[`components/file_search_result/FileSearchResultItem should match snapsho fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -322,6 +325,7 @@ exports[`components/file_search_result/FileSearchResultItem should match snapsho fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, diff --git a/webapp/channels/src/components/single_image_view/__snapshots__/single_image_view.test.tsx.snap b/webapp/channels/src/components/single_image_view/__snapshots__/single_image_view.test.tsx.snap index f9ca68e61e..38adf53387 100644 --- a/webapp/channels/src/components/single_image_view/__snapshots__/single_image_view.test.tsx.snap +++ b/webapp/channels/src/components/single_image_view/__snapshots__/single_image_view.test.tsx.snap @@ -45,6 +45,7 @@ exports[`components/SingleImageView permalink preview should render with permali fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -120,6 +121,7 @@ exports[`components/SingleImageView should match snapshot 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -195,6 +197,7 @@ exports[`components/SingleImageView should match snapshot 2`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -274,6 +277,7 @@ exports[`components/SingleImageView should match snapshot, SVG image 1`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -353,6 +357,7 @@ exports[`components/SingleImageView should match snapshot, SVG image 2`] = ` fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, @@ -428,6 +433,7 @@ exports[`components/SingleImageView should set loaded state on callback of onIma fileInfo={ Object { "archived": false, + "channel_id": "channel_id", "clientId": "client_id", "create_at": 1, "delete_at": 1, diff --git a/webapp/channels/src/packages/mattermost-redux/test/test_helper.ts b/webapp/channels/src/packages/mattermost-redux/test/test_helper.ts index 53b9866252..b9a9ed1737 100644 --- a/webapp/channels/src/packages/mattermost-redux/test/test_helper.ts +++ b/webapp/channels/src/packages/mattermost-redux/test/test_helper.ts @@ -575,6 +575,7 @@ class TestHelper { return { id: '', user_id: '', + channel_id: 'channel_id', create_at: 0, update_at: 0, delete_at: 0, @@ -597,6 +598,7 @@ class TestHelper { files.push({ id: this.generateId(), user_id: 'user_id', + channel_id: 'channel_id', create_at: 1, update_at: 1, delete_at: 1, diff --git a/webapp/channels/src/utils/test_helper.ts b/webapp/channels/src/utils/test_helper.ts index 153eeb729b..e6d50e2663 100644 --- a/webapp/channels/src/utils/test_helper.ts +++ b/webapp/channels/src/utils/test_helper.ts @@ -360,6 +360,7 @@ export class TestHelper { const defaultFileInfo: FileInfo = { id: 'file_info_id', user_id: 'user_id', + channel_id: 'channel_id', create_at: 1, update_at: 1, delete_at: 1, diff --git a/webapp/package-lock.json b/webapp/package-lock.json index a93c1be0f8..e2b3253f92 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -8770,7 +8770,8 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true }, "node_modules/at-least-node": { "version": "1.0.0", @@ -10516,6 +10517,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -11767,6 +11769,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "engines": { "node": ">=0.4.0" } @@ -14079,6 +14082,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -20841,6 +20845,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -20852,6 +20857,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -28176,9 +28182,6 @@ "name": "@mattermost/client", "version": "9.3.0", "license": "MIT", - "dependencies": { - "form-data": "^4.0.0" - }, "devDependencies": { "@types/jest": "28.1.8", "jest": "27.1.0", diff --git a/webapp/platform/client/package.json b/webapp/platform/client/package.json index e6cbc24a19..4eb307c2a6 100644 --- a/webapp/platform/client/package.json +++ b/webapp/platform/client/package.json @@ -17,9 +17,6 @@ "url": "github:mattermost/mattermost", "directory": "webapp/platform/client" }, - "dependencies": { - "form-data": "^4.0.0" - }, "devDependencies": { "@types/jest": "28.1.8", "jest": "27.1.0", diff --git a/webapp/platform/client/src/client4.ts b/webapp/platform/client/src/client4.ts index 3add78f75f..14ff7fb905 100644 --- a/webapp/platform/client/src/client4.ts +++ b/webapp/platform/client/src/client4.ts @@ -3,7 +3,6 @@ /* eslint-disable max-lines */ -import FormData from 'form-data'; import { TrackPropertyUser, TrackPropertyUserAgent, TrackScheduledPostsFeature, diff --git a/webapp/platform/types/src/files.ts b/webapp/platform/types/src/files.ts index ff6712ddb3..4ecaddeaf1 100644 --- a/webapp/platform/types/src/files.ts +++ b/webapp/platform/types/src/files.ts @@ -4,6 +4,7 @@ export type FileInfo = { id: string; user_id: string; + channel_id: string; create_at: number; update_at: number; delete_at: number;