Add share attrs + download permission support in frontend

Added download permission checkbox in frontend
Added share attributes parsing and setting in frontend.

Signed-off-by: Vincent Petry <vincent@nextcloud.com>
This commit is contained in:
Vincent Petry 2022-06-02 11:31:21 +02:00 committed by Carl Schwan
parent 92e60e3858
commit a11c6e7cc3
No known key found for this signature in database
GPG key ID: C3AA6B3A5EFA7AC5
7 changed files with 147 additions and 2 deletions

View file

@ -47,6 +47,7 @@ export default async function(url) {
<nc:mount-type />
<nc:is-encrypted />
<ocs:share-permissions />
<nc:share-attributes />
<oc:tags />
<oc:favorite />
<oc:comments-unread />

View file

@ -78,6 +78,12 @@
{{ t('files_sharing', 'Allow resharing') }}
</ActionCheckbox>
<ActionCheckbox ref="canDownload"
:checked.sync="canDownload"
:disabled="saving || !canSetDownload">
{{ t('files_sharing', 'Allow download') }}
</ActionCheckbox>
<!-- expiration date -->
<ActionCheckbox :checked.sync="hasExpirationDate"
:disabled="config.isDefaultInternalExpireDateEnforced || saving"
@ -271,6 +277,18 @@ export default {
return (this.fileInfo.sharePermissions & OC.PERMISSION_SHARE) || this.canReshare
},
/**
* Can the sharer set whether the sharee can download the file ?
*
* @return {boolean}
*/
canSetDownload() {
// If the owner revoked the permission after the resharer granted it
// the share still has the permission, and the resharer is still
// allowed to revoke it too (but not to grant it again).
return (this.fileInfo.canDownload() || this.canDownload)
},
/**
* Can the sharee edit the shared file ?
*/
@ -319,6 +337,18 @@ export default {
},
},
/**
* Can the sharee download files or only view them ?
*/
canDownload: {
get() {
return this.share.hasDownloadPermission
},
set(checked) {
this.updatePermissions({ isDownloadChecked: checked })
},
},
/**
* Is this share readable
* Needed for some federated shares that might have been added from file drop links
@ -380,7 +410,13 @@ export default {
},
methods: {
updatePermissions({ isEditChecked = this.canEdit, isCreateChecked = this.canCreate, isDeleteChecked = this.canDelete, isReshareChecked = this.canReshare } = {}) {
updatePermissions({
isEditChecked = this.canEdit,
isCreateChecked = this.canCreate,
isDeleteChecked = this.canDelete,
isReshareChecked = this.canReshare,
isDownloadChecked = this.canDownload,
} = {}) {
// calc permissions if checked
const permissions = 0
| (this.hasRead ? this.permissionsRead : 0)
@ -390,6 +426,10 @@ export default {
| (isReshareChecked ? this.permissionsShare : 0)
this.share.permissions = permissions
if (this.share.hasDownloadPermission !== isDownloadChecked) {
this.share.hasDownloadPermission = isDownloadChecked
this.queueUpdate('attributes')
}
this.queueUpdate('permissions')
},

View file

@ -229,7 +229,13 @@ export default {
const properties = {}
// force value to string because that is what our
// share api controller accepts
propertyNames.map(p => (properties[p] = this.share[p].toString()))
propertyNames.forEach(name => {
if ((typeof this.share[name]) === 'object') {
properties[name] = JSON.stringify(this.share[name])
} else {
properties[name] = this.share[name].toString()
}
})
this.updateQueue.add(async () => {
this.saving = true

View file

@ -43,6 +43,14 @@ export default class Share {
ocsData.hide_download = !!ocsData.hide_download
ocsData.mail_send = !!ocsData.mail_send
if (ocsData.attributes) {
try {
ocsData.attributes = JSON.parse(ocsData.attributes)
} catch (e) {
console.warn('Could not parse share attributes returned by server: "' + ocsData.attributes + '"')
}
}
// store state
this._share = ocsData
}
@ -96,6 +104,17 @@ export default class Share {
return this._share.permissions
}
/**
* Get the share attributes
*
* @return {Array}
* @readonly
* @memberof Share
*/
get attributes() {
return this._share.attributes
}
/**
* Set the share permissions
* See OC.PERMISSION_* variables
@ -527,6 +546,47 @@ export default class Share {
return !!((this.permissions & OC.PERMISSION_SHARE))
}
/**
* Does this share have download permissions
*
* @return {boolean}
* @readonly
* @memberof Share
*/
get hasDownloadPermission() {
for (const i in this._share.attributes) {
const attr = this._share.attributes[i]
if (attr.scope === 'permissions' && attr.key === 'download') {
return attr.enabled
}
}
return true
}
set hasDownloadPermission(enabled) {
this.setAttribute('permissions', 'download', !!enabled)
}
setAttribute(scope, key, enabled) {
const attrUpdate = {
scope,
key,
enabled,
}
// try and replace existing
for (const i in this._share.attributes) {
const attr = this._share.attributes[i]
if (attr.scope === attrUpdate.scope && attr.key === attrUpdate.key) {
this._share.attributes[i] = attrUpdate
return
}
}
this._share.attributes.push(attrUpdate)
}
// PERMISSIONS Shortcuts for the CURRENT USER
// ! the permissions above are the share settings,
// ! meaning the permissions for the recipient

View file

@ -92,7 +92,11 @@ import { getCapabilities } from '@nextcloud/capabilities'
delete fileActions.actions.all.Details
delete fileActions.actions.all.Goto
}
if (_.isFunction(fileData.canDownload) && !fileData.canDownload()) {
delete fileActions.actions.all.Download
}
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)
@ -113,6 +117,7 @@ import { getCapabilities } from '@nextcloud/capabilities'
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

View file

@ -104,6 +104,7 @@ import escapeHTML from 'escape-html'
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'
@ -160,6 +161,10 @@ import escapeHTML from 'escape-html'
* Share permissions
*/
[Client.NS_OCS, 'share-permissions'],
/**
* Share attributes
*/
[Client.NS_NEXTCLOUD, 'share-attributes'],
]
/**
@ -416,6 +421,18 @@ import escapeHTML from 'escape-html'
data.sharePermissions = parseInt(sharePermissionsProp)
}
const shareAttributesProp = props[Client.PROPERTY_SHARE_ATTRIBUTES]
if (!_.isUndefined(shareAttributesProp)) {
try {
data.shareAttributes = JSON.parse(shareAttributesProp)
} catch (e) {
console.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

View file

@ -155,7 +155,23 @@
*/
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.enabled
}
}
return true
},
}
if (!OC.Files) {