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 'source' URL in viewer #1419

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
5 changes: 3 additions & 2 deletions src/components/Collection/CollectionContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import FilesListViewer from '.././FilesListViewer.vue'
import File from '.././File.vue'
import FolderIllustration from '../../assets/Illustrations/folder.svg'
import SemaphoreWithPriority from '../../utils/semaphoreWithPriority.js'
import { toViewerFileInfo } from '../../utils/fileUtils.js'

export default {
name: 'CollectionContent',
Expand Down Expand Up @@ -129,8 +130,8 @@ export default {
openViewer(fileId) {
const file = this.files[fileId]
OCA.Viewer.open({
fileInfo: file,
list: this.collectionFileIds.map(fileId => this.files[fileId]).filter(file => !file.sectionHeader),
fileInfo: toViewerFileInfo(file),
list: this.collectionFileIds.map(fileId => toViewerFileInfo(this.files[fileId])).filter(file => !file.sectionHeader),
loadMore: file.loadMore ? async () => await file.loadMore(true) : () => [],
canLoop: file.canLoop,
})
Expand Down
5 changes: 3 additions & 2 deletions src/components/FileLegacy.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import { generateUrl } from '@nextcloud/router'

import UserConfig from '../mixins/UserConfig.js'
import { toViewerFileInfo } from '../utils/fileUtils.js'

export default {
name: 'FileLegacy',
Expand Down Expand Up @@ -105,8 +106,8 @@ export default {
methods: {
openViewer() {
OCA.Viewer.open({
path: this.item.injected.filename,
list: this.item.injected.list,
fileInfo: toViewerFileInfo(this.item.injected),
list: this.item.injected.list.map(toViewerFileInfo),
loadMore: this.item.injected.loadMore ? async () => await this.item.injected.loadMore(true) : () => [],
canLoop: this.item.injected.canLoop,
})
Expand Down
7 changes: 5 additions & 2 deletions src/mixins/FetchFacesMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { getCurrentUser } from '@nextcloud/auth'
import client from '../services/DavClient.js'
import logger from '../services/logger.js'
import DavRequest from '../services/DavRequest'
import { genFileInfo } from '../utils/fileUtils'
import { genFileInfo, toAbsoluteFilePath } from '../utils/fileUtils'
import AbortControllerMixin from './AbortControllerMixin'

export default {
Expand Down Expand Up @@ -117,9 +117,12 @@ export default {
}
)

const fixRealpath = file => file.realpath.replace(`/${getCurrentUser().uid}/files`, '')

fetchedFiles = fetchedFiles
.map(file => genFileInfo(file))
.map(file => ({ ...file, filename: file.realpath.replace(`/${getCurrentUser().uid}/files`, '') }))
.map(file => ({ ...file, filename: toAbsoluteFilePath(fixRealpath(file)) }))
.map(file => genFileInfo(file)) // ensure we have a correct source URL

const fileIds = fetchedFiles.map(file => '' + file.fileid)

Expand Down
5 changes: 3 additions & 2 deletions src/services/AlbumContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import { genFileInfo, encodeFilePath } from '../utils/fileUtils.js'
import { genFileInfo, encodeFilePath, toRelativeFilePath } from '../utils/fileUtils.js'
import allowedMimes from './AllowedMimes.js'

/**
Expand All @@ -37,6 +37,7 @@ export default async function(path = '/', options = {}) {
const prefixPath = generateUrl(`/apps/photos/api/v1/${options.shared ? 'shared' : 'albums'}`)

// fetch listing
path = toRelativeFilePath(path)
const response = await axios.get(prefixPath + encodeFilePath(path), options)
const list = response.data.map(data => genFileInfo(data))

Expand All @@ -47,7 +48,7 @@ export default async function(path = '/', options = {}) {

for (const entry of list) {
// is this the current provided path ?
if (entry.filename === path) {
if (toRelativeFilePath(entry.filename) === path) {
folder = entry
} else if (entry.type !== 'file') {
folders.push(entry)
Expand Down
8 changes: 4 additions & 4 deletions src/services/FileInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
*
*/

import client, { prefixPath } from './DavClient.js'
import client from './DavClient.js'
import request from './DavRequest.js'
import { genFileInfo } from '../utils/fileUtils.js'
import { genFileInfo, toAbsoluteFilePath } from '../utils/fileUtils.js'

/**
* Get a file info
Expand All @@ -32,10 +32,10 @@ import { genFileInfo } from '../utils/fileUtils.js'
*/
export default async function(path) {
// getDirectoryContents doesn't accept / for root
const fixedPath = path === '/' ? '' : path
const fixedPath = toAbsoluteFilePath(path.endsWith('/') ? path.substring(0, -1) : path)

// fetch listing
const response = await client.stat(prefixPath + fixedPath, {
const response = await client.stat(fixedPath, {
data: request,
details: true,
})
Expand Down
8 changes: 4 additions & 4 deletions src/services/FolderInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
*
*/

import client, { prefixPath } from './DavClient.js'
import client from './DavClient.js'
import request from './DavRequest.js'
import { genFileInfo } from '../utils/fileUtils.js'
import { genFileInfo, toAbsoluteFilePath } from '../utils/fileUtils.js'

/**
* List files from a folder and filter out unwanted mimes
Expand All @@ -32,10 +32,10 @@ import { genFileInfo } from '../utils/fileUtils.js'
*/
export default async function(path) {
// getDirectoryContents doesn't accept / for root
const fixedPath = path === '/' ? '' : path
const fixedPath = toAbsoluteFilePath(path.endsWith('/') ? path.substring(0, -1) : path)

// fetch listing
const response = await client.stat(prefixPath + fixedPath, {
const response = await client.stat(fixedPath, {
data: request,
details: true,
})
Expand Down
3 changes: 2 additions & 1 deletion src/services/PhotoSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*
*/

import { genFileInfo } from '../utils/fileUtils.js'
import { genFileInfo, toRelativeFilePath } from '../utils/fileUtils.js'
import { getCurrentUser } from '@nextcloud/auth'
import { allMimes } from './AllowedMimes.js'
import client from './DavClient.js'
Expand Down Expand Up @@ -52,6 +52,7 @@ export default async function(path = '', options = {}) {
}

const prefixPath = `/files/${getCurrentUser().uid}`
path = toRelativeFilePath(path)

// generating the search or condition
// based on the allowed mimetypes
Expand Down
2 changes: 0 additions & 2 deletions src/services/TaggedImages.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,4 @@ export default async function(id, options = {}) {
// hardcoded props and mime is not one of them
// https://github.com/nextcloud/server/blob/5bf3d1bb384da56adbf205752be8f840aac3b0c5/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php#L274
.filter(file => file.mime && allowedMimes.indexOf(file.mime) !== -1)
// remove prefix path from full file path
.map(data => Object.assign({}, data, { filename: data.filename.replace(prefixPath, '') }))
}
7 changes: 4 additions & 3 deletions src/store/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import moment from '@nextcloud/moment'
import { showError } from '@nextcloud/dialogs'

import logger from '../services/logger.js'
import client, { prefixPath } from '../services/DavClient.js'
import client from '../services/DavClient.js'
import { toRelativeFilePath } from '../utils/fileUtils.js'
import Semaphore from '../utils/semaphoreWithPriority.js'

const state = {
Expand All @@ -44,8 +45,8 @@ const mutations = {
const files = {}
newFiles.forEach(file => {
// Ignore the file if the path is excluded
if (state.nomediaPaths.some(nomediaPath => file.filename.startsWith(nomediaPath)
|| file.filename.startsWith(prefixPath + nomediaPath))) {
if (state.nomediaPaths.some(nomediaPath => toRelativeFilePath(file.filename).startsWith(nomediaPath))) {
logger.debug('Excluded file: ', file.filename)
return
}

Expand Down
90 changes: 86 additions & 4 deletions src/utils/fileUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
*
*/
import { generateRemoteUrl } from '@nextcloud/router'
import { getCurrentUser } from '@nextcloud/auth'
import camelcase from 'camelcase'
import { rootPath } from '../services/DavClient.js'
import { rootPath, prefixPath } from '../services/DavClient.js'
import { isNumber } from './numberUtils.js'

/**
Expand Down Expand Up @@ -99,6 +100,84 @@ const sortCompare = function(fileInfo1, fileInfo2, key, asc = true) {
: -fileInfo1[key]?.toString()?.localeCompare(fileInfo2[key].toString(), OC.getLanguage()) || -1
}

const knownApps = ['files', 'photos', 'recognize']

/**
* Checks if the specified path starts with app and user
*
* @param {string} path the path to check
* @return {object} the check result
*/
function analyzePath(path) {
const parts = typeof path === 'string'
? path.split('/').filter(p => p.length > 0)
: []

const [app, user] = parts
const hasCurrentUser = user && user === `${getCurrentUser()?.uid}`
const hasKnownApp = app && knownApps.includes(app)

return { hasCurrentUser, hasKnownApp, parts }
}

/**
* Strips '/app/user/' from path or fileInfo.filename
*
* @param {string|object.filename} path the path or fileInfo to convert
* @return {string|object.filename} the converted input or the original if no conversion was required
*/
function toRelativeFilePath(path) {
if (typeof path === 'object' && 'filename' in path) {
return { ...path, filename: toRelativeFilePath(path.filename) }
}

const { hasKnownApp, hasCurrentUser, parts } = analyzePath(path)
return hasKnownApp || hasCurrentUser
? '/' + parts.slice(2).join('/')
: path
}

/**
* Changes path (or fileInfo.filename) so that it starts with '/app/user/...'
*
* @param {string|object.filename} path the path or fileInfo to convert
* @param {string} contextPath the prefix to add to relative paths
* @return {string|object.filename} the converted input or the original if no conversion was required
*/
function toAbsoluteFilePath(path, contextPath = prefixPath) {
if (typeof path === 'object' && 'filename' in path) {
return { ...path, filename: toAbsoluteFilePath(path.filename) }
}

const { hasKnownApp, hasCurrentUser } = analyzePath(path)
return !hasKnownApp && !hasCurrentUser
? contextPath + path
: path
}

/**
* Converts the given fileInfo to an obj suitable for OCA.Viewer
*
* @param {object} obj the fileInfo to prepare for sending it to OCA.Viewer
* @returns a clone of obj with properties adjusted when needed
*/
function toViewerFileInfo(obj) {
if (typeof obj !== 'object' || typeof obj.filename !== 'string') {
throw new Error('fileInfo obj must be given, found: ' + obj)
}

// according to Viewer docs, filename must be URL when route is not /files/user/
obj = obj.filename.startsWith('/files/')
? { ...obj, filename: toRelativeFilePath(obj.filename) }
: { ...obj, filename: obj.source }

// ensure basename is correct
const [, basename] = extractFilePaths(obj.filename)
obj.basename = basename

return obj
}

/**
* @param {object} obj - object to flatten and format.
*/
Expand All @@ -120,12 +199,15 @@ function genFileInfo(obj) {
}
}, {})

// format source and filename (ensure app & user is always included)
if (fileInfo.filename) {
// Adding context
fileInfo.source = generateRemoteUrl(rootPath) + '/' + fileInfo.filename
fileInfo.filename = toAbsoluteFilePath(fileInfo.filename)

const path = encodeFilePath(fileInfo.filename)
fileInfo.source = generateRemoteUrl(rootPath) + (path.startsWith('/') ? '' : '/') + path
}

return fileInfo
}

export { encodeFilePath, extractFilePaths, sortCompare, genFileInfo }
export { encodeFilePath, extractFilePaths, sortCompare, genFileInfo, toRelativeFilePath, toAbsoluteFilePath, toViewerFileInfo }
8 changes: 3 additions & 5 deletions src/views/FaceContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ import FilesListViewer from '../components/FilesListViewer.vue'
import File from '../components/File.vue'
import logger from '../services/logger.js'
import FetchFacesMixin from '../mixins/FetchFacesMixin.js'
import { toViewerFileInfo } from '../utils/fileUtils.js'
import Vue from 'vue'
import FaceMergeForm from '../components/FaceMergeForm.vue'

Expand Down Expand Up @@ -286,11 +287,8 @@ export default {
openViewer(fileId) {
const file = this.files[fileId]
OCA.Viewer.open({
path: file.filename,
list: this.faceFileIds.map(fileId => ({
...this.files[fileId],
basename: this.files[fileId].basename.split('-').slice(1).join('-'),
})).filter(file => !file.sectionHeader),
path: toViewerFileInfo(file).filename,
list: this.faceFileIds.map(fileId => toViewerFileInfo(this.files[fileId])).filter(file => !file.sectionHeader),
loadMore: file.loadMore ? async () => await file.loadMore(true) : () => [],
canLoop: file.canLoop,
})
Expand Down
7 changes: 6 additions & 1 deletion src/views/Folders.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
:root-title="rootTitle"
@refresh="onRefresh">
<UploadPicker :accept="allowedMimes"
:destination="folder.filename"
:destination="toRelative(folder.filename)"
:multiple="true"
@uploaded="onUpload" />
</HeaderNavigation>
Expand Down Expand Up @@ -78,6 +78,7 @@ import getAlbumContent from '../services/AlbumContent.js'
import AbortControllerMixin from '../mixins/AbortControllerMixin.js'
import GridConfigMixin from '../mixins/GridConfig.js'
import getFileInfo from '../services/FileInfo.js'
import { toRelativeFilePath } from '../utils/fileUtils.js'

export default {
name: 'Folders',
Expand Down Expand Up @@ -218,6 +219,10 @@ export default {
this.fetchFolderContent()
},

toRelative(path) {
return toRelativeFilePath(path)
},

async fetchFolderContent() {
this.error = null
this.loading = true
Expand Down
5 changes: 3 additions & 2 deletions src/views/TagContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import File from '../components/File.vue'
import FilesListViewer from '../components/FilesListViewer.vue'

import SemaphoreWithPriority from '../utils/semaphoreWithPriority.js'
import { toViewerFileInfo } from '../utils/fileUtils.js'
import FilesSelectionMixin from '../mixins/FilesSelectionMixin.js'
import AbortControllerMixin from '../mixins/AbortControllerMixin.js'

Expand Down Expand Up @@ -175,8 +176,8 @@ export default {
openViewer(fileId) {
const file = this.files[fileId]
OCA.Viewer.open({
path: file.filename,
list: this.fileIds.map(fileId => this.files[fileId]),
fileInfo: toViewerFileInfo(file),
list: this.fileIds.map(fileId => toViewerFileInfo(this.files[fileId])),
loadMore: file.loadMore ? async () => await file.loadMore(true) : () => [],
canLoop: file.canLoop,
})
Expand Down
5 changes: 3 additions & 2 deletions src/views/Timeline.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ import { NcModal, NcActions, NcActionButton, NcButton, NcEmptyContent, isMobile
import moment from '@nextcloud/moment'

import { allMimes } from '../services/AllowedMimes.js'
import { toViewerFileInfo } from '../utils/fileUtils.js'
import FetchFilesMixin from '../mixins/FetchFilesMixin.js'
import FilesByMonthMixin from '../mixins/FilesByMonthMixin.js'
import FilesSelectionMixin from '../mixins/FilesSelectionMixin.js'
Expand Down Expand Up @@ -244,8 +245,8 @@ export default {
openViewer(fileId) {
const file = this.files[fileId]
OCA.Viewer.open({
fileInfo: file,
list: Object.values(this.fileIdsByMonth).flat().map(fileId => this.files[fileId]),
fileInfo: toViewerFileInfo(file),
list: Object.values(this.fileIdsByMonth).flat().map(fileId => toViewerFileInfo(this.files[fileId])),
loadMore: file.loadMore ? async () => await file.loadMore(true) : () => [],
canLoop: file.canLoop,
})
Expand Down