fix(settings): Handle email change restriction separately from display name change restriction

Co-authored-by: provokateurin <kate@provokateurin.de>
Co-authored-by: Ferdinand Thiessen <opensource@fthiessen.de>
Co-authored-by: Louis <louis@chmn.me>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
pull/51899/head
provokateurin 2025-03-27 09:31:01 +07:00 committed by Ferdinand Thiessen
parent 57f485d992
commit 80204297d3
No known key found for this signature in database
GPG Key ID: 45FAE7268762B400
7 changed files with 126 additions and 30 deletions

@ -708,14 +708,16 @@ class UsersController extends AUserData {
$targetUser = $currentLoggedInUser;
}
// Editing self (display, email)
if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
if (
$targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
) {
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
$allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
if ($allowDisplayNameChange === true && (
$targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
)) {
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
// Fallback to display name value to avoid changing behavior with the new option.
if ($this->config->getSystemValue('allow_user_to_change_email', $allowDisplayNameChange)) {
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
}
@ -862,15 +864,17 @@ class UsersController extends AUserData {
$permittedFields = [];
if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
// Editing self (display, email)
if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
if (
$targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
) {
$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
$allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
if ($allowDisplayNameChange !== false && (
$targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
)) {
$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
// Fallback to display name value to avoid changing behavior with the new option.
if ($this->config->getSystemValue('allow_user_to_change_email', $allowDisplayNameChange)) {
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
}

@ -74,6 +74,7 @@ use OCP\User\Backend\ISetDisplayNameBackend;
use OCP\UserInterface;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Test\TestCase;
class UsersControllerTest extends TestCase {
@ -1679,6 +1680,8 @@ class UsersControllerTest extends TestCase {
->method('getBackend')
->willReturn($backend);
$this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
$this->assertEquals([], $this->api->editUser('UserToEdit', 'email', 'demo@nextcloud.com')->getData());
}
@ -1873,6 +1876,8 @@ class UsersControllerTest extends TestCase {
->method('getBackend')
->willReturn($backend);
$this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
$this->api->editUser('UserToEdit', 'email', 'demo.org');
}
@ -4244,7 +4249,8 @@ class UsersControllerTest extends TestCase {
public function dataGetEditableFields() {
return [
[false, ISetDisplayNameBackend::class, [
[false, true, ISetDisplayNameBackend::class, [
IAccountManager::PROPERTY_EMAIL,
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
@ -4257,8 +4263,49 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
[true, ISetDisplayNameBackend::class, [
[true, false, ISetDisplayNameBackend::class, [
IAccountManager::PROPERTY_DISPLAYNAME,
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_FEDIVERSE,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
[true, true, ISetDisplayNameBackend::class, [
IAccountManager::PROPERTY_DISPLAYNAME,
IAccountManager::PROPERTY_EMAIL,
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_FEDIVERSE,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
[false, false, ISetDisplayNameBackend::class, [
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_FEDIVERSE,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
[false, true, UserInterface::class, [
IAccountManager::PROPERTY_EMAIL,
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
@ -4272,7 +4319,20 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
[true, UserInterface::class, [
[true, false, UserInterface::class, [
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_FEDIVERSE,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
[true, true, UserInterface::class, [
IAccountManager::PROPERTY_EMAIL,
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
@ -4286,6 +4346,19 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
[false, false, UserInterface::class, [
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_FEDIVERSE,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
];
}
@ -4296,13 +4369,12 @@ class UsersControllerTest extends TestCase {
* @param string $userBackend
* @param array $expected
*/
public function testGetEditableFields(bool $allowedToChangeDisplayName, string $userBackend, array $expected) {
$this->config
->method('getSystemValue')
->with(
$this->equalTo('allow_user_to_change_display_name'),
$this->anything()
)->willReturn($allowedToChangeDisplayName);
public function testGetEditableFields(bool $allowedToChangeDisplayName, bool $allowedToChangeEmail, string $userBackend, array $expected): void {
$this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => match ($key) {
'allow_user_to_change_display_name' => $allowedToChangeDisplayName,
'allow_user_to_change_email' => $allowedToChangeEmail,
default => throw new RuntimeException('Unexpected system config key: ' . $key),
});
$user = $this->createMock(IUser::class);
$this->userSession->method('getUser')

@ -172,6 +172,7 @@ class PersonalInfo implements ISettings {
$accountParameters = [
'avatarChangeSupported' => $user->canChangeAvatar(),
'displayNameChangeSupported' => $user->canChangeDisplayName(),
'emailChangeSupported' => $user->canChangeEmail(),
'federationEnabled' => $federationEnabled,
'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
];

@ -31,7 +31,7 @@
:scope.sync="primaryEmail.scope"
@add-additional="onAddAdditionalEmail" />
<template v-if="displayNameChangeSupported">
<template v-if="emailChangeSupported">
<Email :input-id="inputId"
:primary="true"
:scope.sync="primaryEmail.scope"
@ -74,7 +74,7 @@ import { validateEmail } from '../../../utils/validate.js'
import { handleError } from '../../../utils/handlers.js'
const { emailMap: { additionalEmails, primaryEmail, notificationEmail } } = loadState('settings', 'personalInfoParameters', {})
const { displayNameChangeSupported } = loadState('settings', 'accountParameters', {})
const { emailChangeSupported } = loadState('settings', 'accountParameters', {})
export default {
name: 'EmailSection',
@ -88,7 +88,7 @@ export default {
return {
accountProperty: ACCOUNT_PROPERTY_READABLE_ENUM.EMAIL,
additionalEmails: additionalEmails.map(properties => ({ ...properties, key: this.generateUniqueKey() })),
displayNameChangeSupported,
emailChangeSupported,
primaryEmail: { ...primaryEmail, readable: NAME_READABLE_ENUM[primaryEmail.name] },
notificationEmail,
}

@ -1087,6 +1087,11 @@
<code><![CDATA[null]]></code>
</NullArgument>
</file>
<file src="apps/settings/lib/Settings/Personal/PersonalInfo.php">
<UndefinedInterfaceMethod>
<code><![CDATA[canChangeEmail]]></code>
</UndefinedInterfaceMethod>
</file>
<file src="apps/sharebymail/lib/ShareByMailProvider.php">
<InvalidArgument>
<code><![CDATA[$share->getId()]]></code>
@ -2896,6 +2901,11 @@
<code><![CDATA[false]]></code>
</FalsableReturnStatement>
</file>
<file src="lib/private/User/LazyUser.php">
<UndefinedInterfaceMethod>
<code><![CDATA[canChangeEmail]]></code>
</UndefinedInterfaceMethod>
</file>
<file src="lib/private/User/Manager.php">
<ImplementedReturnTypeMismatch>
<code><![CDATA[IUser|false]]></code>

@ -115,6 +115,10 @@ class LazyUser implements IUser {
return $this->getUser()->canChangeDisplayName();
}
public function canChangeEmail(): bool {
return $this->getUser()->canChangeEmail();
}
public function isEnabled() {
return $this->getUser()->isEnabled();
}

@ -440,6 +440,11 @@ class User implements IUser {
return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
}
public function canChangeEmail(): bool {
// Fallback to display name value to avoid changing behavior with the new option.
return $this->config->getSystemValueBool('allow_user_to_change_email', $this->config->getSystemValueBool('allow_user_to_change_display_name', true));
}
/**
* check if the user is enabled
*