diff --git a/src/components/Albums/CollaboratorsSelectionForm.vue b/src/components/Albums/CollaboratorsSelectionForm.vue index ddd8f5510..a38db1738 100644 --- a/src/components/Albums/CollaboratorsSelectionForm.vue +++ b/src/components/Albums/CollaboratorsSelectionForm.vue @@ -349,7 +349,7 @@ export default { await this.updateAlbumCollaborators() await this.fetchCollection( this.albumFileName, - ['', '', ''] + ['', '', ''], ) }, diff --git a/src/components/FilesListViewer.vue b/src/components/FilesListViewer.vue index 7954c8d75..73b1d0d4b 100644 --- a/src/components/FilesListViewer.vue +++ b/src/components/FilesListViewer.vue @@ -84,7 +84,7 @@ import { NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue' import { subscribe, unsubscribe } from '@nextcloud/event-bus' import TiledLayout from '../components/TiledLayout/TiledLayout.vue' -import { fetchFile } from '../services/fileFetcher.js' +import { fetchFile } from '../services/fileFetcher.ts' import VirtualScrolling from '../components/VirtualScrolling.vue' import EmptyBox from '../assets/Illustrations/empty.svg' diff --git a/src/mixins/FetchFacesMixin.js b/src/mixins/FetchFacesMixin.js index 0cff8cbf5..e39dbf1a5 100644 --- a/src/mixins/FetchFacesMixin.js +++ b/src/mixins/FetchFacesMixin.js @@ -20,17 +20,16 @@ * */ -import { mapActions, mapGetters } from 'vuex' - import { showError } from '@nextcloud/dialogs' import { getCurrentUser } from '@nextcloud/auth' +import { mapActions, mapGetters } from 'vuex' +import he from 'he' -import client from '../services/DavClient.js' -import logger from '../services/logger.js' -import DavRequest from '../services/DavRequest.js' import { genFileInfo } from '../utils/fileUtils.js' +import logger from '../services/logger.js' import AbortControllerMixin from './AbortControllerMixin.js' -import he from 'he' +import { davClient } from '../services/DavClient.ts' +import { getPropFind } from '../services/DavRequest.ts' export default { name: 'FetchFacesMixin', @@ -76,8 +75,8 @@ export default { this.loadingFaces = true this.errorFetchingFaces = null - const { data: faces } = await client.getDirectoryContents(`/recognize/${getCurrentUser()?.uid}/faces/`, { - data: DavRequest, + const { data: faces } = await davClient.getDirectoryContents(`/recognize/${getCurrentUser()?.uid}/faces/`, { + data: getPropFind(), details: true, signal: this.abortController.signal, }) @@ -111,13 +110,13 @@ export default { this.errorFetchingFiles = null this.loadingFiles = true - let { data: fetchedFiles } = await client.getDirectoryContents( + let { data: fetchedFiles } = await davClient.getDirectoryContents( `/recognize/${getCurrentUser()?.uid}/faces/${faceName}`, { - data: DavRequest, + data: getPropFind(), details: true, signal: this.abortController.signal, - } + }, ) fetchedFiles = fetchedFiles @@ -163,13 +162,13 @@ export default { this.errorFetchingFiles = null this.loadingFiles = true - let { data: fetchedFiles } = await client.getDirectoryContents( + let { data: fetchedFiles } = await davClient.getDirectoryContents( `/recognize/${getCurrentUser()?.uid}/unassigned-faces`, { - data: DavRequest, + data: getPropFind(), details: true, signal: this.abortController.signal, - } + }, ) fetchedFiles = fetchedFiles @@ -204,13 +203,13 @@ export default { async fetchUnassignedFacesCount() { try { - const { data: unassignedFacesRoot } = await client.stat( + const { data: unassignedFacesRoot } = await davClient.stat( `/recognize/${getCurrentUser()?.uid}/unassigned-faces`, { - data: DavRequest, + data: getPropFind(), details: true, signal: this.abortController.signal, - } + }, ) const count = Number(unassignedFacesRoot.props.nbItems) diff --git a/src/mixins/FetchFilesMixin.js b/src/mixins/FetchFilesMixin.js index b58031973..794ffbad5 100644 --- a/src/mixins/FetchFilesMixin.js +++ b/src/mixins/FetchFilesMixin.js @@ -20,8 +20,11 @@ * */ -import { davGetClient, davRootPath } from '@nextcloud/files' +import { showError } from '@nextcloud/dialogs' +import { davRootPath } from '@nextcloud/files' import { joinPaths } from '@nextcloud/paths' + +import { davClient } from '../services/DavClient.ts' import logger from '../services/logger.js' import getPhotos from '../services/PhotoSearch.js' import SemaphoreWithPriority from '../utils/semaphoreWithPriority.js' @@ -91,7 +94,7 @@ export default { this.fetchedFileIds.push( ...fileIds .map((fileId) => fileId.toString()) - .filter((fileId) => !blacklist.includes(fileId)) + .filter((fileId) => !blacklist.includes(fileId)), ) this.$store.dispatch('appendFiles', fetchedFiles) @@ -105,7 +108,7 @@ export default { const source = joinPaths(davRootPath, store.state.userConfig.photosSourceFolder ?? '/Photos') + '/' logger.debug('Photo source does not exist, creating it.') try { - await davGetClient().createDirectory(source) + await davClient.createDirectory(source) } catch (error) { logger.error('Fail to create source directory', { error }) } @@ -116,8 +119,8 @@ export default { } // cancelled request, moving on... - logger.error('Error fetching files', { error }) - console.error(error) + showError(t('photos', 'Error fetching files')) + logger.error(error) } finally { this.loadingFiles = false this.fetchSemaphore.release(fetchSemaphoreSymbol) diff --git a/src/services/Albums.js b/src/services/Albums.js index e1e8e7f6d..78878b4fc 100644 --- a/src/services/Albums.js +++ b/src/services/Albums.js @@ -23,10 +23,10 @@ import moment from '@nextcloud/moment' import { translate as t } from '@nextcloud/l10n' -import defaultClient from '../services/DavClient.js' import logger from '../services/logger.js' -import DavRequest from '../services/DavRequest.js' import { genFileInfo } from '../utils/fileUtils.js' +import { davClient } from './DavClient.ts' +import { getPropFind } from './DavRequest.ts' /** * @typedef {object} Album @@ -68,7 +68,7 @@ function getDavRequest(extraProps = '') { * @param {import('webdav').WebDAVClient} client - The DAV client to use. * @return {Promise} */ -export async function fetchAlbum(path, options, extraProps = '', client = defaultClient) { +export async function fetchAlbum(path, options, extraProps = '', client = davClient) { try { const response = await client.stat(path, { data: getDavRequest(extraProps), @@ -96,7 +96,7 @@ export async function fetchAlbum(path, options, extraProps = '', client = defaul * @param {import('webdav').WebDAVClient} client - The DAV client to use. * @return {Promise} */ -export async function fetchAlbums(path, options, extraProps = '', client = defaultClient) { +export async function fetchAlbums(path, options, extraProps = '', client = davClient) { try { const response = await client.getDirectoryContents(path, { data: getDavRequest(extraProps), @@ -164,10 +164,10 @@ function formatAlbum(album) { * @param {import('webdav').WebDAVClient} client - The DAV client to use. * @return {Promise} */ -export async function fetchAlbumContent(path, options, client = defaultClient) { +export async function fetchAlbumContent(path, options, client = davClient) { try { const response = await client.getDirectoryContents(path, { - data: DavRequest, + data: getPropFind(), details: true, ...options, }) diff --git a/src/services/DavClient.js b/src/services/DavClient.js deleted file mode 100644 index c21ddfbe6..000000000 --- a/src/services/DavClient.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @copyright Copyright (c) 2019 John Molakvoæ - * - * @author John Molakvoæ - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -import { createClient, getPatcher } from 'webdav' -import axios from '@nextcloud/axios' -import parseUrl from 'url-parse' -import { generateRemoteUrl } from '@nextcloud/router' -import { getCurrentUser } from '@nextcloud/auth' - -export const rootPath = 'dav' -export const prefixPath = `/files/${getCurrentUser()?.uid}` - -// force our axios -const patcher = getPatcher() -patcher.patch('request', axios) - -// init webdav client on default dav endpoint -const remote = generateRemoteUrl(rootPath) -const client = createClient(remote) - -export const remotePath = parseUrl(remote).pathname -export default client diff --git a/src/services/FileInfo.js b/src/services/DavClient.ts similarity index 51% rename from src/services/FileInfo.js rename to src/services/DavClient.ts index 069590388..b4ff8f22e 100644 --- a/src/services/FileInfo.js +++ b/src/services/DavClient.ts @@ -1,7 +1,7 @@ /** - * @copyright Copyright (c) 2019 John Molakvoæ + * @copyright Copyright (c) 2024 Ferdinand Thiessen * - * @author John Molakvoæ + * @author Ferdinand Thiessen * * @license AGPL-3.0-or-later * @@ -20,25 +20,7 @@ * */ -import client, { prefixPath } from './DavClient.js' -import request from './DavRequest.js' -import { genFileInfo } from '../utils/fileUtils.js' +import type { WebDAVClient } from 'webdav' +import { davGetClient } from '@nextcloud/files' -/** - * Get a file info - * - * @param {string} path the path relative to the user root - * @return {FileInfo} the file info - */ -export default async function(path) { - // getDirectoryContents doesn't accept / for root - const fixedPath = path === '/' ? '' : path - - // fetch listing - const response = await client.stat(prefixPath + fixedPath, { - data: request, - details: true, - }) - - return genFileInfo(response.data) -} +export const davClient: WebDAVClient = davGetClient() diff --git a/src/services/DavRequest.js b/src/services/DavRequest.ts similarity index 55% rename from src/services/DavRequest.js rename to src/services/DavRequest.ts index 28428db2e..987ac1394 100644 --- a/src/services/DavRequest.js +++ b/src/services/DavRequest.ts @@ -2,6 +2,7 @@ * @copyright Copyright (c) 2019 John Molakvoæ * * @author John Molakvoæ + * @author Ferdinand Thiessen * * @license AGPL-3.0-or-later * @@ -19,34 +20,48 @@ * along with this program. If not, see . * */ -const props = ` - - - - - - - - - - - - - - - - - - -` -export { props } -export default ` +import { getDavProperties, registerDavProperty } from '@nextcloud/files' + +const photoDavProps = [ + 'face-detections', + 'face-preview-image', + 'metadata-photos-size', + 'metadata-photos-original_date_time', + 'metadata-files-live-photo', + 'metadata-blurhash', + 'realpath', + 'nbItems', +] + +/** + * Used to cache the props + */ +let props: string|null = null + +/** + * Get the default props + */ +const getDefaultDavProps = () => { + if (props === null) { + photoDavProps.forEach(prop => registerDavProperty(prop)) + props = getDavProperties() + } + return props +} + +/** + * @param extraProps - Extra properties to add to the DAV request. + */ +export function getPropFind(extraProps: string[] = []): string { + return ` - ${props} + ${getDefaultDavProps()} + ${extraProps.join('\n')} ` +} diff --git a/src/services/FolderInfo.js b/src/services/FolderInfo.js deleted file mode 100644 index 9cf94c76a..000000000 --- a/src/services/FolderInfo.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @copyright Copyright (c) 2019 John Molakvoæ - * - * @author John Molakvoæ - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -import client, { prefixPath } from './DavClient.js' -import request from './DavRequest.js' -import { genFileInfo } from '../utils/fileUtils.js' - -/** - * List files from a folder and filter out unwanted mimes - * - * @param {string} path the path relative to the user root - * @return {Array} the file list - */ -export default async function(path) { - // getDirectoryContents doesn't accept / for root - const fixedPath = path === '/' ? '' : path - - // fetch listing - const response = await client.stat(prefixPath + fixedPath, { - data: request, - details: true, - }) - - return genFileInfo(response.data) -} diff --git a/src/services/PhotoSearch.js b/src/services/PhotoSearch.js index 435297da1..e82eef872 100644 --- a/src/services/PhotoSearch.js +++ b/src/services/PhotoSearch.js @@ -20,14 +20,15 @@ * */ -import { genFileInfo } from '../utils/fileUtils.js' -import { getCurrentUser } from '@nextcloud/auth' -import { allMimes } from './AllowedMimes.js' -import client from './DavClient.js' -import { props } from './DavRequest.js' import moment from '@nextcloud/moment' import store from '../store/index.js' +import { allMimes } from './AllowedMimes.js' +import { genFileInfo } from '../utils/fileUtils.js' +import { davProps } from './DavRequest.ts' +import { davClient } from './DavClient.ts' +import { davRootPath } from '@nextcloud/files' + /** * List files from a folder and filter out unwanted mimes * @@ -51,8 +52,6 @@ export default async function(options = {}) { ...options, } - const prefixPath = `/files/${getCurrentUser().uid}` - // generating the search or condition // based on the allowed mimetypes const orMime = options.mimesType.reduce((str, mime) => `${str} @@ -119,12 +118,12 @@ export default async function(options = {}) { - ${props} + ${davProps} - ${prefixPath}/${store.state.userConfig.photosSourceFolder ?? '/Photos'} + ${davRootPath}/${store.state.userConfig.photosSourceFolder ?? '/Photos'} infinity @@ -157,7 +156,7 @@ export default async function(options = {}) { details: true, }, options) - const response = await client.getDirectoryContents('', options) + const response = await davClient.search('/', options) - return response.data.map(data => genFileInfo(data)) + return response.data.results.map(data => genFileInfo(data)) } diff --git a/src/services/SystemTags.js b/src/services/SystemTags.js index 891d98fc1..0252f7cca 100644 --- a/src/services/SystemTags.js +++ b/src/services/SystemTags.js @@ -20,8 +20,8 @@ * */ -import client from './DavClient.js' import { genFileInfo } from '../utils/fileUtils.js' +import { davClient } from './DavClient.ts' /** * List system tags @@ -31,7 +31,7 @@ import { genFileInfo } from '../utils/fileUtils.js' * @return {Promise} the file list */ export default async function(path, options = {}) { - const response = await client.getDirectoryContents('/systemtags-assigned/image', Object.assign({}, { + const response = await davClient.getDirectoryContents('/systemtags-assigned/image', Object.assign({}, { data: ` diff --git a/src/services/TaggedImages.js b/src/services/TaggedImages.js index a0611e4f4..01bf2e13b 100644 --- a/src/services/TaggedImages.js +++ b/src/services/TaggedImages.js @@ -20,10 +20,11 @@ * */ +import { davRootPath } from '@nextcloud/files' import { genFileInfo } from '../utils/fileUtils.js' -import { props } from './DavRequest.js' import allowedMimes from './AllowedMimes.js' -import client, { prefixPath } from './DavClient.js' +import { davClient } from './DavClient.ts' +import { davProps } from './DavRequest.ts' /** * Get tagged files based on provided tag id @@ -35,7 +36,9 @@ import client, { prefixPath } from './DavClient.js' export default async function(id, options = {}) { options = Object.assign({ - method: 'REPORT', + headers: { + method: 'REPORT', + }, data: ` - ${props} + ${davProps} ${id} @@ -52,14 +55,13 @@ export default async function(id, options = {}) { details: true, }, options) - const response = await client.getDirectoryContents(prefixPath, options) - + const response = await davClient.getDirectoryContents(davRootPath, options) return response.data - .map(data => genFileInfo(data)) + .map((data) => genFileInfo(data)) // filter out unwanted mime because server REPORT service only support // 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) + .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, '') })) + .map((data) => Object.assign({}, data, { filename: data.filename.replace(davRootPath, '') })) } diff --git a/src/services/TiledLayout.js b/src/services/TiledLayout.js index b8946f942..a36164e06 100644 --- a/src/services/TiledLayout.js +++ b/src/services/TiledLayout.js @@ -83,7 +83,7 @@ export function splitItemsInRows(items, containerWidth, baseHeight = 200) { rowItems, containerWidth, items.length === currentItem, - baseHeight + baseHeight, ) rows[rowNumber] = { @@ -138,7 +138,7 @@ function computeRowWidth(items, baseHeight) { function computeRowHeight(items, containerWidth, isLastRow, baseHeight) { const sumOfItemsRatio = items .map(item => item.ratio) - .reduce((sum, itemRatio) => sum + itemRatio + .reduce((sum, itemRatio) => sum + itemRatio, ) let rowHeight = containerWidth / sumOfItemsRatio diff --git a/src/services/collectionFetcher.js b/src/services/collectionFetcher.js index eedcb7ed7..e22cca699 100644 --- a/src/services/collectionFetcher.js +++ b/src/services/collectionFetcher.js @@ -23,9 +23,9 @@ import moment from '@nextcloud/moment' import { translate as t } from '@nextcloud/l10n' -import defaultClient from './DavClient.js' import logger from './logger.js' import { genFileInfo } from '../utils/fileUtils.js' +import { davClient } from './DavClient.ts' /** * @typedef {object} Collection @@ -104,7 +104,7 @@ function getCollectionFilesDavRequest(extraProps = []) { * @param {import('webdav').WebDAVClient} client - The DAV client to use. * @return {Promise} */ -export async function fetchCollection(path, options, extraProps = [], client = defaultClient) { +export async function fetchCollection(path, options, extraProps = [], client = davClient) { try { const response = await client.stat(path, { data: getCollectionDavRequest(extraProps), @@ -132,7 +132,7 @@ export async function fetchCollection(path, options, extraProps = [], client = d * @param {import('webdav').WebDAVClient} client - The DAV client to use. * @return {Promise} */ -export async function fetchCollections(path, options, extraProps = [], client = defaultClient) { +export async function fetchCollections(path, options, extraProps = [], client = davClient) { try { const response = await client.getDirectoryContents(path, { data: getCollectionDavRequest(extraProps), @@ -201,7 +201,7 @@ function formatCollection(rawCollection) { * @param {import('webdav').WebDAVClient} client - The DAV client to use. * @return {Promise} */ -export async function fetchCollectionFiles(path, options, extraProps = [], client = defaultClient) { +export async function fetchCollectionFiles(path, options, extraProps = [], client = davClient) { try { const response = await client.getDirectoryContents(path, { data: getCollectionFilesDavRequest(extraProps), diff --git a/src/services/fileFetcher.js b/src/services/fileFetcher.js deleted file mode 100644 index a2cd1075f..000000000 --- a/src/services/fileFetcher.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @copyright Copyright (c) 2023 Louis Chemineau - * - * @author Louis Chemineau - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -import { genFileInfo } from '../utils/fileUtils.js' -import defaultClient from './DavClient.js' - -/** - * @param {string[]} extraProps - Extra properties to add to the DAV request. - * @return {string} - */ -function getCollectionFilesDavRequest(extraProps = []) { - return ` - - - - - - - - - - - - - - - - ${extraProps.join('')} - - ` -} - -/** - * @param {string} fileName - The full file's name - * @param {import('webdav').StatOptions} options - Options to forward to the webdav client. - * @return {Promise} - */ -export async function fetchFile(fileName, options = {}) { - try { - const response = await defaultClient.stat(fileName, { - data: getCollectionFilesDavRequest(), - details: true, - ...options, - }) - - return genFileInfo(response.data) - } catch (error) { - if (error.code === 'ERR_CANCELED') { - return null - } - - throw error - } -} diff --git a/src/services/fileFetcher.ts b/src/services/fileFetcher.ts new file mode 100644 index 000000000..ba84df5a2 --- /dev/null +++ b/src/services/fileFetcher.ts @@ -0,0 +1,49 @@ +/** + * @copyright Copyright (c) 2023 Louis Chemineau + * + * @author Louis Chemineau + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +import type { AxiosError } from 'axios' +import type { FileStat, ResponseDataDetailed, StatOptions } from 'webdav' +import { genFileInfo } from '../utils/fileUtils.js' +import { davClient } from './DavClient' +import { getPropFind } from './DavRequest' + +/** + * @param fileName - The full file's name + * @param options - Options to forward to the webdav client. + */ +export async function fetchFile(fileName: string, options: StatOptions = {}) { + try { + const response = await davClient.stat(fileName, { + data: getPropFind(), + details: true, + ...options, + }) as ResponseDataDetailed + + return genFileInfo(response.data) + } catch (error) { + if ((error as AxiosError).code === 'ERR_CANCELED') { + return null + } + + throw error + } +} diff --git a/src/store/collections.js b/src/store/collections.js index 53bf687e9..5dfb67c33 100644 --- a/src/store/collections.js +++ b/src/store/collections.js @@ -23,9 +23,10 @@ import { showError } from '@nextcloud/dialogs' import { translate as t } from '@nextcloud/l10n' -import client from '../services/DavClient.js' +import { davClient } from '../services/DavClient.ts' import logger from '../services/logger.js' import Semaphore from '../utils/semaphoreWithPriority.js' +import { davRemoteURL } from '@nextcloud/files' /** * Collections are indexed by their `filename`. @@ -191,8 +192,8 @@ const actions = { const symbol = await semaphore.acquire() try { - await client.copyFile( - file.filename, + await davClient.copyFile( + file.source.replace(davRemoteURL, ''), `${collection.filename}/${file.basename}`, ) } catch (error) { @@ -229,7 +230,7 @@ const actions = { const symbol = await semaphore.acquire() try { - await client.deleteFile(file.filename) + await davClient.deleteFile(file.filename) } catch (error) { context.commit('addFilesToCollection', { collectionFileName, fileIdsToAdd: [fileId] }) @@ -252,7 +253,7 @@ const actions = { */ async createCollection(context, { collection }) { try { - await client.createDirectory(collection.filename) + await davClient.createDirectory(collection.filename) context.commit('addCollections', { collections: [collection] }) return collection } catch (error) { @@ -280,7 +281,7 @@ const actions = { try { context.commit('addCollections', { collections: [newCollection] }) context.commit('setCollectionFiles', { collectionFileName: newCollection.filename, fileIds: context.state.collectionsFiles[collectionFileName] }) - await client.moveFile(collection.filename, newCollection.filename) + await davClient.moveFile(collection.filename, newCollection.filename) context.commit('removeCollections', { collectionFileNames: [collectionFileName] }) return newCollection } catch (error) { @@ -321,7 +322,7 @@ const actions = { try { context.commit('updateCollection', { collection: updatedCollection }) - await client.customRequest( + await davClient.customRequest( collection.filename, { method: 'PROPPATCH', @@ -336,7 +337,7 @@ const actions = { `, - } + }, ) return updatedCollection @@ -358,7 +359,7 @@ const actions = { async deleteCollection(context, { collectionFileName }) { try { const collection = context.getters.collections[collectionFileName] - await client.deleteFile(collection.filename) + await davClient.deleteFile(collection.filename) context.commit('removeCollections', { collectionFileNames: [collectionFileName] }) } catch (error) { logger.error(t('photos', 'Failed to delete {collectionFileName}.', { collectionFileName }), { error }) diff --git a/src/store/faces.js b/src/store/faces.js index 364c08bc3..0ecaaf9fd 100644 --- a/src/store/faces.js +++ b/src/store/faces.js @@ -22,11 +22,11 @@ import { showError } from '@nextcloud/dialogs' import { getCurrentUser } from '@nextcloud/auth' +import Vue from 'vue' -import client from '../services/DavClient.js' +import { davClient } from '../services/DavClient.ts' import logger from '../services/logger.js' import Semaphore from '../utils/semaphoreWithPriority.js' -import Vue from 'vue' /** * @typedef {object} Face @@ -170,9 +170,9 @@ const actions = { const symbol = await semaphore.acquire() try { - await client.moveFile( + await davClient.moveFile( oldFace ? `/recognize/${getCurrentUser()?.uid}/faces/${oldFace}/${fileBaseName}` : `/recognize/${getCurrentUser()?.uid}/unassigned-faces/${fileBaseName}`, - `/recognize/${getCurrentUser()?.uid}/faces/${faceName}/${fileBaseName}` + `/recognize/${getCurrentUser()?.uid}/faces/${faceName}/${fileBaseName}`, ) file.faceDetections.find(detection => detection.title === oldFace).title = faceName await context.commit('addFilesToFace', { faceName, fileIdsToAdd: [fileId] }) @@ -212,7 +212,7 @@ const actions = { const symbol = await semaphore.acquire() try { - await client.deleteFile(`/recognize/${getCurrentUser()?.uid}/faces/${faceName}/${fileBaseName}`) + await davClient.deleteFile(`/recognize/${getCurrentUser()?.uid}/faces/${faceName}/${fileBaseName}`) } catch (error) { context.commit('addFilesToFace', { faceName, fileIdsToAdd: [fileId] }) @@ -241,7 +241,7 @@ const actions = { if (state.faces[faceName]) { throw new Error('Name already exists') } - await client.moveFile( + await davClient.moveFile( `/recognize/${getCurrentUser()?.uid}/faces/${oldName}`, `/recognize/${getCurrentUser()?.uid}/faces/${faceName}`, ) @@ -264,7 +264,7 @@ const actions = { */ async deleteFace(context, { faceName }) { try { - await client.deleteFile(`/recognize/${getCurrentUser()?.uid}/faces/${faceName}`) + await davClient.deleteFile(`/recognize/${getCurrentUser()?.uid}/faces/${faceName}`) context.commit('removeFaces', { faceNames: [faceName] }) } catch (error) { logger.error(t('photos', 'Failed to delete {faceName}.', { faceName }), { error }) diff --git a/src/store/files.js b/src/store/files.js index 935d1e19e..a08fdd4b7 100644 --- a/src/store/files.js +++ b/src/store/files.js @@ -23,10 +23,11 @@ import Vue from 'vue' import moment from '@nextcloud/moment' import { showError } from '@nextcloud/dialogs' +import { davRootPath } from '@nextcloud/files' import logger from '../services/logger.js' -import client, { prefixPath } from '../services/DavClient.js' import Semaphore from '../utils/semaphoreWithPriority.js' +import { davClient } from '../services/DavClient.ts' const state = { files: {}, @@ -47,7 +48,7 @@ const mutations = { .forEach(file => { // Ignore the file if the path is excluded if (state.nomediaPaths.some(nomediaPath => file.filename.startsWith(nomediaPath) - || file.filename.startsWith(prefixPath + nomediaPath))) { + || file.filename.startsWith(`${davRootPath}${nomediaPath}`))) { return } @@ -188,7 +189,7 @@ const actions = { const symbol = await semaphore.acquire() try { - await client.deleteFile(file.filename) + await davClient.deleteFile(file.filename) } catch (error) { logger.error(t('photos', 'Failed to delete {fileId}.', { fileId }), { error }) showError(t('photos', 'Failed to delete {fileName}.', { fileName: file.basename })) @@ -220,7 +221,7 @@ const actions = { try { context.commit('favoriteFile', { fileId, favoriteState }) - await client.customRequest( + await davClient.customRequest( file.filename, { method: 'PROPPATCH', @@ -235,7 +236,7 @@ const actions = { `, - } + }, ) } catch (error) { context.commit('favoriteFile', { fileId, favoriteState: favoriteState === 0 ? 1 : 0 }) diff --git a/src/store/userConfig.js b/src/store/userConfig.js index ae201bdac..c0c071b0a 100644 --- a/src/store/userConfig.js +++ b/src/store/userConfig.js @@ -21,7 +21,7 @@ * */ -import { davGetClient, davGetDefaultPropfind, davResultToNode, davRootPath } from '@nextcloud/files' +import { davGetDefaultPropfind, davResultToNode, davRootPath } from '@nextcloud/files' import { loadState } from '@nextcloud/initial-state' import { joinPaths } from '@nextcloud/paths' import { showError } from '@nextcloud/dialogs' @@ -30,13 +30,14 @@ import { translate as t } from '@nextcloud/l10n' import { generateUrl } from '@nextcloud/router' import axios from '@nextcloud/axios' +import { davClient } from '../services/DavClient.ts' import logger from '../services/logger.js' export const configChangedEvent = 'photos:user-config-changed' export async function getFolder(path) { - const davClient = davGetClient() const location = joinPaths(davRootPath, path) + '/' + try { const stat = await davClient.stat(location, { details: true, data: davGetDefaultPropfind() }) return davResultToNode(stat.data) diff --git a/src/utils/fileUtils.js b/src/utils/fileUtils.js index 8454323fa..319cad0b2 100644 --- a/src/utils/fileUtils.js +++ b/src/utils/fileUtils.js @@ -19,9 +19,8 @@ * along with this program. If not, see . * */ -import { generateRemoteUrl } from '@nextcloud/router' +import { davRemoteURL } from '@nextcloud/files' import camelcase from 'camelcase' -import { rootPath } from '../services/DavClient.js' import { isNumber } from './numberUtils.js' /** @@ -60,7 +59,7 @@ const extractFilePaths = function(path) { * @param {object} fileInfo1 file 1 fileinfo * @param {object} fileInfo2 file 2 fileinfo * @param {string} key key to sort with - * @param {boolean} [asc=true] sort ascending? + * @param {boolean} [asc] sort ascending? * @return {number} */ const sortCompare = function(fileInfo1, fileInfo2, key, asc = true) { @@ -106,8 +105,9 @@ function genFileInfo(obj) { const fileInfo = flattenAndFormatObject(obj, flattenAndFormatObject) if (fileInfo.filename) { + const url = new URL(encodeFilePath(fileInfo.filename), davRemoteURL) // Adding context - fileInfo.source = generateRemoteUrl(rootPath) + encodeFilePath(fileInfo.filename) + fileInfo.source = url.href } return fileInfo diff --git a/src/views/AlbumContent.vue b/src/views/AlbumContent.vue index 8302d2fb9..45792afa0 100644 --- a/src/views/AlbumContent.vue +++ b/src/views/AlbumContent.vue @@ -340,7 +340,7 @@ export default { async fetchAlbum() { await this.fetchCollection( this.albumFileName, - ['', '', ''] + ['', '', ''], ) }, diff --git a/src/views/Albums.vue b/src/views/Albums.vue index 2c5463c43..81b8f0c30 100644 --- a/src/views/Albums.vue +++ b/src/views/Albums.vue @@ -147,7 +147,7 @@ export default { fetchAlbums() { this.fetchCollections( `/photos/${getCurrentUser()?.uid}/albums`, - ['', '', ''] + ['', '', ''], ) }, diff --git a/src/views/Folders.vue b/src/views/Folders.vue index d45d782cb..cb835c052 100644 --- a/src/views/Folders.vue +++ b/src/views/Folders.vue @@ -70,7 +70,7 @@