Relates to #3387 Signed-off-by: Corentin Damman <c.damman@intopix.com>tags/v29.0.0beta4
@@ -88,7 +88,7 @@ class Sharing implements IDelegatedSettings { | |||
'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'), | |||
'excludeGroups' => $this->config->getAppValue('core', 'shareapi_exclude_groups', 'no'), | |||
'excludeGroupsList' => json_decode($excludedGroups, true) ?? [], | |||
'publicShareDisclaimerText' => $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null), | |||
'enableLinkPasswordByDefault' => $this->getHumanBooleanConfig('core', 'shareapi_enable_link_password_by_default'), |
@@ -76,19 +76,31 @@ | |||
</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> | |||
<label>{{ t('settings', 'Limit sharing based on groups') }}</label> | |||
<div class="sharing__sub-section"> | |||
<NcCheckboxRadioSwitch :checked.sync="settings.excludeGroups" | |||
name="excludeGroups" value="no" | |||
type="radio" @update:checked="onUpdateExcludeGroups"> | |||
{{ t('settings', 'Allow sharing for everyone (default)') }} | |||
</NcCheckboxRadioSwitch> | |||
<NcCheckboxRadioSwitch :checked.sync="settings.excludeGroups" | |||
name="excludeGroups" value="yes" | |||
type="radio" @update:checked="onUpdateExcludeGroups"> | |||
{{ t('settings', 'Exclude some groups from sharing') }} | |||
</NcCheckboxRadioSwitch> | |||
<NcCheckboxRadioSwitch :checked.sync="settings.excludeGroups" | |||
name="excludeGroups" value="allow" | |||
type="radio" @update:checked="onUpdateExcludeGroups"> | |||
{{ t('settings', 'Limit sharing to some groups') }} | |||
</NcCheckboxRadioSwitch> | |||
<div v-show="settings.excludeGroups !== 'no'" class="sharing__labeled-entry sharing__input"> | |||
<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" | |||
:label="settings.excludeGroups === 'allow' ? t('settings', 'Groups allowed to share') : t('settings', 'Groups excluded from sharing')" | |||
:disabled="settings.excludeGroups === 'no'" | |||
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> | |||
<em id="settings-sharing-excluded-groups-desc">{{ t('settings', 'Not allowed groups will still be able to receive shares, but not to initiate them.') }}</em> | |||
</div> | |||
</div> | |||
@@ -227,7 +239,7 @@ interface IShareSettings { | |||
defaultExpireDate: boolean | |||
expireAfterNDays: string | |||
enforceExpireDate: boolean | |||
excludeGroups: boolean | |||
excludeGroups: string | |||
excludeGroupsList: string[] | |||
publicShareDisclaimerText?: string | |||
enableLinkPasswordByDefault: boolean | |||
@@ -306,6 +318,10 @@ export default defineComponent({ | |||
} | |||
this.settingsData.publicShareDisclaimerText = value | |||
}, 500) as (v?: string) => void, | |||
onUpdateExcludeGroups: debounce(function(value: string) { | |||
window.OCP.AppConfig.setValue('core', 'excludeGroups', value) | |||
this.settings.excludeGroups = value | |||
}, 500) as (v?: string) => void | |||
}, | |||
}) | |||
</script> |
@@ -150,7 +150,7 @@ class SharingTest extends TestCase { | |||
'defaultExpireDate' => false, | |||
'expireAfterNDays' => '7', | |||
'enforceExpireDate' => false, | |||
'excludeGroups' => false, | |||
'excludeGroups' => 'no', | |||
'excludeGroupsList' => [], | |||
'publicShareDisclaimerText' => 'Lorem ipsum', | |||
'enableLinkPasswordByDefault' => true, | |||
@@ -243,7 +243,7 @@ class SharingTest extends TestCase { | |||
'defaultExpireDate' => false, | |||
'expireAfterNDays' => '7', | |||
'enforceExpireDate' => false, | |||
'excludeGroups' => true, | |||
'excludeGroups' => 'yes', | |||
'excludeGroupsList' => ['NoSharers','OtherNoSharers'], | |||
'publicShareDisclaimerText' => 'Lorem ipsum', | |||
'enableLinkPasswordByDefault' => true, |
@@ -193,7 +193,7 @@ class ContactsStore implements IContactsStore { | |||
$restrictEnumerationGroup = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes'; | |||
$restrictEnumerationPhone = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes'; | |||
$allowEnumerationFullMatch = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes'; | |||
$excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes'; | |||
$excludeGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups', 'no'); | |||
// whether to filter out local users | |||
$skipLocal = false; | |||
@@ -202,14 +202,22 @@ class ContactsStore implements IContactsStore { | |||
$selfGroups = $this->groupManager->getUserGroupIds($self); | |||
if ($excludedGroups) { | |||
if ($excludeGroups && $excludeGroups !== 'no') { | |||
$excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', ''); | |||
$decodedExcludeGroups = json_decode($excludedGroups, true); | |||
$excludeGroupsList = $decodedExcludeGroups ?? []; | |||
if (count(array_intersect($excludeGroupsList, $selfGroups)) !== 0) { | |||
// a group of the current user is excluded -> filter all local users | |||
if ($excludeGroups != 'allow') { | |||
if (count(array_intersect($excludeGroupsList, $selfGroups)) !== 0) { | |||
// a group of the current user is excluded -> filter all local users | |||
$skipLocal = true; | |||
} | |||
} else { | |||
$skipLocal = true; | |||
if (count(array_intersect($excludeGroupsList, $selfGroups)) !== 0) { | |||
// a group of the current user is allowed -> do not filter all local users | |||
$skipLocal = false; | |||
} | |||
} | |||
} | |||
@@ -35,7 +35,9 @@ class ShareDisableChecker { | |||
return $this->sharingDisabledForUsersCache[$userId]; | |||
} | |||
if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') { | |||
$excludeGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups', 'no'); | |||
if ($excludeGroups && $excludeGroups !== 'no') { | |||
$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', ''); | |||
$excludedGroups = json_decode($groupsList); | |||
if (is_null($excludedGroups)) { | |||
@@ -48,14 +50,28 @@ class ShareDisableChecker { | |||
return false; | |||
} | |||
$usersGroups = $this->groupManager->getUserGroupIds($user); | |||
if (!empty($usersGroups)) { | |||
$remainingGroups = array_diff($usersGroups, $excludedGroups); | |||
// if the user is only in groups which are disabled for sharing then | |||
// sharing is also disabled for the user | |||
if (empty($remainingGroups)) { | |||
$this->sharingDisabledForUsersCache[$userId] = true; | |||
return true; | |||
if ($excludeGroups !== 'allow') { | |||
if (!empty($usersGroups)) { | |||
$remainingGroups = array_diff($usersGroups, $excludedGroups); | |||
// if the user is only in groups which are disabled for sharing then | |||
// sharing is also disabled for the user | |||
if (empty($remainingGroups)) { | |||
$this->sharingDisabledForUsersCache[$userId] = true; | |||
return true; | |||
} | |||
} | |||
} else { | |||
if (!empty($usersGroups)) { | |||
$remainingGroups = array_intersect($usersGroups, $excludedGroups); | |||
// if the user is in any group which is allowed for sharing then | |||
// sharing is also allowed for the user | |||
if (!empty($remainingGroups)) { | |||
$this->sharingDisabledForUsersCache[$userId] = false; | |||
return false; | |||
} | |||
} | |||
$this->sharingDisabledForUsersCache[$userId] = true; | |||
return true; | |||
} | |||
} | |||
@@ -2099,26 +2099,33 @@ class ManagerTest extends \Test\TestCase { | |||
// No exclude groups | |||
$data[] = ['no', null, null, [], false]; | |||
// empty exclude list, user no groups | |||
// empty exclude / allow list, user no groups | |||
$data[] = ['yes', '', json_encode(['']), [], false]; | |||
$data[] = ['allow', '', json_encode(['']), [], true]; | |||
// empty exclude list, user groups | |||
// empty exclude / allow list, user groups | |||
$data[] = ['yes', '', json_encode(['']), ['group1', 'group2'], false]; | |||
$data[] = ['allow', '', json_encode(['']), ['group1', 'group2'], true]; | |||
// Convert old list to json | |||
$data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), [], false]; | |||
$data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), [], true]; | |||
// Old list partly groups in common | |||
$data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false]; | |||
$data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false]; | |||
// Old list only groups in common | |||
$data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], true]; | |||
$data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], false]; | |||
// New list partly in common | |||
$data[] = ['yes', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false]; | |||
$data[] = ['allow', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false]; | |||
// New list only groups in common | |||
$data[] = ['yes', json_encode(['group1', 'group2']), null, ['group2'], true]; | |||
$data[] = ['allow', json_encode(['group1', 'group2']), null, ['group2'], false]; | |||
return $data; | |||
} |