aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_sharing/src
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_sharing/src')
-rw-r--r--apps/files_sharing/src/components/SharingEntry.vue74
-rw-r--r--apps/files_sharing/src/components/SharingEntryLink.vue10
-rw-r--r--apps/files_sharing/src/components/SharingInput.vue1
-rw-r--r--apps/files_sharing/src/mixins/ShareRequests.js5
-rw-r--r--apps/files_sharing/src/mixins/SharesMixin.js8
-rw-r--r--apps/files_sharing/src/models/Share.js61
-rw-r--r--apps/files_sharing/src/share.js5
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