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: permanent link for share resources #12022

Merged
merged 1 commit into from
Dec 6, 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
6 changes: 6 additions & 0 deletions changelog/unreleased/bugfix-permanent-link-for-shares
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Bugfix: Permanent link for shares

We've fixed an issue where the permanent for shares could not be copied.

https://github.com/owncloud/web/pull/12022
https://github.com/owncloud/web/issues/12001
10 changes: 8 additions & 2 deletions packages/web-client/src/helpers/share/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,12 @@ export const getShareResourcePermissions = ({

export function buildIncomingShareResource({
driveItem,
graphRoles
graphRoles,
serverUrl
}: {
driveItem: DriveItem
graphRoles: Record<string, ShareRole>
serverUrl: string
}): IncomingShareResource {
const resourceName = driveItem.name || driveItem.remoteItem.name
const storageId = extractStorageId(driveItem.remoteItem.id)
Expand Down Expand Up @@ -154,6 +156,7 @@ export function buildIncomingShareResource({
shareRoles,
sharePermissions,
outgoing: false,
privateLink: urlJoin(serverUrl, 'f', driveItem.remoteItem.id),
canRename: () => driveItem['@client.synchronize'],
canDownload: () => sharePermissions.includes(GraphSharePermission.readContent),
canUpload: () => sharePermissions.includes(GraphSharePermission.createUpload),
Expand All @@ -174,10 +177,12 @@ export function buildIncomingShareResource({

export function buildOutgoingShareResource({
driveItem,
user
user,
serverUrl
}: {
driveItem: DriveItem
user: User
serverUrl: string
}): OutgoingShareResource {
const storageId = extractStorageId(driveItem.id)
const path = urlJoin(driveItem.parentReference.path, driveItem.name)
Expand Down Expand Up @@ -213,6 +218,7 @@ export function buildOutgoingShareResource({
type: !!driveItem.folder ? 'folder' : 'file',
mimeType: driveItem.file?.mimeType || 'httpd/unix-directory',
outgoing: true,
privateLink: urlJoin(serverUrl, 'f', driveItem.id),
canRename: () => true,
canDownload: () => true,
canUpload: () => true,
Expand Down
29 changes: 20 additions & 9 deletions packages/web-client/tests/unit/helpers/share/functions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
UnifiedRoleDefinition,
User
} from '../../../../src/graph/generated'
import { urlJoin } from '../../../../src'

describe('share helper functions', () => {
describe('isShareResource', () => {
Expand Down Expand Up @@ -129,7 +130,7 @@ describe('share helper functions', () => {
}

it('sets ids based on the drive item, its first permission and parent reference', () => {
const result = buildIncomingShareResource({ driveItem, graphRoles })
const result = buildIncomingShareResource({ driveItem, graphRoles, serverUrl: '' })

expect(result.id).toEqual(driveItem.id)
expect(result.fileId).toEqual(driveItem.remoteItem.id)
Expand All @@ -140,23 +141,28 @@ describe('share helper functions', () => {
it.each([true, false])('correctly detects if the resource is a folder', (isFolder) => {
const item = { ...driveItem }
item.folder = isFolder ? mock<DriveItem['folder']>() : undefined
const result = buildIncomingShareResource({ driveItem: item, graphRoles })
const result = buildIncomingShareResource({ driveItem: item, graphRoles, serverUrl: '' })

expect(result.isFolder).toEqual(isFolder)
expect(result.type).toEqual(isFolder ? 'folder' : 'file')
})
it('sets outgoing to false', () => {
const result = buildIncomingShareResource({ driveItem, graphRoles })
const result = buildIncomingShareResource({ driveItem, graphRoles, serverUrl: '' })
expect(result.outgoing).toBeFalsy()
})
it('sets sharedBy based on the permission invitation', () => {
const result = buildIncomingShareResource({ driveItem, graphRoles })
const result = buildIncomingShareResource({ driveItem, graphRoles, serverUrl: '' })
expect(result.sharedBy).toEqual([sharedBy])
})
it('sets sharedBy based on the permission invitation', () => {
const result = buildIncomingShareResource({ driveItem, graphRoles })
const result = buildIncomingShareResource({ driveItem, graphRoles, serverUrl: '' })
expect(result.sharedWith).toEqual([{ ...sharedWith, shareType: ShareTypes.user.value }])
})
it('constructs a private link', () => {
const serverUrl = 'https://example.com'
const result = buildIncomingShareResource({ driveItem, graphRoles, serverUrl })
expect(result.privateLink).toEqual(urlJoin(serverUrl, 'f', driveItem.remoteItem.id))
})
})

describe('buildOutgoingShareResource', () => {
Expand All @@ -174,29 +180,34 @@ describe('share helper functions', () => {
const user = { id: '1', displayName: 'user1' } as User

it('sets ids based on the drive item, its first permission and parent reference', () => {
const result = buildOutgoingShareResource({ driveItem, user })
const result = buildOutgoingShareResource({ driveItem, user, serverUrl: '' })

expect(result.id).toEqual(driveItem.id)
expect(result.fileId).toEqual(driveItem.id)
expect(result.driveId).toEqual(driveItem.parentReference.driveId)
expect(result.parentFolderId).toEqual(driveItem.parentReference.id)
})
it('sets outgoing to true', () => {
const result = buildOutgoingShareResource({ driveItem, user })
const result = buildOutgoingShareResource({ driveItem, user, serverUrl: '' })
expect(result.outgoing).toBeTruthy()
})
it('sets the path based on the parent reference path and the drive item name', () => {
const result = buildOutgoingShareResource({ driveItem, user })
const result = buildOutgoingShareResource({ driveItem, user, serverUrl: '' })
expect(result.path).toEqual(`${driveItem.parentReference.path}/${driveItem.name}`)
})
it.each([true, false])('correctly detects if the resource is a folder', (isFolder) => {
const item = { ...driveItem }
item.folder = isFolder ? mock<DriveItem['folder']>() : undefined
const result = buildOutgoingShareResource({ driveItem: item, user })
const result = buildOutgoingShareResource({ driveItem: item, user, serverUrl: '' })

expect(result.isFolder).toEqual(isFolder)
expect(result.type).toEqual(isFolder ? 'folder' : 'file')
})
it('constructs a private link', () => {
const serverUrl = 'https://example.com'
const result = buildOutgoingShareResource({ driveItem, user, serverUrl })
expect(result.privateLink).toEqual(urlJoin(serverUrl, 'f', driveItem.id))
})
})

describe('buildCollaboratorShare', () => {
Expand Down
3 changes: 2 additions & 1 deletion packages/web-pkg/src/components/AppTemplates/AppWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ export default defineComponent({
...fileInfo,
...buildIncomingShareResource({
graphRoles: sharesStore.graphRoles,
driveItem: sharedDriveItem
driveItem: sharedDriveItem,
serverUrl: configStore.serverUrl
}),
tags: fileInfo.tags // tags are always [] in Graph API, hence take them from webdav
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ export class FolderLoaderSharedViaLink implements FolderLoader {

const resources = value
.filter((s) => s.permissions.some(({ link }) => !!link))
.map((driveItem) => buildOutgoingShareResource({ driveItem, user: userStore.user }))
.map((driveItem) =>
buildOutgoingShareResource({
driveItem,
user: userStore.user,
serverUrl: configStore.serverUrl
})
)

resourcesStore.initResourceList({ currentFolder: null, resources })
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export class FolderLoaderSharedWithMe implements FolderLoader {
)

const resources = value.map((driveItem) =>
buildIncomingShareResource({ driveItem, graphRoles: sharesStore.graphRoles })
buildIncomingShareResource({
driveItem,
graphRoles: sharesStore.graphRoles,
serverUrl: configStore.serverUrl
})
)

resourcesStore.initResourceList({ currentFolder: null, resources })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ export class FolderLoaderSharedWithOthers implements FolderLoader {

const resources = value
.filter((s) => s.permissions.some(({ link }) => !link))
.map((driveItem) => buildOutgoingShareResource({ driveItem, user: userStore.user }))
.map((driveItem) =>
buildOutgoingShareResource({
driveItem,
user: userStore.user,
serverUrl: configStore.serverUrl
})
)

resourcesStore.initResourceList({ currentFolder: null, resources })
})
Expand Down
6 changes: 4 additions & 2 deletions packages/web-pkg/src/services/folder/loaders/loaderSpace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export class FolderLoaderSpace implements FolderLoader {
userStore,
authService,
spacesStore,
sharesStore
sharesStore,
configStore
} = context
const { webdav, graphAuthenticated: graphClient } = clientService
const { replaceInvalidFileRoute } = useFileRouteReplace({ router })
Expand Down Expand Up @@ -79,7 +80,8 @@ export class FolderLoaderSpace implements FolderLoader {
if (sharedDriveItem) {
currentFolder = buildIncomingShareResource({
graphRoles: sharesStore.graphRoles,
driveItem: sharedDriveItem
driveItem: sharedDriveItem,
serverUrl: configStore.serverUrl
})
}
} else if (!isPersonalSpaceResource(space) && !isPublicSpaceResource(space)) {
Expand Down
1 change: 1 addition & 0 deletions packages/web-runtime/src/container/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ export const registerSSEEventListeners = ({
messageStore,
userStore,
sharesStore,
configStore,
clientService,
previewService,
language,
Expand Down
27 changes: 23 additions & 4 deletions packages/web-runtime/src/container/sse/shares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export const onSSEShareCreatedEvent = async ({
spacesStore,
sharesStore,
userStore,
configStore,
clientService,
router
}: SSEEventOptions) => {
Expand Down Expand Up @@ -168,7 +169,11 @@ export const onSSEShareCreatedEvent = async ({
if (!driveItem) {
return
}
const resource = buildIncomingShareResource({ driveItem, graphRoles: sharesStore.graphRoles })
const resource = buildIncomingShareResource({
driveItem,
graphRoles: sharesStore.graphRoles,
serverUrl: configStore.serverUrl
})
return resourcesStore.upsertResource(resource)
}

Expand All @@ -179,7 +184,11 @@ export const onSSEShareCreatedEvent = async ({
if (!driveItem) {
return
}
const resource = buildOutgoingShareResource({ driveItem, user: userStore.user })
const resource = buildOutgoingShareResource({
driveItem,
user: userStore.user,
serverUrl: configStore.serverUrl
})
return resourcesStore.upsertResource(resource)
}
}
Expand All @@ -189,6 +198,7 @@ export const onSSEShareUpdatedEvent = async ({
sharesStore,
clientService,
userStore,
configStore,
router
}: SSEEventOptions) => {
if (sseData.initiatorid === clientService.initiatorId) {
Expand All @@ -211,7 +221,11 @@ export const onSSEShareUpdatedEvent = async ({
if (!driveItem) {
return
}
const resource = buildIncomingShareResource({ driveItem, graphRoles: sharesStore.graphRoles })
const resource = buildIncomingShareResource({
driveItem,
graphRoles: sharesStore.graphRoles,
serverUrl: configStore.serverUrl
})
return resourcesStore.upsertResource(resource)
}
}
Expand Down Expand Up @@ -308,6 +322,7 @@ export const onSSELinkCreatedEvent = async ({
resourcesStore,
spacesStore,
userStore,
configStore,
clientService,
router
}: SSEEventOptions) => {
Expand Down Expand Up @@ -353,7 +368,11 @@ export const onSSELinkCreatedEvent = async ({
if (!driveItem) {
return
}
const resource = buildOutgoingShareResource({ driveItem, user: userStore.user })
const resource = buildOutgoingShareResource({
driveItem,
user: userStore.user,
serverUrl: configStore.serverUrl
})
return resourcesStore.upsertResource(resource)
}
}
Expand Down
2 changes: 2 additions & 0 deletions packages/web-runtime/src/container/sse/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from 'zod'
import {
ClientService,
ConfigStore,
MessageStore,
PreviewService,
ResourcesStore,
Expand Down Expand Up @@ -29,6 +30,7 @@ export interface SSEEventOptions {
userStore: UserStore
messageStore: MessageStore
sharesStore: SharesStore
configStore: ConfigStore
clientService: ClientService
previewService: PreviewService
router: Router
Expand Down
3 changes: 3 additions & 0 deletions packages/web-runtime/tests/unit/container/sse/files.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
ClientService,
PreviewService,
useConfigStore,
useMessages,
useResourcesStore,
useSharesStore,
Expand Down Expand Up @@ -442,6 +443,7 @@ const getMocks = ({
const messageStore = useMessages()
const userStore = useUserStore()
const sharesStore = useSharesStore()
const configStore = useConfigStore()
const clientService = mockDeep<ClientService>({ initiatorId: 'local1' })
const previewService = mockDeep<PreviewService>()
const router = mockDeep<Router>()
Expand All @@ -457,6 +459,7 @@ const getMocks = ({
messageStore,
userStore,
sharesStore,
configStore,
clientService,
previewService,
resourceQueue,
Expand Down
3 changes: 3 additions & 0 deletions packages/web-runtime/tests/unit/container/sse/helpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createTestingPinia } from '@ownclouders/web-test-helpers'
import {
ClientService,
PreviewService,
useConfigStore,
useMessages,
useResourcesStore,
useSharesStore,
Expand Down Expand Up @@ -109,6 +110,7 @@ const getMocks = ({
const spacesStore = useSpacesStore()
const messageStore = useMessages()
const userStore = useUserStore()
const configStore = useConfigStore()
const sharesStore = useSharesStore()
const clientService = mockDeep<ClientService>()
const previewService = mockDeep<PreviewService>()
Expand All @@ -123,6 +125,7 @@ const getMocks = ({
messageStore,
userStore,
sharesStore,
configStore,
clientService,
previewService,
resourceQueue,
Expand Down
3 changes: 3 additions & 0 deletions packages/web-runtime/tests/unit/container/sse/shares.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
ClientService,
eventBus,
PreviewService,
useConfigStore,
useMessages,
useResourcesStore,
useSharesStore,
Expand Down Expand Up @@ -697,6 +698,7 @@ const getMocks = ({
spacesStore.spaces = spaces
const messageStore = useMessages()
const userStore = useUserStore()
const configStore = useConfigStore()
userStore.user = mockDeep<User>({ id: '1' })
const sharesStore = useSharesStore()
const clientService = mockDeep<ClientService>({ initiatorId: 'local1' })
Expand Down Expand Up @@ -734,6 +736,7 @@ const getMocks = ({
messageStore,
userStore,
sharesStore,
configStore,
clientService,
previewService,
resourceQueue,
Expand Down