diff options
author | skjnldsv <skjnldsv@protonmail.com> | 2024-07-09 11:00:08 +0200 |
---|---|---|
committer | John Molakvoæ <skjnldsv@users.noreply.github.com> | 2024-07-12 20:14:30 +0200 |
commit | 208ff8013dc750326cab7fcf11d09ceef2a60f51 (patch) | |
tree | bf260ae0d1c26291e5b89c8a47f5cb57d3c5be29 | |
parent | 06462804f7f8b2c046aa3875d8780fb4e4f4d9fc (diff) | |
download | nextcloud-server-208ff8013dc750326cab7fcf11d09ceef2a60f51.tar.gz nextcloud-server-208ff8013dc750326cab7fcf11d09ceef2a60f51.zip |
chore(files_sharing): refactor sharing config
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
14 files changed, 463 insertions, 378 deletions
diff --git a/apps/files_sharing/src/components/NewFileRequestDialog.vue b/apps/files_sharing/src/components/NewFileRequestDialog.vue index 50e3ff485c9..d6fec8f20e2 100644 --- a/apps/files_sharing/src/components/NewFileRequestDialog.vue +++ b/apps/files_sharing/src/components/NewFileRequestDialog.vue @@ -24,21 +24,23 @@ class="file-request-dialog__form" aria-labelledby="file-request-dialog-description" data-cy-file-request-dialog-form - @submit.prevent.stop="onSubmit"> - <FileRequestIntro v-if="currentStep === STEP.FIRST" + @submit.prevent.stop=""> + <FileRequestIntro v-show="currentStep === STEP.FIRST" :context="context" :destination.sync="destination" :disabled="loading" :label.sync="label" :note.sync="note" /> - <FileRequestDatePassword v-else-if="currentStep === STEP.SECOND" + <FileRequestDatePassword v-show="currentStep === STEP.SECOND" :deadline.sync="deadline" :disabled="loading" :password.sync="password" /> - <FileRequestFinish v-else-if="share" + <FileRequestFinish v-if="share" + v-show="currentStep === STEP.LAST" :emails="emails" + :isShareByMailEnabled="isShareByMailEnabled" :share="share" @add-email="email => emails.push(email)" @remove-email="onRemoveEmail" /> @@ -79,17 +81,19 @@ <NcLoadingIcon v-if="loading" /> <IconNext v-else :size="20" /> </template> - {{ continueButtonLabel }} + {{ t('files_sharing', 'Continue') }} </NcButton> <!-- Finish --> <NcButton v-else - :aria-label="t('files_sharing', 'Close the creation dialog')" + :aria-label="finishButtonLabel" + :disabled="loading" data-cy-file-request-dialog-controls="finish" type="primary" - @click="$emit('close')"> + @click="onFinish"> <template #icon> - <IconCheck :size="20" /> + <NcLoadingIcon v-if="loading" /> + <IconCheck v-else :size="20" /> </template> {{ finishButtonLabel }} </NcButton> @@ -99,14 +103,15 @@ <script lang="ts"> import type { AxiosError } from 'axios' -import type { Folder, Node } from '@nextcloud/files' +import { Permission, type Folder, type Node } from '@nextcloud/files' import type { OCSResponse } from '@nextcloud/typings/ocs' import type { PropType } from 'vue' import { defineComponent } from 'vue' import { emit } from '@nextcloud/event-bus' import { generateOcsUrl } from '@nextcloud/router' -import { showError } from '@nextcloud/dialogs' +import { getCapabilities } from '@nextcloud/capabilities' +import { showError, showSuccess } from '@nextcloud/dialogs' import { translate, translatePlural } from '@nextcloud/l10n' import { Type } from '@nextcloud/sharing' import axios from '@nextcloud/axios' @@ -159,9 +164,12 @@ export default defineComponent({ setup() { return { + STEP, + n: translatePlural, t: translate, - STEP, + + isShareByMailEnabled: getCapabilities()?.files_sharing?.sharebymail?.enabled === true } }, @@ -183,13 +191,6 @@ export default defineComponent({ }, computed: { - continueButtonLabel() { - if (this.currentStep === STEP.LAST) { - return this.t('files_sharing', 'Close') - } - return this.t('files_sharing', 'Continue') - }, - finishButtonLabel() { if (this.emails.length === 0) { return this.t('files_sharing', 'Close') @@ -231,8 +232,17 @@ export default defineComponent({ this.$emit('close') }, - onSubmit() { - this.$emit('submit') + async onFinish() { + if (this.emails.length === 0 || this.isShareByMailEnabled === false) { + showSuccess(this.t('files_sharing', 'File request created')) + this.$emit('close') + return + } + + await this.setShareEmails() + await this.sendEmails() + showSuccess(this.t('files_sharing', 'File request created and emails sent')) + this.$emit('close') }, async createShare() { @@ -244,7 +254,7 @@ export default defineComponent({ try { const request = await axios.post(shareUrl, { shareType: Type.SHARE_TYPE_EMAIL, - publicUpload: 'true', + permissions: Permission.CREATE, label: this.label, path: this.destination, @@ -253,13 +263,13 @@ export default defineComponent({ password: this.password || undefined, expireDate, - // Empty string to fallback to the attributes - sharedWith: '', - attributes: JSON.stringify({ - value: this.emails, - key: 'emails', - scope: 'sharedWith', - }) + // Empty string + shareWith: '', + attributes: JSON.stringify([{ + value: true, + key: 'enabled', + scope: 'fileRequest', + }]) }) // If not an ocs request @@ -288,6 +298,74 @@ export default defineComponent({ this.loading = false } }, + + async setShareEmails() { + this.loading = true + + // This should never happen™ + if (!this.share || !this.share?.id) { + throw new Error('Share ID is missing') + } + + const shareUrl = generateOcsUrl('apps/files_sharing/api/v1/shares/' + this.share.id) + try { + // Convert link share to email share + const request = await axios.put(shareUrl, { + attributes: JSON.stringify([{ + value: this.emails, + key: 'emails', + scope: 'shareWith', + }]) + }) + + // If not an ocs request + if (!request?.data?.ocs) { + throw request + } + } catch (error) { + this.onEmailSendError(error) + throw error + } finally { + this.loading = false + } + }, + + async sendEmails () { + this.loading = true + + // This should never happen™ + if (!this.share || !this.share?.id) { + throw new Error('Share ID is missing') + } + + const shareUrl = generateOcsUrl('apps/files_sharing/api/v1/shares/' + this.share.id + '/send-email') + try { + // Convert link share to email share + const request = await axios.post(shareUrl, { + password: this.password || undefined, + }) + + // If not an ocs request + if (!request?.data?.ocs) { + throw request + } + } catch (error) { + this.onEmailSendError(error) + throw error + } finally { + this.loading = false + } + }, + + onEmailSendError(error: AxiosError<OCSResponse>|any) { + const errorMessage = error.response?.data?.ocs?.meta?.message + showError( + errorMessage + ? this.t('files_sharing', 'Error sending emails: {errorMessage}', { errorMessage }) + : this.t('files_sharing', 'Error sending emails'), + ) + logger.error('Error while sending emails', { error, errorMessage }) + }, }, }) </script> diff --git a/apps/files_sharing/src/components/NewFileRequestDialog/FileRequestDatePassword.vue b/apps/files_sharing/src/components/NewFileRequestDialog/FileRequestDatePassword.vue index 6da342da0f1..cf7cf4bcb08 100644 --- a/apps/files_sharing/src/components/NewFileRequestDialog/FileRequestDatePassword.vue +++ b/apps/files_sharing/src/components/NewFileRequestDialog/FileRequestDatePassword.vue @@ -68,7 +68,7 @@ <NcButton :aria-label="t('files_sharing', 'Generate a new password')" :title="t('files_sharing', 'Generate a new password')" type="tertiary-no-background" - @click="generatePassword(); showPassword()"> + @click="onGeneratePassword"> <template #icon> <IconPasswordGen :size="20" /> </template> @@ -90,8 +90,11 @@ import NcPasswordField from '@nextcloud/vue/dist/Components/NcPasswordField.js' import IconPasswordGen from 'vue-material-design-icons/AutoFix.vue' +import Config from '../../services/ConfigService' import GeneratePassword from '../../utils/GeneratePassword' +const sharingConfig = new Config() + export default defineComponent({ name: 'FileRequestDatePassword', @@ -132,16 +135,16 @@ export default defineComponent({ t: translate, // Default expiration date if defaultExpireDateEnabled is true - defaultExpireDate: window.OC.appConfig.core.defaultExpireDate as number, + defaultExpireDate: sharingConfig.defaultExpireDate, // Default expiration date is enabled for public links (can be disabled) - defaultExpireDateEnabled: window.OC.appConfig.core.defaultExpireDateEnabled === true, + defaultExpireDateEnabled: sharingConfig.isDefaultExpireDateEnabled, // Default expiration date is enforced for public links (can't be disabled) - defaultExpireDateEnforced: window.OC.appConfig.core.defaultExpireDateEnforced === true, + defaultExpireDateEnforced: sharingConfig.isDefaultExpireDateEnforced, // Default password protection is enabled for public links (can be disabled) - enableLinkPasswordByDefault: window.OC.appConfig.core.enableLinkPasswordByDefault === true, + enableLinkPasswordByDefault: sharingConfig.enableLinkPasswordByDefault, // Password protection is enforced for public links (can't be disabled) - enforcePasswordForPublicLink: window.OC.appConfig.core.enforcePasswordForPublicLink === true, + enforcePasswordForPublicLink: sharingConfig.enforcePasswordForPublicLink, } }, @@ -176,13 +179,13 @@ export default defineComponent({ mounted() { // If defined, we set the default expiration date - if (this.defaultExpireDate > 0) { - this.$emit('update:deadline', new Date(new Date().setDate(new Date().getDate() + this.defaultExpireDate))) + if (this.defaultExpireDate) { + this.$emit('update:deadline', sharingConfig.defaultExpirationDate) } // If enforced, we cannot set a date before the default expiration days (see admin settings) if (this.defaultExpireDateEnforced) { - this.maxDate = new Date(new Date().setDate(new Date().getDate() + this.defaultExpireDate)) + this.maxDate = sharingConfig.defaultExpirationDate } // If enabled by default, we generate a valid password @@ -204,8 +207,14 @@ export default defineComponent({ this.$emit('update:password', null) }, - generatePassword() { - GeneratePassword().then(password => { + + async onGeneratePassword() { + await this.generatePassword() + this.showPassword() + }, + + async generatePassword() { + await GeneratePassword().then(password => { this.$emit('update:password', password) }) }, diff --git a/apps/files_sharing/src/components/NewFileRequestDialog/FileRequestFinish.vue b/apps/files_sharing/src/components/NewFileRequestDialog/FileRequestFinish.vue index 1162414e049..0c30a8bf261 100644 --- a/apps/files_sharing/src/components/NewFileRequestDialog/FileRequestFinish.vue +++ b/apps/files_sharing/src/components/NewFileRequestDialog/FileRequestFinish.vue @@ -7,7 +7,7 @@ <div> <!-- Request note --> <NcNoteCard type="success"> - {{ t('files_sharing', 'You can now share the link below to allow others to upload files to your directory.') }} + {{ t('files_sharing', 'Once created, you can share the link below to allow people to upload files to your directory.') }} </NcNoteCard> <!-- Copy share link --> @@ -71,7 +71,6 @@ import NcChip from '@nextcloud/vue/dist/Components/NcChip.js' import IconCheck from 'vue-material-design-icons/Check.vue' import IconClipboard from 'vue-material-design-icons/Clipboard.vue' -import { getCapabilities } from '@nextcloud/capabilities' export default defineComponent({ name: 'FileRequestFinish', @@ -95,6 +94,10 @@ export default defineComponent({ type: Array as PropType<string[]>, required: true, }, + isShareByMailEnabled: { + type: Boolean, + required: true, + }, }, emits: ['add-email', 'remove-email'], @@ -103,7 +106,6 @@ export default defineComponent({ return { n: translatePlural, t: translate, - isShareByMailEnabled: getCapabilities()?.files_sharing?.sharebymail?.enabled === true, } }, diff --git a/apps/files_sharing/src/components/SharingEntryLink.vue b/apps/files_sharing/src/components/SharingEntryLink.vue index 210029f617b..e9b7ee44815 100644 --- a/apps/files_sharing/src/components/SharingEntryLink.vue +++ b/apps/files_sharing/src/components/SharingEntryLink.vue @@ -327,6 +327,11 @@ export default { } if (this.share.label && this.share.label.trim() !== '') { if (this.isEmailShareType) { + if (this.isFileRequest) { + return t('files_sharing', 'File request ({label})', { + label: this.share.label.trim(), + }) + } return t('files_sharing', 'Mail share ({label})', { label: this.share.label.trim(), }) @@ -336,6 +341,11 @@ export default { }) } if (this.isEmailShareType) { + if (!this.share.shareWith || this.share.shareWith.trim() === '') { + return this.isFileRequest + ? t('files_sharing', 'File request') + : t('files_sharing', 'Mail share') + } return this.share.shareWith } } @@ -554,9 +564,13 @@ export default { }, canChangeHideDownload() { - const hasDisabledDownload = (shareAttribute) => shareAttribute.key === 'download' && shareAttribute.scope === 'permissions' && shareAttribute.value === false + const hasDisabledDownload = (shareAttribute) => shareAttribute.scope === 'permissions' && shareAttribute.key === 'download'&& shareAttribute.value === false return this.fileInfo.shareAttributes.some(hasDisabledDownload) }, + + isFileRequest() { + return this.share.isFileRequest + }, }, methods: { diff --git a/apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue b/apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue index 0746e9ce61f..f0c2c4f3812 100644 --- a/apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue +++ b/apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue @@ -80,7 +80,7 @@ export default { return t('files_sharing', 'Can edit') }, fileDropText() { - return t('files_sharing', 'File requests') + return t('files_sharing', 'File request') }, customPermissionsText() { return t('files_sharing', 'Custom permissions') diff --git a/apps/files_sharing/src/components/SharingInput.vue b/apps/files_sharing/src/components/SharingInput.vue index e986ff4491f..d9054bc7fc6 100644 --- a/apps/files_sharing/src/components/SharingInput.vue +++ b/apps/files_sharing/src/components/SharingInput.vue @@ -34,7 +34,7 @@ import axios from '@nextcloud/axios' import debounce from 'debounce' import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js' -import Config from '../services/ConfigService.js' +import Config from '../services/ConfigService.ts' import GeneratePassword from '../utils/GeneratePassword.ts' import Share from '../models/Share.js' import ShareRequests from '../mixins/ShareRequests.js' diff --git a/apps/files_sharing/src/mixins/ShareDetails.js b/apps/files_sharing/src/mixins/ShareDetails.js index 6c936b393ea..62b7aea182f 100644 --- a/apps/files_sharing/src/mixins/ShareDetails.js +++ b/apps/files_sharing/src/mixins/ShareDetails.js @@ -4,7 +4,7 @@ */ import Share from '../models/Share.js' -import Config from '../services/ConfigService.js' +import Config from '../services/ConfigService.ts' export default { methods: { diff --git a/apps/files_sharing/src/mixins/SharesMixin.js b/apps/files_sharing/src/mixins/SharesMixin.js index 0d570b16918..ccac8300840 100644 --- a/apps/files_sharing/src/mixins/SharesMixin.js +++ b/apps/files_sharing/src/mixins/SharesMixin.js @@ -14,7 +14,7 @@ import debounce from 'debounce' import Share from '../models/Share.js' import SharesRequests from './ShareRequests.js' import ShareTypes from './ShareTypes.js' -import Config from '../services/ConfigService.js' +import Config from '../services/ConfigService.ts' import logger from '../services/logger.ts' import { diff --git a/apps/files_sharing/src/models/Share.js b/apps/files_sharing/src/models/Share.js index 479d55ca241..dc0f8da082e 100644 --- a/apps/files_sharing/src/models/Share.js +++ b/apps/files_sharing/src/models/Share.js @@ -532,16 +532,27 @@ export default class Share { * @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.value - } + const hasDisabledDownload = (attribute) => { + return attribute.scope === 'permissions' && attribute.key === 'download' && attribute.value === false } + return this.attributes.some(hasDisabledDownload) + } - return true + /** + * Is this mail share a file request ? + * + * @return {boolean} + * @readonly + * @memberof Share + */ + get isFileRequest() { + const isFileRequest = (attribute) => { + return attribute.scope === 'fileRequest' && attribute.key === 'enabled' && attribute.value === true + } + return this.attributes.some(isFileRequest) } + set hasDownloadPermission(enabled) { this.setAttribute('permissions', 'download', !!enabled) } diff --git a/apps/files_sharing/src/services/ConfigService.js b/apps/files_sharing/src/services/ConfigService.js deleted file mode 100644 index 3d9e949724e..00000000000 --- a/apps/files_sharing/src/services/ConfigService.js +++ /dev/null @@ -1,322 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ -import { getCapabilities } from '@nextcloud/capabilities' - -export default class Config { - - constructor() { - this._capabilities = getCapabilities() - } - - /** - * Get default share permissions, if any - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get defaultPermissions() { - return this._capabilities.files_sharing?.default_permissions - } - - /** - * Is public upload allowed on link shares ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isPublicUploadEnabled() { - return this._capabilities.files_sharing?.public.upload - } - - /** - * Are link share allowed ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isShareWithLinkAllowed() { - return document.getElementById('allowShareWithLink') - && document.getElementById('allowShareWithLink').value === 'yes' - } - - /** - * Get the federated sharing documentation link - * - * @return {string} - * @readonly - * @memberof Config - */ - get federatedShareDocLink() { - return OC.appConfig.core.federatedCloudShareDoc - } - - /** - * Get the default link share expiration date - * - * @return {Date|null} - * @readonly - * @memberof Config - */ - get defaultExpirationDate() { - if (this.isDefaultExpireDateEnabled) { - return new Date(new Date().setDate(new Date().getDate() + this.defaultExpireDate)) - } - return null - } - - /** - * Get the default internal expiration date - * - * @return {Date|null} - * @readonly - * @memberof Config - */ - get defaultInternalExpirationDate() { - if (this.isDefaultInternalExpireDateEnabled) { - return new Date(new Date().setDate(new Date().getDate() + this.defaultInternalExpireDate)) - } - return null - } - - /** - * Get the default remote expiration date - * - * @return {Date|null} - * @readonly - * @memberof Config - */ - get defaultRemoteExpirationDateString() { - if (this.isDefaultRemoteExpireDateEnabled) { - return new Date(new Date().setDate(new Date().getDate() + this.defaultRemoteExpireDate)) - } - return null - } - - /** - * Are link shares password-enforced ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get enforcePasswordForPublicLink() { - return OC.appConfig.core.enforcePasswordForPublicLink === true - } - - /** - * Is password asked by default on link shares ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get enableLinkPasswordByDefault() { - return OC.appConfig.core.enableLinkPasswordByDefault === true - } - - /** - * Is link shares expiration enforced ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isDefaultExpireDateEnforced() { - return OC.appConfig.core.defaultExpireDateEnforced === true - } - - /** - * Is there a default expiration date for new link shares ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isDefaultExpireDateEnabled() { - return OC.appConfig.core.defaultExpireDateEnabled === true - } - - /** - * Is internal shares expiration enforced ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isDefaultInternalExpireDateEnforced() { - return OC.appConfig.core.defaultInternalExpireDateEnforced === true - } - - /** - * Is remote shares expiration enforced ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isDefaultRemoteExpireDateEnforced() { - return OC.appConfig.core.defaultRemoteExpireDateEnforced === true - } - - /** - * Is there a default expiration date for new internal shares ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isDefaultInternalExpireDateEnabled() { - return OC.appConfig.core.defaultInternalExpireDateEnabled === true - } - - /** - * Is there a default expiration date for new remote shares ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isDefaultRemoteExpireDateEnabled() { - return OC.appConfig.core.defaultRemoteExpireDateEnabled === true - } - - /** - * Are users on this server allowed to send shares to other servers ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isRemoteShareAllowed() { - return OC.appConfig.core.remoteShareAllowed === true - } - - /** - * Is sharing my mail (link share) enabled ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isMailShareAllowed() { - // eslint-disable-next-line camelcase - return this._capabilities?.files_sharing?.sharebymail !== undefined - // eslint-disable-next-line camelcase - && this._capabilities?.files_sharing?.public?.enabled === true - } - - /** - * Get the default days to link shares expiration - * - * @return {number} - * @readonly - * @memberof Config - */ - get defaultExpireDate() { - return OC.appConfig.core.defaultExpireDate - } - - /** - * Get the default days to internal shares expiration - * - * @return {number} - * @readonly - * @memberof Config - */ - get defaultInternalExpireDate() { - return OC.appConfig.core.defaultInternalExpireDate - } - - /** - * Get the default days to remote shares expiration - * - * @return {number} - * @readonly - * @memberof Config - */ - get defaultRemoteExpireDate() { - return OC.appConfig.core.defaultRemoteExpireDate - } - - /** - * Is resharing allowed ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isResharingAllowed() { - return OC.appConfig.core.resharingAllowed === true - } - - /** - * Is password enforced for mail shares ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get isPasswordForMailSharesRequired() { - return (this._capabilities.files_sharing.sharebymail === undefined) ? false : this._capabilities.files_sharing.sharebymail.password.enforced - } - - /** - * @return {boolean} - * @readonly - * @memberof Config - */ - get shouldAlwaysShowUnique() { - return (this._capabilities.files_sharing?.sharee?.always_show_unique === true) - } - - /** - * Is sharing with groups allowed ? - * - * @return {boolean} - * @readonly - * @memberof Config - */ - get allowGroupSharing() { - return OC.appConfig.core.allowGroupSharing === true - } - - /** - * Get the maximum results of a share search - * - * @return {number} - * @readonly - * @memberof Config - */ - get maxAutocompleteResults() { - return parseInt(OC.config['sharing.maxAutocompleteResults'], 10) || 25 - } - - /** - * Get the minimal string length - * to initiate a share search - * - * @return {number} - * @readonly - * @memberof Config - */ - get minSearchStringLength() { - return parseInt(OC.config['sharing.minSearchStringLength'], 10) || 0 - } - - /** - * Get the password policy config - * - * @return {object} - * @readonly - * @memberof Config - */ - get passwordPolicy() { - return this._capabilities.password_policy ? this._capabilities.password_policy : {} - } - -} diff --git a/apps/files_sharing/src/services/ConfigService.ts b/apps/files_sharing/src/services/ConfigService.ts new file mode 100644 index 00000000000..916de5959c2 --- /dev/null +++ b/apps/files_sharing/src/services/ConfigService.ts @@ -0,0 +1,293 @@ +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +import { getCapabilities } from '@nextcloud/capabilities' + +export default class Config { + _capabilities: Capabilities + + constructor() { + this._capabilities = getCapabilities() as Capabilities + } + + /** + * Get default share permissions, if any + */ + get defaultPermissions(): number { + return this._capabilities.files_sharing?.default_permissions + } + + /** + * Is public upload allowed on link shares ? + * This covers File request and Full upload/edit option. + */ + get isPublicUploadEnabled(): boolean { + return this._capabilities.files_sharing?.public?.upload === true + } + + /** + * Get the federated sharing documentation link + */ + get federatedShareDocLink() { + return window.OC.appConfig.core.federatedCloudShareDoc + } + + /** + * Get the default link share expiration date + */ + get defaultExpirationDate(): Date|null { + if (this.isDefaultExpireDateEnabled && this.defaultExpireDate !== null) { + return new Date(new Date().setDate(new Date().getDate() + this.defaultExpireDate)) + } + return null + } + + /** + * Get the default internal expiration date + */ + get defaultInternalExpirationDate(): Date|null { + if (this.isDefaultInternalExpireDateEnabled && this.defaultInternalExpireDate !== null) { + return new Date(new Date().setDate(new Date().getDate() + this.defaultInternalExpireDate)) + } + return null + } + + /** + * Get the default remote expiration date + */ + get defaultRemoteExpirationDateString(): Date|null { + if (this.isDefaultRemoteExpireDateEnabled && this.defaultRemoteExpireDate !== null) { + return new Date(new Date().setDate(new Date().getDate() + this.defaultRemoteExpireDate)) + } + return null + } + + /** + * Are link shares password-enforced ? + */ + get enforcePasswordForPublicLink(): boolean { + return window.OC.appConfig.core.enforcePasswordForPublicLink === true + } + + /** + * Is password asked by default on link shares ? + */ + get enableLinkPasswordByDefault(): boolean { + return window.OC.appConfig.core.enableLinkPasswordByDefault === true + } + + /** + * Is link shares expiration enforced ? + */ + get isDefaultExpireDateEnforced(): boolean { + return window.OC.appConfig.core.defaultExpireDateEnforced === true + } + + /** + * Is there a default expiration date for new link shares ? + */ + get isDefaultExpireDateEnabled(): boolean { + return window.OC.appConfig.core.defaultExpireDateEnabled === true + } + + /** + * Is internal shares expiration enforced ? + */ + get isDefaultInternalExpireDateEnforced(): boolean { + return window.OC.appConfig.core.defaultInternalExpireDateEnforced === true + } + + /** + * Is there a default expiration date for new internal shares ? + */ + get isDefaultInternalExpireDateEnabled(): boolean { + return window.OC.appConfig.core.defaultInternalExpireDateEnabled === true + } + + /** + * Is remote shares expiration enforced ? + */ + get isDefaultRemoteExpireDateEnforced(): boolean { + return window.OC.appConfig.core.defaultRemoteExpireDateEnforced === true + } + + /** + * Is there a default expiration date for new remote shares ? + */ + get isDefaultRemoteExpireDateEnabled(): boolean { + return window.OC.appConfig.core.defaultRemoteExpireDateEnabled === true + } + + /** + * Are users on this server allowed to send shares to other servers ? + */ + get isRemoteShareAllowed(): boolean { + return window.OC.appConfig.core.remoteShareAllowed === true + } + + /** + * Is sharing my mail (link share) enabled ? + */ + get isMailShareAllowed(): boolean { + // eslint-disable-next-line camelcase + return this._capabilities?.files_sharing?.sharebymail?.enabled === true + // eslint-disable-next-line camelcase + && this._capabilities?.files_sharing?.public?.enabled === true + } + + /** + * Get the default days to link shares expiration + */ + get defaultExpireDate(): number|null { + return window.OC.appConfig.core.defaultExpireDate + } + + /** + * Get the default days to internal shares expiration + */ + get defaultInternalExpireDate(): number|null { + return window.OC.appConfig.core.defaultInternalExpireDate + } + + /** + * Get the default days to remote shares expiration + */ + get defaultRemoteExpireDate(): number|null { + return window.OC.appConfig.core.defaultRemoteExpireDate + } + + /** + * Is resharing allowed ? + */ + get isResharingAllowed(): boolean { + return window.OC.appConfig.core.resharingAllowed === true + } + + /** + * Is password enforced for mail shares ? + */ + get isPasswordForMailSharesRequired(): boolean { + return this._capabilities.files_sharing?.sharebymail?.password?.enforced === true + } + + /** + * Always show the email or userid unique sharee label if enabled by the admin + */ + get shouldAlwaysShowUnique(): boolean { + return this._capabilities.files_sharing?.sharee?.always_show_unique === true + } + + /** + * Is sharing with groups allowed ? + */ + get allowGroupSharing(): boolean { + return window.OC.appConfig.core.allowGroupSharing === true + } + + /** + * Get the maximum results of a share search + */ + get maxAutocompleteResults(): number { + return parseInt(window.OC.config['sharing.maxAutocompleteResults'], 10) || 25 + } + + /** + * Get the minimal string length + * to initiate a share search + */ + get minSearchStringLength(): number { + return parseInt(window.OC.config['sharing.minSearchStringLength'], 10) || 0 + } + + /** + * Get the password policy configuration + */ + get passwordPolicy(): PasswordPolicyCapabilities { + return this._capabilities?.password_policy || {} + } + +} + +type PasswordPolicyCapabilities = { + enforceNonCommonPassword: boolean + enforceNumericCharacters: boolean + enforceSpecialCharacters: boolean + enforceUpperLowerCase: boolean + minLength: number +} + +type FileSharingCapabilities = { + api_enabled: boolean, + public: { + enabled: boolean, + password: { + enforced: boolean, + askForOptionalPassword: boolean + }, + expire_date: { + enabled: boolean, + days: number, + enforced: boolean + }, + multiple_links: boolean, + expire_date_internal: { + enabled: boolean + }, + expire_date_remote: { + enabled: boolean + }, + send_mail: boolean, + upload: boolean, + upload_files_drop: boolean + }, + resharing: boolean, + user: { + send_mail: boolean, + expire_date: { + enabled: boolean + } + }, + group_sharing: boolean, + group: { + enabled: boolean, + expire_date: { + enabled: true + } + }, + default_permissions: number, + federation: { + outgoing: boolean, + incoming: boolean, + expire_date: { + enabled: boolean + }, + expire_date_supported: { + enabled: boolean + } + }, + sharee: { + query_lookup_default: boolean, + always_show_unique: boolean + }, + sharebymail: { + enabled: boolean, + send_password_by_mail: boolean, + upload_files_drop: { + enabled: boolean + }, + password: { + enabled: boolean, + enforced: boolean + }, + expire_date: { + enabled: boolean, + enforced: boolean + } + } +} + +type Capabilities = { + files_sharing: FileSharingCapabilities + password_policy: PasswordPolicyCapabilities +} diff --git a/apps/files_sharing/src/utils/GeneratePassword.ts b/apps/files_sharing/src/utils/GeneratePassword.ts index c7839fe6302..bbfa5e7b27d 100644 --- a/apps/files_sharing/src/utils/GeneratePassword.ts +++ b/apps/files_sharing/src/utils/GeneratePassword.ts @@ -4,7 +4,7 @@ */ import axios from '@nextcloud/axios' -import Config from '../services/ConfigService.js' +import Config from '../services/ConfigService.ts' import { showError, showSuccess } from '@nextcloud/dialogs' import { translate as t } from '@nextcloud/l10n' diff --git a/apps/files_sharing/src/views/SharingDetailsTab.vue b/apps/files_sharing/src/views/SharingDetailsTab.vue index 610f9b99eac..023c137a254 100644 --- a/apps/files_sharing/src/views/SharingDetailsTab.vue +++ b/apps/files_sharing/src/views/SharingDetailsTab.vue @@ -62,7 +62,7 @@ type="radio" button-variant-grouped="vertical" @update:checked="toggleCustomPermissions"> - {{ t('files_sharing', 'File requests') }} + {{ t('files_sharing', 'File request') }} <small class="subline">{{ t('files_sharing', 'Upload only') }}</small> <template #icon> <UploadIcon :size="20" /> diff --git a/apps/files_sharing/src/views/SharingTab.vue b/apps/files_sharing/src/views/SharingTab.vue index 7e58cb6401e..98c40a0a933 100644 --- a/apps/files_sharing/src/views/SharingTab.vue +++ b/apps/files_sharing/src/views/SharingTab.vue @@ -88,7 +88,7 @@ import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js' import axios from '@nextcloud/axios' import { loadState } from '@nextcloud/initial-state' -import Config from '../services/ConfigService.js' +import Config from '../services/ConfigService.ts' import { shareWithTitle } from '../utils/SharedWithMe.js' import Share from '../models/Share.js' import ShareTypes from '../mixins/ShareTypes.js' |