diff --git a/changelog/unreleased/bugfix-external-url-resolving b/changelog/unreleased/bugfix-external-url-resolving
new file mode 100644
index 00000000000..30eb803ccde
--- /dev/null
+++ b/changelog/unreleased/bugfix-external-url-resolving
@@ -0,0 +1,6 @@
+Bugfix: Resolving external URLs
+
+Resolving external URLs when only the file ID is given has been fixed.
+
+https://github.com/owncloud/web/issues/9804
+https://github.com/owncloud/web/pull/9833
diff --git a/packages/design-system/src/components/OcNotificationMessage/OcNotificationMessage.vue b/packages/design-system/src/components/OcNotificationMessage/OcNotificationMessage.vue
index 15ec854d055..319a2c87598 100644
--- a/packages/design-system/src/components/OcNotificationMessage/OcNotificationMessage.vue
+++ b/packages/design-system/src/components/OcNotificationMessage/OcNotificationMessage.vue
@@ -11,7 +11,7 @@
{{ title }}
-
diff --git a/packages/web-app-external/src/App.vue b/packages/web-app-external/src/App.vue
index d8c5a1bcd60..c8a21597c54 100644
--- a/packages/web-app-external/src/App.vue
+++ b/packages/web-app-external/src/App.vue
@@ -39,10 +39,26 @@ import { mapGetters } from 'vuex'
import { computed, defineComponent, unref } from 'vue'
import { urlJoin } from 'web-client/src/utils'
import AppTopBar from 'web-pkg/src/components/AppTopBar.vue'
-import { queryItemAsString, useAppDefaults, useRouteQuery } from 'web-pkg/src/composables'
+import {
+ queryItemAsString,
+ useAppDefaults,
+ useClientService,
+ useRoute,
+ useRouteParam,
+ useRouteQuery,
+ useRouter,
+ useStore
+} from 'web-pkg/src/composables'
import { configurationManager } from 'web-pkg/src/configuration'
import ErrorScreen from './components/ErrorScreen.vue'
import LoadingScreen from './components/LoadingScreen.vue'
+import {
+ Resource,
+ SpaceResource,
+ buildShareSpaceResource,
+ isMountPointSpaceResource
+} from 'web-client/src/helpers'
+import { useLoadFileInfoById } from 'web-pkg/src/composables/fileInfo'
export default defineComponent({
name: 'ExternalApp',
@@ -52,14 +68,99 @@ export default defineComponent({
LoadingScreen
},
setup() {
+ const store = useStore()
+ const router = useRouter()
+ const currentRoute = useRoute()
+ const clientService = useClientService()
+ const { loadFileInfoByIdTask } = useLoadFileInfoById({ clientService })
const appName = useRouteQuery('app')
const applicationName = computed(() => queryItemAsString(unref(appName)))
+
+ const fileIdQueryItem = useRouteQuery('fileId')
+ const fileId = computed(() => {
+ return queryItemAsString(unref(fileIdQueryItem))
+ })
+
+ const driveAliasAndItem = useRouteParam('driveAliasAndItem')
+
+ const getMatchingSpace = (id): SpaceResource => {
+ return store.getters['runtime/spaces/spaces'].find((space) => id.startsWith(space.id))
+ }
+ const findMatchingMountPoint = (id: string | number): SpaceResource => {
+ return store.getters['runtime/spaces/spaces'].find(
+ (space) => isMountPointSpaceResource(space) && space.root?.remoteItem?.id === id
+ )
+ }
+
+ const addMissingDriveAliasAndItem = async () => {
+ const id = unref(fileId)
+ let path: string
+ let matchingSpace = getMatchingSpace(id)
+ if (matchingSpace) {
+ path = await clientService.owncloudSdk.files.getPathForFileId(id)
+ const driveAliasAndItem = matchingSpace.getDriveAliasAndItem({ path } as Resource)
+ console.log(unref(currentRoute).query)
+ return router.push({
+ params: {
+ ...unref(currentRoute).params,
+ driveAliasAndItem
+ },
+ query: {
+ ...(unref(currentRoute).query?.app && { app: unref(currentRoute).query?.app }),
+ contextRouteName: 'files-spaces-generic'
+ }
+ })
+ }
+
+ // no matching space found => the file doesn't lie in own spaces => it's a share.
+ // do PROPFINDs on parents until root of accepted share is found in `mountpoint` spaces
+ await store.dispatch('runtime/spaces/loadMountPoints', {
+ graphClient: clientService.graphAuthenticated
+ })
+ let mountPoint = findMatchingMountPoint(id)
+ const resource = await loadFileInfoByIdTask.perform(id)
+ const sharePathSegments = mountPoint ? [] : [unref(resource).name]
+ let tmpResource = unref(resource)
+ while (!mountPoint) {
+ try {
+ tmpResource = await loadFileInfoByIdTask.perform(tmpResource.parentFolderId)
+ } catch (e) {
+ throw Error(e)
+ }
+ mountPoint = findMatchingMountPoint(tmpResource.id)
+ if (!mountPoint) {
+ sharePathSegments.unshift(tmpResource.name)
+ }
+ }
+ matchingSpace = buildShareSpaceResource({
+ shareId: mountPoint.nodeId,
+ shareName: mountPoint.name,
+ serverUrl: configurationManager.serverUrl
+ })
+ path = urlJoin(...sharePathSegments)
+
+ const driveAliasAndItem = matchingSpace.getDriveAliasAndItem({ path } as Resource)
+ return router.push({
+ params: {
+ ...unref(currentRoute).params,
+ driveAliasAndItem
+ },
+ query: {
+ shareId: matchingSpace.shareId,
+ ...(unref(currentRoute).query?.app && { app: unref(currentRoute).query?.app }),
+ contextRouteName: 'files-shares-with-me'
+ }
+ })
+ }
+
return {
...useAppDefaults({
applicationId: 'external',
applicationName
}),
- applicationName
+ applicationName,
+ driveAliasAndItem,
+ addMissingDriveAliasAndItem
}
},
@@ -94,6 +195,10 @@ export default defineComponent({
async created() {
this.loading = true
try {
+ if (!this.driveAliasAndItem) {
+ await this.addMissingDriveAliasAndItem()
+ }
+
this.resource = await this.getFileInfo(this.currentFileContext, {
davProperties: []
})
diff --git a/packages/web-app-files/src/components/SideBar/Shares/Collaborators/EditDropdown.vue b/packages/web-app-files/src/components/SideBar/Shares/Collaborators/EditDropdown.vue
index 08cad53e625..aa1421abc3f 100644
--- a/packages/web-app-files/src/components/SideBar/Shares/Collaborators/EditDropdown.vue
+++ b/packages/web-app-files/src/components/SideBar/Shares/Collaborators/EditDropdown.vue
@@ -29,8 +29,8 @@
>
diff --git a/packages/web-pkg/src/composables/fileInfo/index.ts b/packages/web-pkg/src/composables/fileInfo/index.ts
new file mode 100644
index 00000000000..2ffc69d647f
--- /dev/null
+++ b/packages/web-pkg/src/composables/fileInfo/index.ts
@@ -0,0 +1 @@
+export * from './useLoadFileInfoById'
diff --git a/packages/web-pkg/src/composables/fileInfo/useLoadFileInfoById.ts b/packages/web-pkg/src/composables/fileInfo/useLoadFileInfoById.ts
new file mode 100644
index 00000000000..42cd94126c5
--- /dev/null
+++ b/packages/web-pkg/src/composables/fileInfo/useLoadFileInfoById.ts
@@ -0,0 +1,38 @@
+import { ClientService } from 'web-pkg/src/services'
+import { useClientService } from 'web-pkg/src/composables'
+import { useTask } from 'vue-concurrency'
+import { buildSpace, buildWebDavSpacesPath } from 'web-client/src/helpers'
+import { DavProperty } from 'web-client/src/webdav/constants'
+
+export interface LoadFileInfoByIdOptions {
+ clientService?: ClientService
+ davProperties?: DavProperty[]
+}
+
+export const useLoadFileInfoById = (options: LoadFileInfoByIdOptions) => {
+ const { webdav } = options.clientService || useClientService()
+ const davProperties = options.davProperties || [
+ DavProperty.FileId,
+ DavProperty.FileParent,
+ DavProperty.Name,
+ DavProperty.ResourceType
+ ]
+
+ const loadFileInfoByIdTask = useTask(function* (signal, fileId: string | number) {
+ const space = buildSpace({
+ id: fileId,
+ webDavPath: buildWebDavSpacesPath(fileId)
+ })
+ return yield webdav.getFileInfo(
+ space,
+ {},
+ {
+ davProperties
+ }
+ )
+ })
+
+ return {
+ loadFileInfoByIdTask
+ }
+}