aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2023-11-16 21:53:14 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2023-11-20 17:07:55 +0100
commit22163c60d42bbd60181818d315442f98fbbe89d0 (patch)
tree2f35ec0757a3166d9c29734da8995ead9ec73a92
parente5b996722a3f850bec68490d467e8c565f3a3341 (diff)
downloadnextcloud-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.php133
-rw-r--r--apps/settings/src/.jshintrc3
-rw-r--r--apps/settings/src/admin-settings-sharing.ts30
-rw-r--r--apps/settings/src/admin.js133
-rw-r--r--apps/settings/src/components/AdminSettingsSharingForm.vue355
-rw-r--r--apps/settings/src/components/SelectSharingPermissions.vue100
-rw-r--r--apps/settings/src/views/AdminSettingsSharing.vue62
-rw-r--r--apps/settings/templates/settings/admin/sharing.php265
-rw-r--r--webpack.modules.js1
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'),