diff --git a/cypress/e2e/circle-with-group.spec.js b/cypress/e2e/circle-with-group.spec.js index 9fc448a37..e45bcc8ad 100644 --- a/cypress/e2e/circle-with-group.spec.js +++ b/cypress/e2e/circle-with-group.spec.js @@ -32,7 +32,6 @@ describe('Pages are accessible via group membership to circle', function() { before(function() { cy.loginAs('jane') - cy.visit('apps/collectives') cy.deleteAndSeedCollective('Group Collective') cy.circleFind('Group Collective') .circleAddMember('Bobs Group', 2) diff --git a/cypress/e2e/collective-members.spec.js b/cypress/e2e/collective-members.spec.js index b764eae5d..b87b5f5b7 100644 --- a/cypress/e2e/collective-members.spec.js +++ b/cypress/e2e/collective-members.spec.js @@ -27,7 +27,6 @@ describe('Collective members', function() { before(function() { cy.loginAs('bob') - cy.visit('apps/collectives') cy.deleteAndSeedCollective('Members Collective') }) diff --git a/cypress/e2e/collective-page-mode.spec.js b/cypress/e2e/collective-page-mode.spec.js new file mode 100644 index 000000000..afa9ae30a --- /dev/null +++ b/cypress/e2e/collective-page-mode.spec.js @@ -0,0 +1,61 @@ +/** + * @copyright Copyright (c) 2021 Azul + * + * @author Azul + * + * @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 . + * + */ + +describe('Collective page mode', function() { + + before(function() { + cy.loginAs('bob') + cy.deleteAndSeedCollective('Our Garden') + .seedPage('Day 1', '', 'Readme.md') + .seedPage('Day 2', '', 'Readme.md') + }) + + beforeEach(function() { + cy.loginAs('bob') + }) + + describe('Changing page mode', function() { + it('Opens edit mode per default', function() { + cy.seedCollectivePageMode('Our Garden', 1) + cy.visit('/apps/collectives/Our Garden') + // make sure the page list loaded properly + cy.contains('.app-content-list-item a', 'Day 1') + cy.openPage('Day 2') + cy.getEditor() + .should('be.visible') + cy.getReadOnlyEditor() + .should('not.be.visible') + }) + + it('Opens view mode per default', function() { + cy.seedCollectivePageMode('Our Garden', 0) + cy.visit('/apps/collectives/Our Garden') + // make sure the page list loaded properly + cy.contains('.app-content-list-item a', 'Day 1') + cy.openPage('Day 2') + cy.getReadOnlyEditor() + .should('be.visible') + cy.getEditor() + .should('not.be.visible') + }) + }) +}) diff --git a/cypress/e2e/collective-readonly.spec.js b/cypress/e2e/collective-readonly.spec.js index afc92f4ea..27458fa27 100644 --- a/cypress/e2e/collective-readonly.spec.js +++ b/cypress/e2e/collective-readonly.spec.js @@ -24,12 +24,11 @@ describe('Read-only collective', function() { before(function() { cy.loginAs('alice') - cy.visit('apps/collectives') cy.deleteAndSeedCollective('PermissionCollective') - cy.seedPage('SecondPage', '', 'Readme.md') - cy.seedCollectivePermissions('PermissionCollective', 'edit', 4) + .seedPage('SecondPage') cy.circleFind('PermissionCollective') .circleAddMember('bob') + cy.seedCollectivePermissions('PermissionCollective', 'edit', 4) }) describe('in read-only collective', function() { diff --git a/cypress/e2e/collective-settings.spec.js b/cypress/e2e/collective-settings.spec.js index 144b80b30..4f837a30c 100644 --- a/cypress/e2e/collective-settings.spec.js +++ b/cypress/e2e/collective-settings.spec.js @@ -27,7 +27,6 @@ describe('Collective settings', function() { before(function() { cy.loginAs('bob') - cy.visit('apps/collectives') cy.deleteCollective('Change me now') cy.deleteAndSeedCollective('Change me') }) diff --git a/cypress/e2e/collective-share.spec.js b/cypress/e2e/collective-share.spec.js index c3b8d8b6b..abc275881 100644 --- a/cypress/e2e/collective-share.spec.js +++ b/cypress/e2e/collective-share.spec.js @@ -29,7 +29,6 @@ describe('Collective Share', function() { before(function() { cy.loginAs('bob') - cy.visit('/apps/collectives') cy.deleteAndSeedCollective('Share me') }) diff --git a/cypress/e2e/collective.spec.js b/cypress/e2e/collective.spec.js index a1e2b65c2..1f00817bf 100644 --- a/cypress/e2e/collective.spec.js +++ b/cypress/e2e/collective.spec.js @@ -29,7 +29,6 @@ describe('Collective', function() { before(function() { cy.loginAs('bob') - cy.visit('apps/collectives') cy.deleteCollective('Preexisting Circle') cy.deleteCollective('History Club') cy.deleteCollective(specialCollective) @@ -39,7 +38,6 @@ describe('Collective', function() { cy.seedCircle('Preexisting Circle') cy.seedCircle('History Club', { visible: true, open: true }) cy.loginAs('jane') - cy.visit('apps/collectives') cy.deleteCollective('Foreign Circle') cy.seedCircle('Foreign Circle', { visible: true, open: true }) }) diff --git a/cypress/e2e/collectives-trash.spec.js b/cypress/e2e/collectives-trash.spec.js index cc4f0efe7..df25d62e0 100644 --- a/cypress/e2e/collectives-trash.spec.js +++ b/cypress/e2e/collectives-trash.spec.js @@ -28,7 +28,6 @@ describe('Collective', function() { describe('move collective to trash and restore', function() { before(function() { cy.loginAs('bob') - cy.visit('apps/collectives') cy.deleteAndSeedCollective('Delete me') }) it('Allows moving the collective to trash', function() { diff --git a/cypress/e2e/dashboard-widget.spec.js b/cypress/e2e/dashboard-widget.spec.js index c9535e531..4671f4aad 100644 --- a/cypress/e2e/dashboard-widget.spec.js +++ b/cypress/e2e/dashboard-widget.spec.js @@ -30,9 +30,8 @@ describe('Collectives dashboard widget', function() { before(function() { cy.loginAs('bob') cy.enableDashboardWidget('collectives-recent-pages') - cy.visit('apps/collectives') cy.deleteAndSeedCollective('Dashboard Collective1') - cy.seedPage('Page 1', '', 'Readme.md') + .seedPage('Page 1', '', 'Readme.md') }) it('Lists pages in the dashboard widget', function() { cy.visit('/apps/dashboard/') diff --git a/cypress/e2e/page-details.spec.js b/cypress/e2e/page-details.spec.js index 78dea1859..ac668ede7 100644 --- a/cypress/e2e/page-details.spec.js +++ b/cypress/e2e/page-details.spec.js @@ -27,11 +27,10 @@ describe('Page details', function() { before(function() { cy.loginAs('bob') - cy.visit('/apps/collectives') cy.deleteAndSeedCollective('Our Garden') - cy.seedPage('Day 1', '', 'Readme.md') + .seedPage('Day 1', '', 'Readme.md') + .seedPage('TableOfContents', '', 'Readme.md') cy.seedPageContent('Our Garden/Day 2.md', 'A test string with Day 2 in the middle and a [link to Day 1](/index.php/apps/collectives/Our%20Garden/Day%201).') - cy.seedPage('TableOfContents', '', 'Readme.md') cy.seedPageContent('Our Garden/TableOfContents.md', '## Second-Level Heading') }) diff --git a/cypress/e2e/page-landingpage.spec.js b/cypress/e2e/page-landingpage.spec.js index 308ebc2df..a2a08d545 100644 --- a/cypress/e2e/page-landingpage.spec.js +++ b/cypress/e2e/page-landingpage.spec.js @@ -29,16 +29,18 @@ const collective = 'Landingpage Collective' describe('Page landing page', function() { before(function() { cy.loginAs('bob') - cy.visit('/apps/collectives') cy.deleteAndSeedCollective(collective) + .seedPage('Page 1', '', 'Readme.md') + .seedPage('Page 2', '', 'Readme.md') + .then(collective => { + // Wait 1 to make sure that page order by time is right + cy.wait(1000) // eslint-disable-line cypress/no-unnecessary-waiting + cy.wrap(collective) + .seedPage('Page 3', '', 'Readme.md') + }) cy.circleFind(collective).circleAddMember('alice') cy.circleFind(collective).circleAddMember('jane') cy.circleFind(collective).circleAddMember('john') - cy.seedPage('Page 1', '', 'Readme.md') - cy.seedPage('Page 2', '', 'Readme.md') - // Wait 1 second to make sure that page order by time is right - cy.wait(1000) // eslint-disable-line cypress/no-unnecessary-waiting - cy.seedPage('Page 3', '', 'Readme.md') }) beforeEach(function() { diff --git a/cypress/e2e/page-list.spec.js b/cypress/e2e/page-list.spec.js index b77fabaca..0d612ab9e 100644 --- a/cypress/e2e/page-list.spec.js +++ b/cypress/e2e/page-list.spec.js @@ -27,24 +27,25 @@ describe('Page list', function() { before(function() { cy.loginAs('bob') - cy.visit('apps/collectives') cy.deleteAndSeedCollective('Our Garden') - cy.seedPage('Target', '', 'Readme.md') - cy.seedPage('Target Subpage', '', 'Target.md') + .as('garden') + .seedPage('Target', '', 'Readme.md') + .seedPage('Target Subpage', '', 'Target.md') // Wait 1 second to make sure that page order by time is right cy.wait(1000) // eslint-disable-line cypress/no-unnecessary-waiting - cy.seedPage('Day 1', '', 'Readme.md') - cy.seedPage('Subpage Title', '', 'Day 1.md') - cy.seedPage('Day 2', '', 'Readme.md') - cy.seedPage('Page Title', '', 'Readme.md') - cy.seedPage('Move me internal', '', 'Readme.md') - cy.seedPage('Copy me internal', '', 'Readme.md') - cy.seedPage('Move me external', '', 'Readme.md') - cy.seedPage('Copy me external', '', 'Readme.md') - cy.seedPage('#% special chars', '', 'Readme.md') + cy.then(() => this.garden) + .seedPage('Day 1', '', 'Readme.md') + .seedPage('Subpage Title', '', 'Day 1.md') + .seedPage('Day 2', '', 'Readme.md') + .seedPage('Page Title', '', 'Readme.md') + .seedPage('Move me internal', '', 'Readme.md') + .seedPage('Copy me internal', '', 'Readme.md') + .seedPage('Move me external', '', 'Readme.md') + .seedPage('Copy me external', '', 'Readme.md') + .seedPage('#% special chars', '', 'Readme.md') cy.deleteAndSeedCollective('MoveCopyTargetCollective') - cy.seedPage('Target external', '', 'Readme.md') - cy.seedPage('Target Subpage external', '', 'Target external.md') + .seedPage('Target external', '', 'Readme.md') + .seedPage('Target Subpage external', '', 'Target external.md') }) beforeEach(function() { @@ -94,7 +95,6 @@ describe('Page list', function() { describe('Move and copy a page using the modal', function() { it('Moves page to a subpage', function() { - cy.visit('apps/collectives/Our%20Garden') cy.openPageMenu('Move me internal') cy.clickMenuButton('Move or copy') cy.get('.picker-list li') @@ -118,7 +118,6 @@ describe('Page list', function() { }) it('Copies page to a subpage', function() { - cy.visit('/apps/collectives/Our%20Garden') cy.openPageMenu('Copy me internal') cy.clickMenuButton('Move or copy') cy.get('.picker-list li') @@ -146,7 +145,6 @@ describe('Page list', function() { }) it('Moves page to a subpage in another collective', function() { - cy.visit('/apps/collectives/Our%20Garden') cy.openPageMenu('Move me external') cy.clickMenuButton('Move or copy') cy.get('.crumbs-home') @@ -176,7 +174,6 @@ describe('Page list', function() { }) it('Copies page to a subpage in another collective', function() { - cy.visit('/apps/collectives/Our%20Garden') cy.openPageMenu('Copy me external') cy.clickMenuButton('Move or copy') cy.get('.crumbs-home') diff --git a/cypress/e2e/page-share.spec.js b/cypress/e2e/page-share.spec.js index c33a8722d..55e21e372 100644 --- a/cypress/e2e/page-share.spec.js +++ b/cypress/e2e/page-share.spec.js @@ -29,10 +29,9 @@ describe('Collective Share', function() { before(function() { cy.loginAs('bob') - cy.visit('/apps/collectives') cy.deleteAndSeedCollective('Share me') - cy.seedPage('Sharepage', '', 'Readme.md') - cy.seedPage('Sharesubpage', '', 'Sharepage.md') + .seedPage('Sharepage', '', 'Readme.md') + .seedPage('Sharesubpage', '', 'Sharepage.md') cy.seedPageContent('Share%20me/Sharepage/Readme.md', '## Shared page') }) diff --git a/cypress/e2e/pages-links.spec.js b/cypress/e2e/pages-links.spec.js index f092b5951..f4447e4a7 100644 --- a/cypress/e2e/pages-links.spec.js +++ b/cypress/e2e/pages-links.spec.js @@ -32,19 +32,18 @@ let anotherCollectiveFirstPageId, linkTargetPageId describe('Page Link Handling', function() { before(function() { cy.loginAs('bob') - cy.visit('/apps/collectives') cy.deleteAndSeedCollective('Another Collective') - cy.seedPage('First Page', '', 'Readme.md').then((id) => { - anotherCollectiveFirstPageId = id - }) + .seedPage('First Page', '', 'Readme.md').then(({ pageId }) => { + anotherCollectiveFirstPageId = pageId + }) cy.deleteAndSeedCollective('Link Testing') - cy.seedPage('Parent', '', 'Readme.md') - cy.seedPage('Child', '', 'Parent.md') - cy.seedPage('Link Target', '', 'Readme.md').then((id) => { - linkTargetPageId = id - }) + .seedPage('Parent', '', 'Readme.md') + .seedPage('Child', '', 'Parent.md') + .seedPage('Link Target', '', 'Readme.md').then(({ pageId }) => { + linkTargetPageId = pageId + }) + .seedPage('Link Source', '', 'Readme.md') cy.seedPageContent('Link%20Testing/Link%20Target.md', 'Some content') - cy.seedPage('Link Source', '', 'Readme.md') cy.uploadFile('test.md', 'text/markdown').then((id) => { textId = id }).then(() => { diff --git a/cypress/e2e/pages.spec.js b/cypress/e2e/pages.spec.js index f8e6d2348..46cce9c80 100644 --- a/cypress/e2e/pages.spec.js +++ b/cypress/e2e/pages.spec.js @@ -25,18 +25,19 @@ */ describe('Page', function() { + before(function() { cy.loginAs('bob') - cy.visit('/apps/collectives') - cy.deleteAndSeedCollective('Our Garden') - cy.seedPage('Day 1', '', 'Readme.md') + cy.deleteAndSeedCollective('Our Garden').as('garden') + .seedPage('Day 1', '', 'Readme.md') // Wait 1 second to make sure that page order by time is right cy.wait(1000) // eslint-disable-line cypress/no-unnecessary-waiting - cy.seedPage('Day 2', '', 'Readme.md') - cy.seedPage('Page Title', '', 'Readme.md') - cy.seedPage('#% special chars', '', 'Readme.md') + cy.then(() => this.garden) + .seedPage('Day 2', '', 'Readme.md') + .seedPage('Page Title', '', 'Readme.md') + .seedPage('#% special chars', '', 'Readme.md') + .seedPage('Template', '', 'Readme.md') cy.seedPageContent('Our Garden/Day 2.md', 'A test string with Day 2 in the middle and a [link to Day 1](/index.php/apps/collectives/Our%20Garden/Day%201).') - cy.seedPage('Template', '', 'Readme.md') cy.seedPageContent('Our Garden/Template.md', 'This is going to be our template.') }) @@ -272,26 +273,6 @@ describe('Page', function() { }) } - describe('Changing page mode', function() { - it('Opens edit mode per default', function() { - cy.seedCollectivePageMode('Our Garden', 1) - cy.openPage('Day 2') - cy.getEditor() - .should('be.visible') - cy.getReadOnlyEditor() - .should('not.be.visible') - }) - - it('Opens view mode per default', function() { - cy.seedCollectivePageMode('Our Garden', 0) - cy.openPage('Day 2') - cy.getReadOnlyEditor() - .should('be.visible') - cy.getEditor() - .should('not.be.visible') - }) - }) - describe('Full width view', function() { it('Allows to toggle persistent full-width view', function() { cy.openPage('Day 2') diff --git a/cypress/e2e/settings.spec.js b/cypress/e2e/settings.spec.js index caa4630ea..341a2d6f2 100644 --- a/cypress/e2e/settings.spec.js +++ b/cypress/e2e/settings.spec.js @@ -27,7 +27,6 @@ describe('Settings', function() { before(function() { cy.loginAs('bob') - cy.visit('apps/collectives') cy.deleteAndSeedCollective('A Collective') }) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 128e8a118..d95c651cf 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -1,20 +1,9 @@ import { login, logout } from '@nextcloud/cypress/commands' import { User } from '@nextcloud/cypress' -import { - GET_COLLECTIVES, - GET_TRASH_COLLECTIVES, - NEW_COLLECTIVE, - TRASH_COLLECTIVE, - DELETE_COLLECTIVE, - UPDATE_COLLECTIVE_EDIT_PERMISSIONS, - UPDATE_COLLECTIVE_SHARE_PERMISSIONS, - UPDATE_COLLECTIVE_PAGE_MODE, - GET_PAGES, - NEW_PAGE, - GET_CIRCLES, -} from '../../src/store/actions.js' +import * as api from '../../src/apis/collectives/index.js' import axios from '@nextcloud/axios' +import { generateOcsUrl } from '@nextcloud/router' const url = Cypress.config('baseUrl').replace(/\/index.php\/?$/g, '') Cypress.env('baseUrl', url) @@ -96,8 +85,8 @@ Cypress.Commands.add('disableApp', appName => { Cypress.Commands.add('setAppEnabled', (appName, value = true) => { const verb = value ? 'enable' : 'disable' - const api = `${Cypress.env('baseUrl')}/index.php/settings/apps/${verb}` - return axios.post(api, + const url = `${Cypress.env('baseUrl')}/index.php/settings/apps/${verb}` + return axios.post(url, { appIds: [appName] }, ) }) @@ -107,8 +96,8 @@ Cypress.Commands.add('setAppEnabled', (appName, value = true) => { */ Cypress.Commands.add('enableDashboardWidget', (widgetName) => { Cypress.log() - const api = `${Cypress.env('baseUrl')}/index.php/apps/dashboard/layout` - return axios.post(api, + const url = `${Cypress.env('baseUrl')}/index.php/apps/dashboard/layout` + return axios.post(url, { layout: widgetName }, ) }) @@ -176,11 +165,20 @@ Cypress.Commands.add('findBy', Cypress.Commands.add('deleteAndSeedCollective', (name) => { Cypress.log() cy.deleteCollective(name) - cy.dispatch(NEW_COLLECTIVE, { name }) - cy.store('getters.updatedCollectivePath') - .then(path => cy.routeTo(path)) - // Make sure new collective is loaded - cy.get('#titleform input').should('have.value', name) + cy.seedCollective(name) + cy.getCollectives() + .findBy({ name }) +}) + +Cypress.Commands.add('seedCollective', (name) => { + return api.newCollective({ name }) + .catch(e => { + if (e.request && e.request.status === 422) { + // The collective already existed... carry on. + } else { + throw e + } + }) }) /** @@ -202,18 +200,45 @@ Cypress.Commands.add('createCollective', (name, members = []) => { }) /** - * Delete a collective if exists and clean it from the trash. + * Delete a collective - no matter if it is in use or trashed. + * + * This command will succeed if the collective does not exist at all. */ Cypress.Commands.add('deleteCollective', (name) => { - cy.dispatch(GET_COLLECTIVES) - cy.store('state.collectives.collectives') + cy.trashCollective(name) + cy.deleteCollectiveFromTrash(name) +}) + +Cypress.Commands.add('getCollectives', () => { + return api.getCollectives() + .then(response => response.data.data) +}) + +/** + * Move a collective into the trash if it exists. + * + * This command will succeed if the collective does not exist at all. + */ +Cypress.Commands.add('trashCollective', (name) => { + cy.getCollectives() .findBy({ name }) - .dispatch(TRASH_COLLECTIVE) - // Try to find and delete collective from trash - cy.dispatch(GET_TRASH_COLLECTIVES) - cy.store('state.collectives.trashCollectives') + .then((found) => found && api.trashCollective(found.id)) +}) + +Cypress.Commands.add('getTrashCollectives', () => { + return api.getTrashCollectives() + .then(response => response.data.data) +}) + +/** + * Clear a collective from the trash if it is in there. + * + * This command will succeed if the collective does not exist at all. + */ +Cypress.Commands.add('deleteCollectiveFromTrash', (name) => { + cy.getTrashCollectives() .findBy({ name }) - .dispatch(DELETE_COLLECTIVE, { circle: true }) + .then((found) => found && api.deleteCollective(found.id, true)) }) /** @@ -222,11 +247,11 @@ Cypress.Commands.add('deleteCollective', (name) => { Cypress.Commands.add('seedCollectivePermissions', (name, type, level) => { Cypress.log() const action = (type === 'edit') - ? UPDATE_COLLECTIVE_EDIT_PERMISSIONS - : UPDATE_COLLECTIVE_SHARE_PERMISSIONS - cy.store('state.collectives.collectives') + ? api.updateCollectiveEditPermissions + : api.updateCollectiveSharePermissions + cy.getCollectives() .findBy({ name }) - .dispatch(action, { level }) + .then((found) => action(found.id, level)) }) /** @@ -234,54 +259,47 @@ Cypress.Commands.add('seedCollectivePermissions', (name, type, level) => { */ Cypress.Commands.add('seedCollectivePageMode', (name, mode) => { Cypress.log() - cy.store('state.collectives.collectives') + cy.getCollectives() .findBy({ name }) - .dispatch(UPDATE_COLLECTIVE_PAGE_MODE, { mode }) + .then((found) => api.updateCollectivePageMode(found.id, mode)) }) /** - * Add a page to a collective + * Context for the given collective for a logged in user. + * + * @param {object} collective - Collective to provide the context for. */ -Cypress.Commands.add('seedPage', (name, parentFilePath, parentFileName) => { - Cypress.log() - cy.dispatch(GET_PAGES) - cy.store('state.pages.pages') - .findBy({ filePath: parentFilePath, fileName: parentFileName }) - .its('id') - .as('parentId') - .then(id => ({ parentId: id })) - .dispatch(NEW_PAGE, { title: name, pagePath: name }) - // Return pageId of created page - cy.get('@parentId').then(parentId => { - return cy.store('state.pages.pages') - .findBy({ parentId, title: name }) - .its('id') - }) +function collectiveContext(collective) { + return { + isPublic: false, + collectiveId: collective.id, + shareTokenParam: null, + } +} + +Cypress.Commands.add('getPages', collective => { + return api.getPages(collectiveContext(collective)) + .then(response => response.data.data) }) /** - * Upload a file + * Add a page to a collective */ -Cypress.Commands.add('uploadFile', (path, mimeType, remotePath = '') => { - Cypress.log() - // Get fixture - return cy.fixture(path, 'base64').then(file => { - // convert the base64 string to a blob - const blob = Cypress.Blob.base64StringToBlob(file, mimeType) - try { - const file = new File([blob], path, { type: mimeType }) - return cy.uploadContent(remotePath + path, file, mimeType) - .then(response => { - const ocFileId = response.headers['oc-fileid'] - const fileId = parseInt(ocFileId.substring(0, ocFileId.indexOf('oc'))) - return fileId - }) - } catch (error) { - cy.log(error) - throw new Error(`Unable to process file ${path}`) - } +Cypress.Commands.add('seedPage', + { prevSubject: true }, + (subject, name, parentFilePath = '', parentFileName = 'Readme.md') => { + Cypress.log() + cy.getPages(subject) + .findBy({ filePath: parentFilePath, fileName: parentFileName }) + .then(({ id: parentId }) => { + return api.createPage( + collectiveContext(subject), + { parentId, title: name, pagePath: name }, + ) + }) + .its('data.data.id') + .then(pageId => ({ ...subject, pageId })) }) -}) /** * Upload content of a page @@ -294,22 +312,37 @@ Cypress.Commands.add('seedPageContent', (pagePath, content) => { cy.uploadContent(`Collectives/${pagePath}`, content) }) +Cypress.Commands.add('uploadFile', (path, mimeType, remotePath = '') => { + Cypress.log() + // Get fixture + return cy.fixture(path, 'base64').then(data => { + // convert the base64 string to a blob + const blob = Cypress.Blob.base64StringToBlob(data, mimeType) + const file = new File([blob], path, { type: mimeType }) + return cy.uploadContent(remotePath + path, file, mimeType) + .then(response => { + const ocFileId = response.headers['oc-fileid'] + const fileId = parseInt(ocFileId.substring(0, ocFileId.indexOf('oc'))) + return fileId + }) + }) +}) + /** * Generic upload of content - used by seedPageContent and uploadPage */ Cypress.Commands.add('uploadContent', (path, content, mimetype = 'text/markdown') => { // @nextcloud/axios automatic handling for request tokens does not work for webdav - cy.window() - .its('app.OC.requestToken') - .then(requesttoken => { - const url = `${Cypress.env('baseUrl')}/remote.php/webdav/${path}` - return axios.put(url, content, { - headers: { - requesttoken, - 'Content-Type': mimetype, - }, - }) + cy.request('/csrftoken').then(({ body }) => { + const requesttoken = body.token + const url = `${Cypress.env('baseUrl')}/remote.php/webdav/${path}` + return axios.put(url, content, { + headers: { + requesttoken, + 'Content-Type': mimetype, + }, }) + }) }) /** @@ -317,14 +350,12 @@ Cypress.Commands.add('uploadContent', (path, content, mimetype = 'text/markdown' */ Cypress.Commands.add('seedCircle', (name, config = null) => { Cypress.log() - cy.dispatch(GET_CIRCLES) - cy.store('state.circles.circles') - .findBy({ sanitizedName: name }) + cy.circleFind(name) .then(async circle => { - const api = `${Cypress.env('baseUrl')}/ocs/v2.php/apps/circles/circles` + const url = `${Cypress.env('baseUrl')}/ocs/v2.php/apps/circles/circles` let circleId if (!circle) { - const response = await axios.post(api, + const response = await axios.post(url, { name, personal: false, local: true }, ) circleId = response.data.ocs.data.id @@ -340,23 +371,27 @@ Cypress.Commands.add('seedCircle', (name, config = null) => { const value = bits .filter(([k, v]) => config[k]) .reduce((sum, [k, v]) => sum + v, 0) - await axios.put(`${api}/${circleId}/config`, + await axios.put(`${url}/${circleId}/config`, { value }, ) } }) }) -/** - * Add someone to a circle - */ +Cypress.Commands.add('getCircles', () => { + return axios.get(generateOcsUrl('apps/circles/circles')) + .then(response => response.data.ocs.data) +}) + Cypress.Commands.add('circleFind', (name) => { Cypress.log() - cy.dispatch(GET_CIRCLES) - return cy.store('state.circles.circles') + cy.getCircles() .findBy({ sanitizedName: name }) }) +/** + * Add someone to a circle + */ Cypress.Commands.add('circleAddMember', { prevSubject: true }, async ({ id }, userId, type = 1) => { diff --git a/cypress/support/navigation.js b/cypress/support/navigation.js index a02469cba..566d02612 100644 --- a/cypress/support/navigation.js +++ b/cypress/support/navigation.js @@ -17,8 +17,7 @@ Cypress.Commands.add('openPageMenu', (pageName) => { Cypress.Commands.add('openCollective', (collectiveName) => { Cypress.log() - cy.get(`.collectives_list_item a[title="${collectiveName}"]`) - .click() + cy.routeTo(collectiveName) }) Cypress.Commands.add('openCollectiveMenu', (collectiveName) => { diff --git a/src/apis/collectives/collectives.js b/src/apis/collectives/collectives.js new file mode 100644 index 000000000..c710bfe2e --- /dev/null +++ b/src/apis/collectives/collectives.js @@ -0,0 +1,119 @@ +import axios from '@nextcloud/axios' +import { collectivesUrl } from './urls.js' + +/** + * Get all active (i.e. not trashed) collectives for the current user + */ +export function getCollectives() { + return axios.get(collectivesUrl()) +} + +/** + * Get the shared collective for a given share token. + * + * @param {string} shareToken authentication token from the share + */ +export function getSharedCollective(shareToken) { + return axios.get(collectivesUrl('p', shareToken)) +} + +/** + * Get all trashed collectives for the current user + */ +export function getTrashCollectives() { + return axios.get(collectivesUrl('trash')) +} + +/** + * Create a new collective with the given properties. + * + * @param {object} collective - properties for the new collective + */ +export function newCollective(collective) { + return axios.post( + collectivesUrl(), + collective, + ) +} + +/** + * Trash the collective with the given id + * + * @param {number} collectiveId - Id of the collective to trash. + */ +export function trashCollective(collectiveId) { + return axios.delete(collectivesUrl(collectiveId)) +} + +/** + * Delete the collective with the given id. + * + * @param {number} collectiveId - id of the collective to delete + * @param {boolean} removeCircle - also remove the circle if true + */ +export function deleteCollective(collectiveId, removeCircle) { + const query = removeCircle ? '?circle=1' : '' + return axios.delete(collectivesUrl('trash', collectiveId + query)) +} + +/** + * Restore a collective with the given id from trash + * + * @param {number} collectiveId Id of the colletive to be restored + */ +export function restoreCollective(collectiveId) { + return axios.patch(collectivesUrl('trash', collectiveId)) +} + +/** + * Update a collective with the given properties + * + * @param {object} collective Properties for the collective + */ +export function updateCollective(collective) { + return axios.put( + collectivesUrl(collective.id), + collective, + ) +} + +/** + * Set the permission level required for editing. + * + * @param {number} collectiveId - id of the collective to update + * @param {number} level - required level for editing + */ +export function updateCollectiveEditPermissions(collectiveId, level) { + return axios.put( + collectivesUrl(collectiveId, 'editLevel'), + { level }, + ) +} + +/** + * Set the permission level required for sharing. + * + * @param {number} collectiveId - id of the collective to update + * @param {number} level - required level for sharing + */ +export function updateCollectiveSharePermissions(collectiveId, level) { + return axios.put( + collectivesUrl(collectiveId, 'shareLevel'), + { level }, + ) +} + +/** + * Set the edit mode for the given collective + * + * @param {number} collectiveId - id of the collective to update + * @param {number} mode - pageMode to use. + * + * Possible modes: pageModes.MODE_VIEW or pageModes.MODE_EDIT + */ +export function updateCollectivePageMode(collectiveId, mode) { + return axios.put( + collectivesUrl(collectiveId, 'pageMode'), + { mode }, + ) +} diff --git a/src/apis/collectives/index.js b/src/apis/collectives/index.js new file mode 100644 index 000000000..50cc7c857 --- /dev/null +++ b/src/apis/collectives/index.js @@ -0,0 +1,6 @@ +export * from './urls.js' +export * from './collectives.js' +export * from './pages.js' +export * from './userSettings.js' +export * from './settings.js' +export * from './shares.js' diff --git a/src/apis/collectives/pages.js b/src/apis/collectives/pages.js new file mode 100644 index 000000000..e0164f7bf --- /dev/null +++ b/src/apis/collectives/pages.js @@ -0,0 +1,207 @@ +import axios from '@nextcloud/axios' +import { pagesUrl } from './urls.js' + +/** + * Get all pages in the given context (collective or public share) + * + * @param {object} context - either the current collective or a share context + */ +export function getPages(context) { + return axios.get(pagesUrl(context)) +} + +/** + * Get all trashed pages in the given context. + * + * @param {object} context - either the current collective or a share context + */ +export function getTrashPages(context) { + return axios.get(pagesUrl(context, 'trash')) +} + +/** + * Create a new page in the given context (collective or public share) + * + * @param {object} context - either the current collective or a share context + * @param {object} page - properties of the new page + */ +export function createPage(context, page) { + return axios.post( + pagesUrl(context, page.parentId), + page, + ) +} + +/** + * Get a page in the given context (collective or public share) + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to retrieve + */ +export function getPage(context, pageId) { + return axios.get(pagesUrl(context, pageId)) +} + +/** + * Touch a page in the given context (collective or public share) + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to touch + */ +export function touchPage(context, pageId) { + return axios.get(pagesUrl(context, pageId, '/touch')) +} + +/** + * Rename a page in the given context (collective or public share) + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to rename + * @param {string} title - New title for the page + */ +export function renamePage(context, pageId, title) { + return axios.put( + pagesUrl(context, pageId), + { title }, + ) +} + +/** + * Copy a page inside the given context (collective or public share) + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to copy + * @param {number} parentId - Id of the page to copy to + * @param {number} index - Index for subpage order of parent page + */ +export function copyPage(context, pageId, parentId, index) { + return axios.put( + pagesUrl(context, pageId), + { parentId, index, copy: true }, + ) +} + +/** + * Move a page inside the given context (collective or public share) + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to move + * @param {number} parentId - Id of the page to move to + * @param {number} index - Index for subpage order of parent page + */ +export function movePage(context, pageId, parentId, index) { + return axios.put( + pagesUrl(context, pageId), + { parentId, index }, + ) +} + +/** + * Copy page to another collective + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to move + * @param {number} collectiveId - Id of the new collective + * @param {number} parentId - Id of the page to move to + * @param {number} index - Index for subpage order of parent page + */ +export function copyPageToCollective(context, pageId, collectiveId, parentId, index) { + return axios.put( + pagesUrl(context, pageId, 'to', collectiveId), + { parentId, index, copy: true }, + ) +} + +/** + * Move page to another collective + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to move + * @param {number} collectiveId - Id of the new collective + * @param {number} parentId - Id of the page to move to + * @param {number} index - Index for subpage order of parent page + */ +export function movePageToCollective(context, pageId, collectiveId, parentId, index) { + return axios.put( + pagesUrl(context, pageId, 'to', collectiveId), + { parentId, index }, + ) +} + +/** + * Set emoji for a page + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to update + * @param {string} emoji - New emojie for the page + */ +export function setPageEmoji(context, pageId, emoji) { + return axios.put( + pagesUrl(context, pageId, 'emoji'), + { emoji }, + ) +} + +/** + * Set subpageOrder for a page + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to update + * @param {string} subpageOrder - New subpageOrdere for the page + */ +export function setPageSubpageOrder(context, pageId, subpageOrder) { + return axios.put( + pagesUrl(context, pageId, 'subpageOrder'), + { subpageOrder }, + ) +} + +/** + * Trash a page in the given context (collective or public share) + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to trash + */ +export function trashPage(context, pageId) { + return axios.delete(pagesUrl(context, pageId)) +} + +/** + * Restore the page with the given id from trash + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to restore + */ +export function restorePage(context, pageId) { + return axios.patch(pagesUrl(context, '/trash', pageId)) +} + +/** + * Delete the page with the given id from trash + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to trash + */ +export function deletePage(context, pageId) { + return axios.delete(pagesUrl(context, '/trash', pageId)) +} + +/** + * Get list of attachments for a page + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to list attachments for + */ +export function getPageAttachments(context, pageId) { + return axios.get(pagesUrl(context, pageId, 'attachments')) +} + +/** + * Get list of backlinks for a page + * + * @param {object} context - either the current collective or a share context + * @param {number} pageId - Id of the page to list backlinks for + */ +export function getPageBacklinks(context, pageId) { + return axios.get(pagesUrl(context, pageId, 'backlinks')) +} diff --git a/src/apis/collectives/settings.js b/src/apis/collectives/settings.js new file mode 100644 index 000000000..6f4a1e256 --- /dev/null +++ b/src/apis/collectives/settings.js @@ -0,0 +1,20 @@ +import axios from '@nextcloud/axios' +import { apiUrl } from './urls.js' + +/** + * Get collectives folder setting for the current user + */ +export function getCollectivesFolder() { + return axios.get(apiUrl('v1.0', 'settings/user/user_folder')) +} + +/** + * Set collectives folder setting for the current user + * @param {string} value Name of the collective folder to use + */ +export function setCollectivesFolder(value) { + return axios.post( + apiUrl('v1.0', 'settings/user'), + { key: 'user_folder', value }, + ) +} diff --git a/src/apis/collectives/shares.js b/src/apis/collectives/shares.js new file mode 100644 index 000000000..9550ff298 --- /dev/null +++ b/src/apis/collectives/shares.js @@ -0,0 +1,76 @@ +import axios from '@nextcloud/axios' +import { collectivesUrl } from './urls.js' + +/** + * Get shares of a collective and its pages + * + * @param {number} collectiveId Id of the colletive + */ +export function getShares(collectiveId) { + return axios.get(collectivesUrl(collectiveId, 'shares')) +} + +/** + * Create a public collective share + * + * @param {number} collectiveId Id of the colletive to be shared + */ +export function createCollectiveShare(collectiveId) { + return axios.post(collectivesUrl(collectiveId, 'share')) +} + +/** + * Create a public page share + * + * @param {number} collectiveId Id of the colletive the page belongs to + * @param {number} pageId Id of the page to be shared + */ +export function createPageShare(collectiveId, pageId) { + return axios.post( + collectivesUrl(collectiveId, '_pages', pageId, 'share'), + ) +} + +/** + * Update a public collective share + * + * @param {object} share Share to update + * @param {number} share.collectiveId Id of the colletive + * @param {number} share.pageId Id of the colletive + * @param {string} share.token Token of the share to be updated + * @param {boolean} share.editable editable state to set + */ +export function updateShare(share) { + return axios.put( + shareUrl(share), + { editable: share.editable }, + ) +} + +/** + * Delete a public collective share + * + * @param {object} share Share to update + * @param {number} share.collectiveId Id of the colletive + * @param {number} share.pageId Id of the colletive + * @param {string} share.token Token of the share to be updated + */ +export function deleteShare(share) { + return axios.delete( + shareUrl(share), + ) +} + +/** + * Url of a share + * + * @param {object} share Share to update + * @param {number} share.collectiveId Id of the colletive + * @param {number} share.pageId Id of the colletive + * @param {string} share.token Token of the share to be updated + */ +function shareUrl({ collectiveId, pageId, token }) { + return pageId + ? collectivesUrl(collectiveId, '_pages', pageId, 'share', token) + : collectivesUrl(collectiveId, 'share', token) +} diff --git a/src/apis/collectives/urls.js b/src/apis/collectives/urls.js new file mode 100644 index 000000000..9f652c0e7 --- /dev/null +++ b/src/apis/collectives/urls.js @@ -0,0 +1,36 @@ +import { generateUrl, generateOcsUrl } from '@nextcloud/router' + +/** + * Url for the versioned collectives api + * + * @param {string} version - Version of the api - currently `v1.0` + * @param {...any} parts - url parts to append - will be joined with `/` + */ +export function apiUrl(version, ...parts) { + const path = ['apps/collectives/api', version, ...parts] + .join('/') + return generateOcsUrl(path) +} + +/** + * Url for the collectives app endpoints + * + * @param {...any} parts - url parts to append - will be joined with `/` + */ +export function collectivesUrl(...parts) { + const path = ['apps/collectives/_api', ...parts] + .join('/') + return generateUrl(path) +} + +/** + * Url for pages paths inside the given context. + * + * @param {object} context - either the current collective or a share context + * @param {...any} parts - url parts to append. + */ +export function pagesUrl(context, ...parts) { + return context.isPublic + ? collectivesUrl('p', context.shareTokenParam, '_pages', ...parts) + : collectivesUrl(context.collectiveId, '_pages', ...parts) +} diff --git a/src/apis/collectives/userSettings.js b/src/apis/collectives/userSettings.js new file mode 100644 index 000000000..d2bbd9486 --- /dev/null +++ b/src/apis/collectives/userSettings.js @@ -0,0 +1,28 @@ +import axios from '@nextcloud/axios' +import { collectivesUrl } from './urls.js' + +/** + * Set the page order for the current user + * + * @param {number} collectiveId ID of the colletive to be updated + * @param {number} pageOrder the desired page order for the current user + */ +export function setCollectiveUserSettingPageOrder(collectiveId, pageOrder) { + return axios.put( + collectivesUrl(collectiveId, '_userSettings', 'pageOrder'), + { pageOrder }, + ) +} + +/** + * Set the the `show recent pages` toggle for the current user + * + * @param {number} collectiveId ID of the colletive to be updated + * @param {boolean} showRecentPages the desired value + */ +export function setCollectiveUserSettingShowRecentPages(collectiveId, showRecentPages) { + return axios.put( + collectivesUrl(collectiveId, '_userSettings', 'showRecentPages'), + { showRecentPages }, + ) +} diff --git a/src/store/collectives.js b/src/store/collectives.js index fea78d4c7..6b21673a6 100644 --- a/src/store/collectives.js +++ b/src/store/collectives.js @@ -1,8 +1,7 @@ -import axios from '@nextcloud/axios' -import { generateUrl } from '@nextcloud/router' import { byName } from '../util/sortOrders.js' import randomEmoji from '../util/randomEmoji.js' import { memberLevels } from '../constants.js' +import * as api from '../apis/collectives/index.js' import { SET_COLLECTIVES, @@ -257,8 +256,8 @@ export default { commit('load', 'collectives') try { const response = getters.isPublic - ? await axios.get(generateUrl(`/apps/collectives/_api/p/${getters.shareTokenParam}`)) - : await axios.get(generateUrl('/apps/collectives/_api')) + ? await api.getSharedCollective(getters.shareTokenParam) + : await api.getCollectives() commit(SET_COLLECTIVES, response.data.data) } finally { commit('done', 'collectives') @@ -273,7 +272,7 @@ export default { */ async [GET_TRASH_COLLECTIVES]({ commit }) { commit('load', 'collectiveTrash') - const response = await axios.get(generateUrl('/apps/collectives/_api/trash')) + const response = await api.getTrashCollectives() commit(SET_TRASH_COLLECTIVES, response.data.data) commit('done', 'collectiveTrash') }, @@ -288,10 +287,7 @@ export default { * @param {object} collective Properties for the new collective */ async [NEW_COLLECTIVE]({ commit, rootState, dispatch }, collective) { - const response = await axios.post( - generateUrl('/apps/collectives/_api'), - collective, - ) + const response = await api.newCollective(collective) commit('info', response.data.message) commit(ADD_OR_UPDATE_COLLECTIVE, response.data.data) // If collectives folder wasn't initialized already, now it should be there @@ -308,10 +304,7 @@ export default { * @param {object} collective Properties for the collective */ async [UPDATE_COLLECTIVE]({ commit }, collective) { - const response = await axios.put( - generateUrl('/apps/collectives/_api/' + collective.id), - collective, - ) + const response = await api.updateCollective(collective) commit(ADD_OR_UPDATE_COLLECTIVE, response.data.data) }, @@ -324,7 +317,7 @@ export default { * @param {number} collective.id ID of the collective to be trashed */ async [TRASH_COLLECTIVE]({ commit }, { id }) { - const response = await axios.delete(generateUrl('/apps/collectives/_api/' + id)) + const response = await api.trashCollective(id) commit(MOVE_COLLECTIVE_INTO_TRASH, response.data.data) }, @@ -337,7 +330,7 @@ export default { * @param {number} collective.id ID of the collective to be restored */ async [RESTORE_COLLECTIVE]({ commit }, { id }) { - const response = await axios.patch(generateUrl('/apps/collectives/_api/trash/' + id)) + const response = await api.restoreCollective(id) commit(RESTORE_COLLECTIVE_FROM_TRASH, response.data.data) }, @@ -351,11 +344,7 @@ export default { * @param {boolean} collective.circle Whether to delete the circle as well */ async [DELETE_COLLECTIVE]({ commit }, { id, circle }) { - let doCircle = '' - if (circle) { - doCircle = '?circle=1' - } - const response = await axios.delete(generateUrl('/apps/collectives/_api/trash/' + id + doCircle)) + const response = await api.deleteCollective(id, circle) commit(DELETE_COLLECTIVE_FROM_TRASH, response.data.data) if (circle) { commit(DELETE_CIRCLE_FOR, response.data.data) @@ -371,7 +360,7 @@ export default { */ async [GET_SHARES]({ commit, getters }) { commit('load', 'shares') - const response = await axios.get(generateUrl('/apps/collectives/_api/' + getters.currentCollective.id + '/shares')) + const response = await api.getShares(getters.currentCollective.id) commit(SET_SHARES, response.data.data) commit('done', 'shares') }, @@ -387,31 +376,23 @@ export default { */ async [CREATE_SHARE]({ commit }, { collectiveId, pageId = 0 }) { commit('load', 'share') - const url = pageId - ? '/apps/collectives/_api/' + collectiveId + '/_pages/' + pageId + '/share' - : '/apps/collectives/_api/' + collectiveId + '/share' - const response = await axios.post(generateUrl(url)) + const response = pageId + ? await api.createPageShare(collectiveId, pageId) + : await api.createCollectiveShare(collectiveId) commit(ADD_OR_UPDATE_SHARE, response.data.data) commit('done', 'share') }, /** - * Create a public collective/page share + * Update a public collective/page share * * @param {object} store the vuex store * @param {Function} store.commit commit changes - * @param {object} share the share to be deleted + * @param {object} share the share to be updated */ async [UPDATE_SHARE]({ commit }, share) { commit('load', 'share') - const url = share.pageId - ? '/apps/collectives/_api/' + share.collectiveId + '/_pages/' + share.pageId + '/share/' + share.token - : '/apps/collectives/_api/' + share.collectiveId + '/share/' + share.token - const response = await axios.put( - generateUrl(url), - { editable: share.editable }, - - ) + const response = await api.updateShare(share) commit(ADD_OR_UPDATE_SHARE, response.data.data) commit('done', 'share') }, @@ -425,10 +406,7 @@ export default { */ async [DELETE_SHARE]({ commit }, share) { commit('load', 'unshare') - const url = share.pageId - ? '/apps/collectives/_api/' + share.collectiveId + '/_pages/' + share.pageId + '/share/' + share.token - : '/apps/collectives/_api/' + share.collectiveId + '/share/' + share.token - await axios.delete(generateUrl(url)) + await api.deleteShare(share) commit(REMOVE_SHARE, share) commit('done', 'unshare') }, @@ -441,10 +419,7 @@ export default { * @param {number} data.level new minimum level for sharing */ async [UPDATE_COLLECTIVE_EDIT_PERMISSIONS]({ commit }, { id, level }) { - const response = await axios.put( - generateUrl('/apps/collectives/_api/' + id + '/editLevel'), - { level }, - ) + const response = await api.updateCollectiveEditPermissions(id, level) commit(ADD_OR_UPDATE_COLLECTIVE, response.data.data) }, @@ -456,10 +431,7 @@ export default { * @param {number} data.level new minimum level for sharing */ async [UPDATE_COLLECTIVE_SHARE_PERMISSIONS]({ commit }, { id, level }) { - const response = await axios.put( - generateUrl('/apps/collectives/_api/' + id + '/shareLevel'), - { level }, - ) + const response = await api.updateCollectiveSharePermissions(id, level) commit(ADD_OR_UPDATE_COLLECTIVE, response.data.data) }, @@ -471,27 +443,27 @@ export default { * @param {number} data.mode page mode */ async [UPDATE_COLLECTIVE_PAGE_MODE]({ commit }, { id, mode }) { - const response = await axios.put( - generateUrl('/apps/collectives/_api/' + id + '/pageMode'), - { mode }, - ) + const response = await api.updateCollectivePageMode(id, mode) commit(ADD_OR_UPDATE_COLLECTIVE, response.data.data) }, + /** + * Set the page order for the current user + * + * @param {object} store the vuex store + * @param {Function} store.commit commit changes + * @param {object} data the data object + * @param {number} data.id ID of the colletive to be updated + * @param {number} data.pageOrder the desired page order for the current user + */ async [SET_COLLECTIVE_USER_SETTING_PAGE_ORDER]({ commit }, { id, pageOrder }) { - await axios.put( - generateUrl('/apps/collectives/_api/' + id + '/_userSettings/pageOrder'), - { pageOrder }, - ) + await api.setCollectiveUserSettingPageOrder(id, pageOrder) commit(PATCH_COLLECTIVE_WITH_PROPERTY, { id, property: 'userPageOrder', value: pageOrder }) }, async [SET_COLLECTIVE_USER_SETTING_SHOW_RECENT_PAGES]({ commit }, { id, showRecentPages }) { commit(PATCH_COLLECTIVE_WITH_PROPERTY, { id, property: 'userShowRecentPages', value: showRecentPages }) - await axios.put( - generateUrl('/apps/collectives/_api/' + id + '/_userSettings/showRecentPages'), - { showRecentPages }, - ) + await api.setCollectiveUserSettingShowRecentPages(id, showRecentPages) }, [MARK_COLLECTIVE_DELETED]({ commit }, collective) { diff --git a/src/store/pages.js b/src/store/pages.js index 7ded7bac0..6afe08513 100644 --- a/src/store/pages.js +++ b/src/store/pages.js @@ -1,11 +1,11 @@ import { set } from 'vue' import { getCurrentUser } from '@nextcloud/auth' import { getBuilder } from '@nextcloud/browser-storage' -import axios from '@nextcloud/axios' -import { generateRemoteUrl, generateUrl } from '@nextcloud/router' +import { generateRemoteUrl } from '@nextcloud/router' /* eslint import/namespace: ['error', { allowComputed: true }] */ import * as sortOrders from '../util/sortOrders.js' import { sortedSubpages, pageParents } from './pageExtracts.js' +import * as api from '../apis/collectives/index.js' import { SET_PAGES, @@ -244,46 +244,12 @@ export default { return state.newPage && getters.pagePath(state.newPage) }, - pagesUrl(_state, getters) { - return getters.isPublic - ? generateUrl(`/apps/collectives/_api/p/${getters.shareTokenParam}/_pages`) - : generateUrl(`/apps/collectives/_api/${getters.currentCollective.id}/_pages`) - }, - - pageCreateUrl(_state, getters) { - return parentId => `${getters.pagesUrl}/${parentId}` - }, - - pageUrl(_state, getters) { - return (pageId) => `${getters.pagesUrl}/${pageId}` - }, - - emojiUrl(_state, getters) { - return (pageId) => `${getters.pageUrl(pageId)}/emoji` - }, - - subpageOrderUrl(_state, getters) { - return (pageId) => `${getters.pageUrl(pageId)}/subpageOrder` - }, - - touchUrl(_state, getters) { - return `${getters.pageUrl(getters.currentPage.id)}/touch` - }, - - attachmentsUrl(_state, getters) { - return (pageId) => `${getters.pageUrl(pageId)}/attachments` - }, - - backlinksUrl(_state, getters) { - return (pageId) => `${getters.pageUrl(pageId)}/backlinks` - }, - - trashIndexUrl(_state, getters) { - return `${getters.pagesUrl}/trash` - }, - - trashActionUrl(_state, getters) { - return (pageId) => `${getters.pagesUrl}/trash/${pageId}` + context(_state, getters) { + return { + isPublic: getters.isPublic, + collectiveId: getters.currentCollective.id, + shareTokenParam: getters.shareTokenParam, + } }, pageTitle(state, getters) { @@ -509,7 +475,7 @@ export default { if (setLoading) { commit('load', 'collective') } - const response = await axios.get(getters.pagesUrl) + const response = await api.getPages(getters.context) commit(SET_PAGES, { pages: response.data.data, current: getters.currentPage, @@ -526,7 +492,7 @@ export default { */ async [GET_TRASH_PAGES]({ commit, getters }) { commit('load', 'pageTrash') - const response = await axios.get(getters.trashIndexUrl) + const response = await api.getTrashPages(getters.context) commit(SET_TRASH_PAGES, response.data.data) commit('done', 'pageTrash') }, @@ -541,7 +507,7 @@ export default { * @param {number} pageId Page ID */ async [GET_PAGE]({ commit, getters, state }, pageId) { - const response = await axios.get(getters.pageUrl(pageId)) + const response = await api.getPage(getters.context, pageId) commit(UPDATE_PAGE, response.data.data) }, @@ -559,13 +525,13 @@ export default { // We'll be done when the editor is loaded. commit('load', 'newPageContent') - const response = await axios.post(getters.pageCreateUrl(page.parentId), page) + const response = await api.createPage(getters.context, page) // Add new page to the beginning of pages array commit(ADD_PAGE, response.data.data) }, /** - * Create a new page + * Create a new template page * * @param {object} store the vuex store * @param {Function} store.commit commit changes @@ -581,7 +547,7 @@ export default { // We'll be done when the editor is loaded. commit('load', 'newPageContent') - const response = await axios.post(getters.pageCreateUrl(page.parentId), page) + const response = await api.createPage(getters.context, page) // Add new page to the beginning of pages array commit(ADD_PAGE, response.data.data) }, @@ -594,7 +560,7 @@ export default { * @param {object} store.getters getters of the store */ async [TOUCH_PAGE]({ commit, getters }) { - const response = await axios.get(getters.touchUrl) + const response = await api.touchPage(getters.context, getters.currentPage.id) commit(UPDATE_PAGE, response.data.data) }, @@ -607,8 +573,7 @@ export default { * @param {string} newTitle new title for the page */ async [RENAME_PAGE]({ commit, getters }, newTitle) { - const url = getters.pageUrl(getters.currentPage.id) - const response = await axios.put(url, { title: newTitle }) + const response = await api.renamePage(getters.context, getters.currentPage.id, newTitle) await commit(UPDATE_PAGE, response.data.data) }, @@ -637,9 +602,8 @@ export default { index += 1 } - const url = getters.pageUrl(pageId) try { - await axios.put(url, { index, parentId: newParentId, copy: true }) + await api.copyPage(getters.context, pageId, newParentId, index) // Reload the page list to make new page appear await dispatch(GET_PAGES, false) } finally { @@ -676,9 +640,8 @@ export default { page.parentId = newParentId commit(UPDATE_PAGE, page) - const url = getters.pageUrl(pageId) try { - const response = await axios.put(url, { index, parentId: newParentId }) + const response = await api.movePage(getters.context, pageId, newParentId, index) commit(UPDATE_PAGE, response.data.data) } catch (e) { commit(UPDATE_PAGE, pageClone) @@ -711,8 +674,7 @@ export default { async [COPY_PAGE_TO_COLLECTIVE]({ commit, getters, state, dispatch }, { collectiveId, newParentId, pageId, index }) { commit('load', 'pagelist') - const url = `${getters.pageUrl(pageId)}/to/${collectiveId}` - await axios.put(url, { index, parentId: newParentId, copy: true }) + await api.copyPageToCollective(getters.context, pageId, collectiveId, newParentId, index) commit('done', 'pagelist') }, @@ -735,8 +697,7 @@ export default { const page = { ...state.pages.find(p => p.id === pageId) } const hasSubpages = getters.visibleSubpages(pageId).length > 0 - const url = `${getters.pageUrl(pageId)}/to/${collectiveId}` - await axios.put(url, { index, parentId: newParentId }) + await api.movePageToCollective(getters.context, pageId, collectiveId, newParentId, index) commit(REMOVE_PAGE, page) commit('done', 'pagelist') @@ -759,7 +720,7 @@ export default { */ async [SET_PAGE_EMOJI]({ commit, getters }, { pageId, emoji }) { commit('load', `pageEmoji-${pageId}`) - const response = await axios.put(getters.emojiUrl(pageId), { emoji }) + const response = await api.setPageEmoji(getters.context, pageId, emoji) commit(UPDATE_PAGE, response.data.data) commit('done', `pageEmoji-${pageId}`) }, @@ -788,9 +749,10 @@ export default { commit(UPDATE_PAGE, page) try { - const response = await axios.put( - getters.subpageOrderUrl(pageId), - { subpageOrder: JSON.stringify(subpageOrder) }, + const response = await api.setPageSubpageOrder( + getters.context, + pageId, + JSON.stringify(subpageOrder), ) commit(UPDATE_PAGE, response.data.data) } catch (e) { @@ -811,7 +773,7 @@ export default { * @param {number} page.pageId ID of the page */ async [TRASH_PAGE]({ commit, getters }, { pageId }) { - const response = await axios.delete(getters.pageUrl(pageId)) + const response = await api.trashPage(getters.context, pageId) commit(MOVE_PAGE_INTO_TRASH, response.data.data) }, @@ -825,7 +787,7 @@ export default { * @param {number} page.pageId ID of the page to restore */ async [RESTORE_PAGE]({ commit, getters }, { pageId }) { - const response = await axios.patch(getters.trashActionUrl(pageId)) + const response = await api.restorePage(getters.context, pageId) commit(RESTORE_PAGE_FROM_TRASH, response.data.data) }, @@ -839,7 +801,7 @@ export default { * @param {number} page.pageId ID of the page to delete */ async [DELETE_PAGE]({ commit, getters }, { pageId }) { - axios.delete(getters.trashActionUrl(pageId)) + await api.deletePage(getters.context, pageId) commit(DELETE_PAGE_FROM_TRASH_BY_ID, pageId) }, @@ -852,7 +814,7 @@ export default { * @param {object} page Page to get attachments for */ async [GET_ATTACHMENTS]({ commit, getters }, page) { - const response = await axios.get(getters.attachmentsUrl(page.id)) + const response = await api.getPageAttachments(getters.context, page.id) commit(SET_ATTACHMENTS, { attachments: response.data.data }) }, @@ -865,7 +827,7 @@ export default { * @param {object} page Page to get backlinks for */ async [GET_BACKLINKS]({ commit, getters }, page) { - const response = await axios.get(getters.backlinksUrl(page.id)) + const response = await api.getPageBacklinks(getters.context, page.id) commit(SET_BACKLINKS, { pages: response.data.data }) }, diff --git a/src/store/settings.js b/src/store/settings.js index f7961ada6..9ff6bb75f 100644 --- a/src/store/settings.js +++ b/src/store/settings.js @@ -1,10 +1,9 @@ -import axios from '@nextcloud/axios' -import { generateOcsUrl } from '@nextcloud/router' import { GET_COLLECTIVES_FOLDER, UPDATE_COLLECTIVES_FOLDER, } from './actions.js' import { SET_COLLECTIVES_FOLDER } from './mutations.js' +import * as settings from '../apis/collectives/settings.js' export default { state: { @@ -25,7 +24,7 @@ export default { * @param {Function} store.commit commit changes */ async [GET_COLLECTIVES_FOLDER]({ commit }) { - const response = await axios.get(generateOcsUrl('apps/collectives/api/v1.0/settings/user/user_folder')) + const response = await settings.getCollectivesFolder() commit(SET_COLLECTIVES_FOLDER, response.data.ocs.data) }, @@ -37,10 +36,7 @@ export default { * @param {string} collectivesFolder path to collectives folder */ async [UPDATE_COLLECTIVES_FOLDER]({ commit }, collectivesFolder) { - const response = await axios.post(generateOcsUrl('apps/collectives/api/v1.0/settings/user'), { - key: 'user_folder', - value: collectivesFolder, - }) + const response = await settings.setCollectivesFolder(collectivesFolder) commit(SET_COLLECTIVES_FOLDER, response.data.ocs.data) }, },