diff options
Diffstat (limited to 'apps/files_sharing/src')
-rw-r--r-- | apps/files_sharing/src/components/SharingEntry.vue | 74 | ||||
-rw-r--r-- | apps/files_sharing/src/components/SharingEntryLink.vue | 10 | ||||
-rw-r--r-- | apps/files_sharing/src/components/SharingInput.vue | 1 | ||||
-rw-r--r-- | apps/files_sharing/src/mixins/ShareRequests.js | 5 | ||||
-rw-r--r-- | apps/files_sharing/src/mixins/SharesMixin.js | 8 | ||||
-rw-r--r-- | apps/files_sharing/src/models/Share.js | 61 | ||||
-rw-r--r-- | apps/files_sharing/src/share.js | 5 |
7 files changed, 157 insertions, 7 deletions
diff --git a/apps/files_sharing/src/components/SharingEntry.vue b/apps/files_sharing/src/components/SharingEntry.vue index 25baf536f2f..f873ef542ed 100644 --- a/apps/files_sharing/src/components/SharingEntry.vue +++ b/apps/files_sharing/src/components/SharingEntry.vue @@ -78,6 +78,13 @@ {{ t('files_sharing', 'Allow resharing') }} </ActionCheckbox> + <ActionCheckbox ref="canDownload" + :checked.sync="canDownload" + v-if="isSetDownloadButtonVisible" + :disabled="saving || !canSetDownload"> + {{ allowDownloadText }} + </ActionCheckbox> + <!-- expiration date --> <ActionCheckbox :checked.sync="hasExpirationDate" :disabled="config.isDefaultInternalExpireDateEnforced || saving" @@ -272,6 +279,18 @@ export default { }, /** + * 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 ? */ canEdit: { @@ -320,6 +339,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 */ @@ -377,10 +408,46 @@ export default { return (typeof this.share.status === 'object' && !Array.isArray(this.share.status)) }, + /** + * @return {string} + */ + allowDownloadText() { + if (this.isFolder) { + return t('files_sharing', 'Allow download of office files') + } else { + return t('files_sharing', 'Allow download') + } + }, + + /** + * @return {boolean} + */ + isSetDownloadButtonVisible() { + const allowedMimetypes = [ + // Office documents + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.ms-powerpoint', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.oasis.opendocument.text', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.oasis.opendocument.presentation', + ] + + return this.isFolder || allowedMimetypes.includes(this.fileInfo.mimetype) + }, }, 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,7 +457,10 @@ export default { | (isReshareChecked ? this.permissionsShare : 0) this.share.permissions = permissions - this.queueUpdate('permissions') + if (this.share.hasDownloadPermission !== isDownloadChecked) { + this.share.hasDownloadPermission = isDownloadChecked + } + this.queueUpdate('permissions', 'attributes') }, /** diff --git a/apps/files_sharing/src/components/SharingEntryLink.vue b/apps/files_sharing/src/components/SharingEntryLink.vue index 672b32c1cd1..328d0108332 100644 --- a/apps/files_sharing/src/components/SharingEntryLink.vue +++ b/apps/files_sharing/src/components/SharingEntryLink.vue @@ -159,7 +159,7 @@ <ActionSeparator /> <ActionCheckbox :checked.sync="share.hideDownload" - :disabled="saving" + :disabled="saving || canChangeHideDownload" @change="queueUpdate('hideDownload')"> {{ t('files_sharing', 'Hide download') }} </ActionCheckbox> @@ -607,6 +607,12 @@ export default { isPasswordPolicyEnabled() { return typeof this.config.passwordPolicy === 'object' }, + + canChangeHideDownload() { + const hasDisabledDownload = (shareAttribute) => shareAttribute.key === 'download' && shareAttribute.scope === 'permissions' && shareAttribute.enabled === false + + return this.fileInfo.shareAttributes.some(hasDisabledDownload) + }, }, methods: { @@ -697,6 +703,7 @@ export default { shareType: ShareTypes.SHARE_TYPE_LINK, password: share.password, expireDate: share.expireDate, + attributes: JSON.stringify(this.fileInfo.shareAttributes), // we do not allow setting the publicUpload // before the share creation. // Todo: We also need to fix the createShare method in @@ -867,7 +874,6 @@ export default { this.$emit('remove:share', this.share) }, }, - } </script> diff --git a/apps/files_sharing/src/components/SharingInput.vue b/apps/files_sharing/src/components/SharingInput.vue index 9cb40697636..df987942552 100644 --- a/apps/files_sharing/src/components/SharingInput.vue +++ b/apps/files_sharing/src/components/SharingInput.vue @@ -478,6 +478,7 @@ export default { shareWith: value.shareWith, password, permissions: this.fileInfo.sharePermissions & OC.getCapabilities().files_sharing.default_permissions, + attributes: JSON.stringify(this.fileInfo.shareAttributes), }) // If we had a password, we need to show it to the user as it was generated diff --git a/apps/files_sharing/src/mixins/ShareRequests.js b/apps/files_sharing/src/mixins/ShareRequests.js index e2668c15d65..9eaad8c4161 100644 --- a/apps/files_sharing/src/mixins/ShareRequests.js +++ b/apps/files_sharing/src/mixins/ShareRequests.js @@ -47,12 +47,13 @@ export default { * @param {boolean} [data.sendPasswordByTalk=false] send the password via a talk conversation * @param {string} [data.expireDate=''] expire the shareautomatically after * @param {string} [data.label=''] custom label + * @param {string} [data.attributes=null] Share attributes encoded as json * @return {Share} the new share * @throws {Error} */ - async createShare({ path, permissions, shareType, shareWith, publicUpload, password, sendPasswordByTalk, expireDate, label }) { + async createShare({ path, permissions, shareType, shareWith, publicUpload, password, sendPasswordByTalk, expireDate, label, attributes }) { try { - const request = await axios.post(shareUrl, { path, permissions, shareType, shareWith, publicUpload, password, sendPasswordByTalk, expireDate, label }) + const request = await axios.post(shareUrl, { path, permissions, shareType, shareWith, publicUpload, password, sendPasswordByTalk, expireDate, label, attributes }) if (!request?.data?.ocs) { throw request } diff --git a/apps/files_sharing/src/mixins/SharesMixin.js b/apps/files_sharing/src/mixins/SharesMixin.js index daeacfa4b8b..053babd3a1d 100644 --- a/apps/files_sharing/src/mixins/SharesMixin.js +++ b/apps/files_sharing/src/mixins/SharesMixin.js @@ -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 diff --git a/apps/files_sharing/src/models/Share.js b/apps/files_sharing/src/models/Share.js index 5644ce0c2b3..e6512c67f8c 100644 --- a/apps/files_sharing/src/models/Share.js +++ b/apps/files_sharing/src/models/Share.js @@ -43,6 +43,15 @@ 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 + '"') + } + } + ocsData.attributes = ocsData.attributes ?? [] + // store state this._share = ocsData } @@ -97,6 +106,17 @@ export default class Share { } /** + * 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 +547,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 diff --git a/apps/files_sharing/src/share.js b/apps/files_sharing/src/share.js index c533e7b8109..76c007b5218 100644 --- a/apps/files_sharing/src/share.js +++ b/apps/files_sharing/src/share.js @@ -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 |