feat: max files per upload (#991)

This commit is contained in:
diced
2026-03-03 23:52:53 -08:00
parent 281ab666c1
commit 056a19b946
10 changed files with 19 additions and 1 deletions

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "public"."Zipline" ADD COLUMN "filesMaxFilesPerUpload" INTEGER NOT NULL DEFAULT 1000;

View File

@@ -46,6 +46,7 @@ model Zipline {
filesRandomWordsNumAdjectives Int @default(2) filesRandomWordsNumAdjectives Int @default(2)
filesRandomWordsSeparator String @default("-") filesRandomWordsSeparator String @default("-")
filesDefaultCompressionFormat String? @default("jpg") filesDefaultCompressionFormat String? @default("jpg")
filesMaxFilesPerUpload Int @default(1000)
urlsRoute String @default("/go") urlsRoute String @default("/go")
urlsLength Int @default(6) urlsLength Int @default(6)

View File

@@ -8,7 +8,6 @@ export default function ActionButton({ onClick, Icon }: { onClick: () => void; I
<ActionIcon <ActionIcon
onClick={onClick} onClick={onClick}
variant='filled' variant='filled'
color='blue'
radius='md' radius='md'
size='xl' size='xl'
className='zip-click-action-button' className='zip-click-action-button'

View File

@@ -37,6 +37,7 @@ export default function Files({
filesRandomWordsNumAdjectives: number; filesRandomWordsNumAdjectives: number;
filesRandomWordsSeparator: string; filesRandomWordsSeparator: string;
filesDefaultCompressionFormat: string; filesDefaultCompressionFormat: string;
filesMaxFilesPerUpload: number;
}>({ }>({
initialValues: { initialValues: {
filesRoute: '/u', filesRoute: '/u',
@@ -52,6 +53,7 @@ export default function Files({
filesRandomWordsNumAdjectives: 3, filesRandomWordsNumAdjectives: 3,
filesRandomWordsSeparator: '-', filesRandomWordsSeparator: '-',
filesDefaultCompressionFormat: 'jpg', filesDefaultCompressionFormat: 'jpg',
filesMaxFilesPerUpload: 1000,
}, },
enhanceGetInputProps: (payload) => ({ enhanceGetInputProps: (payload) => ({
disabled: data?.tampered?.includes(payload.field) || false, disabled: data?.tampered?.includes(payload.field) || false,
@@ -110,6 +112,7 @@ export default function Files({
filesRandomWordsNumAdjectives: data.settings.filesRandomWordsNumAdjectives ?? 3, filesRandomWordsNumAdjectives: data.settings.filesRandomWordsNumAdjectives ?? 3,
filesRandomWordsSeparator: data.settings.filesRandomWordsSeparator ?? '-', filesRandomWordsSeparator: data.settings.filesRandomWordsSeparator ?? '-',
filesDefaultCompressionFormat: data.settings.filesDefaultCompressionFormat ?? 'jpg', filesDefaultCompressionFormat: data.settings.filesDefaultCompressionFormat ?? 'jpg',
filesMaxFilesPerUpload: data.settings.filesMaxFilesPerUpload ?? 1000,
}); });
}, [data]); }, [data]);
@@ -218,6 +221,13 @@ export default function Files({
]} ]}
{...form.getInputProps('filesDefaultCompressionFormat')} {...form.getInputProps('filesDefaultCompressionFormat')}
/> />
<NumberInput
label='Max Files Per Upload'
description='The maximum number of files allowed per upload. Requires a server restart.'
min={1}
{...form.getInputProps('filesMaxFilesPerUpload')}
/>
</SimpleGrid> </SimpleGrid>
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}> <Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>

View File

@@ -32,6 +32,7 @@ export const DATABASE_TO_PROP = {
filesRandomWordsNumAdjectives: 'files.randomWordsNumAdjectives', filesRandomWordsNumAdjectives: 'files.randomWordsNumAdjectives',
filesRandomWordsSeparator: 'files.randomWordsSeparator', filesRandomWordsSeparator: 'files.randomWordsSeparator',
filesDefaultCompressionFormat: 'files.defaultCompressionFormat', filesDefaultCompressionFormat: 'files.defaultCompressionFormat',
filesMaxFilesPerUpload: 'files.maxFilesPerUpload',
urlsRoute: 'urls.route', urlsRoute: 'urls.route',
urlsLength: 'urls.length', urlsLength: 'urls.length',

View File

@@ -65,6 +65,7 @@ export const ENVS = [
env('files.randomWordsNumAdjectives', 'FILES_RANDOM_WORDS_NUM_ADJECTIVES', 'number', true), env('files.randomWordsNumAdjectives', 'FILES_RANDOM_WORDS_NUM_ADJECTIVES', 'number', true),
env('files.randomWordsSeparator', 'FILES_RANDOM_WORDS_SEPARATOR', 'string', true), env('files.randomWordsSeparator', 'FILES_RANDOM_WORDS_SEPARATOR', 'string', true),
env('files.defaultCompressionFormat', 'FILES_DEFAULT_COMPRESSION_FORMAT', 'string', true), env('files.defaultCompressionFormat', 'FILES_DEFAULT_COMPRESSION_FORMAT', 'string', true),
env('files.maxFilesPerUpload', 'FILES_MAX_FILES_PER_UPLOAD', 'number', true),
env('urls.route', 'URLS_ROUTE', 'string', true), env('urls.route', 'URLS_ROUTE', 'string', true),
env('urls.length', 'URLS_LENGTH', 'number', true), env('urls.length', 'URLS_LENGTH', 'number', true),

View File

@@ -48,6 +48,7 @@ export const rawConfig: any = {
randomWordsNumAdjectives: undefined, randomWordsNumAdjectives: undefined,
randomWordsSeparator: undefined, randomWordsSeparator: undefined,
defaultCompressionFormat: undefined, defaultCompressionFormat: undefined,
maxFilesPerUpload: undefined,
}, },
urls: { urls: {
route: undefined, route: undefined,

View File

@@ -144,6 +144,7 @@ export const schema = z.object({
.enum(COMPRESS_TYPES) .enum(COMPRESS_TYPES)
.default('jpg') .default('jpg')
.refine((v) => checkOutput(v), 'System does not support outputting this image format.'), .refine((v) => checkOutput(v), 'System does not support outputting this image format.'),
maxFilesPerUpload: z.number().max(2147483647).min(1).default(1000),
}), }),
urls: z.object({ urls: z.object({
route: z.string().startsWith('/').min(1).trim().toLowerCase().default('/go'), route: z.string().startsWith('/').min(1).trim().toLowerCase().default('/go'),

View File

@@ -126,6 +126,7 @@ async function main() {
await server.register(fastifyMultipart, { await server.register(fastifyMultipart, {
limits: { limits: {
fileSize: bytes(config.files.maxFileSize), fileSize: bytes(config.files.maxFileSize),
parts: config.files.maxFilesPerUpload,
}, },
}); });

View File

@@ -200,6 +200,7 @@ export default typedPlugin(
filesDefaultCompressionFormat: z filesDefaultCompressionFormat: z
.enum(COMPRESS_TYPES) .enum(COMPRESS_TYPES)
.refine((v) => checkOutput(v), 'System does not support outputting this image format.'), .refine((v) => checkOutput(v), 'System does not support outputting this image format.'),
filesMaxFilesPerUpload: z.number().min(1).max(2147483647),
urlsRoute: z urlsRoute: z
.string() .string()