Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Access node owner by top level owner property #47287

Merged
merged 2 commits into from
Aug 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/files/src/components/FileEntry/FileEntryActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
:close-after-click="!isMenu(action.id)"
:data-cy-files-list-row-action="action.id"
:is-menu="isMenu(action.id)"
:aria-label="action.title?.([source], currentView)"
:title="action.title?.([source], currentView)"
@click="onActionClick(action)">
<template #icon>
Expand Down
2 changes: 1 addition & 1 deletion apps/files/src/newMenu/newFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const entry = {
source,
id: fileid,
mtime: new Date(),
owner: getCurrentUser()?.uid || null,
owner: context.owner,
permissions: Permission.ALL,
root: context?.root || '/files/' + getCurrentUser()?.uid,
// Include mount-type from parent folder as this is inherited
Expand Down
40 changes: 25 additions & 15 deletions apps/files_sharing/src/actions/sharingStatusAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ export const action = new FileAction({
displayName(nodes: Node[]) {
const node = nodes[0]
const shareTypes = Object.values(node?.attributes?.['share-types'] || {}).flat() as number[]
const ownerId = node?.attributes?.['owner-id']

if (shareTypes.length > 0
|| (ownerId !== getCurrentUser()?.uid || isExternal(node))) {
|| (node.owner !== getCurrentUser()?.uid || isExternal(node))) {
return t('files_sharing', 'Shared')
}

Expand All @@ -38,19 +37,32 @@ export const action = new FileAction({

title(nodes: Node[]) {
const node = nodes[0]
const ownerId = node?.attributes?.['owner-id']
const ownerDisplayName = node?.attributes?.['owner-display-name']

// Mixed share types
if (Array.isArray(node.attributes?.['share-types']) && node.attributes?.['share-types'].length > 1) {
if (node.owner && (node.owner !== getCurrentUser()?.uid || isExternal(node))) {
const ownerDisplayName = node?.attributes?.['owner-display-name']
return t('files_sharing', 'Shared by {ownerDisplayName}', { ownerDisplayName })
}

const shareTypes = Object.values(node?.attributes?.['share-types'] || {}).flat() as number[]
if (shareTypes.length > 1) {
return t('files_sharing', 'Shared multiple times with different people')
}

if (ownerId && (ownerId !== getCurrentUser()?.uid || isExternal(node))) {
return t('files_sharing', 'Shared by {ownerDisplayName}', { ownerDisplayName })
const sharees = node.attributes.sharees?.sharee as { id: string, 'display-name': string, type: ShareType }[] | undefined
if (!sharees) {
// No sharees so just show the default message to create a new share
return t('files_sharing', 'Show sharing options')
}

return t('files_sharing', 'Show sharing options')
const sharee = [sharees].flat()[0] // the property is sometimes weirdly normalized, so we need to compensate
switch (sharee.type) {
case ShareType.User:
return t('files_sharing', 'Shared with {user}', { user: sharee['display-name'] })
case ShareType.Group:
return t('files_sharing', 'Shared with group {group}', { group: sharee['display-name'] ?? sharee.id })
default:
return t('files_sharing', 'Shared with others')
}
},

iconSvgInline(nodes: Node[]) {
Expand All @@ -69,7 +81,7 @@ export const action = new FileAction({
}

// Group shares
if (shareTypes.includes(ShareType.Grup)
if (shareTypes.includes(ShareType.Group)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good one 😅🙈

|| shareTypes.includes(ShareType.RemoteGroup)) {
return AccountGroupSvg
}
Expand All @@ -79,9 +91,8 @@ export const action = new FileAction({
return CircleSvg
}

const ownerId = node?.attributes?.['owner-id']
if (ownerId && (ownerId !== getCurrentUser()?.uid || isExternal(node))) {
return generateAvatarSvg(ownerId, isExternal(node))
if (node.owner && (node.owner !== getCurrentUser()?.uid || isExternal(node))) {
return generateAvatarSvg(node.owner, isExternal(node))
}

return AccountPlusSvg
Expand All @@ -93,7 +104,6 @@ export const action = new FileAction({
}

const node = nodes[0]
const ownerId = node?.attributes?.['owner-id']
const shareTypes = node.attributes?.['share-types']
const isMixed = Array.isArray(shareTypes) && shareTypes.length > 0

Expand All @@ -104,7 +114,7 @@ export const action = new FileAction({
}

// If the node is shared by someone else
if (ownerId && (ownerId !== getCurrentUser()?.uid || isExternal(node))) {
if (node.owner !== getCurrentUser()?.uid || isExternal(node)) {
return true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ async function updateAvailableAccounts(path: string = '/') {
const { contents } = await currentView.value.getContents(path)
const available = new Map<string, IUserSelectData>()
for (const node of contents) {
const owner = node.owner ?? node.attributes['owner-id']
const owner = node.owner
if (owner && !available.has(owner)) {
available.set(owner, {
id: owner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import NcUserBubble from '@nextcloud/vue/dist/Components/NcUserBubble.js'
const folder = ref<Folder>()
const note = computed<string>(() => folder.value?.attributes.note ?? '')
const user = computed(() => {
const id = folder.value?.attributes?.['owner-id']
const id = folder.value?.owner
const displayName = folder.value?.attributes?.['owner-display-name']
if (id !== getCurrentUser()?.uid) {
return {
Expand Down
105 changes: 105 additions & 0 deletions cypress/e2e/files_sharing/files-inline-action.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*!
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { User } from '@nextcloud/cypress'
import { createShare } from './FilesSharingUtils.ts'
import { closeSidebar, getRowForFile } from '../files/FilesUtils.ts'

describe('files_sharing: Files inline status action', { testIsolation: true }, () => {
/**
* Regression test of https://github.com/nextcloud/server/issues/45723
*/
it('No "shared" tag when user ID is purely numerical', () => {
const user = {
language: 'en',
password: 'test1234',
userId: String(Math.floor(Math.random() * 1000)),
Dismissed Show dismissed Hide dismissed
} as User
cy.createUser(user)
cy.mkdir(user, '/folder')
cy.login(user)

cy.visit('/apps/files')

getRowForFile('folder')
.should('be.visible')
.find('[data-cy-files-list-row-actions]')
.findByRole('button', { name: 'Shared' })
.should('not.exist')
})

describe('', () => {
let user: User
let sharee: User

beforeEach(() => {
cy.createRandomUser().then(($user) => {
user = $user
})
cy.createRandomUser().then(($user) => {
sharee = $user
})
})

it('Render quick option for sharing', () => {
cy.mkdir(user, '/folder')
cy.login(user)

cy.visit('/apps/files')
getRowForFile('folder')
.should('be.visible')

getRowForFile('folder')
.should('be.visible')
.find('[data-cy-files-list-row-actions]')
.findByRole('button', { name: /Show sharing options/ })
.should('be.visible')
.click()

// check the click opened the sidebar
cy.get('[data-cy-sidebar]')
.should('be.visible')
// and ensure the sharing tab is selected
.findByRole('tab', { name: 'Sharing', selected: true })
.should('exist')
})

it('Render inline status action for sharer', () => {
cy.mkdir(user, '/folder')
cy.login(user)

cy.visit('/apps/files')
getRowForFile('folder')
.should('be.visible')
createShare('folder', sharee.userId)
closeSidebar()

getRowForFile('folder')
.should('be.visible')
.find('[data-cy-files-list-row-actions]')
.findByRole('button', { name: /^Shared with/i })
.should('be.visible')
})

it('Render inline status action for sharee', () => {
cy.mkdir(user, '/folder')
cy.login(user)

cy.visit('/apps/files')
getRowForFile('folder')
.should('be.visible')
createShare('folder', sharee.userId)
closeSidebar()

cy.login(sharee)
cy.visit('/apps/files')

getRowForFile('folder')
.should('be.visible')
.find('[data-cy-files-list-row-actions]')
.findByRole('button', { name: `Shared by ${user.userId}` })
.should('be.visible')
})
})
})
2 changes: 0 additions & 2 deletions dist/5804-5804.js

This file was deleted.

Loading
Loading