Browse Source

fix(files_versions): correctly show version author also for shared files

The users endpoint is not available for other users if the current user
has no admin privileges, so instead use the displaynames endpoint.

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
pull/51722/head
Ferdinand Thiessen 8 months ago
parent
commit
a140d9f261
No known key found for this signature in database GPG Key ID: 45FAE7268762B400
  1. 56
      apps/files_versions/src/components/Version.vue
  2. 41
      apps/files_versions/src/views/VersionTab.vue
  3. 14
      cypress/e2e/files_versions/version_creation.cy.ts
  4. 46
      cypress/e2e/files_versions/version_sharing.cy.ts

56
apps/files_versions/src/components/Version.vue

@ -30,16 +30,19 @@
<div class="version__info">
<div v-if="versionLabel"
class="version__info__label"
data-cy-files-version-label
:title="versionLabel">
{{ versionLabel }}
</div>
<div v-if="versionAuthor" class="version__info">
<div v-if="versionAuthor"
class="version__info"
data-cy-files-version-author-name>
<span v-if="versionLabel"></span>
<NcAvatar class="avatar"
:user="version.author"
:size="16"
:disable-menu="true"
:disable-tooltip="true"
:size="20"
disable-menu
disable-tooltip
:show-user-status="false" />
<div>{{ versionAuthor }}</div>
</div>
@ -52,7 +55,7 @@
<NcDateTime class="version__info__date"
relative-time="short"
:timestamp="version.mtime" />
<!-- Separate dot to improve alignement -->
<!-- Separate dot to improve alignment -->
<span></span>
<span>{{ humanReadableSize }}</span>
</div>
@ -114,6 +117,17 @@
import type { PropType } from 'vue'
import type { Version } from '../utils/versions'
import { getCurrentUser } from '@nextcloud/auth'
import { Permission, formatFileSize } from '@nextcloud/files'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { joinPaths } from '@nextcloud/paths'
import { getRootUrl, generateUrl } from '@nextcloud/router'
import { defineComponent } from 'vue'
import axios from '@nextcloud/axios'
import logger from '../utils/logger'
import BackupRestore from 'vue-material-design-icons/BackupRestore.vue'
import Delete from 'vue-material-design-icons/Delete.vue'
import Download from 'vue-material-design-icons/Download.vue'
@ -128,15 +142,6 @@ import NcDateTime from '@nextcloud/vue/dist/Components/NcDateTime.js'
import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js'
import { getRootUrl, generateOcsUrl } from '@nextcloud/router'
import { joinPaths } from '@nextcloud/paths'
import { loadState } from '@nextcloud/initial-state'
import { Permission, formatFileSize } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import { defineComponent } from 'vue'
import axios from '@nextcloud/axios'
const hasPermission = (permissions: number, permission: number): boolean => (permissions & permission) !== 0
export default defineComponent({
@ -198,7 +203,7 @@ export default defineComponent({
previewLoaded: false,
previewErrored: false,
capabilities: loadState('core', 'capabilities', { files: { version_labeling: false, version_deletion: false } }),
versionAuthor: '',
versionAuthor: '' as string|null,
}
},
@ -290,21 +295,26 @@ export default defineComponent({
},
async fetchDisplayName() {
// check to make sure that we have a valid author - in case database did not migrate, null author, etc.
if (this.version.author) {
this.versionAuthor = null
if (!this.version.author) {
return
}
if (this.version.author === getCurrentUser()?.uid) {
this.versionAuthor = t('files_versions', 'You')
} else {
try {
const { data } = await axios.get(generateOcsUrl(`/cloud/users/${this.version.author}`))
this.versionAuthor = data.ocs.data.displayname
} catch (e) {
// Promise got rejected - default to null author to not try to load author profile
this.versionAuthor = null
const { data } = await axios.post(generateUrl('/displaynames'), { users: [this.version.author] })
this.versionAuthor = data.users[this.version.author]
} catch (error) {
logger.warn('Could not load user display name', { error })
}
}
},
click() {
if (!this.canView) {
window.location = this.downloadURL
window.location.href = this.downloadURL
return
}
this.$emit('click', { version: this.version })

41
apps/files_versions/src/views/VersionTab.vue

@ -4,28 +4,27 @@
-->
<template>
<div class="versions-tab__container">
<VirtualScrolling :sections="sections"
<VirtualScrolling v-slot="{ visibleSections }"
:sections="sections"
:header-height="0">
<template slot-scope="{visibleSections}">
<ul data-files-versions-versions-list>
<template v-if="visibleSections.length === 1">
<Version v-for="(row) of visibleSections[0].rows"
:key="row.items[0].mtime"
:can-view="canView"
:can-compare="canCompare"
:load-preview="isActive"
:version="row.items[0]"
:file-info="fileInfo"
:is-current="row.items[0].mtime === fileInfo.mtime"
:is-first-version="row.items[0].mtime === initialVersionMtime"
@click="openVersion"
@compare="compareVersion"
@restore="handleRestore"
@label-update-request="handleLabelUpdateRequest(row.items[0])"
@delete="handleDelete" />
</template>
</ul>
</template>
<ul :aria-label="t('files_versions', 'File versions')" data-files-versions-versions-list>
<template v-if="visibleSections.length === 1">
<Version v-for="(row) of visibleSections[0].rows"
:key="row.items[0].mtime"
:can-view="canView"
:can-compare="canCompare"
:load-preview="isActive"
:version="row.items[0]"
:file-info="fileInfo"
:is-current="row.items[0].mtime === fileInfo.mtime"
:is-first-version="row.items[0].mtime === initialVersionMtime"
@click="openVersion"
@compare="compareVersion"
@restore="handleRestore"
@label-update-request="handleLabelUpdateRequest(row.items[0])"
@delete="handleDelete" />
</template>
</ul>
<NcLoadingIcon v-if="loading" slot="loader" class="files-list-viewer__loader" />
</VirtualScrolling>
<VersionLabelDialog v-if="editedVersion"

14
cypress/e2e/files_versions/version_creation.cy.ts

@ -30,4 +30,18 @@ describe('Versions creation', () => {
cy.get('[data-files-versions-version]').eq(2).contains('Initial version')
})
})
it('See yourself as version author', () => {
cy.visit('/apps/files')
openVersionsPanel(randomFileName)
cy.findByRole('tabpanel', { name: 'Versions' })
.findByRole('list', { name: 'File versions' })
.findAllByRole('listitem')
.should('have.length', 3)
.first()
.find('[data-cy-files-version-author-name]')
.should('exist')
.and('contain.text', 'You')
})
})

46
cypress/e2e/files_versions/version_sharing.cy.ts

@ -0,0 +1,46 @@
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { User } from '@nextcloud/cypress'
import { openVersionsPanel, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts'
import { navigateToFolder, triggerActionForFile } from '../files/FilesUtils.ts'
describe('Versions on shares', () => {
const randomSharedFolderName = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 10)
const randomFileName = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 10) + '.txt'
const randomFilePath = `${randomSharedFolderName}/${randomFileName}`
let alice: User
let bob: User
before(() => {
cy.createRandomUser()
.then((user) => {
alice = user
})
.then(() => {
cy.mkdir(alice, `/${randomSharedFolderName}`)
return setupTestSharedFileFromUser(alice, randomSharedFolderName, {})
})
.then((user) => { bob = user })
.then(() => uploadThreeVersions(alice, randomFilePath))
})
it('See sharees display name as author', () => {
cy.login(bob)
cy.visit('/apps/files')
navigateToFolder(randomSharedFolderName)
triggerActionForFile(randomFileName, 'details')
cy.findByRole('tab', { name: 'Versions' }).click()
cy.findByRole('tabpanel', { name: 'Versions' })
.findByRole('list', { name: 'File versions' })
.findAllByRole('listitem')
.first()
.find('[data-cy-files-version-author-name]')
.should('be.visible')
.and('contain.text', alice.userId)
})
})
Loading…
Cancel
Save