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 | |
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>
-rw-r--r-- | apps/settings/lib/Settings/Admin/Sharing.php | 133 | ||||
-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 | ||||
-rw-r--r-- | apps/settings/templates/settings/admin/sharing.php | 265 | ||||
-rw-r--r-- | webpack.modules.js | 1 |
9 files changed, 603 insertions, 479 deletions
diff --git a/apps/settings/lib/Settings/Admin/Sharing.php b/apps/settings/lib/Settings/Admin/Sharing.php index 32b09f333a9..f4d3a5c107b 100644 --- a/apps/settings/lib/Settings/Admin/Sharing.php +++ b/apps/settings/lib/Settings/Admin/Sharing.php @@ -13,8 +13,9 @@ * @author Sascha Wiswedel <sascha.wiswedel@nextcloud.com> * @author Vincent Petry <vincent@nextcloud.com> * @author Thomas Citharel <nextcloud@tcit.fr> + * @author Ferdinand Thiessen <opensource@fthiessen.de> * - * @license GNU AGPL version 3 or any later version + * @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 @@ -34,31 +35,25 @@ namespace OCA\Settings\Settings\Admin; use OCP\App\IAppManager; use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Services\IInitialState; use OCP\Constants; use OCP\IConfig; use OCP\IL10N; +use OCP\IURLGenerator; use OCP\Settings\IDelegatedSettings; use OCP\Share\IManager; use OCP\Util; class Sharing implements IDelegatedSettings { - /** @var IConfig */ - private $config; - - /** @var IL10N */ - private $l; - - /** @var IManager */ - private $shareManager; - - /** @var IAppManager */ - private $appManager; - - public function __construct(IConfig $config, IL10N $l, IManager $shareManager, IAppManager $appManager) { - $this->config = $config; - $this->l = $l; - $this->shareManager = $shareManager; - $this->appManager = $appManager; + public function __construct( + private IConfig $config, + private IL10N $l, + private IManager $shareManager, + private IAppManager $appManager, + private IURLGenerator $urlGenerator, + private IInitialState $initialState, + private string $appName, + ) { } /** @@ -66,85 +61,57 @@ class Sharing implements IDelegatedSettings { */ public function getForm() { $excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', ''); - $excludeGroupsList = !is_null(json_decode($excludedGroups)) - ? implode('|', json_decode($excludedGroups, true)) : ''; $linksExcludedGroups = $this->config->getAppValue('core', 'shareapi_allow_links_exclude_groups', ''); - $linksExcludeGroupsList = !is_null(json_decode($linksExcludedGroups)) - ? implode('|', json_decode($linksExcludedGroups, true)) : ''; - $excludedPasswordGroups = $this->config->getAppValue('core', 'shareapi_enforce_links_password_excluded_groups', ''); - $excludedPasswordGroupsList = !is_null(json_decode($excludedPasswordGroups)) - ? implode('|', json_decode($excludedPasswordGroups, true)) : ''; - $parameters = [ // Built-In Sharing - 'sharingAppEnabled' => $this->appManager->isEnabledForUser('files_sharing'), - 'allowGroupSharing' => $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes'), - 'allowLinks' => $this->config->getAppValue('core', 'shareapi_allow_links', 'yes'), - 'allowLinksExcludeGroups' => $linksExcludeGroupsList, - 'allowPublicUpload' => $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes'), - 'allowResharing' => $this->config->getAppValue('core', 'shareapi_allow_resharing', 'yes'), - 'allowShareDialogUserEnumeration' => $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes'), - 'restrictUserEnumerationToGroup' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no'), - 'restrictUserEnumerationToPhone' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no'), - 'restrictUserEnumerationFullMatch' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes'), - 'restrictUserEnumerationFullMatchUserId' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_userid', 'yes'), - 'restrictUserEnumerationFullMatchEmail' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_email', 'yes'), - 'restrictUserEnumerationFullMatchIgnoreSecondDN' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_ignore_second_dn', 'no'), - 'enforceLinkPassword' => Util::isPublicLinkPasswordRequired(false), - 'passwordExcludedGroups' => $excludedPasswordGroupsList, + 'enabled' => $this->getHumanBooleanConfig('core', 'shareapi_enabled', true), + 'allowGroupSharing' => $this->getHumanBooleanConfig('core', 'shareapi_allow_group_sharing', true), + 'allowLinks' => $this->getHumanBooleanConfig('core', 'shareapi_allow_links', true), + 'allowLinksExcludeGroups' => json_decode($linksExcludedGroups, true) ?? [], + 'allowPublicUpload' => $this->getHumanBooleanConfig('core', 'shareapi_allow_public_upload', true), + 'allowResharing' => $this->getHumanBooleanConfig('core', 'shareapi_allow_resharing', true), + 'allowShareDialogUserEnumeration' => $this->getHumanBooleanConfig('core', 'shareapi_allow_share_dialog_user_enumeration', true), + 'restrictUserEnumerationToGroup' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_to_group'), + 'restrictUserEnumerationToPhone' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_to_phone'), + 'restrictUserEnumerationFullMatch' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_full_match', true), + 'restrictUserEnumerationFullMatchUserId' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_full_match_userid', true), + 'restrictUserEnumerationFullMatchEmail' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_full_match_email', true), + 'restrictUserEnumerationFullMatchIgnoreSecondDN' => $this->getHumanBooleanConfig('core', 'shareapi_restrict_user_enumeration_full_match_ignore_second_dn'), + 'enforceLinksPassword' => Util::isPublicLinkPasswordRequired(false), + 'passwordExcludedGroups' => json_decode($excludedPasswordGroups) ?? [], 'passwordExcludedGroupsFeatureEnabled' => $this->config->getSystemValueBool('sharing.allow_disabled_password_enforcement_groups', false), 'onlyShareWithGroupMembers' => $this->shareManager->shareWithGroupMembersOnly(), - 'shareAPIEnabled' => $this->config->getAppValue('core', 'shareapi_enabled', 'yes'), - 'shareDefaultExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no'), - 'shareExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7'), - 'shareEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no'), - 'shareExcludeGroups' => $this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes', - 'shareExcludedGroupsList' => $excludeGroupsList, + 'defaultExpireDate' => $this->getHumanBooleanConfig('core', 'shareapi_default_expire_date'), + 'expireAfterNDays' => $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7'), + 'enforceExpireDate' => $this->getHumanBooleanConfig('core', 'shareapi_enforce_expire_date'), + 'excludeGroups' => $this->getHumanBooleanConfig('core', 'shareapi_exclude_groups'), + 'excludeGroupsList' => json_decode($excludedGroups, true) ?? [], 'publicShareDisclaimerText' => $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null), - 'enableLinkPasswordByDefault' => $this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no'), - 'shareApiDefaultPermissions' => (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL), - 'shareApiDefaultPermissionsCheckboxes' => $this->getSharePermissionList(), - 'shareDefaultInternalExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no'), - 'shareInternalExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7'), - 'shareInternalEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no'), - 'shareDefaultRemoteExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no'), - 'shareRemoteExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7'), - 'shareRemoteEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no'), + 'enableLinkPasswordByDefault' => $this->getHumanBooleanConfig('core', 'shareapi_enable_link_password_by_default'), + 'defaultPermissions' => (int)$this->config->getAppValue('core', 'shareapi_default_permissions', (string)Constants::PERMISSION_ALL), + 'defaultInternalExpireDate' => $this->getHumanBooleanConfig('core', 'shareapi_default_internal_expire_date'), + 'internalExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7'), + 'enforceInternalExpireDate' => $this->getHumanBooleanConfig('core', 'shareapi_enforce_internal_expire_date'), + 'defaultRemoteExpireDate' => $this->getHumanBooleanConfig('core', 'shareapi_default_remote_expire_date'), + 'remoteExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7'), + 'enforceRemoteExpireDate' => $this->getHumanBooleanConfig('core', 'shareapi_enforce_remote_expire_date'), ]; - return new TemplateResponse('settings', 'settings/admin/sharing', $parameters, ''); + $this->initialState->provideInitialState('sharingAppEnabled', $this->appManager->isEnabledForUser('files_sharing')); + $this->initialState->provideInitialState('sharingDocumentation', $this->urlGenerator->linkToDocs('admin-sharing')); + $this->initialState->provideInitialState('sharingSettings', $parameters); + + \OCP\Util::addScript($this->appName, 'vue-settings-admin-sharing'); + return new TemplateResponse($this->appName, 'settings/admin/sharing', [], ''); } /** - * get share permission list for template - * - * @return array + * Helper function to retrive boolean values from human readable strings ('yes' / 'no') */ - private function getSharePermissionList() { - return [ - [ - 'id' => 'cancreate', - 'label' => $this->l->t('Create'), - 'value' => Constants::PERMISSION_CREATE - ], - [ - 'id' => 'canupdate', - 'label' => $this->l->t('Change'), - 'value' => Constants::PERMISSION_UPDATE - ], - [ - 'id' => 'candelete', - 'label' => $this->l->t('Delete'), - 'value' => Constants::PERMISSION_DELETE - ], - [ - 'id' => 'canshare', - 'label' => $this->l->t('Reshare'), - 'value' => Constants::PERMISSION_SHARE - ], - ]; + private function getHumanBooleanConfig(string $app, string $key, bool $default = false): bool { + return $this->config->getAppValue($app, $key, $default ? 'yes' : 'no') === 'yes'; } /** 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> diff --git a/apps/settings/templates/settings/admin/sharing.php b/apps/settings/templates/settings/admin/sharing.php index 2918a764d89..4ddc9a8ada0 100644 --- a/apps/settings/templates/settings/admin/sharing.php +++ b/apps/settings/templates/settings/admin/sharing.php @@ -1,11 +1,10 @@ <?php /** - * @copyright Copyright (c) 2016 Arthur Schiwon <blizzz@arthur-schiwon.de> + * @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de> * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Thomas Citharel <nextcloud@tcit.fr> + * @author Ferdinand Thiessen <opensource@fthiessen.de> * - * @license GNU AGPL version 3 or any later version + * @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 @@ -18,263 +17,9 @@ * 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/>. + * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ - -/** @var \OCP\IL10N $l */ -/** @var array $_ */ - ?> -<div class="section loading" id="shareAPI"> - <h2><?php p($l->t('Sharing'));?></h2> - <?php if ($_['sharingAppEnabled'] === false) { ?> - <p class="warning"><?php p($l->t('You need to enable the File sharing App.')); ?></p> - <?php } else { ?> - <a target="_blank" rel="noreferrer noopener" class="icon-info" - title="<?php p($l->t('Open documentation'));?>" - href="<?php p(link_to_docs('admin-sharing')); ?>"></a> - <div> - <p class="settings-hint"><?php p($l->t('As admin you can fine-tune the sharing behavior. Please see the documentation for more information.'));?></p> - <p id="enable"> - <input type="checkbox" name="shareapi_enabled" id="shareAPIEnabled" class="checkbox" - value="1" <?php if ($_['shareAPIEnabled'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareAPIEnabled"><?php p($l->t('Allow apps to use the Share API'));?></label><br/> - </p> - - <p id="internalShareSettings" class="indent <?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -} ?>"> - <input type="checkbox" name="shareapi_default_internal_expire_date" id="shareapiDefaultInternalExpireDate" class="checkbox" - value="1" <?php if ($_['shareDefaultInternalExpireDateSet'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapiDefaultInternalExpireDate"><?php p($l->t('Set default expiration date for shares'));?></label><br/> - </p> - <p id="setDefaultInternalExpireDate" class="double-indent <?php if ($_['shareDefaultInternalExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <?php p($l->t('Expire after') . ' '); ?> - <input type="text" name='shareapi_internal_expire_after_n_days' id="shareapiInternalExpireAfterNDays" placeholder="<?php p('7')?>" - value='<?php p($_['shareInternalExpireAfterNDays']) ?>' /> - <?php p($l->t('day(s)')); ?> - <input type="checkbox" name="shareapi_enforce_internal_expire_date" id="shareapiInternalEnforceExpireDate" class="checkbox" - value="1" <?php if ($_['shareInternalEnforceExpireDate'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapiInternalEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/> - </p> - - <p id="remoteShareSettings" class="indent <?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -} ?>"> - <input type="checkbox" name="shareapi_default_remote_expire_date" id="shareapiDefaultRemoteExpireDate" class="checkbox" - value="1" <?php if ($_['shareDefaultRemoteExpireDateSet'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapiDefaultRemoteExpireDate"><?php p($l->t('Set default expiration date for shares to other servers'));?></label><br/> - </p> - <p id="setDefaultRemoteExpireDate" class="double-indent <?php if ($_['shareDefaultRemoteExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <?php p($l->t('Expire after'). ' '); ?> - <input type="text" name='shareapi_remote_expire_after_n_days' id="shareapiRemoteExpireAfterNDays" placeholder="<?php p('7')?>" - value='<?php p($_['shareRemoteExpireAfterNDays']) ?>' /> - <?php p($l->t('day(s)')); ?> - <input type="checkbox" name="shareapi_enforce_remote_expire_date" id="shareapiRemoteEnforceExpireDate" class="checkbox" - value="1" <?php if ($_['shareRemoteEnforceExpireDate'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapiRemoteEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/> - </p> - - <p class="<?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <input type="checkbox" name="shareapi_allow_links" id="allowLinks" class="checkbox" - value="1" <?php if ($_['allowLinks'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="allowLinks"><?php p($l->t('Allow users to share via link and emails'));?></label><br/> - </p> - - <p id="publicLinkSettings" class="indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareAPIEnabled'] === 'no') { - p('hidden'); -} ?>"> - <input type="checkbox" name="shareapi_allow_public_upload" id="allowPublicUpload" class="checkbox" - value="1" <?php if ($_['allowPublicUpload'] == 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="allowPublicUpload"><?php p($l->t('Allow public uploads'));?></label><br/> - <input type="checkbox" name="shareapi_enable_link_password_by_default" id="enableLinkPasswordByDefault" class="checkbox" - value="1" <?php if ($_['enableLinkPasswordByDefault'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="enableLinkPasswordByDefault"><?php p($l->t('Always ask for a password'));?></label><br/> - <input type="checkbox" name="shareapi_enforce_links_password" id="enforceLinkPassword" class="checkbox" - value="1" <?php if ($_['enforceLinkPassword']) { - print_unescaped('checked="checked"'); -} ?> <?php if ($_['enableLinkPasswordByDefault'] !== 'yes') { - print_unescaped('disabled'); -} ?> /> - <label for="enforceLinkPassword" class="indent"><?php p($l->t('Enforce password protection'));?></label><br/> - -<?php if ($_['passwordExcludedGroupsFeatureEnabled']) { ?> - <span id="selectPasswordsExcludedGroups" class="double-indent <?php if (!$_['enforceLinkPassword']) { p('hidden'); } ?>"> - <label for="shareapi_enforce_links_password_excluded_groups"><?php p($l->t('Exclude groups from password requirements:'));?></label><br/> - <input name="shareapi_enforce_links_password_excluded_groups" id="passwordsExcludedGroups" value="<?php p($_['passwordExcludedGroups']) ?>" - style="width: 400px" class="noJSAutoUpdate double-indent" <?php if ($_['enableLinkPasswordByDefault'] !== 'yes') { - print_unescaped('disabled'); -} ?> /> - </span><br/> -<?php } ?> - - <input type="checkbox" name="shareapi_default_expire_date" id="shareapiDefaultExpireDate" class="checkbox" - value="1" <?php if ($_['shareDefaultExpireDateSet'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date'));?></label><br/> - - </p> - <p id="setDefaultExpireDate" class="double-indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareDefaultExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <?php p($l->t('Expire after'). ' '); ?> - <input type="text" name='shareapi_expire_after_n_days' id="shareapiExpireAfterNDays" placeholder="<?php p('7')?>" - value='<?php p($_['shareExpireAfterNDays']) ?>' /> - <?php p($l->t('day(s)')); ?> - <input type="checkbox" name="shareapi_enforce_expire_date" id="shareapiEnforceExpireDate" class="checkbox" - value="1" <?php if ($_['shareEnforceExpireDate'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapiEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/> - </p> - <p class="<?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <p class="indent"> - <?php p($l->t('Exclude groups from creating link shares:'));?> - </p> - <p id="selectLinksExcludedGroups" class="indent <?php if ($_['allowLinks'] === 'no') { - p('hidden'); -} ?>"> - <input name="shareapi_allow_links_exclude_groups" type="hidden" id="linksExcludedGroups" value="<?php p($_['allowLinksExcludeGroups']) ?>" style="width: 400px" class="noJSAutoUpdate"/> - </p> - <input type="checkbox" name="shareapi_allow_resharing" id="allowResharing" class="checkbox" - value="1" <?php if ($_['allowResharing'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="allowResharing"><?php p($l->t('Allow resharing'));?></label><br/> - </p> - <p class="<?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <input type="checkbox" name="shareapi_allow_group_sharing" id="allowGroupSharing" class="checkbox" - value="1" <?php if ($_['allowGroupSharing'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="allowGroupSharing"><?php p($l->t('Allow sharing with groups'));?></label><br /> - </p> - <p class="<?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <input type="checkbox" name="shareapi_only_share_with_group_members" id="onlyShareWithGroupMembers" class="checkbox" - value="1" <?php if ($_['onlyShareWithGroupMembers']) { - print_unescaped('checked="checked"'); -} ?> /> - <label for="onlyShareWithGroupMembers"><?php p($l->t('Restrict users to only share with users in their groups'));?></label><br/> - </p> - <p class="<?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <input type="checkbox" name="shareapi_exclude_groups" id="shareapiExcludeGroups" class="checkbox" - value="1" <?php if ($_['shareExcludeGroups']) { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapiExcludeGroups"><?php p($l->t('Exclude groups from sharing'));?></label><br/> - </p> - <p id="selectExcludedGroups" class="indent <?php if (!$_['shareExcludeGroups'] || $_['shareAPIEnabled'] === 'no') { - p('hidden'); -} ?>"> - <input name="shareapi_exclude_groups_list" type="hidden" id="excludedGroups" value="<?php p($_['shareExcludedGroupsList']) ?>" style="width: 400px" class="noJSAutoUpdate"/> - <br /> - <em><?php p($l->t('These groups will still be able to receive shares, but not to initiate them.')); ?></em> - </p> - - <p class="<?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <input type="checkbox" name="shareapi_allow_share_dialog_user_enumeration" value="1" id="shareapi_allow_share_dialog_user_enumeration" class="checkbox" - <?php if ($_['allowShareDialogUserEnumeration'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapi_allow_share_dialog_user_enumeration"><?php p($l->t('Allow username autocompletion in share dialog and allow access to the system address book'));?></label><br /> - </p> - - <p id="shareapi_restrict_user_enumeration_to_group_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') { - p('hidden'); -}?>"> - <input type="checkbox" name="shareapi_restrict_user_enumeration_to_group" value="1" id="shareapi_restrict_user_enumeration_to_group" class="checkbox" - <?php if ($_['restrictUserEnumerationToGroup'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapi_restrict_user_enumeration_to_group"><?php p($l->t('Allow username autocompletion to users within the same groups and limit system address books to users in the same groups'));?></label><br /> - </p> - - <p id="shareapi_restrict_user_enumeration_to_phone_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') { - p('hidden'); -}?>"> - <input type="checkbox" name="shareapi_restrict_user_enumeration_to_phone" value="1" id="shareapi_restrict_user_enumeration_to_phone" class="checkbox" - <?php if ($_['restrictUserEnumerationToPhone'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapi_restrict_user_enumeration_to_phone"><?php p($l->t('Allow username autocompletion to users based on phone number integration'));?></label><br /> - </p> - <p id="shareapi_restrict_user_enumeration_combinewarning_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') { - p('hidden'); -}?>"> - <em><?php p($l->t('If autocompletion "same group" and "phone number integration" are enabled a match in either is enough to show the user.'));?></em><br /> - </p> - <p id="shareapi_restrict_user_enumeration_full_match_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -}?>"> - <input type="checkbox" name="shareapi_restrict_user_enumeration_full_match" value="1" id="shareapi_restrict_user_enumeration_full_match" class="checkbox" - <?php if ($_['restrictUserEnumerationFullMatch'] === 'yes') { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapi_restrict_user_enumeration_full_match"><?php p($l->t('Allow autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)'));?></label><br /> - </p> - - <p> - <input type="checkbox" id="publicShareDisclaimer" class="checkbox noJSAutoUpdate" - <?php if ($_['publicShareDisclaimerText'] !== null) { - print_unescaped('checked="checked"'); -} ?> /> - <label for="publicShareDisclaimer"><?php p($l->t('Show disclaimer text on the public link upload page (only shown when the file list is hidden)'));?></label> - <span id="publicShareDisclaimerStatus" class="msg" style="display:none"></span> - <br/> - <textarea placeholder="<?php p($l->t('This text will be shown on the public link upload page when the file list is hidden.')) ?>" id="publicShareDisclaimerText" <?php if ($_['publicShareDisclaimerText'] === null) { - print_unescaped('class="hidden"'); -} ?>><?php p($_['publicShareDisclaimerText']) ?></textarea> - </p> - - <h3><?php p($l->t('Default share permissions'));?></h3> - <input type="hidden" name="shareapi_default_permissions" id="shareApiDefaultPermissions" class="checkbox" - value="<?php p($_['shareApiDefaultPermissions']) ?>" /> - <p id="shareApiDefaultPermissionsSection" class="indent <?php if ($_['shareAPIEnabled'] === 'no') { - p('hidden'); -} ?>"> - <?php foreach ($_['shareApiDefaultPermissionsCheckboxes'] as $perm): ?> - <input type="checkbox" name="shareapi_default_permission_<?php p($perm['id']) ?>" id="shareapi_default_permission_<?php p($perm['id']) ?>" - class="noautosave checkbox" value="<?php p($perm['value']) ?>" <?php if (($_['shareApiDefaultPermissions'] & $perm['value']) !== 0) { - print_unescaped('checked="checked"'); -} ?> /> - <label for="shareapi_default_permission_<?php p($perm['id']) ?>"><?php p($perm['label']);?></label> - <?php endforeach ?> - </p> - </div> - <?php } ?> -</div> +<div id="vue-admin-settings-sharing"></div>
\ No newline at end of file diff --git a/webpack.modules.js b/webpack.modules.js index d749f13b81f..677d0b17aaa 100644 --- a/webpack.modules.js +++ b/webpack.modules.js @@ -91,6 +91,7 @@ module.exports = { 'vue-settings-admin-ai': path.join(__dirname, 'apps/settings/src', 'main-admin-ai.js'), 'vue-settings-admin-delegation': path.join(__dirname, 'apps/settings/src', 'main-admin-delegation.js'), 'vue-settings-admin-security': path.join(__dirname, 'apps/settings/src', 'main-admin-security.js'), + 'vue-settings-admin-sharing': path.join(__dirname, 'apps/settings/src', 'admin-settings-sharing.ts'), 'vue-settings-apps-users-management': path.join(__dirname, 'apps/settings/src', 'main-apps-users-management.js'), 'vue-settings-nextcloud-pdf': path.join(__dirname, 'apps/settings/src', 'main-nextcloud-pdf.js'), 'vue-settings-personal-info': path.join(__dirname, 'apps/settings/src', 'main-personal-info.js'), |