Merge pull request #54338 from nextcloud/chore/cleanup

pull/54540/head
John Molakvoæ 2 months ago committed by GitHub
commit 0958fda1b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      apps/files_sharing/src/additionalScripts.js
  2. 505
      apps/files_sharing/src/share.js
  3. 62
      apps/files_sharing/src/sharebreadcrumbview.js
  4. 17
      apps/files_sharing/src/style/sharebreadcrumb.scss
  5. 4
      dist/core-common.js
  6. 2
      dist/core-common.js.map
  7. 4
      dist/files_sharing-additionalScripts.js
  8. 20
      dist/files_sharing-additionalScripts.js.license
  9. 2
      dist/files_sharing-additionalScripts.js.map

@ -4,9 +4,6 @@
*/
import { getCSPNonce } from '@nextcloud/auth'
import './share.js'
import './sharebreadcrumbview.js'
import './style/sharebreadcrumb.scss'
import './collaborationresourceshandler.js'
// eslint-disable-next-line camelcase

@ -1,505 +0,0 @@
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2011-2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/* eslint-disable */
import escapeHTML from 'escape-html'
import { ShareType } from '@nextcloud/sharing'
import { getCapabilities } from '@nextcloud/capabilities'
(function() {
_.extend(OC.Files.Client, {
PROPERTY_SHARE_TYPES: '{' + OC.Files.Client.NS_OWNCLOUD + '}share-types',
PROPERTY_OWNER_ID: '{' + OC.Files.Client.NS_OWNCLOUD + '}owner-id',
PROPERTY_OWNER_DISPLAY_NAME: '{' + OC.Files.Client.NS_OWNCLOUD + '}owner-display-name'
})
if (!OCA.Sharing) {
OCA.Sharing = {}
}
/**
* @namespace
*/
OCA.Sharing.Util = {
/**
* Regular expression for splitting parts of remote share owners:
* "user@example.com/"
* "user@example.com/path/to/owncloud"
* "user@anotherexample.com@example.com/path/to/owncloud
*/
_REMOTE_OWNER_REGEXP: new RegExp('^(([^@]*)@(([^@^/\\s]*)@)?)((https://)?[^[\\s/]*)([/](.*))?$'),
/**
* Initialize the sharing plugin.
*
* Registers the "Share" file action and adds additional
* DOM attributes for the sharing file info.
*
* @param {OCA.Files.FileList} fileList file list to be extended
*/
attach: function(fileList) {
// core sharing is disabled/not loaded
if (!getCapabilities().files_sharing?.api_enabled) {
return
}
if (fileList.id === 'trashbin' || fileList.id === 'files.public') {
return
}
var fileActions = fileList.fileActions
var oldCreateRow = fileList._createRow
fileList._createRow = function(fileData) {
var tr = oldCreateRow.apply(this, arguments)
var sharePermissions = OCA.Sharing.Util.getSharePermissions(fileData)
if (fileData.permissions === 0) {
// no permission, disabling sidebar
delete fileActions.actions.all.Comment
delete fileActions.actions.all.Details
delete fileActions.actions.all.Goto
}
if (_.isFunction(fileData.canDownload) && !fileData.canDownload()) {
delete fileActions.actions.all.Download
if ((fileData.permissions & OC.PERMISSION_UPDATE) === 0) {
// neither move nor copy is allowed, remove the action completely
delete fileActions.actions.all.MoveCopy
}
}
tr.attr('data-share-permissions', sharePermissions)
tr.attr('data-share-attributes', JSON.stringify(fileData.shareAttributes))
if (fileData.shareOwner) {
tr.attr('data-share-owner', fileData.shareOwner)
tr.attr('data-share-owner-id', fileData.shareOwnerId)
// user should always be able to rename a mount point
if (fileData.mountType === 'shared-root') {
tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE)
}
}
if (fileData.recipientData && !_.isEmpty(fileData.recipientData)) {
tr.attr('data-share-recipient-data', JSON.stringify(fileData.recipientData))
}
if (fileData.shareTypes) {
tr.attr('data-share-types', fileData.shareTypes.join(','))
}
return tr
}
var oldElementToFile = fileList.elementToFile
fileList.elementToFile = function($el) {
var fileInfo = oldElementToFile.apply(this, arguments)
fileInfo.shareAttributes = JSON.parse($el.attr('data-share-attributes') || '[]')
fileInfo.sharePermissions = $el.attr('data-share-permissions') || undefined
fileInfo.shareOwner = $el.attr('data-share-owner') || undefined
fileInfo.shareOwnerId = $el.attr('data-share-owner-id') || undefined
if ($el.attr('data-share-types')) {
fileInfo.shareTypes = $el.attr('data-share-types').split(',')
}
if ($el.attr('data-expiration')) {
var expirationTimestamp = parseInt($el.attr('data-expiration'))
fileInfo.shares = []
fileInfo.shares.push({ expiration: expirationTimestamp })
}
return fileInfo
}
var oldGetWebdavProperties = fileList._getWebdavProperties
fileList._getWebdavProperties = function() {
var props = oldGetWebdavProperties.apply(this, arguments)
props.push(OC.Files.Client.PROPERTY_OWNER_ID)
props.push(OC.Files.Client.PROPERTY_OWNER_DISPLAY_NAME)
props.push(OC.Files.Client.PROPERTY_SHARE_TYPES)
return props
}
fileList.filesClient.addFileInfoParser(function(response) {
var data = {}
var props = response.propStat[0].properties
var permissionsProp = props[OC.Files.Client.PROPERTY_PERMISSIONS]
if (permissionsProp && permissionsProp.indexOf('S') >= 0) {
data.shareOwner = props[OC.Files.Client.PROPERTY_OWNER_DISPLAY_NAME]
data.shareOwnerId = props[OC.Files.Client.PROPERTY_OWNER_ID]
}
var shareTypesProp = props[OC.Files.Client.PROPERTY_SHARE_TYPES]
if (shareTypesProp) {
data.shareTypes = _.chain(shareTypesProp).filter(function(xmlvalue) {
return (xmlvalue.namespaceURI === OC.Files.Client.NS_OWNCLOUD && xmlvalue.nodeName.split(':')[1] === 'share-type')
}).map(function(xmlvalue) {
return parseInt(xmlvalue.textContent || xmlvalue.text, 10)
}).value()
}
return data
})
// use delegate to catch the case with multiple file lists
fileList.$el.on('fileActionsReady', function(ev) {
var $files = ev.$files
_.each($files, function(file) {
var $tr = $(file)
var shareTypesStr = $tr.attr('data-share-types') || ''
var shareOwner = $tr.attr('data-share-owner')
if (shareTypesStr || shareOwner) {
var hasLink = false
var hasShares = false
_.each(shareTypesStr.split(',') || [], function(shareTypeStr) {
let shareType = parseInt(shareTypeStr, 10)
if (shareType === ShareType.Link) {
hasLink = true
} else if (shareType === ShareType.Email) {
hasLink = true
} else if (shareType === ShareType.User) {
hasShares = true
} else if (shareType === ShareType.Group) {
hasShares = true
} else if (shareType === ShareType.Remote) {
hasShares = true
} else if (shareType === ShareType.RemoteGroup) {
hasShares = true
} else if (shareType === ShareType.Team) {
hasShares = true
} else if (shareType === ShareType.Room) {
hasShares = true
} else if (shareType === ShareType.Deck) {
hasShares = true
}
})
OCA.Sharing.Util._updateFileActionIcon($tr, hasShares, hasLink)
}
})
})
fileList.$el.on('changeDirectory', function() {
OCA.Sharing.sharesLoaded = false
})
fileActions.registerAction({
name: 'Share',
displayName: function(context) {
if (context && context.$file) {
var shareType = parseInt(context.$file.data('share-types'), 10)
var shareOwner = context.$file.data('share-owner-id')
if (shareType >= 0 || shareOwner) {
return t('files_sharing', 'Shared')
}
}
return t('files_sharing', 'Share')
},
altText: t('files_sharing', 'Share'),
mime: 'all',
order: -150,
permissions: OC.PERMISSION_ALL,
iconClass: function(fileName, context) {
var shareType = parseInt(context.$file.data('share-types'), 10)
if (shareType === ShareType.Email
|| shareType === ShareType.Link) {
return 'icon-public'
}
return 'icon-shared'
},
icon: function(fileName, context) {
var shareOwner = context.$file.data('share-owner-id')
if (shareOwner) {
return OC.generateUrl(`/avatar/${shareOwner}/32`)
}
},
type: OCA.Files.FileActions.TYPE_INLINE,
actionHandler: function(fileName, context) {
// details view disabled in some share lists
if (!fileList._detailsView) {
return
}
// do not open sidebar if permission is set and equal to 0
var permissions = parseInt(context.$file.data('share-permissions'), 10)
if (isNaN(permissions) || permissions > 0) {
fileList.showDetailsView(fileName, 'sharing')
}
},
render: function(actionSpec, isDefault, context) {
var permissions = parseInt(context.$file.data('permissions'), 10)
// if no share permissions but share owner exists, still show the link
if ((permissions & OC.PERMISSION_SHARE) !== 0 || context.$file.attr('data-share-owner')) {
return fileActions._defaultRenderAction.call(fileActions, actionSpec, isDefault, context)
}
// don't render anything
return null
}
})
// register share breadcrumbs component
var breadCrumbSharingDetailView = new OCA.Sharing.ShareBreadCrumbView()
fileList.registerBreadCrumbDetailView(breadCrumbSharingDetailView)
},
/**
* Update file list data attributes
*/
_updateFileListDataAttributes: function(fileList, $tr, shareModel) {
// files app current cannot show recipients on load, so we don't update the
// icon when changed for consistency
if (fileList.id === 'files') {
return
}
var recipients = _.pluck(shareModel.get('shares'), 'share_with_displayname')
// note: we only update the data attribute because updateIcon()
if (recipients.length) {
var recipientData = _.mapObject(shareModel.get('shares'), function(share) {
return { shareWith: share.share_with, shareWithDisplayName: share.share_with_displayname }
})
$tr.attr('data-share-recipient-data', JSON.stringify(recipientData))
} else {
$tr.removeAttr('data-share-recipient-data')
}
},
/**
* Update the file action share icon for the given file
*
* @param $tr file element of the file to update
* @param {boolean} hasUserShares true if a user share exists
* @param {boolean} hasLinkShares true if a link share exists
*
* @returns {boolean} true if the icon was set, false otherwise
*/
_updateFileActionIcon: function($tr, hasUserShares, hasLinkShares) {
// if the statuses are loaded already, use them for the icon
// (needed when scrolling to the next page)
if (hasUserShares || hasLinkShares || $tr.attr('data-share-recipient-data') || $tr.attr('data-share-owner')) {
OCA.Sharing.Util._markFileAsShared($tr, true, hasLinkShares)
return true
}
return false
},
/**
* Marks/unmarks a given file as shared by changing its action icon
* and folder icon.
*
* @param $tr file element to mark as shared
* @param hasShares whether shares are available
* @param hasLink whether link share is available
*/
_markFileAsShared: function($tr, hasShares, hasLink) {
var action = $tr.find('.fileactions .action[data-action="Share"]')
var type = $tr.data('type')
var icon = action.find('.icon')
var message, recipients, avatars
var ownerId = $tr.attr('data-share-owner-id')
var owner = $tr.attr('data-share-owner')
var mountType = $tr.attr('data-mounttype')
var shareFolderIcon
var iconClass = 'icon-shared'
action.removeClass('shared-style')
// update folder icon
var isEncrypted = $tr.attr('data-e2eencrypted')
if (type === 'dir' && isEncrypted === 'true') {
shareFolderIcon = OC.MimeType.getIconUrl('dir-encrypted')
$tr.attr('data-icon', shareFolderIcon)
} else if (type === 'dir' && (hasShares || hasLink || ownerId)) {
if (typeof mountType !== 'undefined' && mountType !== 'shared-root' && mountType !== 'shared') {
shareFolderIcon = OC.MimeType.getIconUrl('dir-' + mountType)
} else if (hasLink) {
shareFolderIcon = OC.MimeType.getIconUrl('dir-public')
} else {
shareFolderIcon = OC.MimeType.getIconUrl('dir-shared')
}
$tr.find('.filename .thumbnail').css('background-image', 'url(' + shareFolderIcon + ')')
$tr.attr('data-icon', shareFolderIcon)
} else if (type === 'dir') {
// FIXME: duplicate of FileList._createRow logic for external folder,
// need to refactor the icon logic into a single code path eventually
if (mountType && mountType.indexOf('external') === 0) {
shareFolderIcon = OC.MimeType.getIconUrl('dir-external')
$tr.attr('data-icon', shareFolderIcon)
} else {
shareFolderIcon = OC.MimeType.getIconUrl('dir')
// back to default
$tr.removeAttr('data-icon')
}
$tr.find('.filename .thumbnail').css('background-image', 'url(' + shareFolderIcon + ')')
}
// update share action text / icon
if (hasShares || ownerId) {
recipients = $tr.data('share-recipient-data')
action.addClass('shared-style')
avatars = '<span>' + t('files_sharing', 'Shared') + '</span>'
// even if reshared, only show "Shared by"
if (ownerId) {
message = t('files_sharing', 'Shared by')
avatars = OCA.Sharing.Util._formatRemoteShare(ownerId, owner, message)
} else if (recipients) {
avatars = OCA.Sharing.Util._formatShareList(recipients)
}
action.html(avatars).prepend(icon)
if (ownerId || recipients) {
var avatarElement = action.find('.avatar')
avatarElement.each(function() {
$(this).avatar($(this).data('username'), 32)
})
}
} else {
action.html('<span class="hidden-visually">' + t('files_sharing', 'Shared') + '</span>').prepend(icon)
}
if (hasLink) {
iconClass = 'icon-public'
}
icon.removeClass('icon-shared icon-public').addClass(iconClass)
},
/**
* Format a remote address
*
* @param {String} shareWith userid, full remote share, or whatever
* @param {String} shareWithDisplayName
* @param {String} message
* @returns {String} HTML code to display
*/
_formatRemoteShare: function(shareWith, shareWithDisplayName, message) {
var parts = OCA.Sharing.Util._REMOTE_OWNER_REGEXP.exec(shareWith)
if (!parts || !parts[7]) {
// display avatar of the user
var avatar = '<span class="avatar" data-username="' + escapeHTML(shareWith) + '" title="' + message + ' ' + escapeHTML(shareWithDisplayName) + '"></span>'
var hidden = '<span class="hidden-visually">' + message + ' ' + escapeHTML(shareWithDisplayName) + '</span> '
return avatar + hidden
}
var userName = parts[2]
var userDomain = parts[4]
var server = parts[5]
var protocol = parts[6]
var serverPath = parts[8] ? parts[7] : ''; // no trailing slash on root
var tooltip = message + ' ' + userName
if (userDomain) {
tooltip += '@' + userDomain
}
if (server) {
tooltip += '@' + server.replace(protocol, '') + serverPath
}
var html = '<span class="remoteAddress" title="' + escapeHTML(tooltip) + '">'
html += '<span class="username">' + escapeHTML(userName) + '</span>'
if (userDomain) {
html += '<span class="userDomain">@' + escapeHTML(userDomain) + '</span>'
}
html += '</span> '
return html
},
/**
* Loop over all recipients in the list and format them using
* all kind of fancy magic.
*
* @param {Object} recipients array of all the recipients
* @returns {String[]} modified list of recipients
*/
_formatShareList: function(recipients) {
var _parent = this
recipients = _.toArray(recipients)
recipients.sort(function(a, b) {
return a.shareWithDisplayName.localeCompare(b.shareWithDisplayName)
})
return $.map(recipients, function(recipient) {
return _parent._formatRemoteShare(recipient.shareWith, recipient.shareWithDisplayName, t('files_sharing', 'Shared with'))
})
},
/**
* Marks/unmarks a given file as shared by changing its action icon
* and folder icon.
*
* @param $tr file element to mark as shared
* @param hasShares whether shares are available
* @param hasLink whether link share is available
*/
markFileAsShared: function($tr, hasShares, hasLink) {
var action = $tr.find('.fileactions .action[data-action="Share"]')
var type = $tr.data('type')
var icon = action.find('.icon')
var message, recipients, avatars
var ownerId = $tr.attr('data-share-owner-id')
var owner = $tr.attr('data-share-owner')
var mountType = $tr.attr('data-mounttype')
var shareFolderIcon
var iconClass = 'icon-shared'
action.removeClass('shared-style')
// update folder icon
if (type === 'dir' && (hasShares || hasLink || ownerId)) {
if (typeof mountType !== 'undefined' && mountType !== 'shared-root' && mountType !== 'shared') {
shareFolderIcon = OC.MimeType.getIconUrl('dir-' + mountType)
} else if (hasLink) {
shareFolderIcon = OC.MimeType.getIconUrl('dir-public')
} else {
shareFolderIcon = OC.MimeType.getIconUrl('dir-shared')
}
$tr.find('.filename .thumbnail').css('background-image', 'url(' + shareFolderIcon + ')')
$tr.attr('data-icon', shareFolderIcon)
} else if (type === 'dir') {
var isEncrypted = $tr.attr('data-e2eencrypted')
// FIXME: duplicate of FileList._createRow logic for external folder,
// need to refactor the icon logic into a single code path eventually
if (isEncrypted === 'true') {
shareFolderIcon = OC.MimeType.getIconUrl('dir-encrypted')
$tr.attr('data-icon', shareFolderIcon)
} else if (mountType && mountType.indexOf('external') === 0) {
shareFolderIcon = OC.MimeType.getIconUrl('dir-external')
$tr.attr('data-icon', shareFolderIcon)
} else {
shareFolderIcon = OC.MimeType.getIconUrl('dir')
// back to default
$tr.removeAttr('data-icon')
}
$tr.find('.filename .thumbnail').css('background-image', 'url(' + shareFolderIcon + ')')
}
// update share action text / icon
if (hasShares || ownerId) {
recipients = $tr.data('share-recipient-data')
action.addClass('shared-style')
avatars = '<span>' + t('files_sharing', 'Shared') + '</span>'
// even if reshared, only show "Shared by"
if (ownerId) {
message = t('files_sharing', 'Shared by')
avatars = this._formatRemoteShare(ownerId, owner, message)
} else if (recipients) {
avatars = this._formatShareList(recipients)
}
action.html(avatars).prepend(icon)
if (ownerId || recipients) {
var avatarElement = action.find('.avatar')
avatarElement.each(function() {
$(this).avatar($(this).data('username'), 32)
})
}
} else {
action.html('<span class="hidden-visually">' + t('files_sharing', 'Shared') + '</span>').prepend(icon)
}
if (hasLink) {
iconClass = 'icon-public'
}
icon.removeClass('icon-shared icon-public').addClass(iconClass)
},
/**
* @param {Array} fileData
* @returns {String}
*/
getSharePermissions: function(fileData) {
return fileData.sharePermissions
}
}
})()
OC.Plugins.register('OCA.Files.FileList', OCA.Sharing.Util)

@ -1,62 +0,0 @@
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { ShareType } from '@nextcloud/sharing'
(function() {
'use strict'
const BreadCrumbView = OC.Backbone.View.extend({
tagName: 'span',
events: {
click: '_onClick',
},
_dirInfo: undefined,
render(data) {
this._dirInfo = data.dirInfo || null
if (this._dirInfo !== null && (this._dirInfo.path !== '/' || this._dirInfo.name !== '')) {
const isShared = data.dirInfo && data.dirInfo.shareTypes && data.dirInfo.shareTypes.length > 0
this.$el.removeClass('shared icon-public icon-shared')
if (isShared) {
this.$el.addClass('shared')
if (data.dirInfo.shareTypes.indexOf(ShareType.Link) !== -1) {
this.$el.addClass('icon-public')
} else {
this.$el.addClass('icon-shared')
}
} else {
this.$el.addClass('icon-shared')
}
this.$el.show()
this.delegateEvents()
} else {
this.$el.removeClass('shared icon-public icon-shared')
this.$el.hide()
}
return this
},
_onClick(e) {
e.preventDefault()
e.stopPropagation()
const fileInfoModel = new OCA.Files.FileInfoModel(this._dirInfo)
const self = this
fileInfoModel.on('change', function() {
self.render({
dirInfo: self._dirInfo,
})
})
const path = fileInfoModel.attributes.path + '/' + fileInfoModel.attributes.name
OCA.Files.Sidebar.open(path)
OCA.Files.Sidebar.setActiveTab('sharing')
},
})
OCA.Sharing.ShareBreadCrumbView = BreadCrumbView
})()

@ -1,17 +0,0 @@
/*!
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
li.crumb span.icon-shared,
li.crumb span.icon-public {
display: inline-block;
cursor: pointer;
opacity: 0.2;
margin-inline-end: 6px;
}
li.crumb span.icon-shared.shared,
li.crumb span.icon-public.shared {
opacity: 0.7;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -2,10 +2,8 @@ SPDX-License-Identifier: MIT
SPDX-License-Identifier: ISC
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-License-Identifier: AGPL-3.0-or-later
SPDX-FileCopyrightText: escape-html developers
SPDX-FileCopyrightText: Tobias Koppers @sokra
SPDX-FileCopyrightText: Roman Shtylman <shtylman@gmail.com>
SPDX-FileCopyrightText: Roeland Jago Douma
SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
SPDX-FileCopyrightText: GitHub Inc.
SPDX-FileCopyrightText: Christoph Wurst
@ -18,33 +16,15 @@ This file is generated from multiple sources. Included packages:
- @nextcloud/browser-storage
- version: 0.4.0
- license: GPL-3.0-or-later
- @nextcloud/initial-state
- version: 2.2.0
- license: GPL-3.0-or-later
- @nextcloud/capabilities
- version: 1.2.0
- license: GPL-3.0-or-later
- semver
- version: 7.6.3
- license: ISC
- @nextcloud/event-bus
- version: 3.3.2
- license: GPL-3.0-or-later
- @nextcloud/sharing
- version: 0.2.5
- license: GPL-3.0-or-later
- css-loader
- version: 7.1.2
- license: MIT
- escape-html
- version: 1.0.3
- license: MIT
- process
- version: 0.11.10
- license: MIT
- style-loader
- version: 4.0.0
- license: MIT
- webpack
- version: 5.101.2
- license: MIT

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save