diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2023-11-16 21:53:14 +0100 |
---|---|---|
committer | Ferdinand Thiessen <opensource@fthiessen.de> | 2023-11-20 17:07:55 +0100 |
commit | 22163c60d42bbd60181818d315442f98fbbe89d0 (patch) | |
tree | 2f35ec0757a3166d9c29734da8995ead9ec73a92 /apps/settings/src | |
parent | e5b996722a3f850bec68490d467e8c565f3a3341 (diff) | |
download | nextcloud-server-22163c60d42bbd60181818d315442f98fbbe89d0.tar.gz nextcloud-server-22163c60d42bbd60181818d315442f98fbbe89d0.zip |
enh(settings): Migrate admin settings for sharing to vue
This is required to get the fixes for a11y from `@nextcloud/vue`.
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/settings/src')
-rw-r--r-- | apps/settings/src/.jshintrc | 3 | ||||
-rw-r--r-- | apps/settings/src/admin-settings-sharing.ts | 30 | ||||
-rw-r--r-- | apps/settings/src/admin.js | 133 | ||||
-rw-r--r-- | apps/settings/src/components/AdminSettingsSharingForm.vue | 355 | ||||
-rw-r--r-- | apps/settings/src/components/SelectSharingPermissions.vue | 100 | ||||
-rw-r--r-- | apps/settings/src/views/AdminSettingsSharing.vue | 62 |
6 files changed, 547 insertions, 136 deletions
diff --git a/apps/settings/src/.jshintrc b/apps/settings/src/.jshintrc deleted file mode 100644 index fc024bea970..00000000000 --- a/apps/settings/src/.jshintrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "esversion": 6 -} diff --git a/apps/settings/src/admin-settings-sharing.ts b/apps/settings/src/admin-settings-sharing.ts new file mode 100644 index 00000000000..2cb269f9a5d --- /dev/null +++ b/apps/settings/src/admin-settings-sharing.ts @@ -0,0 +1,30 @@ +/** + * @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de> + * + * @author Ferdinand Thiessen <opensource@fthiessen.de> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import Vue from 'vue' +import AdminSettingsSharing from './views/AdminSettingsSharing.vue' + +export default new Vue({ + name: 'AdminSettingsSharingSection', + el: '#vue-admin-settings-sharing', + render: (h) => h(AdminSettingsSharing), +}) diff --git a/apps/settings/src/admin.js b/apps/settings/src/admin.js index c8d04049ded..35f5266acba 100644 --- a/apps/settings/src/admin.js +++ b/apps/settings/src/admin.js @@ -1,133 +1,10 @@ window.addEventListener('DOMContentLoaded', () => { - $('#linksExcludedGroups,#passwordsExcludedGroups').each(function(index, element) { - OC.Settings.setupGroupsSelect($(element)) - $(element).change(function(ev) { - let groups = ev.val || [] - groups = JSON.stringify(groups) - OCP.AppConfig.setValue('core', $(this).attr('name'), groups) - }) - }) - $('#loglevel').change(function() { $.post(OC.generateUrl('/settings/admin/log/level'), { level: $(this).val() }, () => { OC.Log.reload() }) }) - $('#shareAPIEnabled').change(function() { - $('#shareAPI p:not(#enable)').toggleClass('hidden', !this.checked) - }) - - $('#shareapiExpireAfterNDays').on('input', function() { - this.value = this.value.replace(/\D/g, '') - }) - - $('#shareAPI input:not(.noJSAutoUpdate)').change(function() { - let value = $(this).val() - if ($(this).attr('type') === 'checkbox') { - if (this.checked) { - value = 'yes' - } else { - value = 'no' - } - } - OCP.AppConfig.setValue('core', $(this).attr('name'), value) - }) - - $('#shareapiDefaultExpireDate').change(function() { - $('#setDefaultExpireDate').toggleClass('hidden', !this.checked) - }) - - $('#shareapiDefaultInternalExpireDate').change(function() { - $('#setDefaultInternalExpireDate').toggleClass('hidden', !this.checked) - }) - - $('#shareapiDefaultRemoteExpireDate').change(function() { - $('#setDefaultRemoteExpireDate').toggleClass('hidden', !this.checked) - }) - - $('#enableLinkPasswordByDefault').change(function() { - if (this.checked) { - $('#enforceLinkPassword').removeAttr('disabled') - $('#passwordsExcludedGroups').removeAttr('disabled') - } else { - $('#enforceLinkPassword').attr('disabled', '') - $('#passwordsExcludedGroups').attr('disabled', '') - - // Uncheck "Enforce password protection" when "Always asks for a - // password" is unchecked; the change event needs to be explicitly - // triggered so it behaves like a change done by the user. - $('#enforceLinkPassword').removeAttr('checked').trigger('change') - } - }) - - $('#enforceLinkPassword').change(function() { - $('#selectPasswordsExcludedGroups').toggleClass('hidden', !this.checked) - }) - - $('#publicShareDisclaimer').change(function() { - $('#publicShareDisclaimerText').toggleClass('hidden', !this.checked) - if (!this.checked) { - savePublicShareDisclaimerText('') - } - }) - - $('#shareApiDefaultPermissionsSection input').change(function(ev) { - const $el = $('#shareApiDefaultPermissions') - const $target = $(ev.target) - - let value = $el.val() - if ($target.is(':checked')) { - value = value | $target.val() - } else { - value = value & ~$target.val() - } - - // always set read permission - value |= OC.PERMISSION_READ - - // this will trigger the field's change event and will save it - $el.val(value).change() - - ev.preventDefault() - - return false - }) - - const savePublicShareDisclaimerText = _.debounce(function(value) { - const options = { - success: () => { - OC.msg.finishedSuccess('#publicShareDisclaimerStatus', t('settings', 'Saved')) - }, - error: () => { - OC.msg.finishedError('#publicShareDisclaimerStatus', t('settings', 'Not saved')) - }, - } - - OC.msg.startSaving('#publicShareDisclaimerStatus') - if (_.isString(value) && value !== '') { - OCP.AppConfig.setValue('core', 'shareapi_public_link_disclaimertext', value, options) - } else { - $('#publicShareDisclaimerText').val('') - OCP.AppConfig.deleteKey('core', 'shareapi_public_link_disclaimertext', options) - } - }, 500) - - $('#publicShareDisclaimerText').on('change, keyup', function() { - savePublicShareDisclaimerText(this.value) - }) - - $('#shareapi_allow_share_dialog_user_enumeration').on('change', function() { - $('#shareapi_restrict_user_enumeration_to_group_setting').toggleClass('hidden', !this.checked) - $('#shareapi_restrict_user_enumeration_to_phone_setting').toggleClass('hidden', !this.checked) - $('#shareapi_restrict_user_enumeration_combinewarning_setting').toggleClass('hidden', !this.checked) - }) - - $('#allowLinks').change(function() { - $('#publicLinkSettings').toggleClass('hidden', !this.checked) - $('#setDefaultExpireDate').toggleClass('hidden', !(this.checked && $('#shareapiDefaultExpireDate')[0].checked)) - }) - $('#mail_smtpauth').change(function() { if (!this.checked) { $('#mail_credentials').addClass('hidden') @@ -221,14 +98,6 @@ window.addEventListener('DOMContentLoaded', () => { }) }) - $('#allowGroupSharing').change(function() { - $('#allowGroupSharing').toggleClass('hidden', !this.checked) - }) - - $('#shareapiExcludeGroups').change(function() { - $('#selectExcludedGroups').toggleClass('hidden', !this.checked) - }) - const setupChecks = () => { // run setup checks then gather error messages $.when( @@ -301,6 +170,4 @@ window.addEventListener('DOMContentLoaded', () => { if (document.getElementById('security-warning') !== null) { setupChecks() } - - $('#shareAPI').removeClass('loading') }) diff --git a/apps/settings/src/components/AdminSettingsSharingForm.vue b/apps/settings/src/components/AdminSettingsSharingForm.vue new file mode 100644 index 00000000000..de23adf67d2 --- /dev/null +++ b/apps/settings/src/components/AdminSettingsSharingForm.vue @@ -0,0 +1,355 @@ +<!-- + - @copyright 2023 Ferdinand Thiessen <opensource@fthiessen.de> + - + - @author Ferdinand Thiessen <opensource@fthiessen.de> + - + - @license AGPL-3.0-or-later + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - +--> +<template> + <form class="sharing"> + <NcCheckboxRadioSwitch aria-controls="settings-sharing-api settings-sharing-api-settings settings-sharing-default-permissions settings-sharing-privary-related" + type="switch" + :checked.sync="settings.enabled"> + {{ t('settings', 'Allow apps to use the Share API') }} + </NcCheckboxRadioSwitch> + + <div v-show="settings.enabled" id="settings-sharing-api-settings" class="sharing__sub-section"> + <NcCheckboxRadioSwitch :checked.sync="settings.allowResharing"> + {{ t('settings', 'Allow resharing') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch :checked.sync="settings.allowGroupSharing"> + {{ t('settings', 'Allow sharing with groups') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch :checked.sync="settings.onlyShareWithGroupMembers"> + {{ t('settings', 'Restrict users to only share with users in their groups') }} + </NcCheckboxRadioSwitch> + </div> + + <div v-show="settings.enabled" id="settings-sharing-api" class="sharing__section"> + <NcCheckboxRadioSwitch type="switch" + aria-controls="settings-sharing-api-public-link" + :checked.sync="settings.allowLinks"> + {{ t('settings', 'Allow users to share via link and emails') }} + </NcCheckboxRadioSwitch> + <fieldset v-show="settings.allowLinks" id="settings-sharing-api-public-link" class="sharing__sub-section"> + <NcCheckboxRadioSwitch :checked.sync="settings.allowPublicUpload"> + {{ t('settings', 'Allow public uploads') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch :checked.sync="settings.enableLinkPasswordByDefault"> + {{ t('settings', 'Always ask for a password') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch :checked.sync="settings.enforceLinksPassword" :disabled="!settings.enableLinkPasswordByDefault"> + {{ t('settings', 'Enforce password protection') }} + </NcCheckboxRadioSwitch> + <label v-if="settings.passwordExcludedGroupsFeatureEnabled" class="sharing__labeled-entry sharing__input"> + <span>{{ t('settings', 'Exclude groups from password requirements') }}</span> + <NcSettingsSelectGroup v-model="settings.passwordExcludedGroups" + style="width: 100%" + :disabled="!settings.enforceLinksPassword || !settings.enableLinkPasswordByDefault" /> + </label> + <label class="sharing__labeled-entry sharing__input"> + <span>{{ t('settings', 'Exclude groups from creating link shares') }}</span> + <NcSettingsSelectGroup v-model="settings.allowLinksExcludeGroups" + :label="t('settings', 'Exclude groups from creating link shares')" + style="width: 100%" /> + </label> + </fieldset> + + <NcCheckboxRadioSwitch type="switch" :checked.sync="settings.excludeGroups"> + {{ t('settings', 'Exclude groups from sharing') }} + </NcCheckboxRadioSwitch> + <div v-show="settings.excludeGroups" class="sharing__sub-section"> + <div class="sharing__labeled-entry sharing__input"> + <label for="settings-sharing-excluded-groups">{{ t('settings', 'Groups excluded from sharing') }}</label> + <NcSettingsSelectGroup id="settings-sharing-excluded-groups" + v-model="settings.excludeGroupsList" + aria-describedby="settings-sharing-excluded-groups-desc" + :label="t('settings', 'Groups excluded from sharing')" + :disabled="!settings.excludeGroups" + style="width: 100%" /> + <em id="settings-sharing-excluded-groups-desc">{{ t('settings', 'These groups will still be able to receive shares, but not to initiate them.') }}</em> + </div> + </div> + + <NcCheckboxRadioSwitch type="switch" + aria-controls="settings-sharing-api-expiration" + :checked.sync="settings.defaultInternalExpireDate"> + {{ t('settings', 'Set default expiration date for shares') }} + </NcCheckboxRadioSwitch> + <fieldset v-show="settings.defaultInternalExpireDate" id="settings-sharing-api-expiration" class="sharing__sub-section"> + <NcCheckboxRadioSwitch :checked.sync="settings.enforceInternalExpireDate"> + {{ t('settings', 'Enforce expiration date') }} + </NcCheckboxRadioSwitch> + <NcTextField type="number" + class="sharing__input" + :label="t('settings', 'Default expiration time of new shares in days')" + :placeholder="t('settings', 'Expire shares after x days')" + :value.sync="settings.internalExpireAfterNDays" /> + </fieldset> + + <NcCheckboxRadioSwitch type="switch" + aria-controls="settings-sharing-remote-api-expiration" + :checked.sync="settings.defaultRemoteExpireDate"> + {{ t('settings', 'Set default expiration date for shares to other servers') }} + </NcCheckboxRadioSwitch> + <fieldset v-show="settings.defaultRemoteExpireDate" id="settings-sharing-remote-api-expiration" class="sharing__sub-section"> + <NcCheckboxRadioSwitch :checked.sync="settings.enforceRemoteExpireDate"> + {{ t('settings', 'Enforce expiration date for remote shares') }} + </NcCheckboxRadioSwitch> + <NcTextField type="number" + class="sharing__input" + :label="t('settings', 'Default expiration time of remote shares in days')" + :placeholder="t('settings', 'Expire remote shares after x days')" + :value.sync="settings.remoteExpireAfterNDays" /> + </fieldset> + + <NcCheckboxRadioSwitch type="switch" + aria-controls="settings-sharing-api-api-expiration" + :checked.sync="settings.defaultExpireDate" + :disabled="!settings.allowLinks"> + {{ t('settings', 'Set default expiration date for shares via link or mail') }} + </NcCheckboxRadioSwitch> + <fieldset v-show="settings.allowLinks && settings.defaultExpireDate" id="settings-sharing-link-api-expiration" class="sharing__sub-section"> + <NcCheckboxRadioSwitch :checked.sync="settings.enforceExpireDate"> + {{ t('settings', 'Enforce expiration date for remote shares') }} + </NcCheckboxRadioSwitch> + <NcTextField type="number" + class="sharing__input" + :label="t('settings', 'Default expiration time of shares in days')" + :placeholder="t('settings', 'Expire shares after x days')" + :value.sync="settings.expireAfterNDays" /> + </fieldset> + </div> + + <div v-show="settings.enabled" id="settings-sharing-privary-related" class="sharing__section"> + <h3>{{ t('settings', 'Privacy settings for sharing') }}</h3> + + <NcCheckboxRadioSwitch type="switch" + aria-controls="settings-sharing-privacy-user-enumeration" + :checked.sync="settings.allowShareDialogUserEnumeration"> + {{ t('settings', 'Allow username autocompletion in share dialog and allow access to the system address book') }} + </NcCheckboxRadioSwitch> + <fieldset v-show="settings.allowShareDialogUserEnumeration" id="settings-sharing-privacy-user-enumeration" class="sharing__sub-section"> + <em> + {{ t('settings', 'If autocompletion "same group" and "phone number integration" are enabled a match in either is enough to show the user.') }} + </em> + <NcCheckboxRadioSwitch :checked.sync="settings.restrictUserEnumerationToGroup"> + {{ t('settings', 'Allow username autocompletion to users within the same groups and limit system address books to users in the same groups') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch :checked.sync="settings.restrictUserEnumerationToPhone"> + {{ t('settings', 'Allow username autocompletion to users based on phone number integration') }} + </NcCheckboxRadioSwitch> + </fieldset> + + <NcCheckboxRadioSwitch type="switch" :checked.sync="settings.restrictUserEnumerationFullMatch"> + {{ t('settings', 'Allow autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)') }} + </NcCheckboxRadioSwitch> + + <NcCheckboxRadioSwitch type="switch" + aria-controls="settings-sharing-privary-related-disclaimer" + :checked.sync="publicShareDisclaimerEnabled"> + {{ t('settings', 'Show disclaimer text on the public link upload page (only shown when the file list is hidden)') }} + </NcCheckboxRadioSwitch> + <div v-if="typeof settings.publicShareDisclaimerText === 'string'" + id="settings-sharing-privary-related-disclaimer" + aria-describedby="settings-sharing-privary-related-disclaimer-hint" + class="sharing__sub-section"> + <NcTextArea class="sharing__input" + :label="t('settings', 'Disclaimer text')" + :value="settings.publicShareDisclaimerText" + @update:value="onUpdateDisclaimer" /> + <em id="settings-sharing-privary-related-disclaimer-hint" class="sharing__input"> + {{ t('settings', 'This text will be shown on the public link upload page when the file list is hidden.') }} + </em> + </div> + </div> + + <div id="settings-sharing-default-permissions" class="sharing__section"> + <h3>{{ t('settings', 'Default share permissions') }}</h3> + <SelectSharingPermissions :value.sync="settings.defaultPermissions" /> + </div> + </form> +</template> + +<script lang="ts"> +import { + NcCheckboxRadioSwitch, + NcSettingsSelectGroup, + NcTextArea, + NcTextField, +} from '@nextcloud/vue' +import { showError, showSuccess } from '@nextcloud/dialogs' +import { translate as t } from '@nextcloud/l10n' +import { loadState } from '@nextcloud/initial-state' +import { defineComponent } from 'vue' + +import SelectSharingPermissions from './SelectSharingPermissions.vue' +import { snakeCase, debounce } from 'lodash' + +interface IShareSettings { + enabled: boolean + allowGroupSharing: boolean + allowLinks: boolean + allowLinksExcludeGroups: unknown + allowPublicUpload: boolean + allowResharing: boolean + allowShareDialogUserEnumeration: boolean + restrictUserEnumerationToGroup: boolean + restrictUserEnumerationToPhone: boolean + restrictUserEnumerationFullMatch: boolean + restrictUserEnumerationFullMatchUserId: boolean + restrictUserEnumerationFullMatchEmail: boolean + restrictUserEnumerationFullMatchIgnoreSecondDN: boolean + enforceLinksPassword: boolean + passwordExcludedGroups: string[] + passwordExcludedGroupsFeatureEnabled: boolean + onlyShareWithGroupMembers: boolean + defaultExpireDate: boolean + expireAfterNDays: string + enforceExpireDate: boolean + excludeGroups: boolean + excludeGroupsList: string[] + publicShareDisclaimerText?: string + enableLinkPasswordByDefault: boolean + defaultPermissions: number + defaultInternalExpireDate: boolean + internalExpireAfterNDays: string + enforceInternalExpireDate: boolean + defaultRemoteExpireDate: boolean + remoteExpireAfterNDays: string + enforceRemoteExpireDate: boolean +} + +export default defineComponent({ + name: 'AdminSettingsSharingForm', + components: { + NcCheckboxRadioSwitch, + NcSettingsSelectGroup, + NcTextArea, + NcTextField, + SelectSharingPermissions, + }, + data() { + return { + settingsData: loadState<IShareSettings>('settings', 'sharingSettings'), + } + }, + computed: { + settings() { + console.warn('new proxy') + return new Proxy(this.settingsData, { + get(target, property) { + return target[property] + }, + set(target, property: string, newValue) { + const configName = `shareapi_${snakeCase(property)}` + const value = typeof newValue === 'boolean' ? (newValue ? 'yes' : 'no') : (typeof newValue === 'string' ? newValue : JSON.stringify(newValue)) + window.OCP.AppConfig.setValue('core', configName, value) + target[property] = newValue + return true + }, + }) + }, + publicShareDisclaimerEnabled: { + get() { + return typeof this.settingsData.publicShareDisclaimerText === 'string' + }, + set(value) { + if (value) { + this.settingsData.publicShareDisclaimerText = '' + } else { + this.onUpdateDisclaimer() + } + }, + }, + }, + methods: { + t, + + onUpdateDisclaimer: debounce(function(value?: string) { + const options = { + success() { + if (value) { + showSuccess(t('settings', 'Changed disclaimer text')) + } else { + showSuccess(t('settings', 'Deleted disclaimer text')) + } + }, + error() { + showError(t('settings', 'Could not set disclaimer text')) + }, + } + if (!value) { + window.OCP.AppConfig.deleteKey('core', 'shareapi_public_link_disclaimertext', options) + } else { + window.OCP.AppConfig.setValue('core', 'shareapi_public_link_disclaimertext', value, options) + } + this.settingsData.publicShareDisclaimerText = value + }, 500) as (v?: string) => void, + }, +}) +</script> + +<style scoped lang="scss"> +.sharing { + display: flex; + flex-direction: column; + gap: 12px; + + &__labeled-entry { + display: flex; + flex: 1 0; + flex-direction: column; + gap: 4px; + } + + &__section { + display: flex; + flex-direction: column; + gap: 4px; + margin-block-end: 12px + } + + &__sub-section { + display: flex; + flex-direction: column; + gap: 4px; + + margin-inline-start: 44px; + margin-block-end: 12px + } + + &__input { + max-width: 500px; + // align with checkboxes + margin-inline-start: 14px; + + :deep(.v-select.select) { + width: 100%; + } + } +} + +@media only screen and (max-width: 350px) { + // ensure no overflow happens on small devices (required for WCAG) + .sharing { + &__sub-section { + margin-inline-start: 14px; + } + } +} +</style> diff --git a/apps/settings/src/components/SelectSharingPermissions.vue b/apps/settings/src/components/SelectSharingPermissions.vue new file mode 100644 index 00000000000..278b7b623df --- /dev/null +++ b/apps/settings/src/components/SelectSharingPermissions.vue @@ -0,0 +1,100 @@ +<!-- + - @copyright 2023 Ferdinand Thiessen <opensource@fthiessen.de> + - + - @author Ferdinand Thiessen <opensource@fthiessen.de> + - + - @license AGPL-3.0-or-later + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - +--> +<template> + <fieldset class="permissions-select"> + <NcCheckboxRadioSwitch :checked="canCreate" @update:checked="toggle(PERMISSION_CREATE)"> + {{ t('settings', 'Create') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch :checked="canUpdate" @update:checked="toggle(PERMISSION_UPDATE)"> + {{ t('settings', 'Change') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch :checked="canDelete" @update:checked="toggle(PERMISSION_DELETE)"> + {{ t('settings', 'Delete') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch :checked="canShare" @update:checked="toggle(PERMISSION_SHARE)"> + {{ t('settings', 'Reshare') }} + </NcCheckboxRadioSwitch> + </fieldset> +</template> + +<script lang="ts"> +import { translate } from '@nextcloud/l10n' +import { NcCheckboxRadioSwitch } from '@nextcloud/vue' +import { defineComponent } from 'vue' + +export default defineComponent({ + name: 'SelectSharingPermissions', + components: { + NcCheckboxRadioSwitch, + }, + props: { + value: { + type: Number, + required: true, + }, + }, + emits: { + 'update:value': (value: number) => typeof value === 'number', + }, + data() { + return { + PERMISSION_UPDATE: 2, + PERMISSION_CREATE: 4, + PERMISSION_DELETE: 8, + PERMISSION_SHARE: 16, + } + }, + computed: { + canCreate() { + return (this.value & this.PERMISSION_CREATE) !== 0 + }, + canUpdate() { + return (this.value & this.PERMISSION_UPDATE) !== 0 + }, + canDelete() { + return (this.value & this.PERMISSION_DELETE) !== 0 + }, + canShare() { + return (this.value & this.PERMISSION_SHARE) !== 0 + }, + }, + methods: { + t: translate, + /** + * Toggle a permission + * @param permission The permission (bit) to toggle + */ + toggle(permission: number) { + // xor to toggle the bit + this.$emit('update:value', this.value ^ permission) + }, + }, +}) +</script> + +<style scoped> +.permissions-select { + display: flex; + flex-wrap: wrap; + gap: 4px; +} +</style> diff --git a/apps/settings/src/views/AdminSettingsSharing.vue b/apps/settings/src/views/AdminSettingsSharing.vue new file mode 100644 index 00000000000..c0846969a11 --- /dev/null +++ b/apps/settings/src/views/AdminSettingsSharing.vue @@ -0,0 +1,62 @@ +<!-- + - @copyright 2023 Ferdinand Thiessen <opensource@fthiessen.de> + - + - @author Ferdinand Thiessen <opensource@fthiessen.de> + - + - @license AGPL-3.0-or-later + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - +--> +<template> + <NcSettingsSection data-cy-settings-sharing-section + :limit-width="true" + :doc-url="documentationLink" + :name="t('settings', 'Sharing')" + :description="t('settings', 'As admin you can fine-tune the sharing behavior. Please see the documentation for more information.')"> + <NcNoteCard v-if="!sharingAppEnabled" type="warning"> + {{ t('settings', 'You need to enable the File sharing App.') }} + </NcNoteCard> + <AdminSettingsSharingForm v-else /> + </NcSettingsSection> +</template> + +<script lang="ts"> +import { + NcNoteCard, + NcSettingsSection, +} from '@nextcloud/vue' +import { loadState } from '@nextcloud/initial-state' +import { translate as t } from '@nextcloud/l10n' +import { defineComponent } from 'vue' +import AdminSettingsSharingForm from '../components/AdminSettingsSharingForm.vue' + +export default defineComponent({ + name: 'AdminSettingsSharing', + components: { + AdminSettingsSharingForm, + NcNoteCard, + NcSettingsSection, + }, + data() { + return { + documentationLink: loadState<string>('settings', 'sharingDocumentation', ''), + sharingAppEnabled: loadState<boolean>('settings', 'sharingAppEnabled', false), + } + }, + methods: { + t, + }, +}) +</script> |