From 4181650d7b96ca5dbabf960dc1b92980e5189c09 Mon Sep 17 00:00:00 2001 From: Alexander Alemayhu Date: Tue, 31 Dec 2024 05:10:16 +0100 Subject: [PATCH] chore: inform uploader of zip uploads with no valid files Signed-off-by: Alexander Alemayhu --- package-lock.json | 27 +++++++++++++++++---------- package.json | 4 ++-- src/lib/parser/ParserRules.test.ts | 27 --------------------------- src/lib/storage/checks.ts | 5 +++++ src/lib/zip/zip.tsx | 15 ++++++++++++++- 5 files changed, 38 insertions(+), 40 deletions(-) delete mode 100644 src/lib/parser/ParserRules.test.ts diff --git a/package-lock.json b/package-lock.json index c6f920aa..8cd9d7fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,8 +36,8 @@ "morgan": "^1.10.0", "multer": "^1.4.4-lts.1", "pg": "^8.11.3", - "react": "^18.2.0", - "react-dom": "^19.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "showdown": "^2.1.0", "stripe": "^16.8.0", "xlsx": "^0.18.5" @@ -11206,6 +11206,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -11214,14 +11215,16 @@ } }, "node_modules/react-dom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", - "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", "dependencies": { - "scheduler": "^0.25.0" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^19.0.0" + "react": "^18.3.1" } }, "node_modules/react-is": { @@ -11524,9 +11527,13 @@ } }, "node_modules/scheduler": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", - "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==" + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } }, "node_modules/selderee": { "version": "0.11.0", diff --git a/package.json b/package.json index 10169e06..db876be5 100644 --- a/package.json +++ b/package.json @@ -58,8 +58,8 @@ "morgan": "^1.10.0", "multer": "^1.4.4-lts.1", "pg": "^8.11.3", - "react": "^18.2.0", - "react-dom": "^19.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "showdown": "^2.1.0", "stripe": "^16.8.0", "xlsx": "^0.18.5" diff --git a/src/lib/parser/ParserRules.test.ts b/src/lib/parser/ParserRules.test.ts deleted file mode 100644 index 4bb1bd6a..00000000 --- a/src/lib/parser/ParserRules.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { getDatabase } from '../../data_layer'; -import ParserRules from './ParserRules'; - -jest.mock('../../data_layer', () => ({ - getDatabase: jest.fn(), -})); - -describe('ParserRules', () => { - it('should handle missing flashcard_is gracefully', async () => { - // Mock the database to return undefined - (getDatabase as jest.Mock).mockReturnValue(() => ({ - where: jest.fn().mockReturnValue({ - returning: jest.fn().mockReturnValue({ - first: jest.fn().mockResolvedValue(undefined), // Simulate missing data - }), - }), - })); - - try { - await ParserRules.Load('owner', 'id'); - } catch (error) { - const typedError = error as TypeError; - expect(typedError).toBeInstanceOf(TypeError); - expect(typedError.message).toContain('Cannot read properties of undefined'); - } - }); -}); \ No newline at end of file diff --git a/src/lib/storage/checks.ts b/src/lib/storage/checks.ts index 968e4926..16a09d49 100644 --- a/src/lib/storage/checks.ts +++ b/src/lib/storage/checks.ts @@ -60,3 +60,8 @@ export const isImageFile = (name: string) => name.toLowerCase().endsWith('.svg')); export const isXLSXFile = (fileName: string) => /.xlsx$/i.test(fileName); + +export const isHiddenFileOrDirectory = (fileName: string) => + fileName.startsWith('.') || + fileName.endsWith('/') || + fileName.startsWith('__MACOSX'); diff --git a/src/lib/zip/zip.tsx b/src/lib/zip/zip.tsx index 6596e712..a1653ca5 100644 --- a/src/lib/zip/zip.tsx +++ b/src/lib/zip/zip.tsx @@ -3,6 +3,7 @@ import { Body } from 'aws-sdk/clients/s3'; import { renderToStaticMarkup } from 'react-dom/server'; import { getUploadLimits } from '../misc/getUploadLimits'; import { + isHiddenFileOrDirectory, isHTMLFile, isImageFile, isMarkdownFile, @@ -62,14 +63,26 @@ class ZipHandler { try { const loadedZip = unzipSync(zipData, { - filter: (file) => !file.name.endsWith('/'), + filter: (file) => !isHiddenFileOrDirectory(file.name), }); + let noSuffixCount = 0; + const totalFiles = Object.keys(loadedZip).length; + for (const name in loadedZip) { const file = loadedZip[name]; + if (!name.includes('.')) { + noSuffixCount++; + } await this.handleFile(name, file, paying, settings); } + if (noSuffixCount === totalFiles) { + throw new Error( + 'The zip file contains only files with no suffix. Supported file types are: .zip, .html, .csv, .md, .pdf, .ppt, and .pptx.' + ); + } + this.addCombinedHTMLToFiles(paying, settings); } catch (error: unknown) { await this.handleZipError(error, zipData, paying);