feat: more options for text uploads & password protect them
This commit is contained in:
parent
d432b388f6
commit
4552643ff8
4 changed files with 125 additions and 5 deletions
|
@ -1,9 +1,9 @@
|
|||
import { Button, Group, Select, Tabs, Title } from '@mantine/core';
|
||||
import { Button, Group, PasswordInput, Select, Tabs, Title, Tooltip } from '@mantine/core';
|
||||
import { Prism } from '@mantine/prism';
|
||||
import { Language } from 'prism-react-renderer';
|
||||
import { showNotification, updateNotification } from '@mantine/notifications';
|
||||
import CodeInput from 'components/CodeInput';
|
||||
import { ImageIcon, TypeIcon, UploadIcon } from 'components/icons';
|
||||
import { ClockIcon, ImageIcon, TypeIcon, UploadIcon } from 'components/icons';
|
||||
import Link from 'components/Link';
|
||||
import exts from 'lib/exts';
|
||||
import { userSelector } from 'lib/recoil/user';
|
||||
|
@ -15,10 +15,47 @@ export default function Upload() {
|
|||
|
||||
const [value, setValue] = useState('');
|
||||
const [lang, setLang] = useState('txt');
|
||||
const [password, setPassword] = useState('');
|
||||
const [expires, setExpires] = useState('never');
|
||||
|
||||
const handleUpload = async () => {
|
||||
const file = new File([value], 'text.' + lang);
|
||||
|
||||
const expires_at =
|
||||
expires === 'never'
|
||||
? null
|
||||
: new Date(
|
||||
{
|
||||
'5min': Date.now() + 5 * 60 * 1000,
|
||||
'10min': Date.now() + 10 * 60 * 1000,
|
||||
'15min': Date.now() + 15 * 60 * 1000,
|
||||
'30min': Date.now() + 30 * 60 * 1000,
|
||||
'1h': Date.now() + 60 * 60 * 1000,
|
||||
'2h': Date.now() + 2 * 60 * 60 * 1000,
|
||||
'3h': Date.now() + 3 * 60 * 60 * 1000,
|
||||
'4h': Date.now() + 4 * 60 * 60 * 1000,
|
||||
'5h': Date.now() + 5 * 60 * 60 * 1000,
|
||||
'6h': Date.now() + 6 * 60 * 60 * 1000,
|
||||
'8h': Date.now() + 8 * 60 * 60 * 1000,
|
||||
'12h': Date.now() + 12 * 60 * 60 * 1000,
|
||||
'1d': Date.now() + 24 * 60 * 60 * 1000,
|
||||
'3d': Date.now() + 3 * 24 * 60 * 60 * 1000,
|
||||
'5d': Date.now() + 5 * 24 * 60 * 60 * 1000,
|
||||
'7d': Date.now() + 7 * 24 * 60 * 60 * 1000,
|
||||
'1w': Date.now() + 7 * 24 * 60 * 60 * 1000,
|
||||
'1.5w': Date.now() + 1.5 * 7 * 24 * 60 * 60 * 1000,
|
||||
'2w': Date.now() + 2 * 7 * 24 * 60 * 60 * 1000,
|
||||
'3w': Date.now() + 3 * 7 * 24 * 60 * 60 * 1000,
|
||||
'1m': Date.now() + 30 * 24 * 60 * 60 * 1000,
|
||||
'1.5m': Date.now() + 1.5 * 30 * 24 * 60 * 60 * 1000,
|
||||
'2m': Date.now() + 2 * 30 * 24 * 60 * 60 * 1000,
|
||||
'3m': Date.now() + 3 * 30 * 24 * 60 * 60 * 1000,
|
||||
'6m': Date.now() + 6 * 30 * 24 * 60 * 60 * 1000,
|
||||
'8m': Date.now() + 8 * 30 * 24 * 60 * 60 * 1000,
|
||||
'1y': Date.now() + 365 * 24 * 60 * 60 * 1000,
|
||||
}[expires]
|
||||
);
|
||||
|
||||
showNotification({
|
||||
id: 'upload-text',
|
||||
title: 'Uploading...',
|
||||
|
@ -58,6 +95,9 @@ export default function Upload() {
|
|||
req.setRequestHeader('Authorization', user.token);
|
||||
req.setRequestHeader('UploadText', 'true');
|
||||
|
||||
expires !== 'never' && req.setRequestHeader('Expires-At', 'date=' + expires_at.toISOString());
|
||||
password !== '' && req.setRequestHeader('Password', password);
|
||||
|
||||
req.send(body);
|
||||
};
|
||||
|
||||
|
@ -99,6 +139,51 @@ export default function Upload() {
|
|||
icon={<TypeIcon />}
|
||||
searchable
|
||||
/>
|
||||
<Tooltip label='Add a password to your files (optional, leave blank for none)'>
|
||||
<PasswordInput
|
||||
style={{ width: '252px' }}
|
||||
placeholder='Password'
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.currentTarget.value)}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip label='Set an expiration date for your files (optional, defaults to never)'>
|
||||
<Select
|
||||
value={expires}
|
||||
onChange={(e) => setExpires(e)}
|
||||
icon={<ClockIcon size={14} />}
|
||||
data={[
|
||||
{ value: 'never', label: 'Never' },
|
||||
{ value: '5min', label: '5 minutes' },
|
||||
{ value: '10min', label: '10 minutes' },
|
||||
{ value: '15min', label: '15 minutes' },
|
||||
{ value: '30min', label: '30 minutes' },
|
||||
{ value: '1h', label: '1 hour' },
|
||||
{ value: '2h', label: '2 hours' },
|
||||
{ value: '3h', label: '3 hours' },
|
||||
{ value: '4h', label: '4 hours' },
|
||||
{ value: '5h', label: '5 hours' },
|
||||
{ value: '6h', label: '6 hours' },
|
||||
{ value: '8h', label: '8 hours' },
|
||||
{ value: '12h', label: '12 hours' },
|
||||
{ value: '1d', label: '1 day' },
|
||||
{ value: '3d', label: '3 days' },
|
||||
{ value: '5d', label: '5 days' },
|
||||
{ value: '7d', label: '7 days' },
|
||||
{ value: '1w', label: '1 week' },
|
||||
{ value: '1.5w', label: '1.5 weeks' },
|
||||
{ value: '2w', label: '2 weeks' },
|
||||
{ value: '3w', label: '3 weeks' },
|
||||
{ value: '1m', label: '1 month' },
|
||||
{ value: '1.5m', label: '1.5 months' },
|
||||
{ value: '2m', label: '2 months' },
|
||||
{ value: '3m', label: '3 months' },
|
||||
{ value: '6m', label: '6 months' },
|
||||
{ value: '8m', label: '8 months' },
|
||||
{ value: '1y', label: '1 year' },
|
||||
]}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Button
|
||||
leftIcon={<UploadIcon />}
|
||||
onClick={handleUpload}
|
||||
|
|
|
@ -4,4 +4,4 @@ if (!global.prisma) {
|
|||
if (!process.env.ZIPLINE_DOCKER_BUILD) global.prisma = new PrismaClient();
|
||||
}
|
||||
|
||||
export default global.prisma;
|
||||
export default global.prisma as PrismaClient;
|
||||
|
|
|
@ -6,10 +6,13 @@ import config from 'lib/config';
|
|||
import prisma from 'lib/prisma';
|
||||
import { parse } from 'lib/utils/client';
|
||||
import exts from 'lib/exts';
|
||||
import { Image } from '@prisma/client';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function EmbeddedImage({ image, user, pass }) {
|
||||
export default function EmbeddedImage({ image, user, pass, prismRender }) {
|
||||
const dataURL = (route: string) => `${route}/${image.file}`;
|
||||
|
||||
const router = useRouter();
|
||||
const [opened, setOpened] = useState(pass);
|
||||
const [password, setPassword] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
|
@ -22,6 +25,7 @@ export default function EmbeddedImage({ image, user, pass }) {
|
|||
|
||||
if (res.ok) {
|
||||
setError('');
|
||||
if (prismRender) return router.push(`/code/${image.file}?password=${password}`);
|
||||
updateImage(`/api/auth/image?id=${image.id}&password=${password}`);
|
||||
setOpened(false);
|
||||
} else {
|
||||
|
@ -193,13 +197,25 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
|
|||
image.created_at = image.created_at.toString();
|
||||
|
||||
const prismRender = Object.keys(exts).includes(image.file.split('.').pop());
|
||||
if (prismRender)
|
||||
if (prismRender && !image.password)
|
||||
return {
|
||||
redirect: {
|
||||
destination: `/code/${image.file}`,
|
||||
permanent: true,
|
||||
},
|
||||
};
|
||||
else if (prismRender && image.password) {
|
||||
const pass = image.password ? true : false;
|
||||
delete image.password;
|
||||
return {
|
||||
props: {
|
||||
image,
|
||||
user,
|
||||
pass,
|
||||
prismRender: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (!image.mimetype.startsWith('image') && !image.mimetype.startsWith('video')) {
|
||||
const { default: datasource } = await import('lib/datasource');
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { Prism } from '@mantine/prism';
|
||||
import prisma from 'lib/prisma';
|
||||
import exts from 'lib/exts';
|
||||
import { streamToString } from 'lib/utils/streams';
|
||||
import { GetServerSideProps } from 'next';
|
||||
import { checkPassword } from 'lib/util';
|
||||
|
||||
type CodeProps = {
|
||||
code: string;
|
||||
|
@ -33,6 +35,23 @@ export const getServerSideProps: GetServerSideProps<CodeProps> = async (context)
|
|||
notFound: true,
|
||||
};
|
||||
|
||||
const file = await prisma.image.findFirst({
|
||||
where: {
|
||||
file: context.params.id as string,
|
||||
},
|
||||
});
|
||||
if (!file) return { notFound: true };
|
||||
|
||||
if (file.password && !context.query.password)
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
|
||||
if (file.password && context.query.password) {
|
||||
const valid = await checkPassword(context.query.password as string, file.password);
|
||||
if (!valid) return { notFound: true };
|
||||
}
|
||||
|
||||
context.res.setHeader('Cache-Control', 'public, max-age=2628000, stale-while-revalidate=86400');
|
||||
|
||||
return {
|
||||
|
|
Loading…
Add table
Reference in a new issue