mirror of
https://github.com/diced/zipline.git
synced 2025-04-11 23:31:17 -05:00
Different EXT system. Locked vals now warn instead
This commit is contained in:
parent
e8ab4dec00
commit
000c22da30
20 changed files with 1349 additions and 1580 deletions
|
@ -1,5 +1,5 @@
|
|||
import { Response } from '@/lib/api/response';
|
||||
import { Group, SimpleGrid, Skeleton, Stack, Title } from '@mantine/core';
|
||||
import { Group, SimpleGrid, Skeleton, Stack, Title, Tooltip } from '@mantine/core';
|
||||
import useSWR from 'swr';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
|
@ -93,3 +93,42 @@ export default function DashboardSettings() {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function EnvTooltip(
|
||||
props: React.PropsWithChildren<{
|
||||
envVar: string;
|
||||
data: any;
|
||||
varKey: string;
|
||||
}>,
|
||||
) {
|
||||
const state = checkPropSafe(props);
|
||||
const enabled = state !== false;
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
label={
|
||||
enabled
|
||||
? `WARNING: The ${props.envVar} environment variable takes priority over this value. Currently "${state}"`
|
||||
: ''
|
||||
}
|
||||
color='red'
|
||||
events={{
|
||||
hover: enabled,
|
||||
focus: false,
|
||||
touch: false,
|
||||
}}
|
||||
>
|
||||
<div>{props.children}</div>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
function checkPropSafe(props: any): boolean | string {
|
||||
const data = props.data;
|
||||
if (data === undefined) return false;
|
||||
const locked = data.locked;
|
||||
if (locked === undefined) return false;
|
||||
const val = locked[props.varKey];
|
||||
if (val === undefined) return false;
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsChunks({
|
||||
swr: { data, isLoading },
|
||||
|
@ -39,39 +40,38 @@ export default function ServerSettingsChunks({
|
|||
<Title order={2}>Chunks</Title>
|
||||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<Switch
|
||||
mt='md'
|
||||
label='Enable Chunks'
|
||||
description='Enable chunked uploads.'
|
||||
disabled={data?.locked['chunksEnabled'] ? true : false}
|
||||
{...form.getInputProps('chunksEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='CHUNKS_ENABLED' data={data} varKey='chunksEnabled'>
|
||||
<Switch
|
||||
mt='md'
|
||||
label='Enable Chunks'
|
||||
description='Enable chunked uploads.'
|
||||
{...form.getInputProps('chunksEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Max Chunk Size'
|
||||
description='Maximum size of an upload before it is split into chunks.'
|
||||
placeholder='95mb'
|
||||
disabled={!form.values.chunksEnabled || data?.locked['chunksMax']}
|
||||
{...form.getInputProps('chunksMax')}
|
||||
/>
|
||||
<EnvTooltip envVar='CHUNKS_MAX' data={data} varKey='chunksMax'>
|
||||
<TextInput
|
||||
label={'Max Chunk Size'}
|
||||
description='Maximum size of an upload before it is split into chunks.'
|
||||
placeholder='95mb'
|
||||
disabled={!form.values.chunksEnabled}
|
||||
{...form.getInputProps('chunksMax')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Chunk Size'
|
||||
description='Size of each chunk.'
|
||||
placeholder='25mb'
|
||||
disabled={!form.values.chunksEnabled || data?.locked['chunksSize']}
|
||||
{...form.getInputProps('chunksSize')}
|
||||
/>
|
||||
<EnvTooltip envVar='CHUNKS_SIZE' data={data} varKey='chunksSize'>
|
||||
<TextInput
|
||||
label='Chunk Size'
|
||||
description='Size of each chunk.'
|
||||
placeholder='25mb'
|
||||
disabled={!form.values.chunksEnabled}
|
||||
{...form.getInputProps('chunksSize')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={data?.locked['chunksEnabled'] && data?.locked['chunksMax'] && data?.locked['chunksSize']}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsCore({
|
||||
swr: { data, isLoading },
|
||||
|
@ -49,43 +50,36 @@ export default function ServerSettingsCore({
|
|||
<Title order={2}>Core</Title>
|
||||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<Switch
|
||||
mt='md'
|
||||
label='Return HTTPS URLs'
|
||||
description='Return URLs with HTTPS protocol.'
|
||||
disabled={data?.locked['coreReturnHttpsUrls'] ? true : false}
|
||||
{...form.getInputProps('coreReturnHttpsUrls', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='CORE_RETURN_HTTPS_URLS' data={data} varKey='coreReturnHttpsUrls'>
|
||||
<Switch
|
||||
mt='md'
|
||||
label='Return HTTPS URLs'
|
||||
description='Return URLs with HTTPS protocol.'
|
||||
{...form.getInputProps('coreReturnHttpsUrls', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Default Domain'
|
||||
description='The domain to use when generating URLs. This value should not include the protocol.'
|
||||
placeholder='example.com'
|
||||
disabled={data?.locked['coreDefaultDomain']}
|
||||
{...form.getInputProps('coreDefaultDomain')}
|
||||
/>
|
||||
<EnvTooltip envVar='CORE_DEFAULT_DOMAIN' data={data} varKey='coreDefaultDomain'>
|
||||
<TextInput
|
||||
label='Default Domain'
|
||||
description='The domain to use when generating URLs. This value should not include the protocol.'
|
||||
placeholder='example.com'
|
||||
{...form.getInputProps('coreDefaultDomain')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Temporary Directory'
|
||||
description='The directory to store temporary files. If the path is invalid, certain functions may break. Requires a server restart.'
|
||||
placeholder='/tmp/zipline'
|
||||
disabled={data?.locked['coreTempDirectory']}
|
||||
{...form.getInputProps('coreTempDirectory')}
|
||||
/>
|
||||
<EnvTooltip envVar='CORE_TEMP_DIRECTORY' data={data} varKey='coreTempDirectory'>
|
||||
<TextInput
|
||||
label='Temporary Directory'
|
||||
description='The directory to store temporary files. If the path is invalid, certain functions may break. Requires a server restart.'
|
||||
placeholder='/tmp/zipline'
|
||||
{...form.getInputProps('coreTempDirectory')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
data?.locked['coreReturnHttpsUrls'] &&
|
||||
data?.locked['coreDefaultDomain'] &&
|
||||
data?.locked['coreTempDirectory']
|
||||
}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -16,6 +16,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
type DiscordEmbed = Record<string, any>;
|
||||
|
||||
|
@ -169,43 +170,36 @@ export default function ServerSettingsDiscord({
|
|||
<Title order={2}>Discord Webhook</Title>
|
||||
|
||||
<form onSubmit={formMain.onSubmit(onSubmitMain)}>
|
||||
<TextInput
|
||||
mt='md'
|
||||
label='Webhook URL'
|
||||
description='The Discord webhook URL to send notifications to'
|
||||
placeholder='https://discord.com/api/webhooks/...'
|
||||
disabled={data?.locked['discordWebhookUrl']}
|
||||
{...formMain.getInputProps('discordWebhookUrl')}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_WEBHOOK_URL' data={data} varKey='discordWebhookUrl'>
|
||||
<TextInput
|
||||
mt='md'
|
||||
label='Webhook URL'
|
||||
description='The Discord webhook URL to send notifications to'
|
||||
placeholder='https://discord.com/api/webhooks/...'
|
||||
{...formMain.getInputProps('discordWebhookUrl')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Username'
|
||||
description='The username to send notifications as'
|
||||
disabled={data?.locked['discordUsername']}
|
||||
{...formMain.getInputProps('discordUsername')}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_USERNAME' data={data} varKey='discordUsername'>
|
||||
<TextInput
|
||||
label='Username'
|
||||
description='The username to send notifications as'
|
||||
{...formMain.getInputProps('discordUsername')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Avatar URL'
|
||||
description='The avatar for the webhook'
|
||||
placeholder='https://example.com/avatar.png'
|
||||
disabled={data?.locked['discordAvatarUrl']}
|
||||
{...formMain.getInputProps('discordAvatarUrl')}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_AVATAR_URL' data={data} varKey='discordAvatarUrl'>
|
||||
<TextInput
|
||||
label='Avatar URL'
|
||||
description='The avatar for the webhook'
|
||||
placeholder='https://example.com/avatar.png'
|
||||
{...formMain.getInputProps('discordAvatarUrl')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
data?.locked['discordWebhookUrl'] &&
|
||||
data?.locked['discordUsername'] &&
|
||||
data?.locked['discordAvatarUrl']
|
||||
}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
@ -215,119 +209,112 @@ export default function ServerSettingsDiscord({
|
|||
<Title order={3}>On Upload</Title>
|
||||
|
||||
<form onSubmit={formOnUpload.onSubmit(onSubmitNotif('upload'))}>
|
||||
<TextInput
|
||||
mt='md'
|
||||
label='Webhook URL'
|
||||
description='The Discord webhook URL to send notifications to. If this is left blank, the main webhook url will be used'
|
||||
placeholder='https://discord.com/api/webhooks/...'
|
||||
disabled={data?.locked['discordOnUploadWebhookUrl']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadWebhookUrl')}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_ON_UPLOAD_WEBHOOK_URL' data={data} varKey='discordOnUploadWebhookUrl'>
|
||||
<TextInput
|
||||
mt='md'
|
||||
label='Webhook URL'
|
||||
description='The Discord webhook URL to send notifications to. If this is left blank, the main webhook url will be used'
|
||||
placeholder='https://discord.com/api/webhooks/...'
|
||||
{...formOnUpload.getInputProps('discordOnUploadWebhookUrl')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Username'
|
||||
description='The username to send notifications as. If this is left blank, the main username will be used'
|
||||
disabled={data?.locked['discordOnUploadUsername']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadUsername')}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_ON_UPLOAD_USERNAME' data={data} varKey='discordOnUploadUsername'>
|
||||
<TextInput
|
||||
label='Username'
|
||||
description='The username to send notifications as. If this is left blank, the main username will be used'
|
||||
{...formOnUpload.getInputProps('discordOnUploadUsername')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Avatar URL'
|
||||
description='The avatar for the webhook. If this is left blank, the main avatar will be used'
|
||||
placeholder='https://example.com/avatar.png'
|
||||
disabled={data?.locked['discordOnUploadAvatarUrl']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadAvatarUrl')}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_ON_UPLOAD_AVATAR_URL' data={data} varKey='discordOnUploadAvatarUrl'>
|
||||
<TextInput
|
||||
label='Avatar URL'
|
||||
description='The avatar for the webhook. If this is left blank, the main avatar will be used'
|
||||
placeholder='https://example.com/avatar.png'
|
||||
{...formOnUpload.getInputProps('discordOnUploadAvatarUrl')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Textarea
|
||||
mt='md'
|
||||
label='Content'
|
||||
description='The content of the notification. This can be blank, but at least one of the content or embed fields must be filled out'
|
||||
minRows={1}
|
||||
maxRows={7}
|
||||
disabled={data?.locked['discordOnUploadContent']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadContent')}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_ON_UPLOAD_CONTENT' data={data} varKey='discordOnUploadContent'>
|
||||
<Textarea
|
||||
mt='md'
|
||||
label='Content'
|
||||
description='The content of the notification. This can be blank, but at least one of the content or embed fields must be filled out'
|
||||
minRows={1}
|
||||
maxRows={7}
|
||||
{...formOnUpload.getInputProps('discordOnUploadContent')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
mt='md'
|
||||
label='Embed'
|
||||
description='Send the notification as an embed. This will allow for more customization below.'
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbed', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_ON_UPLOAD_EMBED' data={data} varKey='discordOnUploadEmbed'>
|
||||
<Switch
|
||||
mt='md'
|
||||
label='Embed'
|
||||
description='Send the notification as an embed. This will allow for more customization below.'
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbed', { type: 'checkbox' })}
|
||||
/>
|
||||
|
||||
<Collapse in={formOnUpload.values.discordOnUploadEmbed}>
|
||||
<Paper withBorder p='sm' mt='md'>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Title'
|
||||
description='The title of the embed'
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedTitle')}
|
||||
/>
|
||||
<Collapse in={formOnUpload.values.discordOnUploadEmbed}>
|
||||
<Paper withBorder p='sm' mt='md'>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Title'
|
||||
description='The title of the embed'
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedTitle')}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label='Description'
|
||||
description='The description of the embed'
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedDescription')}
|
||||
/>
|
||||
<TextInput
|
||||
label='Description'
|
||||
description='The description of the embed'
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedDescription')}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label='Footer'
|
||||
description='The footer of the embed'
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedFooter')}
|
||||
/>
|
||||
<TextInput
|
||||
label='Footer'
|
||||
description='The footer of the embed'
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedFooter')}
|
||||
/>
|
||||
|
||||
<ColorInput
|
||||
label='Color'
|
||||
description='The color of the embed'
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedColor')}
|
||||
/>
|
||||
<ColorInput
|
||||
label='Color'
|
||||
description='The color of the embed'
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedColor')}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label='Thumbnail'
|
||||
description="Show the thumbnail (it will show the file if it's an image) in the embed"
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedThumbnail', { type: 'checkbox' })}
|
||||
/>
|
||||
<Switch
|
||||
label='Thumbnail'
|
||||
description="Show the thumbnail (it will show the file if it's an image) in the embed"
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedThumbnail', { type: 'checkbox' })}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label='Image/Video'
|
||||
description='Show the image or video in the embed'
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedImageOrVideo', { type: 'checkbox' })}
|
||||
/>
|
||||
<Switch
|
||||
label='Image/Video'
|
||||
description='Show the image or video in the embed'
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedImageOrVideo', {
|
||||
type: 'checkbox',
|
||||
})}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label='Timestamp'
|
||||
description='Show the timestamp in the embed'
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedTimestamp', { type: 'checkbox' })}
|
||||
/>
|
||||
<Switch
|
||||
label='Timestamp'
|
||||
description='Show the timestamp in the embed'
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedTimestamp', { type: 'checkbox' })}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label='URL'
|
||||
description='Makes the title clickable and links to the URL of the file'
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedUrl', { type: 'checkbox' })}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
</Paper>
|
||||
</Collapse>
|
||||
<Switch
|
||||
label='URL'
|
||||
description='Makes the title clickable and links to the URL of the file'
|
||||
{...formOnUpload.getInputProps('discordOnUploadEmbedUrl', { type: 'checkbox' })}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
</Paper>
|
||||
</Collapse>
|
||||
</EnvTooltip>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={data?.locked['discordOnUploadEmbed']}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
@ -337,105 +324,106 @@ export default function ServerSettingsDiscord({
|
|||
<Title order={3}>On Shorten</Title>
|
||||
|
||||
<form onSubmit={formOnShorten.onSubmit(onSubmitNotif('shorten'))}>
|
||||
<TextInput
|
||||
mt='md'
|
||||
label='Webhook URL'
|
||||
description='The Discord webhook URL to send notifications to. If this is left blank, the main webhook url will be used'
|
||||
placeholder='https://discord.com/api/webhooks/...'
|
||||
disabled={data?.locked['discordOnShortenWebhookUrl']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenWebhookUrl')}
|
||||
/>
|
||||
<EnvTooltip
|
||||
envVar='DISCORD_ON_SHORTEN_WEBHOOK_URL'
|
||||
data={data}
|
||||
varKey='discordOnShortenWebhookUrl'
|
||||
>
|
||||
<TextInput
|
||||
mt='md'
|
||||
label='Webhook URL'
|
||||
description='The Discord webhook URL to send notifications to. If this is left blank, the main webhook url will be used'
|
||||
placeholder='https://discord.com/api/webhooks/...'
|
||||
{...formOnShorten.getInputProps('discordOnShortenWebhookUrl')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Username'
|
||||
description='The username to send notifications as. If this is left blank, the main username will be used'
|
||||
disabled={data?.locked['discordOnShortenUsername']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenUsername')}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_ON_SHORTEN_USERNAME' data={data} varKey='discordOnShortenUsername'>
|
||||
<TextInput
|
||||
label='Username'
|
||||
description='The username to send notifications as. If this is left blank, the main username will be used'
|
||||
{...formOnShorten.getInputProps('discordOnShortenUsername')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Avatar URL'
|
||||
description='The avatar for the webhook. If this is left blank, the main avatar will be used'
|
||||
placeholder='https://example.com/avatar.png'
|
||||
disabled={data?.locked['discordOnShortenAvatarUrl']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenAvatarUrl')}
|
||||
/>
|
||||
<EnvTooltip
|
||||
envVar='DISCORD_ON_SHORTEN_AVATAR_URL'
|
||||
data={data}
|
||||
varKey='discordOnShortenAvatarUrl'
|
||||
>
|
||||
<TextInput
|
||||
label='Avatar URL'
|
||||
description='The avatar for the webhook. If this is left blank, the main avatar will be used'
|
||||
placeholder='https://example.com/avatar.png'
|
||||
{...formOnShorten.getInputProps('discordOnShortenAvatarUrl')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Textarea
|
||||
mt='md'
|
||||
label='Content'
|
||||
description='The content of the notification. This can be blank, but at least one of the content or embed fields must be filled out'
|
||||
minRows={1}
|
||||
maxRows={7}
|
||||
disabled={data?.locked['discordOnShortenContent']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenContent')}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_ON_SHORTEN_CONTENT' data={data} varKey='discordOnShortenContent'>
|
||||
<Textarea
|
||||
mt='md'
|
||||
label='Content'
|
||||
description='The content of the notification. This can be blank, but at least one of the content or embed fields must be filled out'
|
||||
minRows={1}
|
||||
maxRows={7}
|
||||
{...formOnShorten.getInputProps('discordOnShortenContent')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
mt='md'
|
||||
label='Embed'
|
||||
description='Send the notification as an embed. This will allow for more customization below.'
|
||||
disabled={data?.locked['discordOnShortenEmbed']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbed', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='DISCORD_ON_SHORTEN_EMBED' data={data} varKey='discordOnShortenEmbed'>
|
||||
<Switch
|
||||
mt='md'
|
||||
label='Embed'
|
||||
description='Send the notification as an embed. This will allow for more customization below.'
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbed', { type: 'checkbox' })}
|
||||
/>
|
||||
|
||||
<Collapse in={formOnShorten.values.discordOnShortenEmbed}>
|
||||
<Paper withBorder p='sm' mt='md'>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Title'
|
||||
description='The title of the embed'
|
||||
disabled={data?.locked['discordOnShortenEmbed']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedTitle')}
|
||||
/>
|
||||
<Collapse in={formOnShorten.values.discordOnShortenEmbed}>
|
||||
<Paper withBorder p='sm' mt='md'>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Title'
|
||||
description='The title of the embed'
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedTitle')}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label='Description'
|
||||
description='The description of the embed'
|
||||
disabled={data?.locked['discordOnShortenEmbed']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedDescription')}
|
||||
/>
|
||||
<TextInput
|
||||
label='Description'
|
||||
description='The description of the embed'
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedDescription')}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label='Footer'
|
||||
description='The footer of the embed'
|
||||
disabled={data?.locked['discordOnShortenEmbed']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedFooter')}
|
||||
/>
|
||||
<TextInput
|
||||
label='Footer'
|
||||
description='The footer of the embed'
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedFooter')}
|
||||
/>
|
||||
|
||||
<ColorInput
|
||||
label='Color'
|
||||
description='The color of the embed'
|
||||
disabled={data?.locked['discordOnShortenEmbed']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedColor')}
|
||||
/>
|
||||
<ColorInput
|
||||
label='Color'
|
||||
description='The color of the embed'
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedColor')}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label='Timestamp'
|
||||
description='Show the timestamp in the embed'
|
||||
disabled={data?.locked['discordOnShortenEmbed']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedTimestamp', { type: 'checkbox' })}
|
||||
/>
|
||||
<Switch
|
||||
label='Timestamp'
|
||||
description='Show the timestamp in the embed'
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedTimestamp', { type: 'checkbox' })}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label='URL'
|
||||
description='Makes the title clickable and links to the URL of the file'
|
||||
disabled={data?.locked['discordOnShortenEmbed']}
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedUrl', { type: 'checkbox' })}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
</Paper>
|
||||
</Collapse>
|
||||
<Switch
|
||||
label='URL'
|
||||
description='Makes the title clickable and links to the URL of the file'
|
||||
{...formOnShorten.getInputProps('discordOnShortenEmbedUrl', { type: 'checkbox' })}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
</Paper>
|
||||
</Collapse>
|
||||
</EnvTooltip>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={data?.locked['discordOnShortenEmbed']}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsFeatures({
|
||||
swr: { data, isLoading },
|
||||
|
@ -54,106 +55,107 @@ export default function ServerSettingsFeatures({
|
|||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<Switch
|
||||
label='Image Compression'
|
||||
description='Allows the ability for users to compress images.'
|
||||
disabled={data?.locked['featuresImageCompression']}
|
||||
{...form.getInputProps('featuresImageCompression', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FEATURES_IMAGE_COMPRESSION' data={data} varKey='featuresImageCompression'>
|
||||
<Switch
|
||||
label='Image Compression'
|
||||
description='Allows the ability for users to compress images.'
|
||||
{...form.getInputProps('featuresImageCompression', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='/robots.txt'
|
||||
description='Enables a robots.txt file for search engine optimization. Requires a server restart.'
|
||||
disabled={data?.locked['featuresRobotsTxt']}
|
||||
{...form.getInputProps('featuresRobotsTxt', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FEATURES_ROBOTS_TXT' data={data} varKey='featuresRobotsTxt'>
|
||||
<Switch
|
||||
label='/robots.txt'
|
||||
description='Enables a robots.txt file for search engine optimization. Requires a server restart.'
|
||||
{...form.getInputProps('featuresRobotsTxt', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Healthcheck'
|
||||
description='Enables a healthcheck route for uptime monitoring. Requires a server restart.'
|
||||
disabled={data?.locked['featuresHealthcheck']}
|
||||
{...form.getInputProps('featuresHealthcheck', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FEATURES_HEALTHCHECK' data={data} varKey='featuresHealthcheck'>
|
||||
<Switch
|
||||
label='Healthcheck'
|
||||
description='Enables a healthcheck route for uptime monitoring. Requires a server restart.'
|
||||
{...form.getInputProps('featuresHealthcheck', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='User Registration'
|
||||
description='Allows users to register an account on the server.'
|
||||
disabled={data?.locked['featuresUserRegistration']}
|
||||
{...form.getInputProps('featuresUserRegistration', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FEATURES_USER_REGISTRATION' data={data} varKey='featuresUserRegistration'>
|
||||
<Switch
|
||||
label='User Registration'
|
||||
description='Allows users to register an account on the server.'
|
||||
{...form.getInputProps('featuresUserRegistration', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='OAuth Registration'
|
||||
description='Allows users to register an account using OAuth providers.'
|
||||
disabled={data?.locked['featuresOauthRegistration']}
|
||||
{...form.getInputProps('featuresOauthRegistration', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FEATURES_OAUTH_REGISTRATION' data={data} varKey='featuresOauthRegistration'>
|
||||
<Switch
|
||||
label='OAuth Registration'
|
||||
description='Allows users to register an account using OAuth providers.'
|
||||
{...form.getInputProps('featuresOauthRegistration', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Delete on Max Views'
|
||||
description='Automatically deletes files/urls after they reach the maximum view count. Requires a server restart.'
|
||||
disabled={data?.locked['featuresDeleteOnMaxViews']}
|
||||
{...form.getInputProps('featuresDeleteOnMaxViews', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FEATURES_DELETE_ON_MAX_VIEWS' data={data} varKey='featuresDeleteOnMaxViews'>
|
||||
<Switch
|
||||
label='Delete on Max Views'
|
||||
description='Automatically deletes files/urls after they reach the maximum view count. Requires a server restart.'
|
||||
{...form.getInputProps('featuresDeleteOnMaxViews', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Enable Metrics'
|
||||
description='Enables metrics for the server. Requires a server restart.'
|
||||
disabled={data?.locked['featuresMetricsEnabled']}
|
||||
{...form.getInputProps('featuresMetricsEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FEATURES_METRICS_ENABLED' data={data} varKey='featuresMetricsEnabled'>
|
||||
<Switch
|
||||
label='Enable Metrics'
|
||||
description='Enables metrics for the server. Requires a server restart.'
|
||||
{...form.getInputProps('featuresMetricsEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Admin Only Metrics'
|
||||
description='Requires an administrator to view metrics.'
|
||||
disabled={data?.locked['featuresMetricsAdminOnly']}
|
||||
{...form.getInputProps('featuresMetricsAdminOnly', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FEATURES_METRICS_ADMIN_ONLY' data={data} varKey='featuresMetricsAdminOnly'>
|
||||
<Switch
|
||||
label='Admin Only Metrics'
|
||||
description='Requires an administrator to view metrics.'
|
||||
{...form.getInputProps('featuresMetricsAdminOnly', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Show User Specific Metrics'
|
||||
description='Shows metrics specific to each user, for all users.'
|
||||
disabled={data?.locked['featuresMetricsShowUserSpecific']}
|
||||
{...form.getInputProps('featuresMetricsShowUserSpecific', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip
|
||||
envVar='FEATURES_METRICS_SHOW_USER_SPECIFIC'
|
||||
data={data}
|
||||
varKey='featuresMetricsShowUserSpecific'
|
||||
>
|
||||
<Switch
|
||||
label='Show User Specific Metrics'
|
||||
description='Shows metrics specific to each user, for all users.'
|
||||
{...form.getInputProps('featuresMetricsShowUserSpecific', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Enable Thumbnails'
|
||||
description='Enables thumbnail generation for images. Requires a server restart.'
|
||||
disabled={data?.locked['featuresThumbnailsEnabled']}
|
||||
{...form.getInputProps('featuresThumbnailsEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FEATURES_THUMBNAILS_ENABLED' data={data} varKey='featuresThumbnailsEnabled'>
|
||||
<Switch
|
||||
label='Enable Thumbnails'
|
||||
description='Enables thumbnail generation for images. Requires a server restart.'
|
||||
{...form.getInputProps('featuresThumbnailsEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<NumberInput
|
||||
label='Thumbnails Number Threads'
|
||||
description='Number of threads to use for thumbnail generation, usually the number of CPU threads. Requires a server restart.'
|
||||
placeholder='Enter a number...'
|
||||
min={1}
|
||||
max={16}
|
||||
disabled={data?.locked['featuresThumbnailsNumberThreads']}
|
||||
{...form.getInputProps('featuresThumbnailsNumberThreads')}
|
||||
/>
|
||||
<EnvTooltip
|
||||
envVar='FEATURES_THUMBNAILS_NUMBER_THREADS'
|
||||
data={data}
|
||||
varKey='featuresThumbnailsNumberThreads'
|
||||
>
|
||||
<NumberInput
|
||||
label='Thumbnails Number Threads'
|
||||
description='Number of threads to use for thumbnail generation, usually the number of CPU threads. Requires a server restart.'
|
||||
placeholder='Enter a number...'
|
||||
min={1}
|
||||
max={16}
|
||||
{...form.getInputProps('featuresThumbnailsNumberThreads')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
data?.locked['featuresImageCompression'] &&
|
||||
data?.locked['featuresRobotsTxt'] &&
|
||||
data?.locked['featuresHealthcheck'] &&
|
||||
data?.locked['featuresUserRegistration'] &&
|
||||
data?.locked['featuresOauthRegistration'] &&
|
||||
data?.locked['featuresDeleteOnMaxViews'] &&
|
||||
data?.locked['featuresThumbnailsEnabled'] &&
|
||||
data?.locked['featuresThumbnailsNumberThreads'] &&
|
||||
data?.locked['featuresMetricsEnabled'] &&
|
||||
data?.locked['featuresMetricsAdminOnly'] &&
|
||||
data?.locked['featuresMetricsShowUserSpecific']
|
||||
}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -15,6 +15,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsFiles({
|
||||
swr: { data, isLoading },
|
||||
|
@ -103,115 +104,112 @@ export default function ServerSettingsFiles({
|
|||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Route'
|
||||
description='The route to use for file uploads. Requires a server restart.'
|
||||
placeholder='/u'
|
||||
disabled={data?.locked['filesRoute']}
|
||||
{...form.getInputProps('filesRoute')}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_ROUTE' data={data} varKey='filesRoute'>
|
||||
<TextInput
|
||||
label='Route'
|
||||
description='The route to use for file uploads. Requires a server restart.'
|
||||
placeholder='/u'
|
||||
{...form.getInputProps('filesRoute')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<NumberInput
|
||||
label='Length'
|
||||
description='The length of the file name (for randomly generated names).'
|
||||
min={1}
|
||||
max={64}
|
||||
disabled={data?.locked['filesLength']}
|
||||
{...form.getInputProps('filesLength')}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_LENGTH' data={data} varKey='filesLength'>
|
||||
<NumberInput
|
||||
label='Length'
|
||||
description='The length of the file name (for randomly generated names).'
|
||||
min={1}
|
||||
max={64}
|
||||
{...form.getInputProps('filesLength')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Assume Mimetypes'
|
||||
description='Assume the mimetype of a file for its extension.'
|
||||
disabled={data?.locked['filesAssumeMimetypes']}
|
||||
{...form.getInputProps('filesAssumeMimetypes', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_ASSUME_MIMETYPES' data={data} varKey='filesAssumeMimetypes'>
|
||||
<Switch
|
||||
label='Assume Mimetypes'
|
||||
description='Assume the mimetype of a file for its extension.'
|
||||
{...form.getInputProps('filesAssumeMimetypes', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Remove GPS Metadata'
|
||||
description='Remove GPS metadata from files.'
|
||||
disabled={data?.locked['filesRemoveGpsMetadata']}
|
||||
{...form.getInputProps('filesRemoveGpsMetadata', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_REMOVE_GPS_METADATA' data={data} varKey='filesRemoveGpsMetadata'>
|
||||
<Switch
|
||||
label='Remove GPS Metadata'
|
||||
description='Remove GPS metadata from files.'
|
||||
{...form.getInputProps('filesRemoveGpsMetadata', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Select
|
||||
label='Default Format'
|
||||
description='The default format to use for file names.'
|
||||
placeholder='random'
|
||||
data={['random', 'date', 'uuid', 'name', 'gfycat']}
|
||||
disabled={data?.locked['filesDefaultFormat']}
|
||||
{...form.getInputProps('filesDefaultFormat')}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_DEFAULT_FORMAT' data={data} varKey='filesDefaultFormat'>
|
||||
<Select
|
||||
label='Default Format'
|
||||
description='The default format to use for file names.'
|
||||
placeholder='random'
|
||||
data={['random', 'date', 'uuid', 'name', 'gfycat']}
|
||||
{...form.getInputProps('filesDefaultFormat')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Disabled Extensions'
|
||||
description='Extensions to disable, separated by commas.'
|
||||
placeholder='exe, bat, sh'
|
||||
disabled={data?.locked['filesDisabledExtensions']}
|
||||
{...form.getInputProps('filesDisabledExtensions')}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_DISABLED_EXTENSIONS' data={data} varKey='filesDisabledExtensions'>
|
||||
<TextInput
|
||||
label='Disabled Extensions'
|
||||
description='Extensions to disable, separated by commas.'
|
||||
placeholder='exe, bat, sh'
|
||||
{...form.getInputProps('filesDisabledExtensions')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Max File Size'
|
||||
description='The maximum file size allowed.'
|
||||
placeholder='100mb'
|
||||
disabled={data?.locked['filesMaxFileSize']}
|
||||
{...form.getInputProps('filesMaxFileSize')}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_MAX_FILE_SIZE' data={data} varKey='filesMaxFileSize'>
|
||||
<TextInput
|
||||
label='Max File Size'
|
||||
description='The maximum file size allowed.'
|
||||
placeholder='100mb'
|
||||
{...form.getInputProps('filesMaxFileSize')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Default Expiration'
|
||||
description='The default expiration time for files.'
|
||||
placeholder='30d'
|
||||
disabled={data?.locked['filesDefaultExpiration']}
|
||||
{...form.getInputProps('filesDefaultExpiration')}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_DEFAULT_EXPIRATION' data={data} varKey='filesDefaultExpiration'>
|
||||
<TextInput
|
||||
label='Default Expiration'
|
||||
description='The default expiration time for files.'
|
||||
placeholder='30d'
|
||||
{...form.getInputProps('filesDefaultExpiration')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Default Date Format'
|
||||
description='The default date format to use.'
|
||||
placeholder='YYYY-MM-DD_HH:mm:ss'
|
||||
disabled={data?.locked['filesDefaultDateFormat']}
|
||||
{...form.getInputProps('filesDefaultDateFormat')}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_DEFAULT_DATE_FORMAT' data={data} varKey='filesDefaultDateFormat'>
|
||||
<TextInput
|
||||
label='Default Date Format'
|
||||
description='The default date format to use.'
|
||||
placeholder='YYYY-MM-DD_HH:mm:ss'
|
||||
{...form.getInputProps('filesDefaultDateFormat')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<NumberInput
|
||||
label='Random Words Num Adjectives'
|
||||
description='The number of adjectives to use for the random-words/gfycat format.'
|
||||
min={1}
|
||||
max={10}
|
||||
disabled={data?.locked['filesRandomWordsNumAdjectives']}
|
||||
{...form.getInputProps('filesRandomWordsNumAdjectives')}
|
||||
/>
|
||||
<EnvTooltip
|
||||
envVar='FILES_RANDOM_WORDS_NUM_ADJECTIVES'
|
||||
data={data}
|
||||
varKey='filesRandomWordsNumAdjectives'
|
||||
>
|
||||
<NumberInput
|
||||
label='Random Words Num Adjectives'
|
||||
description='The number of adjectives to use for the random-words/gfycat format.'
|
||||
min={1}
|
||||
max={10}
|
||||
{...form.getInputProps('filesRandomWordsNumAdjectives')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Random Words Separator'
|
||||
description='The separator to use for the random-words/gfycat format.'
|
||||
placeholder='-'
|
||||
disabled={data?.locked['filesRandomWordsSeparator']}
|
||||
{...form.getInputProps('filesRandomWordsSeparator')}
|
||||
/>
|
||||
<EnvTooltip envVar='FILES_RANDOM_WORDS_SEPARATOR' data={data} varKey='filesRandomWordsSeparator'>
|
||||
<TextInput
|
||||
label='Random Words Separator'
|
||||
description='The separator to use for the random-words/gfycat format.'
|
||||
placeholder='-'
|
||||
{...form.getInputProps('filesRandomWordsSeparator')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
data?.locked['filesRoute'] &&
|
||||
data?.locked['filesLength'] &&
|
||||
data?.locked['filesDefaultFormat'] &&
|
||||
data?.locked['filesDisabledExtensions'] &&
|
||||
data?.locked['filesMaxFileSize'] &&
|
||||
data?.locked['filesDefaultExpiration'] &&
|
||||
data?.locked['filesAssumeMimetypes'] &&
|
||||
data?.locked['filesDefaultDateFormat'] &&
|
||||
data?.locked['filesRemoveGpsMetadata'] &&
|
||||
data?.locked['filesRandomWordsNumAdjectives'] &&
|
||||
data?.locked['filesRandomWordsSeparator']
|
||||
}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsHttpWebhook({
|
||||
swr: { data, isLoading },
|
||||
|
@ -50,30 +51,26 @@ export default function ServerSettingsHttpWebhook({
|
|||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='On Upload'
|
||||
description='The URL to send a POST request to when a file is uploaded.'
|
||||
placeholder='https://example.com/upload'
|
||||
disabled={data?.locked['httpWebhookOnUpload']}
|
||||
{...form.getInputProps('httpWebhookOnUpload')}
|
||||
/>
|
||||
<EnvTooltip envVar='HTTP_WEBHOOK_ON_UPLOAD' data={data} varKey='httpWebhookOnUpload'>
|
||||
<TextInput
|
||||
label='On Upload'
|
||||
description='The URL to send a POST request to when a file is uploaded.'
|
||||
placeholder='https://example.com/upload'
|
||||
{...form.getInputProps('httpWebhookOnUpload')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='On Shorten'
|
||||
description='The URL to send a POST request to when a URL is shortened.'
|
||||
placeholder='https://example.com/shorten'
|
||||
disabled={data?.locked['httpWebhookOnShorten']}
|
||||
{...form.getInputProps('httpWebhookOnShorten')}
|
||||
/>
|
||||
<EnvTooltip envVar='HTTP_WEBHOOK_ON_SHORTEN' data={data} varKey='httpWebhookOnShorten'>
|
||||
<TextInput
|
||||
label='On Shorten'
|
||||
description='The URL to send a POST request to when a URL is shortened.'
|
||||
placeholder='https://example.com/shorten'
|
||||
{...form.getInputProps('httpWebhookOnShorten')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={data?.locked['httpWebhookOnUpload'] && data?.locked['httpWebhookOnShorten']}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsInvites({
|
||||
swr: { data, isLoading },
|
||||
|
@ -38,31 +39,28 @@ export default function ServerSettingsInvites({
|
|||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<Switch
|
||||
label='Enable Invites'
|
||||
description='Enable the use of invite links to register new users.'
|
||||
disabled={data?.locked['invitesEnabled']}
|
||||
{...form.getInputProps('invitesEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='INVITES_ENABLED' data={data} varKey='invitesEnabled'>
|
||||
<Switch
|
||||
label='Enable Invites'
|
||||
description='Enable the use of invite links to register new users.'
|
||||
{...form.getInputProps('invitesEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<NumberInput
|
||||
label='Length'
|
||||
description='The length of the invite code.'
|
||||
placeholder='6'
|
||||
min={1}
|
||||
max={64}
|
||||
disabled={!form.values.invitesEnabled || data?.locked['invitesLength']}
|
||||
{...form.getInputProps('invitesLength')}
|
||||
/>
|
||||
<EnvTooltip envVar='INVITES_LENGTH' data={data} varKey='invitesLength'>
|
||||
<NumberInput
|
||||
label='Length'
|
||||
description='The length of the invite code.'
|
||||
placeholder='6'
|
||||
min={1}
|
||||
max={64}
|
||||
disabled={!form.values.invitesEnabled}
|
||||
{...form.getInputProps('invitesLength')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={data?.locked['invitesEnabled'] && data?.locked['invitesLength']}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsMfa({
|
||||
swr: { data, isLoading },
|
||||
|
@ -40,37 +41,33 @@ export default function ServerSettingsMfa({
|
|||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<Switch
|
||||
label='Passkeys'
|
||||
description='Enable the use of passwordless login with the use of WebAuthn passkeys like your phone, security keys, etc.'
|
||||
disabled={data?.locked['mfaPasskeys']}
|
||||
{...form.getInputProps('mfaPasskeys', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='MFA_TOTP_ENABLED' data={data} varKey='mfaTotpEnabled'>
|
||||
<Switch
|
||||
label='Passkeys'
|
||||
description='Enable the use of passwordless login with the use of WebAuthn passkeys like your phone, security keys, etc.'
|
||||
{...form.getInputProps('mfaPasskeys', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Enable TOTP'
|
||||
description='Enable Time-based One-Time Passwords with the use of an authenticator app.'
|
||||
disabled={data?.locked['mfaTotpEnabled']}
|
||||
{...form.getInputProps('mfaTotpEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
<TextInput
|
||||
label='Issuer'
|
||||
description='The issuer to use for the TOTP token.'
|
||||
placeholder='Zipline'
|
||||
disabled={data?.locked['mfaTotpIssuer']}
|
||||
{...form.getInputProps('mfaTotpIssuer')}
|
||||
/>
|
||||
<EnvTooltip envVar='MFA_TOTP_ENABLED' data={data} varKey='mfaTotpEnabled'>
|
||||
<Switch
|
||||
label='Enable TOTP'
|
||||
description='Enable Time-based One-Time Passwords with the use of an authenticator app.'
|
||||
{...form.getInputProps('mfaTotpEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='MFA_TOTP_ISSUER' data={data} varKey='mfaTotpIssuer'>
|
||||
<TextInput
|
||||
label='Issuer'
|
||||
description='The issuer to use for the TOTP token.'
|
||||
placeholder='Zipline'
|
||||
{...form.getInputProps('mfaTotpIssuer')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
data?.locked['mfaTotpEnabled'] && data?.locked['mfaTotpIssuer'] && data?.locked['mfaPasskeys']
|
||||
}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -15,6 +15,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsOauth({
|
||||
swr: { data, isLoading },
|
||||
|
@ -107,19 +108,21 @@ export default function ServerSettingsOauth({
|
|||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<Switch
|
||||
label='Bypass Local Login'
|
||||
description='Skips the local login page and redirects to the OAuth provider, this only works with one provider enabled.'
|
||||
disabled={data?.locked['oauthBypassLocalLogin']}
|
||||
{...form.getInputProps('oauthBypassLocalLogin', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='OAUTH_BYPASS_LOCAL_LOGIN' data={data} varKey='oauthBypassLocalLogin'>
|
||||
<Switch
|
||||
label='Bypass Local Login'
|
||||
description='Skips the local login page and redirects to the OAuth provider, this only works with one provider enabled.'
|
||||
{...form.getInputProps('oauthBypassLocalLogin', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Login Only'
|
||||
description='Disables registration and only allows login with OAuth, existing users can link providers for example.'
|
||||
disabled={data?.locked['oauthLoginOnly']}
|
||||
{...form.getInputProps('oauthLoginOnly', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='OAUTH_LOGIN_ONLY' data={data} varKey='oauthLoginOnly'>
|
||||
<Switch
|
||||
label='Login Only'
|
||||
description='Disables registration and only allows login with OAuth, existing users can link providers for example.'
|
||||
{...form.getInputProps('oauthLoginOnly', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<Paper withBorder p='sm'>
|
||||
|
@ -129,22 +132,21 @@ export default function ServerSettingsOauth({
|
|||
</Title>
|
||||
</Anchor>
|
||||
|
||||
<TextInput
|
||||
label='Discord Client ID'
|
||||
disabled={data?.locked['oauthDiscordClientId']}
|
||||
{...form.getInputProps('oauthDiscordClientId')}
|
||||
/>
|
||||
<TextInput
|
||||
label='Discord Client Secret'
|
||||
disabled={data?.locked['oauthDiscordClientSecret']}
|
||||
{...form.getInputProps('oauthDiscordClientSecret')}
|
||||
/>
|
||||
<TextInput
|
||||
label='Discord Redirect URL'
|
||||
description='The redirect URL to use instead of the host when logging in. This is not required if the URL generated by Zipline works as intended.'
|
||||
disabled={data?.locked['oauthDiscordRedirectUri']}
|
||||
{...form.getInputProps('oauthDiscordRedirectUri')}
|
||||
/>
|
||||
<EnvTooltip envVar='OAUTH_DISCORD_CLIENT_ID' data={data} varKey='oauthDiscordClientId'>
|
||||
<TextInput label='Discord Client ID' {...form.getInputProps('oauthDiscordClientId')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_DISCORD_CLIENT_SECRET' data={data} varKey='oauthDiscordClientSecret'>
|
||||
<TextInput label='Discord Client Secret' {...form.getInputProps('oauthDiscordClientSecret')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_DISCORD_REDIRECT_URI' data={data} varKey='oauthDiscordRedirectUri'>
|
||||
<TextInput
|
||||
label='Discord Redirect URL'
|
||||
description='The redirect URL to use instead of the host when logging in. This is not required if the URL generated by Zipline works as intended.'
|
||||
{...form.getInputProps('oauthDiscordRedirectUri')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Paper>
|
||||
<Paper withBorder p='sm'>
|
||||
<Anchor href='https://console.developers.google.com/' target='_blank'>
|
||||
|
@ -153,22 +155,21 @@ export default function ServerSettingsOauth({
|
|||
</Title>
|
||||
</Anchor>
|
||||
|
||||
<TextInput
|
||||
label='Google Client ID'
|
||||
disabled={data?.locked['oauthGoogleClientId']}
|
||||
{...form.getInputProps('oauthGoogleClientId')}
|
||||
/>
|
||||
<TextInput
|
||||
label='Google Client Secret'
|
||||
disabled={data?.locked['oauthGoogleClientSecret']}
|
||||
{...form.getInputProps('oauthGoogleClientSecret')}
|
||||
/>
|
||||
<TextInput
|
||||
label='Google Redirect URL'
|
||||
description='The redirect URL to use instead of the host when logging in. This is not required if the URL generated by Zipline works as intended.'
|
||||
disabled={data?.locked['oauthGoogleRedirectUri']}
|
||||
{...form.getInputProps('oauthGoogleRedirectUri')}
|
||||
/>
|
||||
<EnvTooltip envVar='OAUTH_GOOGLE_CLIENT_ID' data={data} varKey='oauthGoogleClientId'>
|
||||
<TextInput label='Google Client ID' {...form.getInputProps('oauthGoogleClientId')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_GOOGLE_CLIENT_SECRET' data={data} varKey='oauthGoogleClientSecret'>
|
||||
<TextInput label='Google Client Secret' {...form.getInputProps('oauthGoogleClientSecret')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_GOOGLE_REDIRECT_URI' data={data} varKey='oauthGoogleRedirectUri'>
|
||||
<TextInput
|
||||
label='Google Redirect URL'
|
||||
description='The redirect URL to use instead of the host when logging in. This is not required if the URL generated by Zipline works as intended.'
|
||||
{...form.getInputProps('oauthGoogleRedirectUri')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Paper>
|
||||
</SimpleGrid>
|
||||
|
||||
|
@ -180,22 +181,21 @@ export default function ServerSettingsOauth({
|
|||
</Anchor>
|
||||
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='GitHub Client ID'
|
||||
disabled={data?.locked['oauthGithubClientId']}
|
||||
{...form.getInputProps('oauthGithubClientId')}
|
||||
/>
|
||||
<TextInput
|
||||
label='GitHub Client Secret'
|
||||
disabled={data?.locked['oauthGithubClientSecret']}
|
||||
{...form.getInputProps('oauthGithubClientSecret')}
|
||||
/>
|
||||
<TextInput
|
||||
label='GitHub Redirect URL'
|
||||
description='The redirect URL to use instead of the host when logging in. This is not required if the URL generated by Zipline works as intended.'
|
||||
disabled={data?.locked['oauthGithubRedirectUri']}
|
||||
{...form.getInputProps('oauthGithubRedirectUri')}
|
||||
/>
|
||||
<EnvTooltip envVar='OAUTH_GITHUB_CLIENT_ID' data={data} varKey='oauthGithubClientId'>
|
||||
<TextInput label='GitHub Client ID' {...form.getInputProps('oauthGithubClientId')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_GITHUB_CLIENT_SECRET' data={data} varKey='oauthGithubClientSecret'>
|
||||
<TextInput label='GitHub Client Secret' {...form.getInputProps('oauthGithubClientSecret')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_GITHUB_REDIRECT_URI' data={data} varKey='oauthGithubRedirectUri'>
|
||||
<TextInput
|
||||
label='GitHub Redirect URL'
|
||||
description='The redirect URL to use instead of the host when logging in. This is not required if the URL generated by Zipline works as intended.'
|
||||
{...form.getInputProps('oauthGithubRedirectUri')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
</Paper>
|
||||
|
||||
|
@ -203,65 +203,37 @@ export default function ServerSettingsOauth({
|
|||
<Title order={4}>OpenID Connect</Title>
|
||||
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='OIDC Client ID'
|
||||
disabled={data?.locked['oauthOidcClientId']}
|
||||
{...form.getInputProps('oauthOidcClientId')}
|
||||
/>
|
||||
<TextInput
|
||||
label='OIDC Client Secret'
|
||||
disabled={data?.locked['oauthOidcClientSecret']}
|
||||
{...form.getInputProps('oauthOidcClientSecret')}
|
||||
/>
|
||||
<TextInput
|
||||
label='OIDC Authorize URL'
|
||||
disabled={data?.locked['oauthOidcAuthorizeUrl']}
|
||||
{...form.getInputProps('oauthOidcAuthorizeUrl')}
|
||||
/>
|
||||
<TextInput
|
||||
label='OIDC Token URL'
|
||||
disabled={data?.locked['oauthOidcTokenUrl']}
|
||||
{...form.getInputProps('oauthOidcTokenUrl')}
|
||||
/>
|
||||
<TextInput
|
||||
label='OIDC Userinfo URL'
|
||||
disabled={data?.locked['oauthOidcUserinfoUrl']}
|
||||
{...form.getInputProps('oauthOidcUserinfoUrl')}
|
||||
/>
|
||||
<TextInput
|
||||
label='OIDC Redirect URL'
|
||||
description='The redirect URL to use instead of the host when logging in. This is not required if the URL generated by Zipline works as intended.'
|
||||
disabled={data?.locked['oauthOidcRedirectUri']}
|
||||
{...form.getInputProps('oauthOidcRedirectUri')}
|
||||
/>
|
||||
<EnvTooltip envVar='OAUTH_OIDC_CLIENT_ID' data={data} varKey='oauthOidcClientId'>
|
||||
<TextInput label='OIDC Client ID' {...form.getInputProps('oauthOidcClientId')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_OIDC_CLIENT_SECRET' data={data} varKey='oauthOidcClientSecret'>
|
||||
<TextInput label='OIDC Client Secret' {...form.getInputProps('oauthOidcClientSecret')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_OIDC_AUTHORIZE_URL' data={data} varKey='oauthOidcAuthorizeUrl'>
|
||||
<TextInput label='OIDC Authorize URL' {...form.getInputProps('oauthOidcAuthorizeUrl')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_OIDC_TOKEN_URL' data={data} varKey='oauthOidcTokenUrl'>
|
||||
<TextInput label='OIDC Token URL' {...form.getInputProps('oauthOidcTokenUrl')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_OIDC_USERINFO_URL' data={data} varKey='oauthOidcUserinfoUrl'>
|
||||
<TextInput label='OIDC Userinfo URL' {...form.getInputProps('oauthOidcUserinfoUrl')} />
|
||||
</EnvTooltip>
|
||||
|
||||
<EnvTooltip envVar='OAUTH_OIDC_REDIRECT_URI' data={data} varKey='oauthOidcRedirectUri'>
|
||||
<TextInput
|
||||
label='OIDC Redirect URL'
|
||||
description='The redirect URL to use instead of the host when logging in. This is not required if the URL generated by Zipline works as intended.'
|
||||
{...form.getInputProps('oauthOidcRedirectUri')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
</Paper>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
data?.locked['oauthBypassLocalLogin'] &&
|
||||
data?.locked['oauthLoginOnly'] &&
|
||||
data?.locked['oauthDiscordClientId'] &&
|
||||
data?.locked['oauthDiscordClientSecret'] &&
|
||||
data?.locked['oauthDiscordRedirectUri'] &&
|
||||
data?.locked['oauthGoogleClientId'] &&
|
||||
data?.locked['oauthGoogleClientSecret'] &&
|
||||
data?.locked['oauthGoogleRedirectUri'] &&
|
||||
data?.locked['oauthGithubClientId'] &&
|
||||
data?.locked['oauthGithubClientSecret'] &&
|
||||
data?.locked['oauthGithubRedirectUri'] &&
|
||||
data?.locked['oauthOidcClientId'] &&
|
||||
data?.locked['oauthOidcClientSecret'] &&
|
||||
data?.locked['oauthOidcAuthorizeUrl'] &&
|
||||
data?.locked['oauthOidcTokenUrl'] &&
|
||||
data?.locked['oauthOidcUserinfoUrl'] &&
|
||||
data?.locked['oauthOidcRedirectUri']
|
||||
}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -16,6 +16,7 @@ import { IconDeviceFloppy, IconRefresh } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsPWA({
|
||||
swr: { data, isLoading },
|
||||
|
@ -74,70 +75,69 @@ export default function ServerSettingsPWA({
|
|||
</Text>
|
||||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<Switch
|
||||
mt='md'
|
||||
label='PWA Enabled'
|
||||
description='Allow users to install the Zipline PWA on their devices.'
|
||||
disabled={data?.locked['pwaEnabled']}
|
||||
{...form.getInputProps('pwaEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='PWA_ENABLED' data={data} varKey='pwaEnabled'>
|
||||
<Switch
|
||||
mt='md'
|
||||
label='PWA Enabled'
|
||||
description='Allow users to install the Zipline PWA on their devices.'
|
||||
{...form.getInputProps('pwaEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Title'
|
||||
description='The title for the PWA'
|
||||
placeholder='Zipline'
|
||||
disabled={!form.values.pwaEnabled || data?.locked['pwaTitle']}
|
||||
{...form.getInputProps('pwaTitle')}
|
||||
/>
|
||||
<EnvTooltip envVar='PWA_TITLE' data={data} varKey='pwaTitle'>
|
||||
<TextInput
|
||||
label='Title'
|
||||
description='The title for the PWA'
|
||||
placeholder='Zipline'
|
||||
disabled={!form.values.pwaEnabled}
|
||||
{...form.getInputProps('pwaTitle')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Short Name'
|
||||
description='The short name for the PWA'
|
||||
placeholder='Zipline'
|
||||
disabled={!form.values.pwaEnabled || data?.locked['pwaShortName']}
|
||||
{...form.getInputProps('pwaShortName')}
|
||||
/>
|
||||
<EnvTooltip envVar='PWA_SHORT_NAME' data={data} varKey='pwaShortName'>
|
||||
<TextInput
|
||||
label='Short Name'
|
||||
description='The short name for the PWA'
|
||||
placeholder='Zipline'
|
||||
disabled={!form.values.pwaEnabled}
|
||||
{...form.getInputProps('pwaShortName')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Description'
|
||||
description='The description for the PWA'
|
||||
placeholder='Zipline'
|
||||
disabled={!form.values.pwaEnabled || data?.locked['pwaDescription']}
|
||||
{...form.getInputProps('pwaDescription')}
|
||||
/>
|
||||
<EnvTooltip envVar='PWA_DESCRIPTION' data={data} varKey='pwaDescription'>
|
||||
<TextInput
|
||||
label='Description'
|
||||
description='The description for the PWA'
|
||||
placeholder='Zipline'
|
||||
disabled={!form.values.pwaEnabled}
|
||||
{...form.getInputProps('pwaDescription')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<ColorInput
|
||||
label='Theme Color'
|
||||
description='The theme color for the PWA'
|
||||
placeholder='#000000'
|
||||
disabled={!form.values.pwaEnabled || data?.locked['pwaThemeColor']}
|
||||
{...form.getInputProps('pwaThemeColor')}
|
||||
/>
|
||||
<EnvTooltip envVar='PWA_THEME_COLOR' data={data} varKey='pwaThemeColor'>
|
||||
<ColorInput
|
||||
label='Theme Color'
|
||||
description='The theme color for the PWA'
|
||||
placeholder='#000000'
|
||||
disabled={!form.values.pwaEnabled}
|
||||
{...form.getInputProps('pwaThemeColor')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<ColorInput
|
||||
label='Background Color'
|
||||
description='The background color for the PWA'
|
||||
placeholder='#ffffff'
|
||||
disabled={!form.values.pwaEnabled || data?.locked['pwaBackgroundColor']}
|
||||
{...form.getInputProps('pwaBackgroundColor')}
|
||||
/>
|
||||
<EnvTooltip envVar='PWA_BACKGROUND_COLOR' data={data} varKey='pwaBackgroundColor'>
|
||||
<ColorInput
|
||||
label='Background Color'
|
||||
description='The background color for the PWA'
|
||||
placeholder='#ffffff'
|
||||
disabled={!form.values.pwaEnabled}
|
||||
{...form.getInputProps('pwaBackgroundColor')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Group mt='md'>
|
||||
<Button
|
||||
type='submit'
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
data?.locked['pwaEnabled'] &&
|
||||
data?.locked['pwaTitle'] &&
|
||||
data?.locked['pwaShortName'] &&
|
||||
data?.locked['pwaDescription'] &&
|
||||
data?.locked['pwaThemeColor'] &&
|
||||
data?.locked['pwaBackgroundColor']
|
||||
}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
<Button onClick={() => router.reload()} leftSection={<IconRefresh size='1rem' />}>
|
||||
|
|
|
@ -15,6 +15,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsRatelimit({
|
||||
swr: { data, isLoading },
|
||||
|
@ -82,45 +83,54 @@ export default function ServerSettingsRatelimit({
|
|||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<Switch
|
||||
label='Enable Ratelimit'
|
||||
description='Enable ratelimiting for the server.'
|
||||
disabled={data?.locked['ratelimitEnabled']}
|
||||
{...form.getInputProps('ratelimitEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='RATELIMIT_ENABLED' data={data} varKey='ratelimitEnabled'>
|
||||
<Switch
|
||||
label='Enable Ratelimit'
|
||||
description='Enable ratelimiting for the server.'
|
||||
{...form.getInputProps('ratelimitEnabled', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<Switch
|
||||
label='Admin Bypass'
|
||||
description='Allow admins to bypass the ratelimit.'
|
||||
disabled={!form.values.ratelimitEnabled || data?.locked['ratelimitAdminBypass']}
|
||||
{...form.getInputProps('ratelimitAdminBypass', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip envVar='RATELIMIT_ADMIN_BYPASS' data={data} varKey='ratelimitAdminBypass'>
|
||||
<Switch
|
||||
label='Admin Bypass'
|
||||
description='Allow admins to bypass the ratelimit.'
|
||||
disabled={!form.values.ratelimitEnabled}
|
||||
{...form.getInputProps('ratelimitAdminBypass', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<NumberInput
|
||||
label='Max Requests'
|
||||
description='The maximum number of requests allowed within the window. If no window is set, this is the maximum number of requests until it reaches the limit.'
|
||||
placeholder='10'
|
||||
min={1}
|
||||
disabled={!form.values.ratelimitEnabled || data?.locked['ratelimitMax']}
|
||||
{...form.getInputProps('ratelimitMax')}
|
||||
/>
|
||||
<EnvTooltip envVar='RATELIMIT_MAX' data={data} varKey='ratelimitMax'>
|
||||
<NumberInput
|
||||
label='Max Requests'
|
||||
description='The maximum number of requests allowed within the window. If no window is set, this is the maximum number of requests until it reaches the limit.'
|
||||
placeholder='10'
|
||||
min={1}
|
||||
disabled={!form.values.ratelimitEnabled}
|
||||
{...form.getInputProps('ratelimitMax')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<NumberInput
|
||||
label='Window'
|
||||
description='The window in seconds to allow the max requests.'
|
||||
placeholder='60'
|
||||
min={1}
|
||||
disabled={!form.values.ratelimitEnabled || data?.locked['ratelimitWindow']}
|
||||
{...form.getInputProps('ratelimitWindow')}
|
||||
/>
|
||||
<EnvTooltip envVar='RATELIMIT_WINDOW' data={data} varKey='ratelimitWindow'>
|
||||
<NumberInput
|
||||
label='Window'
|
||||
description='The window in seconds to allow the max requests.'
|
||||
placeholder='60'
|
||||
min={1}
|
||||
disabled={!form.values.ratelimitEnabled}
|
||||
{...form.getInputProps('ratelimitWindow')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Allow List'
|
||||
description='A comma-separated list of IP addresses to bypass the ratelimit.'
|
||||
placeholder='1.1.1.1, 8.8.8.8'
|
||||
disabled={!form.values.ratelimitEnabled || data?.locked['ratelimitAllowList']}
|
||||
{...form.getInputProps('ratelimitAllowList')}
|
||||
/>
|
||||
<EnvTooltip envVar='RATELIMIT_ALLOW_LIST' data={data} varKey='ratelimitAllowList'>
|
||||
<TextInput
|
||||
label='Allow List'
|
||||
description='A comma-separated list of IP addresses to bypass the ratelimit.'
|
||||
placeholder='1.1.1.1, 8.8.8.8'
|
||||
disabled={!form.values.ratelimitEnabled}
|
||||
{...form.getInputProps('ratelimitAllowList')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsTasks({
|
||||
swr: { data, isLoading },
|
||||
|
@ -48,51 +49,44 @@ export default function ServerSettingsTasks({
|
|||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Delete Files Interval'
|
||||
description='How often to check and delete expired files.'
|
||||
placeholder='30m'
|
||||
disabled={data?.locked['tasksDeleteInterval']}
|
||||
{...form.getInputProps('tasksDeleteInterval')}
|
||||
/>
|
||||
<EnvTooltip envVar='TASKS_DELETE_INTERVAL' data={data} varKey='tasksDeleteInterval'>
|
||||
<TextInput
|
||||
label='Delete Files Interval'
|
||||
description='How often to check and delete expired files.'
|
||||
placeholder='30m'
|
||||
{...form.getInputProps('tasksDeleteInterval')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Clear Invites Interval'
|
||||
description='How often to check and clear expired/used invites.'
|
||||
placeholder='30m'
|
||||
disabled={data?.locked['tasksClearInvitesInterval']}
|
||||
{...form.getInputProps('tasksClearInvitesInterval')}
|
||||
/>
|
||||
<EnvTooltip envVar='TASKS_METRICS_INTERVAL' data={data} varKey='tasksMetricsInterval'>
|
||||
<TextInput
|
||||
label='Clear Invites Interval'
|
||||
description='How often to check and clear expired/used invites.'
|
||||
placeholder='30m'
|
||||
{...form.getInputProps('tasksClearInvitesInterval')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Max Views Interval'
|
||||
description='How often to check and delete files that have reached max views.'
|
||||
placeholder='30m'
|
||||
disabled={data?.locked['tasksMaxViewsInterval']}
|
||||
{...form.getInputProps('tasksMaxViewsInterval')}
|
||||
/>
|
||||
<EnvTooltip envVar='TASKS_MAX_VIEWS_INTERVAL' data={data} varKey='tasksMaxViewsInterval'>
|
||||
<TextInput
|
||||
label='Max Views Interval'
|
||||
description='How often to check and delete files that have reached max views.'
|
||||
placeholder='30m'
|
||||
{...form.getInputProps('tasksMaxViewsInterval')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<TextInput
|
||||
label='Thumbnails Interval'
|
||||
description='How often to check and generate thumbnails for video files.'
|
||||
placeholder='30m'
|
||||
disabled={data?.locked['tasksThumbnailsInterval']}
|
||||
{...form.getInputProps('tasksThumbnailsInterval')}
|
||||
/>
|
||||
<EnvTooltip envVar='TASKS_THUMBNAILS_INTERVAL' data={data} varKey='tasksThumbnailsInterval'>
|
||||
<TextInput
|
||||
label='Thumbnails Interval'
|
||||
description='How often to check and generate thumbnails for video files.'
|
||||
placeholder='30m'
|
||||
{...form.getInputProps('tasksThumbnailsInterval')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
data?.locked['tasksDeleteInterval'] &&
|
||||
data?.locked['tasksClearInvitesInterval'] &&
|
||||
data?.locked['tasksMaxViewsInterval'] &&
|
||||
data?.locked['tasksThumbnailsInterval']
|
||||
}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
export default function ServerSettingsUrls({
|
||||
swr: { data, isLoading },
|
||||
|
@ -38,32 +39,28 @@ export default function ServerSettingsUrls({
|
|||
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||
<TextInput
|
||||
label='Route'
|
||||
description='The route to use for short URLs. Requires a server restart.'
|
||||
placeholder='/go'
|
||||
disabled={data?.locked['urlsRoute']}
|
||||
{...form.getInputProps('urlsRoute')}
|
||||
/>
|
||||
<EnvTooltip envVar='URLS_ROUTE' data={data} varKey='urlsRoute'>
|
||||
<TextInput
|
||||
label='Route'
|
||||
description='The route to use for short URLs. Requires a server restart.'
|
||||
placeholder='/go'
|
||||
{...form.getInputProps('urlsRoute')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
|
||||
<NumberInput
|
||||
label='Length'
|
||||
description='The length of the short URL (for randomly generated names).'
|
||||
placeholder='6'
|
||||
min={1}
|
||||
max={64}
|
||||
disabled={data?.locked['urlsLength']}
|
||||
{...form.getInputProps('urlsLength')}
|
||||
/>
|
||||
<EnvTooltip envVar='URLS_LENGTH' data={data} varKey='urlsLength'>
|
||||
<NumberInput
|
||||
label='Length'
|
||||
description='The length of the short URL (for randomly generated names).'
|
||||
placeholder='6'
|
||||
min={1}
|
||||
max={64}
|
||||
{...form.getInputProps('urlsLength')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</SimpleGrid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={data?.locked['urlsRoute'] && data?.locked['urlsLength']}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { IconDeviceFloppy } from '@tabler/icons-react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import { settingsOnSubmit } from '../settingsOnSubmit';
|
||||
import { EnvTooltip } from '..';
|
||||
|
||||
const defaultExternalLinks = [
|
||||
{
|
||||
|
@ -97,127 +98,126 @@ export default function ServerSettingsWebsite({
|
|||
{/* <SimpleGrid mt='md' cols={{ base: 1, md: 2 }} spacing='lg'> */}
|
||||
<Grid>
|
||||
<Grid.Col span={{ base: 12, md: 6 }}>
|
||||
<TextInput
|
||||
label='Title'
|
||||
description='The title of the website in browser tabs and at the top.'
|
||||
placeholder='Zipline'
|
||||
disabled={data?.locked['websiteTitle']}
|
||||
{...form.getInputProps('websiteTitle')}
|
||||
/>
|
||||
<EnvTooltip envVar='WEBSITE_TITLE' data={data} varKey='websiteTitle'>
|
||||
<TextInput
|
||||
label='Title'
|
||||
description='The title of the website in browser tabs and at the top.'
|
||||
placeholder='Zipline'
|
||||
{...form.getInputProps('websiteTitle')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col span={{ base: 12, md: 6 }}>
|
||||
<TextInput
|
||||
label='Title Logo'
|
||||
description='The URL to use for the title logo. This is placed to the left of the title.'
|
||||
placeholder='https://example.com/logo.png'
|
||||
disabled={data?.locked['websiteTitleLogo']}
|
||||
{...form.getInputProps('websiteTitleLogo')}
|
||||
/>
|
||||
<EnvTooltip envVar='WEBSITE_TITLE_LOGO' data={data} varKey='websiteTitleLogo'>
|
||||
<TextInput
|
||||
label='Title Logo'
|
||||
description='The URL to use for the title logo. This is placed to the left of the title.'
|
||||
placeholder='https://example.com/logo.png'
|
||||
{...form.getInputProps('websiteTitleLogo')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col span={12}>
|
||||
<JsonInput
|
||||
label='External Links'
|
||||
description='The external links to show in the footer. This must be valid JSON.'
|
||||
formatOnBlur
|
||||
minRows={1}
|
||||
maxRows={7}
|
||||
autosize
|
||||
placeholder={JSON.stringify(defaultExternalLinks, null, 2)}
|
||||
disabled={data?.locked['websiteExternalLinks']}
|
||||
{...form.getInputProps('websiteExternalLinks')}
|
||||
/>
|
||||
<EnvTooltip envVar='WEBSITE_EXTERNAL_LINKS' data={data} varKey='websiteExternalLinks'>
|
||||
<JsonInput
|
||||
label='External Links'
|
||||
description='The external links to show in the footer. This must be valid JSON.'
|
||||
formatOnBlur
|
||||
minRows={1}
|
||||
maxRows={7}
|
||||
autosize
|
||||
placeholder={JSON.stringify(defaultExternalLinks, null, 2)}
|
||||
{...form.getInputProps('websiteExternalLinks')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col span={{ base: 12, md: 6 }}>
|
||||
<TextInput
|
||||
label='Login Background'
|
||||
description='The URL to use for the login background.'
|
||||
placeholder='https://example.com/background.png'
|
||||
disabled={data?.locked['websiteLoginBackground']}
|
||||
{...form.getInputProps('websiteLoginBackground')}
|
||||
/>
|
||||
<EnvTooltip envVar='WEBSITE_LOGIN_BACKGROUND' data={data} varKey='websiteLoginBackground'>
|
||||
<TextInput
|
||||
label='Login Background'
|
||||
description='The URL to use for the login background.'
|
||||
placeholder='https://example.com/background.png'
|
||||
{...form.getInputProps('websiteLoginBackground')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col span={{ base: 12, md: 6 }}>
|
||||
<Switch
|
||||
label='Login Background Blur'
|
||||
description='Whether to blur the login background.'
|
||||
disabled={data?.locked['websiteLoginBackgroundBlur']}
|
||||
{...form.getInputProps('websiteLoginBackgroundBlur', { type: 'checkbox' })}
|
||||
/>
|
||||
<EnvTooltip
|
||||
envVar='WEBSITE_LOGIN_BACKGROUND_BLUR'
|
||||
data={data}
|
||||
varKey='websiteLoginBackgroundBlur'
|
||||
>
|
||||
<Switch
|
||||
label='Login Background Blur'
|
||||
description='Whether to blur the login background.'
|
||||
{...form.getInputProps('websiteLoginBackgroundBlur', { type: 'checkbox' })}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col span={{ base: 12, md: 6 }}>
|
||||
<TextInput
|
||||
label='Default Avatar'
|
||||
description='The path to use for the default avatar. This must be a path to an image, not a URL.'
|
||||
placeholder='/zipline/avatar.png'
|
||||
disabled={data?.locked['websiteDefaultAvatar']}
|
||||
{...form.getInputProps('websiteDefaultAvatar')}
|
||||
/>
|
||||
<EnvTooltip envVar='WEBSITE_DEFAULT_AVATAR' data={data} varKey='websiteDefaultAvatar'>
|
||||
<TextInput
|
||||
label='Default Avatar'
|
||||
description='The path to use for the default avatar. This must be a path to an image, not a URL.'
|
||||
placeholder='/zipline/avatar.png'
|
||||
{...form.getInputProps('websiteDefaultAvatar')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col span={{ base: 12, md: 6 }}>
|
||||
<TextInput
|
||||
label='Terms of Service'
|
||||
description='Path to a Markdown (.md) file to use for the terms of service.'
|
||||
placeholder='/zipline/TOS.md'
|
||||
disabled={data?.locked['websiteTos']}
|
||||
{...form.getInputProps('websiteTos')}
|
||||
/>
|
||||
<EnvTooltip envVar='WEBSITE_TOS' data={data} varKey='websiteTos'>
|
||||
<TextInput
|
||||
label='Terms of Service'
|
||||
description='Path to a Markdown (.md) file to use for the terms of service.'
|
||||
placeholder='/zipline/TOS.md'
|
||||
{...form.getInputProps('websiteTos')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col span={12}>
|
||||
<TextInput
|
||||
label='Default Theme'
|
||||
description='The default theme to use for the website.'
|
||||
placeholder='system'
|
||||
disabled={data?.locked['websiteThemeDefault']}
|
||||
{...form.getInputProps('websiteThemeDefault')}
|
||||
/>
|
||||
<EnvTooltip envVar='WEBSITE_THEME_DEFAULT' data={data} varKey='websiteThemeDefault'>
|
||||
<TextInput
|
||||
label='Default Theme'
|
||||
description='The default theme to use for the website.'
|
||||
placeholder='system'
|
||||
{...form.getInputProps('websiteThemeDefault')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col span={{ base: 12, md: 6 }}>
|
||||
<TextInput
|
||||
label='Dark Theme'
|
||||
description='The dark theme to use for the website when the default theme is "system".'
|
||||
placeholder='builtin:dark_gray'
|
||||
disabled={form.values.websiteThemeDefault !== 'system' || data?.locked['websiteThemeDark']}
|
||||
{...form.getInputProps('websiteThemeDark')}
|
||||
/>
|
||||
<EnvTooltip envVar='WEBSITE_THEME_DARK' data={data} varKey='websiteThemeDark'>
|
||||
<TextInput
|
||||
label='Dark Theme'
|
||||
description='The dark theme to use for the website when the default theme is "system".'
|
||||
placeholder='builtin:dark_gray'
|
||||
disabled={form.values.websiteThemeDefault !== 'system'}
|
||||
{...form.getInputProps('websiteThemeDark')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col span={{ base: 12, md: 6 }}>
|
||||
<TextInput
|
||||
label='Light Theme'
|
||||
description='The light theme to use for the website when the default theme is "system".'
|
||||
placeholder='builtin:light_gray'
|
||||
disabled={form.values.websiteThemeDefault !== 'system' || data?.locked['websiteThemeLight']}
|
||||
{...form.getInputProps('websiteThemeLight')}
|
||||
/>
|
||||
<EnvTooltip envVar='WEBSITE_THEME_LIGHT' data={data} varKey='websiteThemeLight'>
|
||||
<TextInput
|
||||
label='Light Theme'
|
||||
description='The light theme to use for the website when the default theme is "system".'
|
||||
placeholder='builtin:light_gray'
|
||||
disabled={form.values.websiteThemeDefault !== 'system'}
|
||||
{...form.getInputProps('websiteThemeLight')}
|
||||
/>
|
||||
</EnvTooltip>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
mt='md'
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
data?.locked['websiteTitle'] &&
|
||||
data?.locked['websiteTitleLogo'] &&
|
||||
data?.locked['websiteExternalLinks'] &&
|
||||
data?.locked['websiteLoginBackground'] &&
|
||||
data?.locked['websiteLoginBackgroundBlur'] &&
|
||||
data?.locked['websiteDefaultAvatar'] &&
|
||||
data?.locked['websiteTos'] &&
|
||||
data?.locked['websiteThemeDefault'] &&
|
||||
data?.locked['websiteThemeDark'] &&
|
||||
data?.locked['websiteThemeLight']
|
||||
}
|
||||
leftSection={<IconDeviceFloppy size='1rem' />}
|
||||
>
|
||||
<Button type='submit' mt='md' loading={isLoading} leftSection={<IconDeviceFloppy size='1rem' />}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
@ -631,8 +631,15 @@ export function replaceDatabaseValueWithEnv<T>(
|
|||
return databaseValue;
|
||||
}
|
||||
|
||||
export function valueIsFromEnv(Key: keyof typeof DATABASE_TO_PROP): boolean {
|
||||
return databaseToEnv(Key).some((key) => process.env[key] !== undefined);
|
||||
export function valueIsFromEnv(Key: keyof typeof DATABASE_TO_PROP): string | undefined {
|
||||
const envKeys = databaseToEnv(Key);
|
||||
|
||||
for (let i = 0; i !== envKeys.length; ++i) {
|
||||
const value = process.env[envKeys[i]];
|
||||
if (value !== undefined) return value;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function databaseToEnv(key: keyof typeof DATABASE_TO_PROP): string[] {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Prisma, PrismaClient } from '@prisma/client';
|
|||
import { userViewSchema } from './models/user';
|
||||
import { metricDataSchema } from './models/metric';
|
||||
import { metadataSchema } from './models/incompleteFile';
|
||||
import { replaceDatabaseValueWithEnv } from '../config/read';
|
||||
import { SettingsExtension } from './settingsExtension';
|
||||
|
||||
const building = !!process.env.ZIPLINE_BUILD;
|
||||
|
||||
|
@ -39,674 +39,44 @@ function getClient() {
|
|||
|
||||
const client = new PrismaClient({
|
||||
log: process.env.ZIPLINE_DB_LOG ? parseDbLog(process.env.ZIPLINE_DB_LOG) : undefined,
|
||||
}).$extends({
|
||||
result: {
|
||||
file: {
|
||||
size: {
|
||||
needs: { size: true },
|
||||
compute({ size }: { size: bigint }) {
|
||||
return Number(size);
|
||||
})
|
||||
.$extends({
|
||||
result: {
|
||||
file: {
|
||||
size: {
|
||||
needs: { size: true },
|
||||
compute({ size }: { size: bigint }) {
|
||||
return Number(size);
|
||||
},
|
||||
},
|
||||
},
|
||||
user: {
|
||||
view: {
|
||||
needs: { view: true },
|
||||
compute({ view }: { view: Prisma.JsonValue }) {
|
||||
return userViewSchema.parse(view);
|
||||
},
|
||||
},
|
||||
},
|
||||
metric: {
|
||||
data: {
|
||||
needs: { data: true },
|
||||
compute({ data }: { data: Prisma.JsonValue }) {
|
||||
return metricDataSchema.parse(data);
|
||||
},
|
||||
},
|
||||
},
|
||||
incompleteFile: {
|
||||
metadata: {
|
||||
needs: { metadata: true },
|
||||
compute({ metadata }: { metadata: Prisma.JsonValue }) {
|
||||
return metadataSchema.parse(metadata);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
user: {
|
||||
view: {
|
||||
needs: { view: true },
|
||||
compute({ view }: { view: Prisma.JsonValue }) {
|
||||
return userViewSchema.parse(view);
|
||||
},
|
||||
},
|
||||
},
|
||||
metric: {
|
||||
data: {
|
||||
needs: { data: true },
|
||||
compute({ data }: { data: Prisma.JsonValue }) {
|
||||
return metricDataSchema.parse(data);
|
||||
},
|
||||
},
|
||||
},
|
||||
incompleteFile: {
|
||||
metadata: {
|
||||
needs: { metadata: true },
|
||||
compute({ metadata }: { metadata: Prisma.JsonValue }) {
|
||||
return metadataSchema.parse(metadata);
|
||||
},
|
||||
},
|
||||
},
|
||||
zipline: {
|
||||
coreReturnHttpsUrls: {
|
||||
needs: { coreReturnHttpsUrls: true },
|
||||
compute({ coreReturnHttpsUrls }: { coreReturnHttpsUrls: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('coreReturnHttpsUrls', coreReturnHttpsUrls, 'boolean');
|
||||
},
|
||||
},
|
||||
coreDefaultDomain: {
|
||||
needs: { coreDefaultDomain: true },
|
||||
compute({ coreDefaultDomain }: { coreDefaultDomain: string }) {
|
||||
return replaceDatabaseValueWithEnv('coreDefaultDomain', coreDefaultDomain, 'string');
|
||||
},
|
||||
},
|
||||
coreTempDirectory: {
|
||||
needs: { coreTempDirectory: true },
|
||||
compute({ coreTempDirectory }: { coreTempDirectory: string }) {
|
||||
return replaceDatabaseValueWithEnv('coreTempDirectory', coreTempDirectory, 'string');
|
||||
},
|
||||
},
|
||||
chunksMax: {
|
||||
needs: { chunksMax: true },
|
||||
compute({ chunksMax }: { chunksMax: string }) {
|
||||
return replaceDatabaseValueWithEnv('chunksMax', chunksMax, 'string');
|
||||
},
|
||||
},
|
||||
chunksSize: {
|
||||
needs: { chunksSize: true },
|
||||
compute({ chunksSize }: { chunksSize: string }) {
|
||||
return replaceDatabaseValueWithEnv('chunksSize', chunksSize, 'string');
|
||||
},
|
||||
},
|
||||
chunksEnabled: {
|
||||
needs: { chunksEnabled: true },
|
||||
compute({ chunksEnabled }: { chunksEnabled: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('chunksEnabled', chunksEnabled, 'boolean');
|
||||
},
|
||||
},
|
||||
tasksDeleteInterval: {
|
||||
needs: { tasksDeleteInterval: true },
|
||||
compute({ tasksDeleteInterval }: { tasksDeleteInterval: string }) {
|
||||
return replaceDatabaseValueWithEnv('tasksDeleteInterval', tasksDeleteInterval, 'ms');
|
||||
},
|
||||
},
|
||||
tasksClearInvitesInterval: {
|
||||
needs: { tasksClearInvitesInterval: true },
|
||||
compute({ tasksClearInvitesInterval }: { tasksClearInvitesInterval: string }) {
|
||||
return replaceDatabaseValueWithEnv('tasksClearInvitesInterval', tasksClearInvitesInterval, 'ms');
|
||||
},
|
||||
},
|
||||
tasksMaxViewsInterval: {
|
||||
needs: { tasksMaxViewsInterval: true },
|
||||
compute({ tasksMaxViewsInterval }: { tasksMaxViewsInterval: string }) {
|
||||
return replaceDatabaseValueWithEnv('tasksMaxViewsInterval', tasksMaxViewsInterval, 'ms');
|
||||
},
|
||||
},
|
||||
tasksThumbnailsInterval: {
|
||||
needs: { tasksThumbnailsInterval: true },
|
||||
compute({ tasksThumbnailsInterval }: { tasksThumbnailsInterval: string }) {
|
||||
return replaceDatabaseValueWithEnv('tasksThumbnailsInterval', tasksThumbnailsInterval, 'ms');
|
||||
},
|
||||
},
|
||||
tasksMetricsInterval: {
|
||||
needs: { tasksMetricsInterval: true },
|
||||
compute({ tasksMetricsInterval }: { tasksMetricsInterval: string }) {
|
||||
return replaceDatabaseValueWithEnv('tasksMetricsInterval', tasksMetricsInterval, 'ms');
|
||||
},
|
||||
},
|
||||
filesRoute: {
|
||||
needs: { filesRoute: true },
|
||||
compute({ filesRoute }: { filesRoute: string }) {
|
||||
return replaceDatabaseValueWithEnv('filesRoute', filesRoute, 'string');
|
||||
},
|
||||
},
|
||||
filesLength: {
|
||||
needs: { filesLength: true },
|
||||
compute({ filesLength }: { filesLength: number }) {
|
||||
return replaceDatabaseValueWithEnv('filesLength', filesLength, 'number');
|
||||
},
|
||||
},
|
||||
filesDefaultFormat: {
|
||||
needs: { filesDefaultFormat: true },
|
||||
compute({ filesDefaultFormat }: { filesDefaultFormat: string }) {
|
||||
return replaceDatabaseValueWithEnv('filesDefaultFormat', filesDefaultFormat, 'string');
|
||||
},
|
||||
},
|
||||
filesDisabledExtensions: {
|
||||
needs: { filesDisabledExtensions: true },
|
||||
compute({ filesDisabledExtensions }: { filesDisabledExtensions: string[] }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'filesDisabledExtensions',
|
||||
filesDisabledExtensions,
|
||||
'string[]',
|
||||
);
|
||||
},
|
||||
},
|
||||
filesMaxFileSize: {
|
||||
needs: { filesMaxFileSize: true },
|
||||
compute({ filesMaxFileSize }: { filesMaxFileSize: string }) {
|
||||
return replaceDatabaseValueWithEnv('filesMaxFileSize', filesMaxFileSize, 'byte');
|
||||
},
|
||||
},
|
||||
filesDefaultExpiration: {
|
||||
needs: { filesDefaultExpiration: true },
|
||||
compute({ filesDefaultExpiration }: { filesDefaultExpiration: string }) {
|
||||
return replaceDatabaseValueWithEnv('filesDefaultExpiration', filesDefaultExpiration, 'string');
|
||||
},
|
||||
},
|
||||
filesAssumeMimetypes: {
|
||||
needs: { filesAssumeMimetypes: true },
|
||||
compute({ filesAssumeMimetypes }: { filesAssumeMimetypes: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('filesAssumeMimetypes', filesAssumeMimetypes, 'boolean');
|
||||
},
|
||||
},
|
||||
filesDefaultDateFormat: {
|
||||
needs: { filesDefaultDateFormat: true },
|
||||
compute({ filesDefaultDateFormat }: { filesDefaultDateFormat: string }) {
|
||||
return replaceDatabaseValueWithEnv('filesDefaultDateFormat', filesDefaultDateFormat, 'string');
|
||||
},
|
||||
},
|
||||
filesRemoveGpsMetadata: {
|
||||
needs: { filesRemoveGpsMetadata: true },
|
||||
compute({ filesRemoveGpsMetadata }: { filesRemoveGpsMetadata: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('filesRemoveGpsMetadata', filesRemoveGpsMetadata, 'boolean');
|
||||
},
|
||||
},
|
||||
filesRandomWordsNumAdjectives: {
|
||||
needs: { filesRandomWordsNumAdjectives: true },
|
||||
compute({ filesRandomWordsNumAdjectives }: { filesRandomWordsNumAdjectives: number }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'filesRandomWordsNumAdjectives',
|
||||
filesRandomWordsNumAdjectives,
|
||||
'number',
|
||||
);
|
||||
},
|
||||
},
|
||||
filesRandomWordsSeparator: {
|
||||
needs: { filesRandomWordsSeparator: true },
|
||||
compute({ filesRandomWordsSeparator }: { filesRandomWordsSeparator: string }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'filesRandomWordsSeparator',
|
||||
filesRandomWordsSeparator,
|
||||
'string',
|
||||
);
|
||||
},
|
||||
},
|
||||
urlsRoute: {
|
||||
needs: { urlsRoute: true },
|
||||
compute({ urlsRoute }: { urlsRoute: string }) {
|
||||
return replaceDatabaseValueWithEnv('urlsRoute', urlsRoute, 'string');
|
||||
},
|
||||
},
|
||||
urlsLength: {
|
||||
needs: { urlsLength: true },
|
||||
compute({ urlsLength }: { urlsLength: number }) {
|
||||
return replaceDatabaseValueWithEnv('urlsLength', urlsLength, 'number');
|
||||
},
|
||||
},
|
||||
featuresImageCompression: {
|
||||
needs: { featuresImageCompression: true },
|
||||
compute({ featuresImageCompression }: { featuresImageCompression: boolean }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'featuresImageCompression',
|
||||
featuresImageCompression,
|
||||
'boolean',
|
||||
);
|
||||
},
|
||||
},
|
||||
featuresRobotsTxt: {
|
||||
needs: { featuresRobotsTxt: true },
|
||||
compute({ featuresRobotsTxt }: { featuresRobotsTxt: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('featuresRobotsTxt', featuresRobotsTxt, 'boolean');
|
||||
},
|
||||
},
|
||||
featuresHealthcheck: {
|
||||
needs: { featuresHealthcheck: true },
|
||||
compute({ featuresHealthcheck }: { featuresHealthcheck: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('featuresHealthcheck', featuresHealthcheck, 'boolean');
|
||||
},
|
||||
},
|
||||
featuresUserRegistration: {
|
||||
needs: { featuresUserRegistration: true },
|
||||
compute({ featuresUserRegistration }: { featuresUserRegistration: boolean }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'featuresUserRegistration',
|
||||
featuresUserRegistration,
|
||||
'boolean',
|
||||
);
|
||||
},
|
||||
},
|
||||
featuresOauthRegistration: {
|
||||
needs: { featuresOauthRegistration: true },
|
||||
compute({ featuresOauthRegistration }: { featuresOauthRegistration: boolean }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'featuresOauthRegistration',
|
||||
featuresOauthRegistration,
|
||||
'boolean',
|
||||
);
|
||||
},
|
||||
},
|
||||
featuresDeleteOnMaxViews: {
|
||||
needs: { featuresDeleteOnMaxViews: true },
|
||||
compute({ featuresDeleteOnMaxViews }: { featuresDeleteOnMaxViews: boolean }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'featuresDeleteOnMaxViews',
|
||||
featuresDeleteOnMaxViews,
|
||||
'boolean',
|
||||
);
|
||||
},
|
||||
},
|
||||
featuresThumbnailsEnabled: {
|
||||
needs: { featuresThumbnailsEnabled: true },
|
||||
compute({ featuresThumbnailsEnabled }: { featuresThumbnailsEnabled: boolean }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'featuresThumbnailsEnabled',
|
||||
featuresThumbnailsEnabled,
|
||||
'boolean',
|
||||
);
|
||||
},
|
||||
},
|
||||
featuresThumbnailsNumberThreads: {
|
||||
needs: { featuresThumbnailsNumberThreads: true },
|
||||
compute({ featuresThumbnailsNumberThreads }: { featuresThumbnailsNumberThreads: number }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'featuresThumbnailsNumberThreads',
|
||||
featuresThumbnailsNumberThreads,
|
||||
'number',
|
||||
);
|
||||
},
|
||||
},
|
||||
featuresMetricsEnabled: {
|
||||
needs: { featuresMetricsEnabled: true },
|
||||
compute({ featuresMetricsEnabled }: { featuresMetricsEnabled: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('featuresMetricsEnabled', featuresMetricsEnabled, 'boolean');
|
||||
},
|
||||
},
|
||||
featuresMetricsAdminOnly: {
|
||||
needs: { featuresMetricsAdminOnly: true },
|
||||
compute({ featuresMetricsAdminOnly }: { featuresMetricsAdminOnly: boolean }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'featuresMetricsAdminOnly',
|
||||
featuresMetricsAdminOnly,
|
||||
'boolean',
|
||||
);
|
||||
},
|
||||
},
|
||||
featuresMetricsShowUserSpecific: {
|
||||
needs: { featuresMetricsShowUserSpecific: true },
|
||||
compute({ featuresMetricsShowUserSpecific }: { featuresMetricsShowUserSpecific: boolean }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'featuresMetricsShowUserSpecific',
|
||||
featuresMetricsShowUserSpecific,
|
||||
'boolean',
|
||||
);
|
||||
},
|
||||
},
|
||||
invitesEnabled: {
|
||||
needs: { invitesEnabled: true },
|
||||
compute({ invitesEnabled }: { invitesEnabled: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('invitesEnabled', invitesEnabled, 'boolean');
|
||||
},
|
||||
},
|
||||
invitesLength: {
|
||||
needs: { invitesLength: true },
|
||||
compute({ invitesLength }: { invitesLength: number }) {
|
||||
return replaceDatabaseValueWithEnv('invitesLength', invitesLength, 'number');
|
||||
},
|
||||
},
|
||||
websiteTitle: {
|
||||
needs: { websiteTitle: true },
|
||||
compute({ websiteTitle }: { websiteTitle: string }) {
|
||||
return replaceDatabaseValueWithEnv('websiteTitle', websiteTitle, 'string');
|
||||
},
|
||||
},
|
||||
websiteTitleLogo: {
|
||||
needs: { websiteTitleLogo: true },
|
||||
compute({ websiteTitleLogo }: { websiteTitleLogo: string }) {
|
||||
return replaceDatabaseValueWithEnv('websiteTitleLogo', websiteTitleLogo, 'string');
|
||||
},
|
||||
},
|
||||
websiteExternalLinks: {
|
||||
needs: { websiteExternalLinks: true },
|
||||
compute({ websiteExternalLinks }: { websiteExternalLinks: Prisma.JsonValue }) {
|
||||
return replaceDatabaseValueWithEnv('websiteExternalLinks', websiteExternalLinks, 'json[]');
|
||||
},
|
||||
},
|
||||
websiteLoginBackground: {
|
||||
needs: { websiteLoginBackground: true },
|
||||
compute({ websiteLoginBackground }: { websiteLoginBackground: string }) {
|
||||
return replaceDatabaseValueWithEnv('websiteLoginBackground', websiteLoginBackground, 'string');
|
||||
},
|
||||
},
|
||||
websiteLoginBackgroundBlur: {
|
||||
needs: { websiteLoginBackgroundBlur: true },
|
||||
compute({ websiteLoginBackgroundBlur }: { websiteLoginBackgroundBlur: boolean }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'websiteLoginBackgroundBlur',
|
||||
websiteLoginBackgroundBlur,
|
||||
'boolean',
|
||||
);
|
||||
},
|
||||
},
|
||||
websiteDefaultAvatar: {
|
||||
needs: { websiteDefaultAvatar: true },
|
||||
compute({ websiteDefaultAvatar }: { websiteDefaultAvatar: string }) {
|
||||
return replaceDatabaseValueWithEnv('websiteDefaultAvatar', websiteDefaultAvatar, 'string');
|
||||
},
|
||||
},
|
||||
websiteTos: {
|
||||
needs: { websiteTos: true },
|
||||
compute({ websiteTos }: { websiteTos: string }) {
|
||||
return replaceDatabaseValueWithEnv('websiteTos', websiteTos, 'string');
|
||||
},
|
||||
},
|
||||
websiteThemeDefault: {
|
||||
needs: { websiteThemeDefault: true },
|
||||
compute({ websiteThemeDefault }: { websiteThemeDefault: string }) {
|
||||
return replaceDatabaseValueWithEnv('websiteThemeDefault', websiteThemeDefault, 'string');
|
||||
},
|
||||
},
|
||||
websiteThemeDark: {
|
||||
needs: { websiteThemeDark: true },
|
||||
compute({ websiteThemeDark }: { websiteThemeDark: string }) {
|
||||
return replaceDatabaseValueWithEnv('websiteThemeDark', websiteThemeDark, 'string');
|
||||
},
|
||||
},
|
||||
websiteThemeLight: {
|
||||
needs: { websiteThemeLight: true },
|
||||
compute({ websiteThemeLight }: { websiteThemeLight: string }) {
|
||||
return replaceDatabaseValueWithEnv('websiteThemeLight', websiteThemeLight, 'string');
|
||||
},
|
||||
},
|
||||
oauthBypassLocalLogin: {
|
||||
needs: { oauthBypassLocalLogin: true },
|
||||
compute({ oauthBypassLocalLogin }: { oauthBypassLocalLogin: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('oauthBypassLocalLogin', oauthBypassLocalLogin, 'boolean');
|
||||
},
|
||||
},
|
||||
oauthLoginOnly: {
|
||||
needs: { oauthLoginOnly: true },
|
||||
compute({ oauthLoginOnly }: { oauthLoginOnly: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('oauthLoginOnly', oauthLoginOnly, 'boolean');
|
||||
},
|
||||
},
|
||||
oauthDiscordClientId: {
|
||||
needs: { oauthDiscordClientId: true },
|
||||
compute({ oauthDiscordClientId }: { oauthDiscordClientId: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthDiscordClientId', oauthDiscordClientId, 'string');
|
||||
},
|
||||
},
|
||||
oauthDiscordClientSecret: {
|
||||
needs: { oauthDiscordClientSecret: true },
|
||||
compute({ oauthDiscordClientSecret }: { oauthDiscordClientSecret: string }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'oauthDiscordClientSecret',
|
||||
oauthDiscordClientSecret,
|
||||
'string',
|
||||
);
|
||||
},
|
||||
},
|
||||
oauthDiscordRedirectUri: {
|
||||
needs: { oauthDiscordRedirectUri: true },
|
||||
compute({ oauthDiscordRedirectUri }: { oauthDiscordRedirectUri: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthDiscordRedirectUri', oauthDiscordRedirectUri, 'string');
|
||||
},
|
||||
},
|
||||
oauthGoogleClientId: {
|
||||
needs: { oauthGoogleClientId: true },
|
||||
compute({ oauthGoogleClientId }: { oauthGoogleClientId: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthGoogleClientId', oauthGoogleClientId, 'string');
|
||||
},
|
||||
},
|
||||
oauthGoogleClientSecret: {
|
||||
needs: { oauthGoogleClientSecret: true },
|
||||
compute({ oauthGoogleClientSecret }: { oauthGoogleClientSecret: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthGoogleClientSecret', oauthGoogleClientSecret, 'string');
|
||||
},
|
||||
},
|
||||
oauthGoogleRedirectUri: {
|
||||
needs: { oauthGoogleRedirectUri: true },
|
||||
compute({ oauthGoogleRedirectUri }: { oauthGoogleRedirectUri: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthGoogleRedirectUri', oauthGoogleRedirectUri, 'string');
|
||||
},
|
||||
},
|
||||
oauthGithubClientId: {
|
||||
needs: { oauthGithubClientId: true },
|
||||
compute({ oauthGithubClientId }: { oauthGithubClientId: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthGithubClientId', oauthGithubClientId, 'string');
|
||||
},
|
||||
},
|
||||
oauthGithubClientSecret: {
|
||||
needs: { oauthGithubClientSecret: true },
|
||||
compute({ oauthGithubClientSecret }: { oauthGithubClientSecret: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthGithubClientSecret', oauthGithubClientSecret, 'string');
|
||||
},
|
||||
},
|
||||
oauthGithubRedirectUri: {
|
||||
needs: { oauthGithubRedirectUri: true },
|
||||
compute({ oauthGithubRedirectUri }: { oauthGithubRedirectUri: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthGithubRedirectUri', oauthGithubRedirectUri, 'string');
|
||||
},
|
||||
},
|
||||
oauthOidcClientId: {
|
||||
needs: { oauthOidcClientId: true },
|
||||
compute({ oauthOidcClientId }: { oauthOidcClientId: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthOidcClientId', oauthOidcClientId, 'string');
|
||||
},
|
||||
},
|
||||
oauthOidcClientSecret: {
|
||||
needs: { oauthOidcClientSecret: true },
|
||||
compute({ oauthOidcClientSecret }: { oauthOidcClientSecret: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthOidcClientSecret', oauthOidcClientSecret, 'string');
|
||||
},
|
||||
},
|
||||
oauthOidcAuthorizeUrl: {
|
||||
needs: { oauthOidcAuthorizeUrl: true },
|
||||
compute({ oauthOidcAuthorizeUrl }: { oauthOidcAuthorizeUrl: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthOidcAuthorizeUrl', oauthOidcAuthorizeUrl, 'string');
|
||||
},
|
||||
},
|
||||
oauthOidcUserinfoUrl: {
|
||||
needs: { oauthOidcUserinfoUrl: true },
|
||||
compute({ oauthOidcUserinfoUrl }: { oauthOidcUserinfoUrl: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthOidcUserinfoUrl', oauthOidcUserinfoUrl, 'string');
|
||||
},
|
||||
},
|
||||
oauthOidcTokenUrl: {
|
||||
needs: { oauthOidcTokenUrl: true },
|
||||
compute({ oauthOidcTokenUrl }: { oauthOidcTokenUrl: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthOidcTokenUrl', oauthOidcTokenUrl, 'string');
|
||||
},
|
||||
},
|
||||
oauthOidcRedirectUri: {
|
||||
needs: { oauthOidcRedirectUri: true },
|
||||
compute({ oauthOidcRedirectUri }: { oauthOidcRedirectUri: string }) {
|
||||
return replaceDatabaseValueWithEnv('oauthOidcRedirectUri', oauthOidcRedirectUri, 'string');
|
||||
},
|
||||
},
|
||||
mfaTotpEnabled: {
|
||||
needs: { mfaTotpEnabled: true },
|
||||
compute({ mfaTotpEnabled }: { mfaTotpEnabled: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('mfaTotpEnabled', mfaTotpEnabled, 'boolean');
|
||||
},
|
||||
},
|
||||
mfaTotpIssuer: {
|
||||
needs: { mfaTotpIssuer: true },
|
||||
compute({ mfaTotpIssuer }: { mfaTotpIssuer: string }) {
|
||||
return replaceDatabaseValueWithEnv('mfaTotpIssuer', mfaTotpIssuer, 'string');
|
||||
},
|
||||
},
|
||||
mfaPasskeys: {
|
||||
needs: { mfaPasskeys: true },
|
||||
compute({ mfaPasskeys }: { mfaPasskeys: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('mfaPasskeys', mfaPasskeys, 'boolean');
|
||||
},
|
||||
},
|
||||
ratelimitEnabled: {
|
||||
needs: { ratelimitEnabled: true },
|
||||
compute({ ratelimitEnabled }: { ratelimitEnabled: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('ratelimitEnabled', ratelimitEnabled, 'boolean');
|
||||
},
|
||||
},
|
||||
ratelimitMax: {
|
||||
needs: { ratelimitMax: true },
|
||||
compute({ ratelimitMax }: { ratelimitMax: number }) {
|
||||
return replaceDatabaseValueWithEnv('ratelimitMax', ratelimitMax, 'number');
|
||||
},
|
||||
},
|
||||
ratelimitWindow: {
|
||||
needs: { ratelimitWindow: true },
|
||||
compute({ ratelimitWindow }: { ratelimitWindow: number }) {
|
||||
return replaceDatabaseValueWithEnv('ratelimitWindow', ratelimitWindow, 'number');
|
||||
},
|
||||
},
|
||||
ratelimitAdminBypass: {
|
||||
needs: { ratelimitAdminBypass: true },
|
||||
compute({ ratelimitAdminBypass }: { ratelimitAdminBypass: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('ratelimitAdminBypass', ratelimitAdminBypass, 'boolean');
|
||||
},
|
||||
},
|
||||
ratelimitAllowList: {
|
||||
needs: { ratelimitAllowList: true },
|
||||
compute({ ratelimitAllowList }: { ratelimitAllowList: string[] }) {
|
||||
return replaceDatabaseValueWithEnv('ratelimitAllowList', ratelimitAllowList, 'string[]');
|
||||
},
|
||||
},
|
||||
httpWebhookOnUpload: {
|
||||
needs: { httpWebhookOnUpload: true },
|
||||
compute({ httpWebhookOnUpload }: { httpWebhookOnUpload: string }) {
|
||||
return replaceDatabaseValueWithEnv('httpWebhookOnUpload', httpWebhookOnUpload, 'string');
|
||||
},
|
||||
},
|
||||
httpWebhookOnShorten: {
|
||||
needs: { httpWebhookOnShorten: true },
|
||||
compute({ httpWebhookOnShorten }: { httpWebhookOnShorten: string }) {
|
||||
return replaceDatabaseValueWithEnv('httpWebhookOnShorten', httpWebhookOnShorten, 'string');
|
||||
},
|
||||
},
|
||||
discordWebhookUrl: {
|
||||
needs: { discordWebhookUrl: true },
|
||||
compute({ discordWebhookUrl }: { discordWebhookUrl: string }) {
|
||||
return replaceDatabaseValueWithEnv('discordWebhookUrl', discordWebhookUrl, 'string');
|
||||
},
|
||||
},
|
||||
discordUsername: {
|
||||
needs: { discordUsername: true },
|
||||
compute({ discordUsername }: { discordUsername: string }) {
|
||||
return replaceDatabaseValueWithEnv('discordUsername', discordUsername, 'string');
|
||||
},
|
||||
},
|
||||
discordAvatarUrl: {
|
||||
needs: { discordAvatarUrl: true },
|
||||
compute({ discordAvatarUrl }: { discordAvatarUrl: string }) {
|
||||
return replaceDatabaseValueWithEnv('discordAvatarUrl', discordAvatarUrl, 'string');
|
||||
},
|
||||
},
|
||||
discordOnUploadWebhookUrl: {
|
||||
needs: { discordOnUploadWebhookUrl: true },
|
||||
compute({ discordOnUploadWebhookUrl }: { discordOnUploadWebhookUrl: string }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'discordOnUploadWebhookUrl',
|
||||
discordOnUploadWebhookUrl,
|
||||
'string',
|
||||
);
|
||||
},
|
||||
},
|
||||
discordOnUploadUsername: {
|
||||
needs: { discordOnUploadUsername: true },
|
||||
compute({ discordOnUploadUsername }: { discordOnUploadUsername: string }) {
|
||||
return replaceDatabaseValueWithEnv('discordOnUploadUsername', discordOnUploadUsername, 'string');
|
||||
},
|
||||
},
|
||||
discordOnUploadAvatarUrl: {
|
||||
needs: { discordOnUploadAvatarUrl: true },
|
||||
compute({ discordOnUploadAvatarUrl }: { discordOnUploadAvatarUrl: string }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'discordOnUploadAvatarUrl',
|
||||
discordOnUploadAvatarUrl,
|
||||
'string',
|
||||
);
|
||||
},
|
||||
},
|
||||
discordOnUploadContent: {
|
||||
needs: { discordOnUploadContent: true },
|
||||
compute({ discordOnUploadContent }: { discordOnUploadContent: string }) {
|
||||
return replaceDatabaseValueWithEnv('discordOnUploadContent', discordOnUploadContent, 'string');
|
||||
},
|
||||
},
|
||||
discordOnUploadEmbed: {
|
||||
needs: { discordOnUploadEmbed: true },
|
||||
compute({ discordOnUploadEmbed }: { discordOnUploadEmbed: Prisma.JsonValue }) {
|
||||
return replaceDatabaseValueWithEnv('discordOnUploadEmbed', discordOnUploadEmbed, 'json[]');
|
||||
},
|
||||
},
|
||||
discordOnShortenWebhookUrl: {
|
||||
needs: { discordOnShortenWebhookUrl: true },
|
||||
compute({ discordOnShortenWebhookUrl }: { discordOnShortenWebhookUrl: string }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'discordOnShortenWebhookUrl',
|
||||
discordOnShortenWebhookUrl,
|
||||
'string',
|
||||
);
|
||||
},
|
||||
},
|
||||
discordOnShortenUsername: {
|
||||
needs: { discordOnShortenUsername: true },
|
||||
compute({ discordOnShortenUsername }: { discordOnShortenUsername: string }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'discordOnShortenUsername',
|
||||
discordOnShortenUsername,
|
||||
'string',
|
||||
);
|
||||
},
|
||||
},
|
||||
discordOnShortenAvatarUrl: {
|
||||
needs: { discordOnShortenAvatarUrl: true },
|
||||
compute({ discordOnShortenAvatarUrl }: { discordOnShortenAvatarUrl: string }) {
|
||||
return replaceDatabaseValueWithEnv(
|
||||
'discordOnShortenAvatarUrl',
|
||||
discordOnShortenAvatarUrl,
|
||||
'string',
|
||||
);
|
||||
},
|
||||
},
|
||||
discordOnShortenContent: {
|
||||
needs: { discordOnShortenContent: true },
|
||||
compute({ discordOnShortenContent }: { discordOnShortenContent: string }) {
|
||||
return replaceDatabaseValueWithEnv('discordOnShortenContent', discordOnShortenContent, 'string');
|
||||
},
|
||||
},
|
||||
discordOnShortenEmbed: {
|
||||
needs: { discordOnShortenEmbed: true },
|
||||
compute({ discordOnShortenEmbed }: { discordOnShortenEmbed: Prisma.JsonValue }) {
|
||||
return replaceDatabaseValueWithEnv('discordOnShortenEmbed', discordOnShortenEmbed, 'json[]');
|
||||
},
|
||||
},
|
||||
pwaEnabled: {
|
||||
needs: { pwaEnabled: true },
|
||||
compute({ pwaEnabled }: { pwaEnabled: boolean }) {
|
||||
return replaceDatabaseValueWithEnv('pwaEnabled', pwaEnabled, 'boolean');
|
||||
},
|
||||
},
|
||||
pwaTitle: {
|
||||
needs: { pwaTitle: true },
|
||||
compute({ pwaTitle }: { pwaTitle: string }) {
|
||||
return replaceDatabaseValueWithEnv('pwaTitle', pwaTitle, 'string');
|
||||
},
|
||||
},
|
||||
pwaShortName: {
|
||||
needs: { pwaShortName: true },
|
||||
compute({ pwaShortName }: { pwaShortName: string }) {
|
||||
return replaceDatabaseValueWithEnv('pwaShortName', pwaShortName, 'string');
|
||||
},
|
||||
},
|
||||
pwaDescription: {
|
||||
needs: { pwaDescription: true },
|
||||
compute({ pwaDescription }: { pwaDescription: string }) {
|
||||
return replaceDatabaseValueWithEnv('pwaDescription', pwaDescription, 'string');
|
||||
},
|
||||
},
|
||||
pwaThemeColor: {
|
||||
needs: { pwaThemeColor: true },
|
||||
compute({ pwaThemeColor }: { pwaThemeColor: string }) {
|
||||
return replaceDatabaseValueWithEnv('pwaThemeColor', pwaThemeColor, 'string');
|
||||
},
|
||||
},
|
||||
pwaBackgroundColor: {
|
||||
needs: { pwaBackgroundColor: true },
|
||||
compute({ pwaBackgroundColor }: { pwaBackgroundColor: string }) {
|
||||
return replaceDatabaseValueWithEnv('pwaBackgroundColor', pwaBackgroundColor, 'string');
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
.$extends(SettingsExtension);
|
||||
client.$connect();
|
||||
|
||||
return client;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { prisma } from '..';
|
||||
|
||||
export async function getZipline() {
|
||||
const zipline = await prisma.zipline.findFirst();
|
||||
const zipline = await prisma.zipline.getSettings();
|
||||
if (!zipline) {
|
||||
return prisma.zipline.create({
|
||||
data: {
|
||||
|
|
401
src/lib/db/settingsExtension.tsx
Normal file
401
src/lib/db/settingsExtension.tsx
Normal file
|
@ -0,0 +1,401 @@
|
|||
import { Prisma } from '@prisma/client';
|
||||
import { prisma } from '.';
|
||||
import { replaceDatabaseValueWithEnv } from '../config/read';
|
||||
|
||||
export const SettingsExtension = Prisma.defineExtension({
|
||||
name: 'settings',
|
||||
model: {
|
||||
zipline: {
|
||||
async getSettings(...args: any[]) {
|
||||
let settings = await prisma.zipline.findFirst(...args);
|
||||
if (!settings) {
|
||||
return settings;
|
||||
}
|
||||
// I was going to do a loop, but i kept getting typescript errors. please forgive me
|
||||
settings = {
|
||||
id: settings.id,
|
||||
createdAt: settings.createdAt,
|
||||
updatedAt: settings.updatedAt,
|
||||
firstSetup: settings.firstSetup,
|
||||
coreReturnHttpsUrls: replaceDatabaseValueWithEnv(
|
||||
'coreReturnHttpsUrls',
|
||||
settings.coreReturnHttpsUrls,
|
||||
'boolean',
|
||||
),
|
||||
coreDefaultDomain: replaceDatabaseValueWithEnv(
|
||||
'coreDefaultDomain',
|
||||
settings.coreDefaultDomain,
|
||||
'string',
|
||||
),
|
||||
coreTempDirectory: replaceDatabaseValueWithEnv(
|
||||
'coreTempDirectory',
|
||||
settings.coreTempDirectory,
|
||||
'string',
|
||||
),
|
||||
chunksMax: replaceDatabaseValueWithEnv('chunksMax', settings.chunksMax, 'string'),
|
||||
chunksSize: replaceDatabaseValueWithEnv('chunksSize', settings.chunksSize, 'string'),
|
||||
chunksEnabled: replaceDatabaseValueWithEnv('chunksEnabled', settings.chunksEnabled, 'boolean'),
|
||||
tasksDeleteInterval: replaceDatabaseValueWithEnv(
|
||||
'tasksDeleteInterval',
|
||||
settings.tasksDeleteInterval,
|
||||
'ms',
|
||||
),
|
||||
tasksClearInvitesInterval: replaceDatabaseValueWithEnv(
|
||||
'tasksClearInvitesInterval',
|
||||
settings.tasksClearInvitesInterval,
|
||||
'ms',
|
||||
),
|
||||
tasksMaxViewsInterval: replaceDatabaseValueWithEnv(
|
||||
'tasksMaxViewsInterval',
|
||||
settings.tasksMaxViewsInterval,
|
||||
'ms',
|
||||
),
|
||||
tasksThumbnailsInterval: replaceDatabaseValueWithEnv(
|
||||
'tasksThumbnailsInterval',
|
||||
settings.tasksThumbnailsInterval,
|
||||
'ms',
|
||||
),
|
||||
tasksMetricsInterval: replaceDatabaseValueWithEnv(
|
||||
'tasksMetricsInterval',
|
||||
settings.tasksMetricsInterval,
|
||||
'ms',
|
||||
),
|
||||
filesRoute: replaceDatabaseValueWithEnv('filesRoute', settings.filesRoute, 'string'),
|
||||
filesLength: replaceDatabaseValueWithEnv('filesLength', settings.filesLength, 'number'),
|
||||
filesDefaultFormat: replaceDatabaseValueWithEnv(
|
||||
'filesDefaultFormat',
|
||||
settings.filesDefaultFormat,
|
||||
'string',
|
||||
),
|
||||
filesDisabledExtensions: replaceDatabaseValueWithEnv(
|
||||
'filesDisabledExtensions',
|
||||
settings.filesDisabledExtensions,
|
||||
'string[]',
|
||||
),
|
||||
filesMaxFileSize: replaceDatabaseValueWithEnv(
|
||||
'filesMaxFileSize',
|
||||
settings.filesMaxFileSize,
|
||||
'byte',
|
||||
),
|
||||
filesDefaultExpiration: replaceDatabaseValueWithEnv(
|
||||
'filesDefaultExpiration',
|
||||
settings.filesDefaultExpiration,
|
||||
'string',
|
||||
),
|
||||
filesAssumeMimetypes: replaceDatabaseValueWithEnv(
|
||||
'filesAssumeMimetypes',
|
||||
settings.filesAssumeMimetypes,
|
||||
'boolean',
|
||||
),
|
||||
filesDefaultDateFormat: replaceDatabaseValueWithEnv(
|
||||
'filesDefaultDateFormat',
|
||||
settings.filesDefaultDateFormat,
|
||||
'string',
|
||||
),
|
||||
filesRemoveGpsMetadata: replaceDatabaseValueWithEnv(
|
||||
'filesRemoveGpsMetadata',
|
||||
settings.filesRemoveGpsMetadata,
|
||||
'boolean',
|
||||
),
|
||||
filesRandomWordsNumAdjectives: replaceDatabaseValueWithEnv(
|
||||
'filesRandomWordsNumAdjectives',
|
||||
settings.filesRandomWordsNumAdjectives,
|
||||
'number',
|
||||
),
|
||||
filesRandomWordsSeparator: replaceDatabaseValueWithEnv(
|
||||
'filesRandomWordsSeparator',
|
||||
settings.filesRandomWordsSeparator,
|
||||
'string',
|
||||
),
|
||||
urlsRoute: replaceDatabaseValueWithEnv('urlsRoute', settings.urlsRoute, 'string'),
|
||||
urlsLength: replaceDatabaseValueWithEnv('urlsLength', settings.urlsLength, 'number'),
|
||||
featuresImageCompression: replaceDatabaseValueWithEnv(
|
||||
'featuresImageCompression',
|
||||
settings.featuresImageCompression,
|
||||
'boolean',
|
||||
),
|
||||
featuresRobotsTxt: replaceDatabaseValueWithEnv(
|
||||
'featuresRobotsTxt',
|
||||
settings.featuresRobotsTxt,
|
||||
'boolean',
|
||||
),
|
||||
featuresHealthcheck: replaceDatabaseValueWithEnv(
|
||||
'featuresHealthcheck',
|
||||
settings.featuresHealthcheck,
|
||||
'boolean',
|
||||
),
|
||||
featuresUserRegistration: replaceDatabaseValueWithEnv(
|
||||
'featuresUserRegistration',
|
||||
settings.featuresUserRegistration,
|
||||
'boolean',
|
||||
),
|
||||
featuresOauthRegistration: replaceDatabaseValueWithEnv(
|
||||
'featuresOauthRegistration',
|
||||
settings.featuresOauthRegistration,
|
||||
'boolean',
|
||||
),
|
||||
featuresDeleteOnMaxViews: replaceDatabaseValueWithEnv(
|
||||
'featuresDeleteOnMaxViews',
|
||||
settings.featuresDeleteOnMaxViews,
|
||||
'boolean',
|
||||
),
|
||||
featuresThumbnailsEnabled: replaceDatabaseValueWithEnv(
|
||||
'featuresThumbnailsEnabled',
|
||||
settings.featuresThumbnailsEnabled,
|
||||
'boolean',
|
||||
),
|
||||
featuresThumbnailsNumberThreads: replaceDatabaseValueWithEnv(
|
||||
'featuresThumbnailsNumberThreads',
|
||||
settings.featuresThumbnailsNumberThreads,
|
||||
'number',
|
||||
),
|
||||
featuresMetricsEnabled: replaceDatabaseValueWithEnv(
|
||||
'featuresMetricsEnabled',
|
||||
settings.featuresMetricsEnabled,
|
||||
'boolean',
|
||||
),
|
||||
featuresMetricsAdminOnly: replaceDatabaseValueWithEnv(
|
||||
'featuresMetricsAdminOnly',
|
||||
settings.featuresMetricsAdminOnly,
|
||||
'boolean',
|
||||
),
|
||||
featuresMetricsShowUserSpecific: replaceDatabaseValueWithEnv(
|
||||
'featuresMetricsShowUserSpecific',
|
||||
settings.featuresMetricsShowUserSpecific,
|
||||
'boolean',
|
||||
),
|
||||
invitesEnabled: replaceDatabaseValueWithEnv('invitesEnabled', settings.invitesEnabled, 'boolean'),
|
||||
invitesLength: replaceDatabaseValueWithEnv('invitesLength', settings.invitesLength, 'number'),
|
||||
websiteTitle: replaceDatabaseValueWithEnv('websiteTitle', settings.websiteTitle, 'string'),
|
||||
websiteTitleLogo: replaceDatabaseValueWithEnv(
|
||||
'websiteTitleLogo',
|
||||
settings.websiteTitleLogo,
|
||||
'string',
|
||||
),
|
||||
websiteExternalLinks: replaceDatabaseValueWithEnv(
|
||||
'websiteExternalLinks',
|
||||
settings.websiteExternalLinks,
|
||||
'json[]',
|
||||
),
|
||||
websiteLoginBackground: replaceDatabaseValueWithEnv(
|
||||
'websiteLoginBackground',
|
||||
settings.websiteLoginBackground,
|
||||
'string',
|
||||
),
|
||||
websiteLoginBackgroundBlur: replaceDatabaseValueWithEnv(
|
||||
'websiteLoginBackgroundBlur',
|
||||
settings.websiteLoginBackgroundBlur,
|
||||
'boolean',
|
||||
),
|
||||
websiteDefaultAvatar: replaceDatabaseValueWithEnv(
|
||||
'websiteDefaultAvatar',
|
||||
settings.websiteDefaultAvatar,
|
||||
'string',
|
||||
),
|
||||
websiteTos: replaceDatabaseValueWithEnv('websiteTos', settings.websiteTos, 'string'),
|
||||
websiteThemeDefault: replaceDatabaseValueWithEnv(
|
||||
'websiteThemeDefault',
|
||||
settings.websiteThemeDefault,
|
||||
'string',
|
||||
),
|
||||
websiteThemeDark: replaceDatabaseValueWithEnv(
|
||||
'websiteThemeDark',
|
||||
settings.websiteThemeDark,
|
||||
'string',
|
||||
),
|
||||
websiteThemeLight: replaceDatabaseValueWithEnv(
|
||||
'websiteThemeLight',
|
||||
settings.websiteThemeLight,
|
||||
'string',
|
||||
),
|
||||
oauthBypassLocalLogin: replaceDatabaseValueWithEnv(
|
||||
'oauthBypassLocalLogin',
|
||||
settings.oauthBypassLocalLogin,
|
||||
'boolean',
|
||||
),
|
||||
oauthLoginOnly: replaceDatabaseValueWithEnv('oauthLoginOnly', settings.oauthLoginOnly, 'boolean'),
|
||||
oauthDiscordClientId: replaceDatabaseValueWithEnv(
|
||||
'oauthDiscordClientId',
|
||||
settings.oauthDiscordClientId,
|
||||
'string',
|
||||
),
|
||||
oauthDiscordClientSecret: replaceDatabaseValueWithEnv(
|
||||
'oauthDiscordClientSecret',
|
||||
settings.oauthDiscordClientSecret,
|
||||
'string',
|
||||
),
|
||||
oauthDiscordRedirectUri: replaceDatabaseValueWithEnv(
|
||||
'oauthDiscordRedirectUri',
|
||||
settings.oauthDiscordRedirectUri,
|
||||
'string',
|
||||
),
|
||||
oauthGoogleClientId: replaceDatabaseValueWithEnv(
|
||||
'oauthGoogleClientId',
|
||||
settings.oauthGoogleClientId,
|
||||
'string',
|
||||
),
|
||||
oauthGoogleClientSecret: replaceDatabaseValueWithEnv(
|
||||
'oauthGoogleClientSecret',
|
||||
settings.oauthGoogleClientSecret,
|
||||
'string',
|
||||
),
|
||||
oauthGoogleRedirectUri: replaceDatabaseValueWithEnv(
|
||||
'oauthGoogleRedirectUri',
|
||||
settings.oauthGoogleRedirectUri,
|
||||
'string',
|
||||
),
|
||||
oauthGithubClientId: replaceDatabaseValueWithEnv(
|
||||
'oauthGithubClientId',
|
||||
settings.oauthGithubClientId,
|
||||
'string',
|
||||
),
|
||||
oauthGithubClientSecret: replaceDatabaseValueWithEnv(
|
||||
'oauthGithubClientSecret',
|
||||
settings.oauthGithubClientSecret,
|
||||
'string',
|
||||
),
|
||||
oauthGithubRedirectUri: replaceDatabaseValueWithEnv(
|
||||
'oauthGithubRedirectUri',
|
||||
settings.oauthGithubRedirectUri,
|
||||
'string',
|
||||
),
|
||||
oauthOidcClientId: replaceDatabaseValueWithEnv(
|
||||
'oauthOidcClientId',
|
||||
settings.oauthOidcClientId,
|
||||
'string',
|
||||
),
|
||||
oauthOidcClientSecret: replaceDatabaseValueWithEnv(
|
||||
'oauthOidcClientSecret',
|
||||
settings.oauthOidcClientSecret,
|
||||
'string',
|
||||
),
|
||||
oauthOidcAuthorizeUrl: replaceDatabaseValueWithEnv(
|
||||
'oauthOidcAuthorizeUrl',
|
||||
settings.oauthOidcAuthorizeUrl,
|
||||
'string',
|
||||
),
|
||||
oauthOidcUserinfoUrl: replaceDatabaseValueWithEnv(
|
||||
'oauthOidcUserinfoUrl',
|
||||
settings.oauthOidcUserinfoUrl,
|
||||
'string',
|
||||
),
|
||||
oauthOidcTokenUrl: replaceDatabaseValueWithEnv(
|
||||
'oauthOidcTokenUrl',
|
||||
settings.oauthOidcTokenUrl,
|
||||
'string',
|
||||
),
|
||||
oauthOidcRedirectUri: replaceDatabaseValueWithEnv(
|
||||
'oauthOidcRedirectUri',
|
||||
settings.oauthOidcRedirectUri,
|
||||
'string',
|
||||
),
|
||||
mfaTotpEnabled: replaceDatabaseValueWithEnv('mfaTotpEnabled', settings.mfaTotpEnabled, 'boolean'),
|
||||
mfaTotpIssuer: replaceDatabaseValueWithEnv('mfaTotpIssuer', settings.mfaTotpIssuer, 'string'),
|
||||
mfaPasskeys: replaceDatabaseValueWithEnv('mfaPasskeys', settings.mfaPasskeys, 'boolean'),
|
||||
ratelimitEnabled: replaceDatabaseValueWithEnv(
|
||||
'ratelimitEnabled',
|
||||
settings.ratelimitEnabled,
|
||||
'boolean',
|
||||
),
|
||||
ratelimitMax: replaceDatabaseValueWithEnv('ratelimitMax', settings.ratelimitMax, 'number'),
|
||||
ratelimitWindow: replaceDatabaseValueWithEnv('ratelimitWindow', settings.ratelimitWindow, 'number'),
|
||||
ratelimitAdminBypass: replaceDatabaseValueWithEnv(
|
||||
'ratelimitAdminBypass',
|
||||
settings.ratelimitAdminBypass,
|
||||
'boolean',
|
||||
),
|
||||
ratelimitAllowList: replaceDatabaseValueWithEnv(
|
||||
'ratelimitAllowList',
|
||||
settings.ratelimitAllowList,
|
||||
'string[]',
|
||||
),
|
||||
httpWebhookOnUpload: replaceDatabaseValueWithEnv(
|
||||
'httpWebhookOnUpload',
|
||||
settings.httpWebhookOnUpload,
|
||||
'string',
|
||||
),
|
||||
httpWebhookOnShorten: replaceDatabaseValueWithEnv(
|
||||
'httpWebhookOnShorten',
|
||||
settings.httpWebhookOnShorten,
|
||||
'string',
|
||||
),
|
||||
discordWebhookUrl: replaceDatabaseValueWithEnv(
|
||||
'discordWebhookUrl',
|
||||
settings.discordWebhookUrl,
|
||||
'string',
|
||||
),
|
||||
discordUsername: replaceDatabaseValueWithEnv('discordUsername', settings.discordUsername, 'string'),
|
||||
discordAvatarUrl: replaceDatabaseValueWithEnv(
|
||||
'discordAvatarUrl',
|
||||
settings.discordAvatarUrl,
|
||||
'string',
|
||||
),
|
||||
discordOnUploadWebhookUrl: replaceDatabaseValueWithEnv(
|
||||
'discordOnUploadWebhookUrl',
|
||||
settings.discordOnUploadWebhookUrl,
|
||||
'string',
|
||||
),
|
||||
discordOnUploadUsername: replaceDatabaseValueWithEnv(
|
||||
'discordOnUploadUsername',
|
||||
settings.discordOnUploadUsername,
|
||||
'string',
|
||||
),
|
||||
discordOnUploadAvatarUrl: replaceDatabaseValueWithEnv(
|
||||
'discordOnUploadAvatarUrl',
|
||||
settings.discordOnUploadAvatarUrl,
|
||||
'string',
|
||||
),
|
||||
discordOnUploadContent: replaceDatabaseValueWithEnv(
|
||||
'discordOnUploadContent',
|
||||
settings.discordOnUploadContent,
|
||||
'string',
|
||||
),
|
||||
discordOnUploadEmbed: replaceDatabaseValueWithEnv(
|
||||
'discordOnUploadEmbed',
|
||||
settings.discordOnUploadEmbed,
|
||||
'json[]',
|
||||
),
|
||||
discordOnShortenWebhookUrl: replaceDatabaseValueWithEnv(
|
||||
'discordOnShortenWebhookUrl',
|
||||
settings.discordOnShortenWebhookUrl,
|
||||
'string',
|
||||
),
|
||||
discordOnShortenUsername: replaceDatabaseValueWithEnv(
|
||||
'discordOnShortenUsername',
|
||||
settings.discordOnShortenUsername,
|
||||
'string',
|
||||
),
|
||||
discordOnShortenAvatarUrl: replaceDatabaseValueWithEnv(
|
||||
'discordOnShortenAvatarUrl',
|
||||
settings.discordOnShortenAvatarUrl,
|
||||
'string',
|
||||
),
|
||||
discordOnShortenContent: replaceDatabaseValueWithEnv(
|
||||
'discordOnShortenContent',
|
||||
settings.discordOnShortenContent,
|
||||
'string',
|
||||
),
|
||||
discordOnShortenEmbed: replaceDatabaseValueWithEnv(
|
||||
'discordOnShortenEmbed',
|
||||
settings.discordOnShortenEmbed,
|
||||
'json[]',
|
||||
),
|
||||
pwaEnabled: replaceDatabaseValueWithEnv('pwaEnabled', settings.pwaEnabled, 'boolean'),
|
||||
pwaTitle: replaceDatabaseValueWithEnv('pwaTitle', settings.pwaTitle, 'string'),
|
||||
pwaShortName: replaceDatabaseValueWithEnv('pwaShortName', settings.pwaShortName, 'string'),
|
||||
pwaDescription: replaceDatabaseValueWithEnv('pwaDescription', settings.pwaDescription, 'string'),
|
||||
pwaThemeColor: replaceDatabaseValueWithEnv('pwaThemeColor', settings.pwaThemeColor, 'string'),
|
||||
pwaBackgroundColor: replaceDatabaseValueWithEnv(
|
||||
'pwaBackgroundColor',
|
||||
settings.pwaBackgroundColor,
|
||||
'string',
|
||||
),
|
||||
};
|
||||
return settings;
|
||||
},
|
||||
async getSettingsRaw(...args: any[]) {
|
||||
return await prisma.zipline.findFirst(...args);
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
import { bytes } from '@/lib/bytes';
|
||||
import { reloadSettings } from '@/lib/config';
|
||||
import { DATABASE_TO_PROP, readDatabaseSettings, valueIsFromEnv } from '@/lib/config/read';
|
||||
import { DATABASE_TO_PROP, readDatabaseSettings, valueIsFromEnv as valueFromEnv } from '@/lib/config/read';
|
||||
import { prisma } from '@/lib/db';
|
||||
import { log } from '@/lib/logger';
|
||||
import { readThemes } from '@/lib/theme/file';
|
||||
|
@ -64,7 +64,7 @@ export default fastifyPlugin(
|
|||
preHandler: [userMiddleware, administratorMiddleware],
|
||||
},
|
||||
async (_, res) => {
|
||||
const settings = await prisma.zipline.findFirst({
|
||||
const settings = await prisma.zipline.getSettingsRaw({
|
||||
omit: {
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
|
@ -80,12 +80,11 @@ export default fastifyPlugin(
|
|||
};
|
||||
|
||||
for (const key in DATABASE_TO_PROP) {
|
||||
if (DATABASE_TO_PROP.hasOwnProperty(key)) {
|
||||
if (valueIsFromEnv(key as keyof typeof DATABASE_TO_PROP)) {
|
||||
// settingsResponse.locked[key] = "This value has been set by the " + databaseToEnv(key as keyof typeof DATABASE_TO_PROP) + " environment variable and cannot be changed here.";
|
||||
settingsResponse.locked[key] = true;
|
||||
}
|
||||
const val = valueFromEnv(key as keyof typeof DATABASE_TO_PROP);
|
||||
if (val === undefined) {
|
||||
continue;
|
||||
}
|
||||
settingsResponse.locked[key] = val;
|
||||
}
|
||||
|
||||
return res.send(settingsResponse);
|
||||
|
@ -98,7 +97,7 @@ export default fastifyPlugin(
|
|||
preHandler: [userMiddleware, administratorMiddleware],
|
||||
},
|
||||
async (req, res) => {
|
||||
const settings = await prisma.zipline.findFirst();
|
||||
const settings = await prisma.zipline.getSettingsRaw();
|
||||
if (!settings) return res.notFound('no settings table found');
|
||||
|
||||
const result: any = await parseSettings(req.body);
|
||||
|
@ -114,15 +113,6 @@ export default fastifyPlugin(
|
|||
});
|
||||
}
|
||||
|
||||
// iterate through every database_to_prop object key
|
||||
for (const key in DATABASE_TO_PROP) {
|
||||
if (DATABASE_TO_PROP.hasOwnProperty(key)) {
|
||||
if (valueIsFromEnv(key as keyof typeof DATABASE_TO_PROP)) {
|
||||
result.data[key] = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const newSettings = await prisma.zipline.update({
|
||||
where: {
|
||||
id: settings.id,
|
||||
|
@ -146,7 +136,22 @@ export default fastifyPlugin(
|
|||
by: req.user.username,
|
||||
});
|
||||
|
||||
return res.send(newSettings);
|
||||
const settingsResponse: ApiServerSettingsResponse = {
|
||||
...newSettings,
|
||||
locked: {},
|
||||
};
|
||||
|
||||
for (const key in DATABASE_TO_PROP) {
|
||||
if (DATABASE_TO_PROP.hasOwnProperty(key)) {
|
||||
const val = valueFromEnv(key as keyof typeof DATABASE_TO_PROP);
|
||||
if (val === undefined) {
|
||||
continue;
|
||||
}
|
||||
settingsResponse.locked[key] = val;
|
||||
}
|
||||
}
|
||||
|
||||
return res.send(settingsResponse);
|
||||
},
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue