Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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 <[email protected]>
  • Loading branch information
PVince81 authored and CarlSchwan committed Jul 28, 2022
commit a11c6e7cc3eec18cba62ebd32e0b8653d97ed929
1 change: 1 addition & 0 deletions apps/files/src/services/FileInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 />
Expand Down
42 changes: 41 additions & 1 deletion apps/files_sharing/src/components/SharingEntry.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 ?
*/
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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')
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: check if we can also skip "permissions"

This comment was marked as resolved.

this.queueUpdate('permissions')
},

Expand Down
8 changes: 7 additions & 1 deletion apps/files_sharing/src/mixins/SharesMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
60 changes: 60 additions & 0 deletions apps/files_sharing/src/models/Share.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions apps/files_sharing/src/share.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
17 changes: 17 additions & 0 deletions core/src/files/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -160,6 +161,10 @@ import escapeHTML from 'escape-html'
* Share permissions
*/
[Client.NS_OCS, 'share-permissions'],
/**
* Share attributes
*/
[Client.NS_NEXTCLOUD, 'share-attributes'],
]

/**
Expand Down Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions core/src/files/fileinfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down