files_external-init.mjs.map 20 KB

1
  1. {"version":3,"file":"files_external-init.mjs","sources":["../apps/files_external/src/utils/credentialsUtils.ts","../apps/files_external/src/utils/externalStorageUtils.ts","../apps/files_external/src/actions/enterCredentialsAction.ts","../apps/files_external/src/services/externalStorage.ts","../apps/files_external/src/actions/inlineStorageCheckAction.ts","../apps/files_external/src/actions/openInFilesAction.ts","../apps/files_external/src/init.ts"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { StorageConfig } from '../services/externalStorage'\n\n// @see https://github.com/nextcloud/server/blob/ac2bc2384efe3c15ff987b87a7432bc60d545c67/lib/public/Files/StorageNotAvailableException.php#L41\nexport enum STORAGE_STATUS {\n\tSUCCESS = 0,\n\tERROR = 1,\n\tINDETERMINATE = 2,\n\tINCOMPLETE_CONF = 3,\n\tUNAUTHORIZED = 4,\n\tTIMEOUT = 5,\n\tNETWORK_ERROR = 6,\n}\n\nexport const isMissingAuthConfig = function(config: StorageConfig) {\n\t// If we don't know the status, assume it is ok\n\tif (!config.status || config.status === STORAGE_STATUS.SUCCESS) {\n\t\treturn false\n\t}\n\n\treturn config.userProvided || config.authMechanism === 'password::global::user'\n}\n","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport { FileType, Node } from '@nextcloud/files'\nimport type { MountEntry } from '../services/externalStorage'\n\nexport const isNodeExternalStorage = function(node: Node) {\n\t// Not a folder, not a storage\n\tif (node.type === FileType.File) {\n\t\t return false\n\t}\n\n\t// No backend or scope, not a storage\n\tconst attributes = node.attributes as MountEntry\n\tif (!attributes.scope || !attributes.backend) {\n\t\treturn false\n\t}\n\n\t// Specific markers that we're sure are ext storage only\n\treturn attributes.scope === 'personal' || attributes.scope === 'system'\n}\n","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n// eslint-disable-next-line n/no-extraneous-import\nimport type { AxiosResponse } from 'axios'\nimport type { Node } from '@nextcloud/files'\nimport type { StorageConfig } from '../services/externalStorage'\n\nimport { generateOcsUrl, generateUrl } from '@nextcloud/router'\nimport { showError, showSuccess } from '@nextcloud/dialogs'\nimport { translate as t } from '@nextcloud/l10n'\nimport axios from '@nextcloud/axios'\nimport LoginSvg from '@mdi/svg/svg/login.svg?raw'\nimport Vue from 'vue'\n\nimport { FileAction, DefaultType } from '@nextcloud/files'\nimport { STORAGE_STATUS, isMissingAuthConfig } from '../utils/credentialsUtils'\nimport { isNodeExternalStorage } from '../utils/externalStorageUtils'\n\ntype OCSAuthResponse = {\n\tocs: {\n\t\tmeta: {\n\t\t\tstatus: string\n\t\t\tstatuscode: number\n\t\t\tmessage: string\n\t\t},\n\t\tdata: {\n\t\t\tuser?: string,\n\t\t\tpassword?: string,\n\t\t}\n\t}\n}\n\nexport const action = new FileAction({\n\tid: 'credentials-external-storage',\n\tdisplayName: () => t('files', 'Enter missing credentials'),\n\ticonSvgInline: () => LoginSvg,\n\n\tenabled: (nodes: Node[]) => {\n\t\t// Only works on single node\n\t\tif (nodes.length !== 1) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst node = nodes[0]\n\t\tif (!isNodeExternalStorage(node)) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst config = (node.attributes?.config || {}) as StorageConfig\n\t\tif (isMissingAuthConfig(config)) {\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t},\n\n\tasync exec(node: Node) {\n\t\t// always resolve auth request, we'll process the data afterwards\n\t\t// Using fetch as axios have integrated auth handling and X-Requested-With header\n\t\tconst response = await fetch(generateOcsUrl('/apps/files_external/api/v1/auth'), {\n\t\t\theaders: new Headers({ Accept: 'application/json' }),\n\t\t\tcredentials: 'include',\n\t\t})\n\n\t\tconst data = (await response?.json() || {}) as OCSAuthResponse\n\t\tif (data.ocs.data.user && data.ocs.data.password) {\n\t\t\tconst configResponse = await axios.put(generateUrl('apps/files_external/userglobalstorages/{id}', node.attributes), {\n\t\t\t\tbackendOptions: data.ocs.data,\n\t\t\t}) as AxiosResponse<StorageConfig>\n\n\t\t\tconst config = configResponse.data\n\t\t\tif (config.status !== STORAGE_STATUS.SUCCESS) {\n\t\t\t\tshowError(t('files_external', 'Unable to update this external storage config. {statusMessage}', {\n\t\t\t\t\tstatusMessage: config?.statusMessage || '',\n\t\t\t\t}))\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\t// Success update config attribute\n\t\t\tshowSuccess(t('files_external', 'New configuration successfully saved'))\n\t\t\tVue.set(node.attributes, 'config', config)\n\t\t}\n\n\t\treturn null\n\t},\n\n\t// Before openFolderAction\n\torder: -1000,\n\tdefault: DefaultType.DEFAULT,\n\tinline: () => true,\n})\n","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n// eslint-disable-next-line n/no-extraneous-import\nimport type { AxiosResponse } from 'axios'\nimport type { ContentsWithRoot } from '@nextcloud/files'\nimport type { OCSResponse } from '@nextcloud/typings/ocs'\n\nimport { Folder, Permission } from '@nextcloud/files'\nimport { generateOcsUrl, generateRemoteUrl, generateUrl } from '@nextcloud/router'\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\n\nimport { STORAGE_STATUS } from '../utils/credentialsUtils'\n\nexport const rootPath = `/files/${getCurrentUser()?.uid}`\n\nexport type StorageConfig = {\n\tapplicableUsers?: string[]\n\tapplicableGroups?: string[]\n\tauthMechanism: string\n\tbackend: string\n\tbackendOptions: Record<string, string>\n\tcan_edit: boolean\n\tid: number\n\tmountOptions?: Record<string, string>\n\tmountPoint: string\n\tpriority: number\n\tstatus: number\n\tstatusMessage: string\n\ttype: 'system' | 'user'\n\tuserProvided: boolean\n}\n\n/**\n * https://github.com/nextcloud/server/blob/ac2bc2384efe3c15ff987b87a7432bc60d545c67/apps/files_external/lib/Controller/ApiController.php#L71-L97\n */\nexport type MountEntry = {\n\tname: string\n\tpath: string,\n\ttype: 'dir',\n\tbackend: 'SFTP',\n\tscope: 'system' | 'personal',\n\tpermissions: number,\n\tid: number,\n\tclass: string\n\tconfig: StorageConfig\n}\n\nconst entryToFolder = (ocsEntry: MountEntry): Folder => {\n\tconst path = (ocsEntry.path + '/' + ocsEntry.name).replace(/^\\//gm, '')\n\treturn new Folder({\n\t\tid: ocsEntry.id,\n\t\tsource: generateRemoteUrl('dav' + rootPath + '/' + path),\n\t\troot: rootPath,\n\t\towner: getCurrentUser()?.uid || null,\n\t\tpermissions: ocsEntry.config.status !== STORAGE_STATUS.SUCCESS\n\t\t\t? Permission.NONE\n\t\t\t: ocsEntry?.permissions || Permission.READ,\n\t\tattributes: {\n\t\t\tdisplayName: path,\n\t\t\t...ocsEntry,\n\t\t},\n\t})\n}\n\nexport const getContents = async (): Promise<ContentsWithRoot> => {\n\tconst response = await axios.get(generateOcsUrl('apps/files_external/api/v1/mounts')) as AxiosResponse<OCSResponse<MountEntry[]>>\n\tconst contents = response.data.ocs.data.map(entryToFolder)\n\n\treturn {\n\t\tfolder: new Folder({\n\t\t\tid: 0,\n\t\t\tsource: generateRemoteUrl('dav' + rootPath),\n\t\t\troot: rootPath,\n\t\t\towner: getCurrentUser()?.uid || null,\n\t\t\tpermissions: Permission.READ,\n\t\t}),\n\t\tcontents,\n\t}\n}\n\nexport const getStatus = function(id: number, global = true) {\n\tconst type = global ? 'userglobalstorages' : 'userstorages'\n\treturn axios.get(generateUrl(`apps/files_external/${type}/${id}?testOnly=false`)) as Promise<AxiosResponse<StorageConfig>>\n}\n","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n// eslint-disable-next-line n/no-extraneous-import\nimport type { AxiosError } from 'axios'\nimport type { Node } from '@nextcloud/files'\n\nimport { showWarning } from '@nextcloud/dialogs'\nimport { translate as t } from '@nextcloud/l10n'\nimport AlertSvg from '@mdi/svg/svg/alert-circle.svg?raw'\nimport Vue from 'vue'\n\nimport '../css/fileEntryStatus.scss'\nimport { getStatus, type StorageConfig } from '../services/externalStorage'\nimport { isMissingAuthConfig, STORAGE_STATUS } from '../utils/credentialsUtils'\nimport { isNodeExternalStorage } from '../utils/externalStorageUtils'\nimport { FileAction } from '@nextcloud/files'\n\nexport const action = new FileAction({\n\tid: 'check-external-storage',\n\tdisplayName: () => '',\n\ticonSvgInline: () => '',\n\n\tenabled: (nodes: Node[]) => {\n\t\treturn nodes.every(node => isNodeExternalStorage(node) === true)\n\t},\n\texec: async () => null,\n\n\t/**\n\t * Use this function to check the storage availability\n\t * We then update the node attributes directly.\n\t */\n\tasync renderInline(node: Node) {\n\t\tlet config = null as any as StorageConfig\n\t\ttry {\n\t\t\tconst response = await getStatus(node.attributes.id, node.attributes.scope === 'system')\n\t\t\tconfig = response.data\n\t\t\tVue.set(node.attributes, 'config', config)\n\n\t\t\tif (config.status !== STORAGE_STATUS.SUCCESS) {\n\t\t\t\tthrow new Error(config?.statusMessage || t('files_external', 'There was an error with this external storage.'))\n\t\t\t}\n\n\t\t\treturn null\n\t\t} catch (error) {\n\t\t\t// If axios failed or if something else prevented\n\t\t\t// us from getting the config\n\t\t\tif ((error as AxiosError).response && !config) {\n\t\t\t\tshowWarning(t('files_external', 'We were unable to check the external storage {basename}', {\n\t\t\t\t\tbasename: node.basename,\n\t\t\t\t}))\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\t// Checking if we really have an error\n\t\t\tconst isWarning = isMissingAuthConfig(config)\n\t\t\tconst overlay = document.createElement('span')\n\t\t\toverlay.classList.add(`files-list__row-status--${isWarning ? 'warning' : 'error'}`)\n\n\t\t\tconst span = document.createElement('span')\n\t\t\tspan.className = 'files-list__row-status'\n\n\t\t\t// Only show an icon for errors, warning like missing credentials\n\t\t\t// have a dedicated inline action button\n\t\t\tif (!isWarning) {\n\t\t\t\tspan.innerHTML = AlertSvg\n\t\t\t\tspan.title = (error as Error).message\n\t\t\t}\n\n\t\t\tspan.prepend(overlay)\n\t\t\treturn span\n\t\t}\n\t},\n\n\torder: 10,\n})\n","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { Node } from '@nextcloud/files'\nimport type { StorageConfig } from '../services/externalStorage'\n\nimport { generateUrl } from '@nextcloud/router'\nimport { translate as t } from '@nextcloud/l10n'\n\nimport { FileAction, DefaultType } from '@nextcloud/files'\nimport { STORAGE_STATUS } from '../utils/credentialsUtils'\n\nexport const action = new FileAction({\n\tid: 'open-in-files-external-storage',\n\tdisplayName: (nodes: Node[]) => {\n\t\tconst config = nodes?.[0]?.attributes?.config as StorageConfig || { status: STORAGE_STATUS.INDETERMINATE }\n\t\tif (config.status !== STORAGE_STATUS.SUCCESS) {\n\t\t\treturn t('files_external', 'Examine this faulty external storage configuration')\n\t\t}\n\t\treturn t('files', 'Open in Files')\n\t},\n\ticonSvgInline: () => '',\n\n\tenabled: (nodes: Node[], view) => view.id === 'extstoragemounts',\n\n\tasync exec(node: Node) {\n\t\tconst config = node.attributes.config as StorageConfig\n\t\tif (config?.status !== STORAGE_STATUS.SUCCESS) {\n\t\t\twindow.OC.dialogs.confirm(\n\t\t\t\tt('files_external', 'There was an error with this external storage. Do you want to review this mount point config in the settings page?'),\n\t\t\t\tt('files_external', 'External mount error'),\n\t\t\t\t(redirect) => {\n\t\t\t\t\tif (redirect === true) {\n\t\t\t\t\t\tconst scope = node.attributes.scope === 'personal' ? 'user' : 'admin'\n\t\t\t\t\t\twindow.location.href = generateUrl(`/settings/${scope}/externalstorages`)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t)\n\t\t\treturn null\n\t\t}\n\n\t\t// Do not use fileid as we don't have that information\n\t\t// from the external storage api\n\t\twindow.OCP.Files.Router.goToRoute(\n\t\t\tnull, // use default route\n\t\t\t{ view: 'files' },\n\t\t\t{ dir: node.path },\n\t\t)\n\t\treturn null\n\t},\n\n\t// Before openFolderAction\n\torder: -1000,\n\tdefault: DefaultType.HIDDEN,\n})\n","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { View, getNavigation, Column, registerFileAction } from '@nextcloud/files'\nimport FolderNetworkSvg from '@mdi/svg/svg/folder-network.svg?raw'\n\nimport { action as enterCredentialsAction } from './actions/enterCredentialsAction'\nimport { action as inlineStorageCheckAction } from './actions/inlineStorageCheckAction'\nimport { action as openInFilesAction } from './actions/openInFilesAction'\nimport { getContents } from './services/externalStorage'\n\nconst allowUserMounting = loadState('files_external', 'allowUserMounting', false)\n\n// Register view\nconst Navigation = getNavigation()\nNavigation.register(new View({\n\tid: 'extstoragemounts',\n\tname: t('files_external', 'External storage'),\n\tcaption: t('files_external', 'List of external storage.'),\n\n\temptyCaption: allowUserMounting\n\t\t? t('files_external', 'There is no external storage configured. You can configure them in your Personal settings.')\n\t\t: t('files_external', 'There is no external storage configured and you don\\'t have the permission to configure them.'),\n\temptyTitle: t('files_external', 'No external storage'),\n\n\ticon: FolderNetworkSvg,\n\torder: 30,\n\n\tcolumns: [\n\t\tnew Column({\n\t\t\tid: 'storage-type',\n\t\t\ttitle: t('files_external', 'Storage type'),\n\t\t\trender(node) {\n\t\t\t\tconst backend = node.attributes?.backend || t('files_external', 'Unknown')\n\t\t\t\tconst span = document.createElement('span')\n\t\t\t\tspan.textContent = backend\n\t\t\t\treturn span\n\t\t\t},\n\t\t}),\n\t\tnew Column({\n\t\t\tid: 'scope',\n\t\t\ttitle: t('files_external', 'Scope'),\n\t\t\trender(node) {\n\t\t\t\tconst span = document.createElement('span')\n\t\t\t\tlet scope = t('files_external', 'Personal')\n\t\t\t\tif (node.attributes?.scope === 'system') {\n\t\t\t\t\tscope = t('files_external', 'System')\n\t\t\t\t}\n\t\t\t\tspan.textContent = scope\n\t\t\t\treturn span\n\t\t\t},\n\t\t}),\n\t],\n\n\tgetContents,\n}))\n\n// Register actions\nregisterFileAction(enterCredentialsAction)\nregisterFileAction(inlineStorageCheckAction)\nregisterFileAction(openInFilesAction)\n"],"names":["STORAGE_STATUS","isMissingAuthConfig","config","isNodeExternalStorage","node","FileType","attributes","action","FileAction","t","LoginSvg","nodes","_a","response","generateOcsUrl","data","axios","generateUrl","showError","showSuccess","Vue","DefaultType","rootPath","getCurrentUser","entryToFolder","ocsEntry","path","Folder","generateRemoteUrl","Permission","getContents","contents","getStatus","id","global","type","error","showWarning","isWarning","overlay","span","AlertSvg","_b","view","redirect","scope","allowUserMounting","loadState","Navigation","getNavigation","View","FolderNetworkSvg","Column","backend","registerFileAction","enterCredentialsAction","inlineStorageCheckAction","openInFilesAction"],"mappings":"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"}