From 3e4bf0eb99775ce4ed954d6a63965ffa684b00c8 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 4 Nov 2024 08:31:37 +0100 Subject: [PATCH] fix(sharing): list accounts with matches in email * Show users with matches in the email address. * List email addresses in sharing dialog. `NcSelect` filters the options based on matches in `label` and `subname`. By using the email address as a subname we ensure options with a matching email address are shown. Signed-off-by: Max --- cypress/e2e/sharingFeatures.js | 21 ++++++++++++++++++ cypress/support/commands.js | 25 ++++++++++++++++++---- src/components/board/SharingTabSidebar.vue | 4 ++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/cypress/e2e/sharingFeatures.js b/cypress/e2e/sharingFeatures.js index b24f70351..abe1ed3f8 100644 --- a/cypress/e2e/sharingFeatures.js +++ b/cypress/e2e/sharingFeatures.js @@ -6,11 +6,14 @@ import { randUser } from '../utils/index.js' import { sampleBoard } from '../utils/sampleBoard' const user = randUser() const recipient = randUser() +const domain = Math.random().toString(36).replace(/[^a-z]+/g, '').slice(0, 10) describe('Board', function() { before(function() { cy.createUser(user) cy.createUser(recipient) + cy.login(recipient) + cy.setUserEmail(recipient, `${recipient.userId}@${domain}.com`) }) beforeEach(function() { @@ -34,6 +37,24 @@ describe('Board', function() { }) }) + it('Share a board to a user by email', function() { + const board = sampleBoard('Shared by email') + cy.createExampleBoard({ user, board }).then((board) => { + const boardId = board.id + cy.visit(`/apps/deck/#/board/${boardId}`) + cy.get('.board-title').contains(board.title) + + // domain is only in the email address - not in user ids. + cy.shareBoardWithUi(domain, recipient.userId) + + cy.login(recipient) + cy.visit(`/apps/deck/#/board/${boardId}`) + cy.get('.board-title').contains(board.title) + cy.get('.button-vue[aria-label*="Add card"]') + .should('not.exist') + }) + }) + it('Share a board to a user as writable', function() { const board = sampleBoard('Editable board') cy.createExampleBoard({ user, board }).then((board) => { diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 17426fb2e..f06c2340d 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -4,12 +4,21 @@ */ import { addCommands } from '@nextcloud/cypress' +import axios from '@nextcloud/axios' addCommands() const url = Cypress.config('baseUrl').replace(/\/index.php\/?$/g, '') Cypress.env('baseUrl', url) +// prepare main cypress window so we can use axios there +// and it will successfully fetch csrf tokens when needed. +window.OC = { + config: { modRewriteWorking: false }, +} +// Prevent @nextcloud/router from reading window.location +window._oc_webroot = url + Cypress.Commands.add('openLeftSidebar', () => { cy.get('.app-navigation button.app-navigation-toggle').click() }) @@ -89,15 +98,23 @@ Cypress.Commands.add('getNavigationEntry', (boardTitle) => { .find('a.app-navigation-entry-link') }) -Cypress.Commands.add('shareBoardWithUi', (userId) => { - cy.intercept({ method: 'GET', url: `**/ocs/v2.php/apps/files_sharing/api/v1/sharees?search=${userId}*` }).as('fetchRecipients') +Cypress.Commands.add('shareBoardWithUi', (query, userId=query) => { + cy.intercept({ method: 'GET', url: `**/ocs/v2.php/apps/files_sharing/api/v1/sharees?search=${query}*` }).as('fetchRecipients') cy.get('[aria-label="Open details"]').click() cy.get('.app-sidebar').should('be.visible') - cy.get('.select input').type(`${userId}`) + cy.get('.select input').type(`${query}`) cy.wait('@fetchRecipients', { timeout: 7000 }) - cy.get('.vs__dropdown-menu .option').first().contains(userId) + cy.get('.vs__dropdown-menu .option').first().contains(query) cy.get('.select input').type('{enter}') cy.get('.shareWithList').contains(userId) }) + +Cypress.Commands.add('setUserEmail', (user, value) => { + Cypress.log() + return axios.put( + `${url}/ocs/v2.php/cloud/users/${user.userId}`, + { key: 'email', value }, + ) +}) diff --git a/src/components/board/SharingTabSidebar.vue b/src/components/board/SharingTabSidebar.vue index da138c662..2669b5d68 100644 --- a/src/components/board/SharingTabSidebar.vue +++ b/src/components/board/SharingTabSidebar.vue @@ -141,9 +141,13 @@ export default { }, formatedSharees() { return this.unallocatedSharees.map(item => { + const subname = item.label === item.shareWithDisplayNameUnique + ? '' + : item.shareWithDisplayNameUnique const sharee = { user: item.value.shareWith, displayName: item.label, + subname, icon: 'icon-user', multiselectKey: item.shareType + ':' + item.primaryKey, }