diff options
Diffstat (limited to 'apps/files_trashbin/src/services')
-rw-r--r-- | apps/files_trashbin/src/services/api.spec.ts | 43 | ||||
-rw-r--r-- | apps/files_trashbin/src/services/api.ts | 28 | ||||
-rw-r--r-- | apps/files_trashbin/src/services/client.ts | 12 | ||||
-rw-r--r-- | apps/files_trashbin/src/services/trashbin.ts | 44 |
4 files changed, 127 insertions, 0 deletions
diff --git a/apps/files_trashbin/src/services/api.spec.ts b/apps/files_trashbin/src/services/api.spec.ts new file mode 100644 index 00000000000..b50a53b8e07 --- /dev/null +++ b/apps/files_trashbin/src/services/api.spec.ts @@ -0,0 +1,43 @@ +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { emptyTrash } from './api.ts' +import * as ncAuth from '@nextcloud/auth' +import * as ncDialogs from '@nextcloud/dialogs' +import * as logger from '../logger.ts' + +const axiosMock = vi.hoisted(() => ({ + delete: vi.fn(), +})) +vi.mock('@nextcloud/axios', () => ({ default: axiosMock })) + +describe('files_trashbin: API - emptyTrash', () => { + beforeEach(() => { + vi.spyOn(ncAuth, 'getCurrentUser').mockImplementationOnce(() => ({ + uid: 'test', + displayName: 'Test', + isAdmin: false, + })) + }) + + it('shows success', async () => { + const dialogSpy = vi.spyOn(ncDialogs, 'showSuccess') + expect(await emptyTrash()).toBe(true) + expect(axiosMock.delete).toBeCalled() + expect(dialogSpy).toBeCalledWith('All files have been permanently deleted') + }) + + it('shows failure', async () => { + axiosMock.delete.mockImplementationOnce(() => { throw new Error() }) + const dialogSpy = vi.spyOn(ncDialogs, 'showError') + const loggerSpy = vi.spyOn(logger.logger, 'error').mockImplementationOnce(() => {}) + + expect(await emptyTrash()).toBe(false) + expect(axiosMock.delete).toBeCalled() + expect(dialogSpy).toBeCalledWith('Failed to empty deleted files') + expect(loggerSpy).toBeCalled() + }) +}) diff --git a/apps/files_trashbin/src/services/api.ts b/apps/files_trashbin/src/services/api.ts new file mode 100644 index 00000000000..b1f2e98b2d9 --- /dev/null +++ b/apps/files_trashbin/src/services/api.ts @@ -0,0 +1,28 @@ +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { getCurrentUser } from '@nextcloud/auth' +import { showError, showSuccess } from '@nextcloud/dialogs' +import { defaultRemoteURL } from '@nextcloud/files/dav' +import { t } from '@nextcloud/l10n' +import axios from '@nextcloud/axios' + +import { logger } from '../logger.ts' + +/** + * Send API request to empty the trashbin. + * Returns true if request succeeded - otherwise false is returned. + */ +export async function emptyTrash(): Promise<boolean> { + try { + await axios.delete(`${defaultRemoteURL}/trashbin/${getCurrentUser()!.uid}/trash`) + showSuccess(t('files_trashbin', 'All files have been permanently deleted')) + return true + } catch (error) { + showError(t('files_trashbin', 'Failed to empty deleted files')) + logger.error('Failed to empty deleted files', { error }) + return false + } +} diff --git a/apps/files_trashbin/src/services/client.ts b/apps/files_trashbin/src/services/client.ts new file mode 100644 index 00000000000..5ee25a6a94f --- /dev/null +++ b/apps/files_trashbin/src/services/client.ts @@ -0,0 +1,12 @@ +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { getCurrentUser } from '@nextcloud/auth' +import { davGetClient } from '@nextcloud/files' + +// init webdav client +export const rootPath = `/trashbin/${getCurrentUser()?.uid}/trash` + +export const client = davGetClient() diff --git a/apps/files_trashbin/src/services/trashbin.ts b/apps/files_trashbin/src/services/trashbin.ts new file mode 100644 index 00000000000..9fef16d032f --- /dev/null +++ b/apps/files_trashbin/src/services/trashbin.ts @@ -0,0 +1,44 @@ +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +import type { FileStat, ResponseDataDetailed } from 'webdav' +import type { ContentsWithRoot } from '@nextcloud/files' + +import { File, Folder, davResultToNode, getDavNameSpaces, getDavProperties } from '@nextcloud/files' +import { client, rootPath } from './client' +import { generateUrl } from '@nextcloud/router' + +const data = `<?xml version="1.0"?> +<d:propfind ${getDavNameSpaces()}> + <d:prop> + <nc:trashbin-deletion-time /> + <nc:trashbin-original-location /> + <nc:trashbin-title /> + <nc:trashbin-deleted-by-id /> + <nc:trashbin-deleted-by-display-name /> + ${getDavProperties()} + </d:prop> +</d:propfind>` + +const resultToNode = (stat: FileStat): File | Folder => { + const node = davResultToNode(stat, rootPath) + node.attributes.previewUrl = generateUrl('/apps/files_trashbin/preview?fileId={fileid}&x=32&y=32', { fileid: node.fileid }) + return node +} + +export const getContents = async (path = '/'): Promise<ContentsWithRoot> => { + const contentsResponse = await client.getDirectoryContents(`${rootPath}${path}`, { + details: true, + data, + includeSelf: true, + }) as ResponseDataDetailed<FileStat[]> + + const contents = contentsResponse.data.map(resultToNode) + const [folder] = contents.splice(contents.findIndex((node) => node.path === path), 1) + + return { + folder: folder as Folder, + contents, + } +} |