Skip to content

Commit c79f082

Browse files
provokateurinsusnuxartonge
committed
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>
1 parent b05a608 commit c79f082

7 files changed

Lines changed: 126 additions & 30 deletions

File tree

apps/provisioning_api/lib/Controller/UsersController.php

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -742,14 +742,16 @@ public function getEditableFieldsForUser(string $userId): DataResponse {
742742
$targetUser = $currentLoggedInUser;
743743
}
744744

745-
// Editing self (display, email)
746-
if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
747-
if (
748-
$targetUser->getBackend() instanceof ISetDisplayNameBackend
749-
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
750-
) {
751-
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
752-
}
745+
$allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
746+
if ($allowDisplayNameChange === true && (
747+
$targetUser->getBackend() instanceof ISetDisplayNameBackend
748+
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
749+
)) {
750+
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
751+
}
752+
753+
// Fallback to display name value to avoid changing behavior with the new option.
754+
if ($this->config->getSystemValue('allow_user_to_change_email', $allowDisplayNameChange)) {
753755
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
754756
}
755757

@@ -900,15 +902,17 @@ public function editUser(string $userId, string $key, string $value): DataRespon
900902

901903
$permittedFields = [];
902904
if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
903-
// Editing self (display, email)
904-
if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
905-
if (
906-
$targetUser->getBackend() instanceof ISetDisplayNameBackend
907-
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
908-
) {
909-
$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
910-
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
911-
}
905+
$allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
906+
if ($allowDisplayNameChange !== false && (
907+
$targetUser->getBackend() instanceof ISetDisplayNameBackend
908+
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
909+
)) {
910+
$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
911+
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
912+
}
913+
914+
// Fallback to display name value to avoid changing behavior with the new option.
915+
if ($this->config->getSystemValue('allow_user_to_change_email', $allowDisplayNameChange)) {
912916
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
913917
}
914918

apps/provisioning_api/tests/Controller/UsersControllerTest.php

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
use OCP\UserInterface;
4242
use PHPUnit\Framework\MockObject\MockObject;
4343
use Psr\Log\LoggerInterface;
44+
use RuntimeException;
4445
use Test\TestCase;
4546

4647
class UsersControllerTest extends TestCase {
@@ -1639,6 +1640,8 @@ public function testEditUserRegularUserSelfEditChangeEmailValid() {
16391640
->method('getBackend')
16401641
->willReturn($backend);
16411642

1643+
$this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
1644+
16421645
$this->assertEquals([], $this->api->editUser('UserToEdit', 'email', 'demo@nextcloud.com')->getData());
16431646
}
16441647

@@ -1833,6 +1836,8 @@ public function testEditUserRegularUserSelfEditChangeEmailInvalid() {
18331836
->method('getBackend')
18341837
->willReturn($backend);
18351838

1839+
$this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
1840+
18361841
$this->api->editUser('UserToEdit', 'email', 'demo.org');
18371842
}
18381843

@@ -4224,7 +4229,8 @@ public function testResendWelcomeMessageFailed() {
42244229

42254230
public function dataGetEditableFields() {
42264231
return [
4227-
[false, ISetDisplayNameBackend::class, [
4232+
[false, true, ISetDisplayNameBackend::class, [
4233+
IAccountManager::PROPERTY_EMAIL,
42284234
IAccountManager::COLLECTION_EMAIL,
42294235
IAccountManager::PROPERTY_PHONE,
42304236
IAccountManager::PROPERTY_ADDRESS,
@@ -4237,8 +4243,49 @@ public function dataGetEditableFields() {
42374243
IAccountManager::PROPERTY_BIOGRAPHY,
42384244
IAccountManager::PROPERTY_PROFILE_ENABLED,
42394245
]],
4240-
[true, ISetDisplayNameBackend::class, [
4246+
[true, false, ISetDisplayNameBackend::class, [
42414247
IAccountManager::PROPERTY_DISPLAYNAME,
4248+
IAccountManager::COLLECTION_EMAIL,
4249+
IAccountManager::PROPERTY_PHONE,
4250+
IAccountManager::PROPERTY_ADDRESS,
4251+
IAccountManager::PROPERTY_WEBSITE,
4252+
IAccountManager::PROPERTY_TWITTER,
4253+
IAccountManager::PROPERTY_FEDIVERSE,
4254+
IAccountManager::PROPERTY_ORGANISATION,
4255+
IAccountManager::PROPERTY_ROLE,
4256+
IAccountManager::PROPERTY_HEADLINE,
4257+
IAccountManager::PROPERTY_BIOGRAPHY,
4258+
IAccountManager::PROPERTY_PROFILE_ENABLED,
4259+
]],
4260+
[true, true, ISetDisplayNameBackend::class, [
4261+
IAccountManager::PROPERTY_DISPLAYNAME,
4262+
IAccountManager::PROPERTY_EMAIL,
4263+
IAccountManager::COLLECTION_EMAIL,
4264+
IAccountManager::PROPERTY_PHONE,
4265+
IAccountManager::PROPERTY_ADDRESS,
4266+
IAccountManager::PROPERTY_WEBSITE,
4267+
IAccountManager::PROPERTY_TWITTER,
4268+
IAccountManager::PROPERTY_FEDIVERSE,
4269+
IAccountManager::PROPERTY_ORGANISATION,
4270+
IAccountManager::PROPERTY_ROLE,
4271+
IAccountManager::PROPERTY_HEADLINE,
4272+
IAccountManager::PROPERTY_BIOGRAPHY,
4273+
IAccountManager::PROPERTY_PROFILE_ENABLED,
4274+
]],
4275+
[false, false, ISetDisplayNameBackend::class, [
4276+
IAccountManager::COLLECTION_EMAIL,
4277+
IAccountManager::PROPERTY_PHONE,
4278+
IAccountManager::PROPERTY_ADDRESS,
4279+
IAccountManager::PROPERTY_WEBSITE,
4280+
IAccountManager::PROPERTY_TWITTER,
4281+
IAccountManager::PROPERTY_FEDIVERSE,
4282+
IAccountManager::PROPERTY_ORGANISATION,
4283+
IAccountManager::PROPERTY_ROLE,
4284+
IAccountManager::PROPERTY_HEADLINE,
4285+
IAccountManager::PROPERTY_BIOGRAPHY,
4286+
IAccountManager::PROPERTY_PROFILE_ENABLED,
4287+
]],
4288+
[false, true, UserInterface::class, [
42424289
IAccountManager::PROPERTY_EMAIL,
42434290
IAccountManager::COLLECTION_EMAIL,
42444291
IAccountManager::PROPERTY_PHONE,
@@ -4252,7 +4299,20 @@ public function dataGetEditableFields() {
42524299
IAccountManager::PROPERTY_BIOGRAPHY,
42534300
IAccountManager::PROPERTY_PROFILE_ENABLED,
42544301
]],
4255-
[true, UserInterface::class, [
4302+
[true, false, UserInterface::class, [
4303+
IAccountManager::COLLECTION_EMAIL,
4304+
IAccountManager::PROPERTY_PHONE,
4305+
IAccountManager::PROPERTY_ADDRESS,
4306+
IAccountManager::PROPERTY_WEBSITE,
4307+
IAccountManager::PROPERTY_TWITTER,
4308+
IAccountManager::PROPERTY_FEDIVERSE,
4309+
IAccountManager::PROPERTY_ORGANISATION,
4310+
IAccountManager::PROPERTY_ROLE,
4311+
IAccountManager::PROPERTY_HEADLINE,
4312+
IAccountManager::PROPERTY_BIOGRAPHY,
4313+
IAccountManager::PROPERTY_PROFILE_ENABLED,
4314+
]],
4315+
[true, true, UserInterface::class, [
42564316
IAccountManager::PROPERTY_EMAIL,
42574317
IAccountManager::COLLECTION_EMAIL,
42584318
IAccountManager::PROPERTY_PHONE,
@@ -4266,6 +4326,19 @@ public function dataGetEditableFields() {
42664326
IAccountManager::PROPERTY_BIOGRAPHY,
42674327
IAccountManager::PROPERTY_PROFILE_ENABLED,
42684328
]],
4329+
[false, false, UserInterface::class, [
4330+
IAccountManager::COLLECTION_EMAIL,
4331+
IAccountManager::PROPERTY_PHONE,
4332+
IAccountManager::PROPERTY_ADDRESS,
4333+
IAccountManager::PROPERTY_WEBSITE,
4334+
IAccountManager::PROPERTY_TWITTER,
4335+
IAccountManager::PROPERTY_FEDIVERSE,
4336+
IAccountManager::PROPERTY_ORGANISATION,
4337+
IAccountManager::PROPERTY_ROLE,
4338+
IAccountManager::PROPERTY_HEADLINE,
4339+
IAccountManager::PROPERTY_BIOGRAPHY,
4340+
IAccountManager::PROPERTY_PROFILE_ENABLED,
4341+
]],
42694342
];
42704343
}
42714344

@@ -4276,13 +4349,12 @@ public function dataGetEditableFields() {
42764349
* @param string $userBackend
42774350
* @param array $expected
42784351
*/
4279-
public function testGetEditableFields(bool $allowedToChangeDisplayName, string $userBackend, array $expected) {
4280-
$this->config
4281-
->method('getSystemValue')
4282-
->with(
4283-
$this->equalTo('allow_user_to_change_display_name'),
4284-
$this->anything()
4285-
)->willReturn($allowedToChangeDisplayName);
4352+
public function testGetEditableFields(bool $allowedToChangeDisplayName, bool $allowedToChangeEmail, string $userBackend, array $expected): void {
4353+
$this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => match ($key) {
4354+
'allow_user_to_change_display_name' => $allowedToChangeDisplayName,
4355+
'allow_user_to_change_email' => $allowedToChangeEmail,
4356+
default => throw new RuntimeException('Unexpected system config key: ' . $key),
4357+
});
42864358

42874359
$user = $this->createMock(IUser::class);
42884360
$this->userSession->method('getUser')

apps/settings/lib/Settings/Personal/PersonalInfo.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ public function getForm(): TemplateResponse {
148148
$accountParameters = [
149149
'avatarChangeSupported' => $user->canChangeAvatar(),
150150
'displayNameChangeSupported' => $user->canChangeDisplayName(),
151+
'emailChangeSupported' => $user->canChangeEmail(),
151152
'federationEnabled' => $federationEnabled,
152153
'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
153154
];

apps/settings/src/components/PersonalInfo/EmailSection/EmailSection.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
:scope.sync="primaryEmail.scope"
1414
@add-additional="onAddAdditionalEmail" />
1515

16-
<template v-if="displayNameChangeSupported">
16+
<template v-if="emailChangeSupported">
1717
<Email :input-id="inputId"
1818
:primary="true"
1919
:scope.sync="primaryEmail.scope"
@@ -56,7 +56,7 @@ import { validateEmail } from '../../../utils/validate.js'
5656
import { handleError } from '../../../utils/handlers.ts'
5757
5858
const { emailMap: { additionalEmails, primaryEmail, notificationEmail } } = loadState('settings', 'personalInfoParameters', {})
59-
const { displayNameChangeSupported } = loadState('settings', 'accountParameters', {})
59+
const { emailChangeSupported } = loadState('settings', 'accountParameters', {})
6060
6161
export default {
6262
name: 'EmailSection',
@@ -70,7 +70,7 @@ export default {
7070
return {
7171
accountProperty: ACCOUNT_PROPERTY_READABLE_ENUM.EMAIL,
7272
additionalEmails: additionalEmails.map(properties => ({ ...properties, key: this.generateUniqueKey() })),
73-
displayNameChangeSupported,
73+
emailChangeSupported,
7474
primaryEmail: { ...primaryEmail, readable: NAME_READABLE_ENUM[primaryEmail.name] },
7575
notificationEmail,
7676
}

build/psalm-baseline.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,11 @@
10681068
<code><![CDATA[null]]></code>
10691069
</NullArgument>
10701070
</file>
1071+
<file src="apps/settings/lib/Settings/Personal/PersonalInfo.php">
1072+
<UndefinedInterfaceMethod>
1073+
<code><![CDATA[canChangeEmail]]></code>
1074+
</UndefinedInterfaceMethod>
1075+
</file>
10711076
<file src="apps/sharebymail/lib/ShareByMailProvider.php">
10721077
<InvalidArgument>
10731078
<code><![CDATA[$share->getId()]]></code>
@@ -2774,6 +2779,11 @@
27742779
<code><![CDATA[false]]></code>
27752780
</FalsableReturnStatement>
27762781
</file>
2782+
<file src="lib/private/User/LazyUser.php">
2783+
<UndefinedInterfaceMethod>
2784+
<code><![CDATA[canChangeEmail]]></code>
2785+
</UndefinedInterfaceMethod>
2786+
</file>
27772787
<file src="lib/private/User/Manager.php">
27782788
<ImplementedReturnTypeMismatch>
27792789
<code><![CDATA[IUser|false]]></code>

lib/private/User/LazyUser.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ public function canChangeDisplayName() {
108108
return $this->getUser()->canChangeDisplayName();
109109
}
110110

111+
public function canChangeEmail(): bool {
112+
return $this->getUser()->canChangeEmail();
113+
}
114+
111115
public function isEnabled() {
112116
return $this->getUser()->isEnabled();
113117
}

lib/private/User/User.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,11 @@ public function canChangeDisplayName() {
428428
return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
429429
}
430430

431+
public function canChangeEmail(): bool {
432+
// Fallback to display name value to avoid changing behavior with the new option.
433+
return $this->config->getSystemValueBool('allow_user_to_change_email', $this->config->getSystemValueBool('allow_user_to_change_display_name', true));
434+
}
435+
431436
/**
432437
* check if the user is enabled
433438
*

0 commit comments

Comments
 (0)