Skip to content

Commit

Permalink
feat: clearing orphaned files (#303)
Browse files Browse the repository at this point in the history
  • Loading branch information
TacticalTechJay authored Feb 26, 2023
1 parent 2d69cd5 commit 95a1c7f
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 53 deletions.
88 changes: 88 additions & 0 deletions src/components/pages/Manage/ClearStorage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { Button, Checkbox, Group, Modal, Text, Title } from '@mantine/core';
import { closeAllModals, openConfirmModal } from '@mantine/modals';
import { showNotification, updateNotification } from '@mantine/notifications';
import { CheckIcon, CrossIcon } from 'components/icons';
import useFetch from 'hooks/useFetch';

export default function ClearStorage({ open, setOpen, check, setCheck }) {
const handleDelete = async (datasource: boolean, orphaned?: boolean) => {
showNotification({
id: 'clear-uploads',
title: 'Clearing...',
message: '',
loading: true,
autoClose: false,
});

const res = await useFetch('/api/admin/clear', 'POST', { datasource, orphaned });

if (res.error) {
updateNotification({
id: 'clear-uploads',
title: 'Error while clearing uploads',
message: res.error,
color: 'red',
icon: <CrossIcon />,
});
} else {
updateNotification({
id: 'clear-uploads',
title: 'Successfully cleared uploads',
message: '',
color: 'green',
icon: <CheckIcon />,
});
}
};

return (
<Modal
opened={open}
onClose={() => setOpen(false)}
title={<Title size='sm'>Are you sure you want to clear all uploads in the database?</Title>}
>
<Checkbox
id='orphanedFiles'
label='Clear only orphaned files?'
description='Orphaned files are not owned by anyone. They can&#39;t be seen the dashboard by anyone.'
checked={check}
onChange={(e) => setCheck(e.currentTarget.checked)}
/>
<Group position='right' mt='md'>
<Button
onClick={() => {
setOpen(() => false);
}}
>
No
</Button>
<Button
onClick={() => {
setOpen(false);
openConfirmModal({
title: 'Do you want to clear storage too?',
labels: { confirm: 'Yes', cancel: check ? 'Ok' : 'No' },
children: check && (
<Text size='sm' color='gray'>
Due to clearing orphaned files, storage clearing will be unavailable.
</Text>
),
confirmProps: { disabled: check },
onConfirm: () => {
closeAllModals();
handleDelete(true);
},
onCancel: () => {
closeAllModals();
handleDelete(false, check);
},
onClose: () => setCheck(false),
});
}}
>
Yes
</Button>
</Group>
</Modal>
);
}
58 changes: 5 additions & 53 deletions src/components/pages/Manage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { bytesToHuman } from 'lib/utils/bytes';
import { capitalize } from 'lib/utils/client';
import { useEffect, useReducer, useState } from 'react';
import { useRecoilState } from 'recoil';
import ClearStorage from './ClearStorage';
import Flameshot from './Flameshot';
import ShareX from './ShareX';
import { TotpModal } from './TotpModal';
Expand Down Expand Up @@ -76,10 +77,12 @@ export default function Manage({ oauth_registration, oauth_providers: raw_oauth_
const [totpOpen, setTotpOpen] = useState(false);
const [shareXOpen, setShareXOpen] = useState(false);
const [flameshotOpen, setFlameshotOpen] = useState(false);
const [clrStorOpen, setClrStorOpen] = useState(false);
const [exports, setExports] = useState([]);
const [file, setFile] = useState<File>(null);
const [fileDataURL, setFileDataURL] = useState(user.avatar ?? null);
const [totpEnabled, setTotpEnabled] = useState(!!user.totpSecret);
const [checked, setCheck] = useState(false);

const getDataURL = (f: File): Promise<string> => {
return new Promise((res, rej) => {
Expand Down Expand Up @@ -312,58 +315,6 @@ export default function Manage({ oauth_registration, oauth_providers: raw_oauth_
}
};

const openClearData = () => {
modals.openConfirmModal({
title: 'Are you sure you want to clear all uploads in the database?',
closeOnConfirm: false,
labels: { confirm: 'Yes', cancel: 'No' },
onConfirm: () => {
modals.openConfirmModal({
title: 'Do you want to clear storage too?',
labels: { confirm: 'Yes', cancel: 'No' },
onConfirm: () => {
handleClearData(true);
modals.closeAll();
},
onCancel: () => {
handleClearData(false);
modals.closeAll();
},
});
},
});
};

const handleClearData = async (datasource?: boolean) => {
showNotification({
id: 'clear-uploads',
title: 'Clearing...',
message: '',
loading: true,
autoClose: false,
});

const res = await useFetch('/api/admin/clear', 'POST', { datasource });

if (res.error) {
updateNotification({
id: 'clear-uploads',
title: 'Error while clearing uploads',
message: res.error,
color: 'red',
icon: <CrossIcon />,
});
} else {
updateNotification({
id: 'clear-uploads',
title: 'Successfully cleared uploads',
message: '',
color: 'green',
icon: <CheckIcon />,
});
}
};

const handleOauthUnlink = async (provider) => {
const res = await useFetch('/api/auth/oauth', 'DELETE', {
provider,
Expand Down Expand Up @@ -598,7 +549,7 @@ export default function Manage({ oauth_registration, oauth_providers: raw_oauth_
<Button size='md' onClick={forceUpdateStats} color='red' rightIcon={<RefreshIcon />}>
Force Update Stats
</Button>
<Button size='md' onClick={openClearData} color='red' rightIcon={<TrashIcon />}>
<Button size='md' onClick={() => setClrStorOpen(true)} color='red' rightIcon={<TrashIcon />}>
Delete all uploads
</Button>
</Group>
Expand All @@ -617,6 +568,7 @@ export default function Manage({ oauth_registration, oauth_providers: raw_oauth_

<ShareX user={user} open={shareXOpen} setOpen={setShareXOpen} />
<Flameshot user={user} open={flameshotOpen} setOpen={setFlameshotOpen} />
<ClearStorage open={clrStorOpen} setOpen={setClrStorOpen} check={checked} setCheck={setCheck} />
</>
);
}
10 changes: 10 additions & 0 deletions src/pages/api/admin/clear.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ const logger = Logger.get('admin');

async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) {
try {
const { datasource, orphaned } = req.body;
if (orphaned) {
const { count } = await prisma.file.deleteMany({
where: {
userId: null,
},
});
logger.info(`User ${user.username} (${user.id}) cleared the database of ${count} orphaned files`);
return res.json({ message: 'cleared storage (orphaned only)' });
}
const { count } = await prisma.file.deleteMany({});
logger.info(`User ${user.username} (${user.id}) cleared the database of ${count} files`);

Expand Down

0 comments on commit 95a1c7f

Please sign in to comment.