diff --git a/apps/files_sharing/src/collaborationresourceshandler.js b/apps/files_sharing/src/collaborationresourceshandler.js deleted file mode 100644 index f636d273e91..00000000000 --- a/apps/files_sharing/src/collaborationresourceshandler.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ -import { getCSPNonce } from '@nextcloud/auth' - -__webpack_nonce__ = getCSPNonce() - -window.OCP.Collaboration.registerType('file', { - action: () => { - return new Promise((resolve, reject) => { - OC.dialogs.filepicker(t('files_sharing', 'Link to a file'), function(f) { - const client = OC.Files.getClient() - client.getFileInfo(f).then((status, fileInfo) => { - resolve(fileInfo.id) - }).fail(() => { - reject(new Error('Cannot get fileinfo')) - }) - }, false, null, false, OC.dialogs.FILEPICKER_TYPE_CHOOSE, '', { allowDirectoryChooser: true }) - }) - }, - typeString: t('files_sharing', 'Link to a file'), - typeIconClass: 'icon-files-dark', -}) diff --git a/apps/files_sharing/src/collaborationresourceshandler.ts b/apps/files_sharing/src/collaborationresourceshandler.ts new file mode 100644 index 00000000000..fd1be71a90c --- /dev/null +++ b/apps/files_sharing/src/collaborationresourceshandler.ts @@ -0,0 +1,28 @@ +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { getCSPNonce } from '@nextcloud/auth' +import { FilePickerType, getFilePickerBuilder } from '@nextcloud/dialogs' +import { t } from '@nextcloud/l10n' + +__webpack_nonce__ = getCSPNonce() + +window.OCP.Collaboration.registerType('file', { + typeString: t('files_sharing', 'Link to a file'), + typeIconClass: 'icon-files-dark', + async action() { + const filePicker = getFilePickerBuilder(t('files_sharing', 'Link to a file')) + .setType(FilePickerType.Choose) + .allowDirectories(true) + .build() + + try { + const [node] = await filePicker.pickNodes() + return node!.fileid + } catch { + throw new Error('Cannot get fileinfo') + } + }, +}) diff --git a/apps/files_sharing/src/services/FileInfo.ts b/apps/files_sharing/src/services/FileInfo.ts index f8ea6b37310..c4a69800861 100644 --- a/apps/files_sharing/src/services/FileInfo.ts +++ b/apps/files_sharing/src/services/FileInfo.ts @@ -5,6 +5,8 @@ import type { Attribute, INode } from '@nextcloud/files' +import { Permission } from '@nextcloud/files' + interface RawLegacyFileInfo { id: number path: string @@ -57,13 +59,31 @@ export default function(node: INode): LegacyFileInfo { attributes: node.attributes, } - const fileInfo = new OC.Files.FileInfo(rawFileInfo) - // TODO remove when no more legacy backbone is used - fileInfo.get = (key) => fileInfo[key] - fileInfo.isDirectory = () => fileInfo.mimetype === 'httpd/unix-directory' - fileInfo.canEdit = () => Boolean(fileInfo.permissions & OC.PERMISSION_UPDATE) - fileInfo.node = node + const fileInfo: LegacyFileInfo = { + ...rawFileInfo, + node, + + get(key) { + return this[key] + }, + isDirectory() { + return this.mimetype === 'httpd/unix-directory' + }, + canEdit() { + return Boolean(this.permissions & Permission.UPDATE) + }, + canDownload() { + for (const i in this.shareAttributes) { + const attr = this.shareAttributes[i] + if (attr.scope === 'permissions' && attr.key === 'download') { + return attr.value === true + } + } + + return true + }, + } return fileInfo } diff --git a/apps/workflowengine/lib/Listener/LoadAdditionalSettingsScriptsListener.php b/apps/workflowengine/lib/Listener/LoadAdditionalSettingsScriptsListener.php index e5a03fdcb2e..d81768fb459 100644 --- a/apps/workflowengine/lib/Listener/LoadAdditionalSettingsScriptsListener.php +++ b/apps/workflowengine/lib/Listener/LoadAdditionalSettingsScriptsListener.php @@ -18,8 +18,6 @@ use OCP\WorkflowEngine\Events\LoadSettingsScriptsEvent; /** @template-implements IEventListener */ class LoadAdditionalSettingsScriptsListener implements IEventListener { public function handle(Event $event): void { - Util::addScript('core', 'files_fileinfo'); - Util::addScript('core', 'files_client'); Util::addScript('core', 'systemtags'); Util::addScript(Application::APP_ID, 'workflowengine'); } diff --git a/build/frontend-legacy/webpack.modules.cjs b/build/frontend-legacy/webpack.modules.cjs index 29369519fda..6f570dc70ef 100644 --- a/build/frontend-legacy/webpack.modules.cjs +++ b/build/frontend-legacy/webpack.modules.cjs @@ -12,8 +12,6 @@ module.exports = { }, core: { 'ajax-cron': path.join(__dirname, 'core/src', 'ajax-cron.ts'), - files_client: path.join(__dirname, 'core/src', 'files/client.js'), - files_fileinfo: path.join(__dirname, 'core/src', 'files/fileinfo.js'), install: path.join(__dirname, 'core/src', 'install.ts'), login: path.join(__dirname, 'core/src', 'login.js'), login_flow: path.join(__dirname, 'core/src', 'login-flow.ts'), diff --git a/core/Listener/BeforeTemplateRenderedListener.php b/core/Listener/BeforeTemplateRenderedListener.php index cc1dee91cfe..0bbf67960bb 100644 --- a/core/Listener/BeforeTemplateRenderedListener.php +++ b/core/Listener/BeforeTemplateRenderedListener.php @@ -54,9 +54,6 @@ class BeforeTemplateRenderedListener implements IEventListener { if ($event->getResponse()->getRenderAs() !== TemplateResponse::RENDER_AS_ERROR) { Util::addScript('core', 'merged-template-prepend', 'core', true); - Util::addScript('core', 'files_client', 'core', true); - Util::addScript('core', 'files_fileinfo', 'core', true); - // If installed and background job is set to ajax, add dedicated script if ($this->appConfig->getValueString('core', 'backgroundjobs_mode', 'ajax') === 'ajax') { diff --git a/core/src/files/client.js b/core/src/files/client.js deleted file mode 100644 index b310a9e0e2a..00000000000 --- a/core/src/files/client.js +++ /dev/null @@ -1,972 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -import { getCurrentUser } from '@nextcloud/auth' -import escapeHTML from 'escape-html' -import $ from 'jquery' -import _ from 'underscore' -import logger from '../logger.js' - -/* global dav */ - -(function(OC, FileInfo) { - /** - * @class OC.Files.Client - * @classdesc Client to access files on the server - * - * @param {object} options - * @param {string} options.host host name - * @param {number} [options.port] port - * @param {boolean} [options.useHTTPS] whether to use https - * @param {string} [options.root] root path - * @param {string} [options.userName] user name - * @param {string} [options.password] password - * - * @since 8.2 - */ - const Client = function(options) { - this._root = options.root - if (this._root.charAt(this._root.length - 1) === '/') { - this._root = this._root.substr(0, this._root.length - 1) - } - - let url = Client.PROTOCOL_HTTP + '://' - if (options.useHTTPS) { - url = Client.PROTOCOL_HTTPS + '://' - } - - url += options.host + this._root - this._host = options.host - this._defaultHeaders = options.defaultHeaders || { - 'X-Requested-With': 'XMLHttpRequest', - requesttoken: OC.requestToken, - } - this._baseUrl = url - - const clientOptions = { - baseUrl: this._baseUrl, - xmlNamespaces: { - 'DAV:': 'd', - 'http://owncloud.org/ns': 'oc', - 'http://nextcloud.org/ns': 'nc', - 'http://open-collaboration-services.org/ns': 'ocs', - }, - } - if (options.userName) { - clientOptions.userName = options.userName - } - if (options.password) { - clientOptions.password = options.password - } - this._client = new dav.Client(clientOptions) - this._client.xhrProvider = _.bind(this._xhrProvider, this) - this._fileInfoParsers = [] - } - - Client.NS_OWNCLOUD = 'http://owncloud.org/ns' - Client.NS_NEXTCLOUD = 'http://nextcloud.org/ns' - Client.NS_DAV = 'DAV:' - Client.NS_OCS = 'http://open-collaboration-services.org/ns' - - Client.PROPERTY_GETLASTMODIFIED = '{' + Client.NS_DAV + '}getlastmodified' - Client.PROPERTY_GETETAG = '{' + Client.NS_DAV + '}getetag' - Client.PROPERTY_GETCONTENTTYPE = '{' + Client.NS_DAV + '}getcontenttype' - Client.PROPERTY_RESOURCETYPE = '{' + Client.NS_DAV + '}resourcetype' - Client.PROPERTY_INTERNAL_FILEID = '{' + Client.NS_OWNCLOUD + '}fileid' - Client.PROPERTY_PERMISSIONS = '{' + Client.NS_OWNCLOUD + '}permissions' - Client.PROPERTY_SIZE = '{' + Client.NS_OWNCLOUD + '}size' - Client.PROPERTY_GETCONTENTLENGTH = '{' + Client.NS_DAV + '}getcontentlength' - Client.PROPERTY_ISENCRYPTED = '{' + Client.NS_DAV + '}is-encrypted' - Client.PROPERTY_SHARE_PERMISSIONS = '{' + Client.NS_OCS + '}share-permissions' - Client.PROPERTY_SHARE_ATTRIBUTES = '{' + Client.NS_NEXTCLOUD + '}share-attributes' - Client.PROPERTY_QUOTA_AVAILABLE_BYTES = '{' + Client.NS_DAV + '}quota-available-bytes' - - Client.PROTOCOL_HTTP = 'http' - Client.PROTOCOL_HTTPS = 'https' - - Client._PROPFIND_PROPERTIES = [ - /** - * Modified time - */ - [Client.NS_DAV, 'getlastmodified'], - /** - * Etag - */ - [Client.NS_DAV, 'getetag'], - /** - * Mime type - */ - [Client.NS_DAV, 'getcontenttype'], - /** - * Resource type "collection" for folders, empty otherwise - */ - [Client.NS_DAV, 'resourcetype'], - /** - * File id - */ - [Client.NS_OWNCLOUD, 'fileid'], - /** - * Letter-coded permissions - */ - [Client.NS_OWNCLOUD, 'permissions'], - // [Client.NS_OWNCLOUD, 'downloadURL'], - /** - * Folder sizes - */ - [Client.NS_OWNCLOUD, 'size'], - /** - * File sizes - */ - [Client.NS_DAV, 'getcontentlength'], - [Client.NS_DAV, 'quota-available-bytes'], - /** - * Preview availability - */ - [Client.NS_NEXTCLOUD, 'has-preview'], - /** - * Mount type - */ - [Client.NS_NEXTCLOUD, 'mount-type'], - /** - * Encryption state - */ - [Client.NS_NEXTCLOUD, 'is-encrypted'], - /** - * Share permissions - */ - [Client.NS_OCS, 'share-permissions'], - /** - * Share attributes - */ - [Client.NS_NEXTCLOUD, 'share-attributes'], - ] - - /** - * @memberof OC.Files - */ - Client.prototype = { - - /** - * Root path of the Webdav endpoint - * - * @type string - */ - _root: null, - - /** - * Client from the library - * - * @type dav.Client - */ - _client: null, - - /** - * Array of file info parsing functions. - * - * @type Array - */ - _fileInfoParsers: [], - - /** - * Returns the configured XHR provider for davclient - * - * @return {XMLHttpRequest} - */ - _xhrProvider: function() { - const headers = this._defaultHeaders - const xhr = new XMLHttpRequest() - const oldOpen = xhr.open - // override open() method to add headers - xhr.open = function() { - const result = oldOpen.apply(this, arguments) - _.each(headers, function(value, key) { - xhr.setRequestHeader(key, value) - }) - return result - } - - OC.registerXHRForErrorProcessing(xhr) - return xhr - }, - - /** - * Prepends the base url to the given path sections - * - * @param {...string} path sections - * - * @return {string} base url + joined path, any leading or trailing slash - * will be kept - */ - _buildUrl: function() { - let path = this._buildPath.apply(this, arguments) - if (path.charAt([path.length - 1]) === '/') { - path = path.substr(0, path.length - 1) - } - if (path.charAt(0) === '/') { - path = path.substr(1) - } - return this._baseUrl + '/' + path - }, - - /** - * Append the path to the root and also encode path - * sections - * - * @param {...string} path sections - * - * @return {string} joined path, any leading or trailing slash - * will be kept - */ - _buildPath: function() { - let path = OC.joinPaths.apply(this, arguments) - const sections = path.split('/') - let i - for (i = 0; i < sections.length; i++) { - sections[i] = encodeURIComponent(sections[i]) - } - path = sections.join('/') - return path - }, - - /** - * Parse headers string into a map - * - * @param {string} headersString headers list as string - * - * @return {Object} map of header name to header contents - */ - _parseHeaders: function(headersString) { - const headerRows = headersString.split('\n') - const headers = {} - for (let i = 0; i < headerRows.length; i++) { - const sepPos = headerRows[i].indexOf(':') - if (sepPos < 0) { - continue - } - - const headerName = headerRows[i].substr(0, sepPos) - const headerValue = headerRows[i].substr(sepPos + 2) - - if (!headers[headerName]) { - // make it an array - headers[headerName] = [] - } - - headers[headerName].push(headerValue) - } - return headers - }, - - /** - * Parses the etag response which is in double quotes. - * - * @param {string} etag etag value in double quotes - * - * @return {string} etag without double quotes - */ - _parseEtag: function(etag) { - if (etag.charAt(0) === '"') { - return etag.split('"')[1] - } - return etag - }, - - /** - * Parse Webdav result - * - * @param {object} response XML object - * - * @return {Array.} array of file info - */ - _parseFileInfo: function(response) { - let path = decodeURIComponent(response.href) - if (path.substr(0, this._root.length) === this._root) { - path = path.substr(this._root.length) - } - - if (path.charAt(path.length - 1) === '/') { - path = path.substr(0, path.length - 1) - } - - if (response.propStat.length === 0 || response.propStat[0].status !== 'HTTP/1.1 200 OK') { - return null - } - - const props = response.propStat[0].properties - - const data = { - id: props[Client.PROPERTY_INTERNAL_FILEID], - path: OC.dirname(path) || '/', - name: OC.basename(path), - mtime: (new Date(props[Client.PROPERTY_GETLASTMODIFIED])).getTime(), - } - - const etagProp = props[Client.PROPERTY_GETETAG] - if (!_.isUndefined(etagProp)) { - data.etag = this._parseEtag(etagProp) - } - - let sizeProp = props[Client.PROPERTY_GETCONTENTLENGTH] - if (!_.isUndefined(sizeProp)) { - data.size = parseInt(sizeProp, 10) - } - - sizeProp = props[Client.PROPERTY_SIZE] - if (!_.isUndefined(sizeProp)) { - data.size = parseInt(sizeProp, 10) - } - - const hasPreviewProp = props['{' + Client.NS_NEXTCLOUD + '}has-preview'] - if (!_.isUndefined(hasPreviewProp)) { - data.hasPreview = hasPreviewProp === 'true' - } else { - data.hasPreview = true - } - - const isEncryptedProp = props['{' + Client.NS_NEXTCLOUD + '}is-encrypted'] - if (!_.isUndefined(isEncryptedProp)) { - data.isEncrypted = isEncryptedProp === '1' - } else { - data.isEncrypted = false - } - - const isFavouritedProp = props['{' + Client.NS_OWNCLOUD + '}favorite'] - if (!_.isUndefined(isFavouritedProp)) { - data.isFavourited = isFavouritedProp === '1' - } else { - data.isFavourited = false - } - - const contentType = props[Client.PROPERTY_GETCONTENTTYPE] - if (!_.isUndefined(contentType)) { - data.mimetype = contentType - } - - const resType = props[Client.PROPERTY_RESOURCETYPE] - if (!data.mimetype && resType) { - const xmlvalue = resType[0] - if (xmlvalue.namespaceURI === Client.NS_DAV && xmlvalue.nodeName.split(':')[1] === 'collection') { - data.mimetype = 'httpd/unix-directory' - } - } - - data.permissions = OC.PERMISSION_NONE - const permissionProp = props[Client.PROPERTY_PERMISSIONS] - if (!_.isUndefined(permissionProp)) { - const permString = permissionProp || '' - data.mountType = null - for (let i = 0; i < permString.length; i++) { - const c = permString.charAt(i) - switch (c) { - // FIXME: twisted permissions - case 'C': - case 'K': - data.permissions |= OC.PERMISSION_CREATE - break - case 'G': - data.permissions |= OC.PERMISSION_READ - break - case 'W': - case 'N': - case 'V': - data.permissions |= OC.PERMISSION_UPDATE - break - case 'D': - data.permissions |= OC.PERMISSION_DELETE - break - case 'R': - data.permissions |= OC.PERMISSION_SHARE - break - case 'M': - if (!data.mountType) { - // TODO: how to identify external-root ? - data.mountType = 'external' - } - break - case 'S': - // TODO: how to identify shared-root ? - data.mountType = 'shared' - break - } - } - } - - const sharePermissionsProp = props[Client.PROPERTY_SHARE_PERMISSIONS] - if (!_.isUndefined(sharePermissionsProp)) { - data.sharePermissions = parseInt(sharePermissionsProp) - } - - const shareAttributesProp = props[Client.PROPERTY_SHARE_ATTRIBUTES] - if (!_.isUndefined(shareAttributesProp)) { - try { - data.shareAttributes = JSON.parse(shareAttributesProp) - } catch { - logger.warn('Could not parse share attributes returned by server: "' + shareAttributesProp + '"') - data.shareAttributes = [] - } - } else { - data.shareAttributes = [] - } - - const mounTypeProp = props['{' + Client.NS_NEXTCLOUD + '}mount-type'] - if (!_.isUndefined(mounTypeProp)) { - data.mountType = mounTypeProp - } - - const quotaAvailableBytes = props['{' + Client.NS_DAV + '}quota-available-bytes'] - if (!_.isUndefined(quotaAvailableBytes)) { - data.quotaAvailableBytes = quotaAvailableBytes - } - - // extend the parsed data using the custom parsers - _.each(this._fileInfoParsers, function(parserFunction) { - _.extend(data, parserFunction(response, data) || {}) - }) - - return new FileInfo(data) - }, - - /** - * Parse Webdav multistatus - * - * @param {Array} responses - */ - _parseResult: function(responses) { - const self = this - return _.map(responses, function(response) { - return self._parseFileInfo(response) - }) - }, - - /** - * Returns whether the given status code means success - * - * @param {number} status status code - * - * @return true if status code is between 200 and 299 included - */ - _isSuccessStatus: function(status) { - return status >= 200 && status <= 299 - }, - - /** - * Parse the Sabre exception out of the given response, if any - * - * @param {object} response object - * @return {object} array of parsed message and exception (only the first one) - */ - _getSabreException: function(response) { - const result = {} - const xml = response.xhr.responseXML - if (xml === null) { - return result - } - const messages = xml.getElementsByTagNameNS('http://sabredav.org/ns', 'message') - const exceptions = xml.getElementsByTagNameNS('http://sabredav.org/ns', 'exception') - if (messages.length) { - result.message = messages[0].textContent - } - if (exceptions.length) { - result.exception = exceptions[0].textContent - } - return result - }, - - /** - * Returns the default PROPFIND properties to use during a call. - * - * @return {Array.} array of properties - */ - getPropfindProperties: function() { - if (!this._propfindProperties) { - this._propfindProperties = _.map(Client._PROPFIND_PROPERTIES, function(propDef) { - return '{' + propDef[0] + '}' + propDef[1] - }) - } - return this._propfindProperties - }, - - /** - * Lists the contents of a directory - * - * @param {string} path path to retrieve - * @param {object} [options] options - * @param {boolean} [options.includeParent] set to true to keep - * the parent folder in the result list - * @param {Array} [options.properties] list of Webdav properties to retrieve - * - * @return {Promise} promise - */ - getFolderContents: function(path, options) { - if (!path) { - path = '' - } - options = options || {} - const self = this - const deferred = $.Deferred() - const promise = deferred.promise() - let properties - if (_.isUndefined(options.properties)) { - properties = this.getPropfindProperties() - } else { - properties = options.properties - } - - this._client.propFind( - this._buildUrl(path), - properties, - 1, - ).then(function(result) { - if (self._isSuccessStatus(result.status)) { - const results = self._parseResult(result.body) - if (!options || !options.includeParent) { - // remove root dir, the first entry - results.shift() - } - deferred.resolve(result.status, results) - } else { - result = _.extend(result, self._getSabreException(result)) - deferred.reject(result.status, result) - } - }) - return promise - }, - - /** - * Fetches a flat list of files filtered by a given filter criteria. - * (currently system tags and circles are supported) - * - * @param {object} filter filter criteria - * @param {object} [filter.systemTagIds] list of system tag ids to filter by - * @param {boolean} [filter.favorite] set it to filter by favorites - * @param {object} [options] options - * @param {Array} [options.properties] list of Webdav properties to retrieve - * - * @return {Promise} promise - */ - getFilteredFiles: function(filter, options) { - options = options || {} - const self = this - const deferred = $.Deferred() - const promise = deferred.promise() - let properties - if (_.isUndefined(options.properties)) { - properties = this.getPropfindProperties() - } else { - properties = options.properties - } - - if (!filter - || (!filter.systemTagIds && _.isUndefined(filter.favorite) && !filter.circlesIds)) { - throw 'Missing filter argument' - } - - // root element with namespaces - let body = '\n' - _.each(properties, function(prop) { - const property = self._client.parseClarkNotation(prop) - body += ' <' + self._client.xmlNamespaces[property.namespace] + ':' + property.name + ' />\n' - }) - - body += ' \n' - - // rules block - body += ' \n' - _.each(filter.systemTagIds, function(systemTagIds) { - body += ' ' + escapeHTML(systemTagIds) + '\n' - }) - _.each(filter.circlesIds, function(circlesIds) { - body += ' ' + escapeHTML(circlesIds) + '\n' - }) - if (filter.favorite) { - body += ' ' + (filter.favorite ? '1' : '0') + '\n' - } - body += ' \n' - - // end of root - body += '\n' - - this._client.request( - 'REPORT', - this._buildUrl(), - {}, - body, - ).then(function(result) { - if (self._isSuccessStatus(result.status)) { - const results = self._parseResult(result.body) - deferred.resolve(result.status, results) - } else { - result = _.extend(result, self._getSabreException(result)) - deferred.reject(result.status, result) - } - }) - return promise - }, - - /** - * Returns the file info of a given path. - * - * @param {string} path path - * @param {Array} [options.properties] list of Webdav properties to retrieve - * - * @param options - * @return {Promise} promise - */ - getFileInfo: function(path, options) { - if (!path) { - path = '' - } - options = options || {} - const self = this - const deferred = $.Deferred() - const promise = deferred.promise() - let properties - if (_.isUndefined(options.properties)) { - properties = this.getPropfindProperties() - } else { - properties = options.properties - } - - // TODO: headers - this._client.propFind( - this._buildUrl(path), - properties, - 0, - ).then(function(result) { - if (self._isSuccessStatus(result.status)) { - deferred.resolve(result.status, self._parseResult([result.body])[0]) - } else { - result = _.extend(result, self._getSabreException(result)) - deferred.reject(result.status, result) - } - }) - return promise - }, - - /** - * Returns the contents of the given file. - * - * @param {string} path path to file - * - * @return {Promise} - */ - getFileContents: function(path) { - if (!path) { - throw 'Missing argument "path"' - } - const self = this - const deferred = $.Deferred() - const promise = deferred.promise() - - this._client.request( - 'GET', - this._buildUrl(path), - ).then(function(result) { - if (self._isSuccessStatus(result.status)) { - deferred.resolve(result.status, result.body) - } else { - result = _.extend(result, self._getSabreException(result)) - deferred.reject(result.status, result) - } - }) - return promise - }, - - /** - * Puts the given data into the given file. - * - * @param {string} path path to file - * @param {string} body file body - * @param {object} [options] - * @param {string} [options.contentType] content type - * @param {boolean} [options.overwrite] whether to overwrite an existing file - * - * @return {Promise} - */ - putFileContents: function(path, body, options) { - if (!path) { - throw 'Missing argument "path"' - } - const self = this - const deferred = $.Deferred() - const promise = deferred.promise() - options = options || {} - const headers = {} - let contentType = 'text/plain;charset=utf-8' - if (options.contentType) { - contentType = options.contentType - } - - headers['Content-Type'] = contentType - - if (_.isUndefined(options.overwrite) || options.overwrite) { - // will trigger 412 precondition failed if a file already exists - headers['If-None-Match'] = '*' - } - - this._client.request( - 'PUT', - this._buildUrl(path), - headers, - body || '', - ).then(function(result) { - if (self._isSuccessStatus(result.status)) { - deferred.resolve(result.status) - } else { - result = _.extend(result, self._getSabreException(result)) - deferred.reject(result.status, result) - } - }) - return promise - }, - - _simpleCall: function(method, path, headers) { - if (!path) { - throw 'Missing argument "path"' - } - - const self = this - const deferred = $.Deferred() - const promise = deferred.promise() - - this._client.request( - method, - this._buildUrl(path), - headers ? headers : {}, - ).then(function(result) { - if (self._isSuccessStatus(result.status)) { - deferred.resolve(result.status) - } else { - result = _.extend(result, self._getSabreException(result)) - deferred.reject(result.status, result) - } - }) - return promise - }, - - /** - * Creates a directory - * - * @param {string} path path to create - * - * @param headers - * @return {Promise} - */ - createDirectory: function(path, headers) { - return this._simpleCall('MKCOL', path, headers) - }, - - /** - * Deletes a file or directory - * - * @param {string} path path to delete - * - * @return {Promise} - */ - remove: function(path) { - return this._simpleCall('DELETE', path) - }, - - /** - * Moves path to another path - * - * @param {string} path path to move - * @param {string} destinationPath destination path - * @param {boolean} [allowOverwrite] true to allow overwriting, - * false otherwise - * @param {object} [headers] additional headers - * - * @return {Promise} promise - */ - move: function(path, destinationPath, allowOverwrite, headers) { - if (!path) { - throw 'Missing argument "path"' - } - if (!destinationPath) { - throw 'Missing argument "destinationPath"' - } - - const self = this - const deferred = $.Deferred() - const promise = deferred.promise() - headers = _.extend({}, headers, { - Destination: this._buildUrl(destinationPath), - }) - - if (!allowOverwrite) { - headers.Overwrite = 'F' - } - - this._client.request( - 'MOVE', - this._buildUrl(path), - headers, - ).then(function(result) { - if (self._isSuccessStatus(result.status)) { - deferred.resolve(result.status) - } else { - result = _.extend(result, self._getSabreException(result)) - deferred.reject(result.status, result) - } - }) - return promise - }, - - /** - * Copies path to another path - * - * @param {string} path path to copy - * @param {string} destinationPath destination path - * @param {boolean} [allowOverwrite] true to allow overwriting, - * false otherwise - * - * @return {Promise} promise - */ - copy: function(path, destinationPath, allowOverwrite) { - if (!path) { - throw 'Missing argument "path"' - } - if (!destinationPath) { - throw 'Missing argument "destinationPath"' - } - - const self = this - const deferred = $.Deferred() - const promise = deferred.promise() - const headers = { - Destination: this._buildUrl(destinationPath), - } - - if (!allowOverwrite) { - headers.Overwrite = 'F' - } - - this._client.request( - 'COPY', - this._buildUrl(path), - headers, - ).then(function(response) { - if (self._isSuccessStatus(response.status)) { - deferred.resolve(response.status) - } else { - deferred.reject(response.status) - } - }) - return promise - }, - - /** - * Add a file info parser function - * - * @param {OC.Files.Client~parseFileInfo} parserFunction - */ - addFileInfoParser: function(parserFunction) { - this._fileInfoParsers.push(parserFunction) - }, - - /** - * Returns the dav.Client instance used internally - * - * @since 11.0.0 - * @return {dav.Client} - */ - getClient: function() { - return this._client - }, - - /** - * Returns the user name - * - * @since 11.0.0 - * @return {string} userName - */ - getUserName: function() { - return this._client.userName - }, - - /** - * Returns the password - * - * @since 11.0.0 - * @return {string} password - */ - getPassword: function() { - return this._client.password - }, - - /** - * Returns the base URL - * - * @since 11.0.0 - * @return {string} base URL - */ - getBaseUrl: function() { - return this._client.baseUrl - }, - - /** - * Returns the host - * - * @since 13.0.0 - * @return {string} base URL - */ - getHost: function() { - return this._host - }, - } - - /** - * File info parser function - * - * This function receives a list of Webdav properties as input and - * should return a hash array of parsed properties, if applicable. - * - * @callback OC.Files.Client~parseFileInfo - * @param {object} XML Webdav properties - * @return {Array} array of parsed property values - */ - - if (!OC.Files) { - /** - * @namespace OC.Files - * - * @since 8.2 - */ - OC.Files = {} - } - - /** - * Returns the default instance of the files client - * - * @return {OC.Files.Client} default client - * - * @since 8.2 - */ - OC.Files.getClient = function() { - if (OC.Files._defaultClient) { - return OC.Files._defaultClient - } - - const client = new OC.Files.Client({ - host: window.location.host, - port: window.location.port, - root: OC.linkToRemoteBase('dav') + '/files/' + getCurrentUser().uid, - useHTTPS: window.location.protocol.startsWith('https'), - }) - OC.Files._defaultClient = client - return client - } - - OC.Files.Client = Client -})(OC, OC.Files.FileInfo) diff --git a/core/src/files/fileinfo.js b/core/src/files/fileinfo.js deleted file mode 100644 index b987c840393..00000000000 --- a/core/src/files/fileinfo.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -import _ from 'underscore' - -(function(OC) { - /** - * @class OC.Files.FileInfo - * @classdesc File information - * - * @param {object} data file data, see attributes for details - * - * @since 8.2 - */ - const FileInfo = function(data) { - const self = this - _.each(data, function(value, key) { - if (!_.isFunction(value)) { - self[key] = value - } - }) - - if (!_.isUndefined(this.id)) { - this.id = parseInt(data.id, 10) - } - - // TODO: normalize path - this.path = data.path || '' - - if (this.type === 'dir') { - this.mimetype = 'httpd/unix-directory' - } else { - this.mimetype = this.mimetype || 'application/octet-stream' - } - - if (!this.type) { - if (this.mimetype === 'httpd/unix-directory') { - this.type = 'dir' - } else { - this.type = 'file' - } - } - } - - /** - * @memberof OC.Files - */ - FileInfo.prototype = { - /** - * File id - * - * @type int - */ - id: null, - - /** - * File name - * - * @type String - */ - name: null, - - /** - * Path leading to the file, without the file name, - * and with a leading slash. - * - * @type String - */ - path: null, - - /** - * Mime type - * - * @type String - */ - mimetype: null, - - /** - * Icon URL. - * - * Can be used to override the mime type icon. - * - * @type String - */ - icon: null, - - /** - * File type. 'file' for files, 'dir' for directories. - * - * @type String - * @deprecated rely on mimetype instead - */ - type: null, - - /** - * Permissions. - * - * @see OC#PERMISSION_ALL for permissions - * @type int - */ - permissions: null, - - /** - * Modification time - * - * @type int - */ - mtime: null, - - /** - * Etag - * - * @type String - */ - etag: null, - - /** - * Mount type. - * - * One of null, "external-root", "shared" or "shared-root" - * - * @type string - */ - mountType: null, - - /** - * @type boolean - */ - hasPreview: true, - - /** - * @type int - */ - sharePermissions: null, - - /** - * @type Array - */ - shareAttributes: [], - - quotaAvailableBytes: -1, - - canDownload: function() { - for (const i in this.shareAttributes) { - const attr = this.shareAttributes[i] - if (attr.scope === 'permissions' && attr.key === 'download') { - return attr.value === true - } - } - - return true - }, - } - - if (!OC.Files) { - OC.Files = {} - } - OC.Files.FileInfo = FileInfo -})(OC)