Skip to content

Commit

Permalink
Merge pull request #38806 from nextcloud/feat/f2v/actions-1
Browse files Browse the repository at this point in the history
  • Loading branch information
skjnldsv authored Jun 21, 2023
2 parents 5fb7ea2 + a70aa61 commit 32bbe3d
Show file tree
Hide file tree
Showing 25 changed files with 1,118 additions and 291 deletions.
15 changes: 0 additions & 15 deletions .codecov.yml

This file was deleted.

13 changes: 9 additions & 4 deletions .github/workflows/node-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ jobs:
uses: skjnldsv/read-package-engines-version-actions@8205673bab74a63eb9b8093402fd9e0e018663a1
id: versions
with:
fallbackNode: '^12'
fallbackNpm: '^6'
fallbackNode: '^16'
fallbackNpm: '^7'

test:
runs-on: ubuntu-latest
Expand All @@ -47,8 +47,13 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Test
run: npm run test
- name: Test and process coverage
run: npm run test:coverage

- name: Collect coverage
uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
with:
files: ./coverage/lcov.info

jsunit:
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ Vagrantfile
/config/config-autotest-backup.php
/config/autoconfig.php
clover.xml
/coverage

# Tests - dependencies
tests/acceptance/vendor/
Expand Down
34 changes: 34 additions & 0 deletions __mocks__/@nextcloud/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @copyright Copyright (c) 2023 John Molakvoæ <[email protected]>
*
* @author John Molakvoæ <[email protected]>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
export const getCurrentUser = function() {
return {
uid: 'test',
displayName: 'Test',
isAdmin: false,
}
}

export const getRequestToken = function() {
return 'test-token-1234'
}

export const onRequestTokenUpdate = function() {}
24 changes: 24 additions & 0 deletions __mocks__/@nextcloud/axios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @copyright Copyright (c) 2023 John Molakvoæ <[email protected]>
*
* @author John Molakvoæ <[email protected]>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
export default {
delete: async () => ({ status: 200, data: {} }),
}
22 changes: 22 additions & 0 deletions __mocks__/svg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @copyright Copyright (c) 2023 John Molakvoæ <[email protected]>
*
* @author John Molakvoæ <[email protected]>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
export default 'SvgMock'
File renamed without changes.
184 changes: 184 additions & 0 deletions apps/files/src/actions/deleteAction.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/**
* @copyright Copyright (c) 2023 John Molakvoæ <[email protected]>
*
* @author John Molakvoæ <[email protected]>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { action } from './deleteAction'
import { expect } from '@jest/globals'
import { File, Folder, Permission } from '@nextcloud/files'
import { FileAction } from '../services/FileAction'
import * as eventBus from '@nextcloud/event-bus'
import axios from '@nextcloud/axios'
import type { Navigation } from '../services/Navigation'
import logger from '../logger'

const view = {
id: 'files',
name: 'Files',
} as Navigation

const trashbinView = {
id: 'trashbin',
name: 'Trashbin',
} as Navigation

describe('Delete action conditions tests', () => {
test('Default values', () => {
expect(action).toBeInstanceOf(FileAction)
expect(action.id).toBe('delete')
expect(action.displayName([], view)).toBe('Delete')
expect(action.iconSvgInline([], view)).toBe('SvgMock')
expect(action.order).toBe(100)
})

test('Default trashbin view values', () => {
expect(action.displayName([], trashbinView)).toBe('Delete permanently')
})
})

describe('Delete action enabled tests', () => {
test('Enabled with DELETE permissions', () => {
const file = new File({
id: 1,
source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt',
owner: 'admin',
mime: 'text/plain',
permissions: Permission.ALL,
})

expect(action.enabled).toBeDefined()
expect(action.enabled!([file], view)).toBe(true)
})

test('Disabled without DELETE permissions', () => {
const file = new File({
id: 1,
source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt',
owner: 'admin',
mime: 'text/plain',
permissions: Permission.READ,
})

expect(action.enabled).toBeDefined()
expect(action.enabled!([file], view)).toBe(false)
})

test('Disabled without nodes', () => {
expect(action.enabled).toBeDefined()
expect(action.enabled!([], view)).toBe(false)
})

test('Disabled if not all nodes can be deleted', () => {
const folder1 = new Folder({
id: 1,
source: 'https://cloud.domain.com/remote.php/dav/files/admin/Foo/',
owner: 'admin',
permissions: Permission.DELETE,
})
const folder2 = new Folder({
id: 2,
source: 'https://cloud.domain.com/remote.php/dav/files/admin/Bar/',
owner: 'admin',
permissions: Permission.READ,
})

expect(action.enabled).toBeDefined()
expect(action.enabled!([folder1], view)).toBe(true)
expect(action.enabled!([folder2], view)).toBe(false)
expect(action.enabled!([folder1, folder2], view)).toBe(false)
})
})

describe('Delete action execute tests', () => {
test('Delete action', async () => {
jest.spyOn(axios, 'delete')
jest.spyOn(eventBus, 'emit')

const file = new File({
id: 1,
source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt',
owner: 'admin',
mime: 'text/plain',
permissions: Permission.READ | Permission.UPDATE | Permission.DELETE,
})

const exec = await action.exec(file, view, '/')

expect(exec).toBe(true)
expect(axios.delete).toBeCalledTimes(1)
expect(axios.delete).toBeCalledWith('https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt')

expect(eventBus.emit).toBeCalledTimes(1)
expect(eventBus.emit).toBeCalledWith('files:node:deleted', file)
})

test('Delete action batch', async () => {
jest.spyOn(axios, 'delete')
jest.spyOn(eventBus, 'emit')

const file1 = new File({
id: 1,
source: 'https://cloud.domain.com/remote.php/dav/files/admin/foo.txt',
owner: 'admin',
mime: 'text/plain',
permissions: Permission.READ | Permission.UPDATE | Permission.DELETE,
})

const file2 = new File({
id: 2,
source: 'https://cloud.domain.com/remote.php/dav/files/admin/bar.txt',
owner: 'admin',
mime: 'text/plain',
permissions: Permission.READ | Permission.UPDATE | Permission.DELETE,
})

const exec = await action.execBatch!([file1, file2], view, '/')

expect(exec).toStrictEqual([true, true])
expect(axios.delete).toBeCalledTimes(2)
expect(axios.delete).toHaveBeenNthCalledWith(1, 'https://cloud.domain.com/remote.php/dav/files/admin/foo.txt')
expect(axios.delete).toHaveBeenNthCalledWith(2, 'https://cloud.domain.com/remote.php/dav/files/admin/bar.txt')

expect(eventBus.emit).toBeCalledTimes(2)
expect(eventBus.emit).toHaveBeenNthCalledWith(1, 'files:node:deleted', file1)
expect(eventBus.emit).toHaveBeenNthCalledWith(2, 'files:node:deleted', file2)
})

test('Delete fails', async () => {
jest.spyOn(axios, 'delete').mockImplementation(() => { throw new Error('Mock error') })
jest.spyOn(logger, 'error').mockImplementation(() => jest.fn())

const file = new File({
id: 1,
source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt',
owner: 'admin',
mime: 'text/plain',
permissions: Permission.READ | Permission.UPDATE | Permission.DELETE,
})

const exec = await action.exec(file, view, '/')

expect(exec).toBe(false)
expect(axios.delete).toBeCalledTimes(1)
expect(axios.delete).toBeCalledWith('https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt')

expect(eventBus.emit).toBeCalledTimes(0)
expect(logger.error).toBeCalledTimes(1)
})
})
10 changes: 6 additions & 4 deletions apps/files/src/actions/deleteAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ import { translate as t } from '@nextcloud/l10n'
import axios from '@nextcloud/axios'
import TrashCan from '@mdi/svg/svg/trash-can.svg?raw'

import { registerFileAction, FileAction } from '../services/FileAction.ts'
import { registerFileAction, FileAction } from '../services/FileAction'
import logger from '../logger.js'
import type { Navigation } from '../services/Navigation.ts'
import type { Navigation } from '../services/Navigation'

registerFileAction(new FileAction({
export const action = new FileAction({
id: 'delete',
displayName(nodes: Node[], view: Navigation) {
return view.id === 'trashbin'
Expand Down Expand Up @@ -63,4 +63,6 @@ registerFileAction(new FileAction({
},

order: 100,
}))
})

registerFileAction(action)
Loading

0 comments on commit 32bbe3d

Please sign in to comment.