From 95a1c7f92c66df4b766f56ac83501dc1e93bd5c4 Mon Sep 17 00:00:00 2001 From: Jayvin Hernandez Date: Sat, 25 Feb 2023 20:35:08 -0800 Subject: [PATCH] feat: clearing orphaned files (#303) --- src/components/pages/Manage/ClearStorage.tsx | 88 ++++++++++++++++++++ src/components/pages/Manage/index.tsx | 58 ++----------- src/pages/api/admin/clear.ts | 10 +++ 3 files changed, 103 insertions(+), 53 deletions(-) create mode 100644 src/components/pages/Manage/ClearStorage.tsx diff --git a/src/components/pages/Manage/ClearStorage.tsx b/src/components/pages/Manage/ClearStorage.tsx new file mode 100644 index 0000000..d4f94df --- /dev/null +++ b/src/components/pages/Manage/ClearStorage.tsx @@ -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: , + }); + } else { + updateNotification({ + id: 'clear-uploads', + title: 'Successfully cleared uploads', + message: '', + color: 'green', + icon: , + }); + } + }; + + return ( + setOpen(false)} + title={Are you sure you want to clear all uploads in the database?} + > + setCheck(e.currentTarget.checked)} + /> + + + + + + ); +} diff --git a/src/components/pages/Manage/index.tsx b/src/components/pages/Manage/index.tsx index 6db0bbe..9fa7d3a 100644 --- a/src/components/pages/Manage/index.tsx +++ b/src/components/pages/Manage/index.tsx @@ -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'; @@ -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(null); const [fileDataURL, setFileDataURL] = useState(user.avatar ?? null); const [totpEnabled, setTotpEnabled] = useState(!!user.totpSecret); + const [checked, setCheck] = useState(false); const getDataURL = (f: File): Promise => { return new Promise((res, rej) => { @@ -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: , - }); - } else { - updateNotification({ - id: 'clear-uploads', - title: 'Successfully cleared uploads', - message: '', - color: 'green', - icon: , - }); - } - }; - const handleOauthUnlink = async (provider) => { const res = await useFetch('/api/auth/oauth', 'DELETE', { provider, @@ -598,7 +549,7 @@ export default function Manage({ oauth_registration, oauth_providers: raw_oauth_ - @@ -617,6 +568,7 @@ export default function Manage({ oauth_registration, oauth_providers: raw_oauth_ + ); } diff --git a/src/pages/api/admin/clear.ts b/src/pages/api/admin/clear.ts index 50a3532..3c3b677 100644 --- a/src/pages/api/admin/clear.ts +++ b/src/pages/api/admin/clear.ts @@ -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`);