Skip to content

Commit be29ea5

Browse files
committed
fix(provisioning_api): read newUser.sendEmail as a boolean
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
1 parent 8077a8e commit be29ea5

6 files changed

Lines changed: 103 additions & 5 deletions

File tree

apps/provisioning_api/lib/Controller/UsersController.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use OCP\Files\IRootFolder;
3838
use OCP\Group\ISubAdmin;
3939
use OCP\HintException;
40+
use OCP\IAppConfig;
4041
use OCP\IConfig;
4142
use OCP\IGroup;
4243
use OCP\IGroupManager;
@@ -83,6 +84,7 @@ public function __construct(
8384
private IEventDispatcher $eventDispatcher,
8485
private IPhoneNumberUtil $phoneNumberUtil,
8586
private IAppManager $appManager,
87+
private IAppConfig $appConfig,
8688
GroupDisplayNameCache $groupDisplayNameCache,
8789
) {
8890
parent::__construct(
@@ -596,7 +598,7 @@ public function addUser(
596598
// Send new user mail only if a mail is set
597599
if ($email !== '') {
598600
$newUser->setSystemEMailAddress($email);
599-
if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
601+
if ($this->appConfig->getValueBool('core', 'newUser.sendEmail', true)) {
600602
try {
601603
$emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
602604
$this->newUserMailHelper->sendMail($newUser, $emailTemplate);

apps/provisioning_api/tests/Controller/UsersControllerTest.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use OCP\EventDispatcher\IEventDispatcher;
2828
use OCP\Files\IRootFolder;
2929
use OCP\Group\ISubAdmin;
30+
use OCP\IAppConfig;
3031
use OCP\IConfig;
3132
use OCP\IGroup;
3233
use OCP\IL10N;
@@ -67,6 +68,7 @@ class UsersControllerTest extends TestCase {
6768
private IRootFolder $rootFolder;
6869
private IPhoneNumberUtil $phoneNumberUtil;
6970
private IAppManager $appManager;
71+
private IAppConfig&MockObject $appConfig;
7072
private GroupDisplayNameCache&MockObject $groupDisplayNameCache;
7173

7274
protected function setUp(): void {
@@ -89,6 +91,7 @@ protected function setUp(): void {
8991
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
9092
$this->phoneNumberUtil = new PhoneNumberUtil();
9193
$this->appManager = $this->createMock(IAppManager::class);
94+
$this->appConfig = $this->createMock(IAppConfig::class);
9295
$this->rootFolder = $this->createMock(IRootFolder::class);
9396
$this->groupDisplayNameCache = $this->createMock(GroupDisplayNameCache::class);
9497

@@ -117,6 +120,7 @@ protected function setUp(): void {
117120
$this->eventDispatcher,
118121
$this->phoneNumberUtil,
119122
$this->appManager,
123+
$this->appConfig,
120124
$this->groupDisplayNameCache,
121125
])
122126
->onlyMethods(['fillStorageInfo'])
@@ -270,6 +274,7 @@ public function testGetUsersDetailsReturnsEmptyGroupsList(): void {
270274
$this->eventDispatcher,
271275
$this->phoneNumberUtil,
272276
$this->appManager,
277+
$this->appConfig,
273278
$this->groupDisplayNameCache,
274279
])
275280
->onlyMethods(['getUserData'])
@@ -587,6 +592,7 @@ public function testAddUserSuccessfulWithDisplayName(): void {
587592
$this->eventDispatcher,
588593
$this->phoneNumberUtil,
589594
$this->appManager,
595+
$this->appConfig,
590596
$this->groupDisplayNameCache,
591597
])
592598
->onlyMethods(['editUser'])
@@ -730,6 +736,67 @@ public function testAddUserSuccessfulGeneratePassword(): void {
730736
));
731737
}
732738

739+
/**
740+
* `newUser.sendEmail` has to be read as a boolean. It is stored as an untyped
741+
* 'yes'/'no' string on instances created before Nextcloud 33 and as a typed
742+
* boolean once the account settings toggle has been used, so comparing it to
743+
* the string 'yes' silently skipped the mail on upgraded instances.
744+
*/
745+
#[\PHPUnit\Framework\Attributes\DataProvider('dataAddUserWelcomeMail')]
746+
public function testAddUserSendsWelcomeMailWhenEnabled(bool $enabled): void {
747+
$this->appConfig
748+
->expects($this->atLeastOnce())
749+
->method('getValueBool')
750+
->with('core', 'newUser.sendEmail', true)
751+
->willReturn($enabled);
752+
753+
$newUser = $this->createMock(IUser::class);
754+
$newUser->expects($this->once())
755+
->method('setSystemEMailAddress')
756+
->with('foo@bar.com');
757+
$this->userManager
758+
->expects($this->once())
759+
->method('userExists')
760+
->with('NewUser')
761+
->willReturn(false);
762+
$this->userManager
763+
->expects($this->once())
764+
->method('createUser')
765+
->willReturn($newUser);
766+
$loggedInUser = $this->createMock(IUser::class);
767+
$loggedInUser
768+
->method('getUID')
769+
->willReturn('adminUser');
770+
$this->userSession
771+
->expects($this->once())
772+
->method('getUser')
773+
->willReturn($loggedInUser);
774+
$this->groupManager
775+
->expects($this->once())
776+
->method('isAdmin')
777+
->with('adminUser')
778+
->willReturn(true);
779+
780+
$emailTemplate = $this->createMock(IEMailTemplate::class);
781+
$this->newUserMailHelper
782+
->expects($enabled ? $this->once() : $this->never())
783+
->method('generateTemplate')
784+
->willReturn($emailTemplate);
785+
$this->newUserMailHelper
786+
->expects($enabled ? $this->once() : $this->never())
787+
->method('sendMail')
788+
->with($newUser, $emailTemplate);
789+
790+
$this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', 'foo@bar.com');
791+
}
792+
793+
public static function dataAddUserWelcomeMail(): array {
794+
return [
795+
'enabled' => [true],
796+
'disabled' => [false],
797+
];
798+
}
799+
733800
public function testAddUserSuccessfulLowercaseEmail(): void {
734801
$this->userManager
735802
->expects($this->once())
@@ -3928,6 +3995,7 @@ public function testGetCurrentUserLoggedIn(): void {
39283995
$this->eventDispatcher,
39293996
$this->phoneNumberUtil,
39303997
$this->appManager,
3998+
$this->appConfig,
39313999
$this->groupDisplayNameCache,
39324000
])
39334001
->onlyMethods(['getUserData'])
@@ -4023,6 +4091,7 @@ public function testGetUser(): void {
40234091
$this->eventDispatcher,
40244092
$this->phoneNumberUtil,
40254093
$this->appManager,
4094+
$this->appConfig,
40264095
$this->groupDisplayNameCache,
40274096
])
40284097
->onlyMethods(['getUserData'])

build/psalm-baseline.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2204,7 +2204,6 @@
22042204
<code><![CDATA[getAppValue]]></code>
22052205
<code><![CDATA[getAppValue]]></code>
22062206
<code><![CDATA[getAppValue]]></code>
2207-
<code><![CDATA[getAppValue]]></code>
22082207
<code><![CDATA[getUserValue]]></code>
22092208
<code><![CDATA[implementsActions]]></code>
22102209
<code><![CDATA[implementsActions]]></code>

core/Command/User/Add.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
180180

181181
$user->setSystemEMailAddress($email);
182182

183-
if ($this->appConfig->getValueString('core', 'newUser.sendEmail', 'yes') === 'yes') {
183+
if ($this->appConfig->getValueBool('core', 'newUser.sendEmail', true)) {
184184
try {
185185
$this->mailHelper->sendMail($user, $this->mailHelper->generateTemplate($user, true));
186186
$output->writeln('Welcome email sent to ' . $email);

tests/Core/Command/User/AddTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ public function testAddEmail(
9999
$this->userManager->method('createUser')
100100
->willReturn($this->user);
101101

102-
$this->appConfig->method('getValueString')
103-
->willReturn($shouldSendEmail ? 'yes' : 'no');
102+
$this->appConfig->method('getValueBool')
103+
->willReturn($shouldSendEmail);
104104

105105
$this->mailHelper->method('generateTemplate')
106106
->willReturn(static::createMock(IEMailTemplate::class));

tests/lib/AppConfigIntegrationTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,34 @@ public function testGetValueBool(): void {
519519
$this->assertSame(true, $config->getValueBool('typed', 'bool'));
520520
}
521521

522+
/**
523+
* Untyped values predate the typed config API and are still in the database of
524+
* every upgraded instance, so they have to keep resolving to a boolean. The
525+
* deprecated setter is used on purpose, as it is the only way to write a value
526+
* without a type.
527+
*/
528+
#[\PHPUnit\Framework\Attributes\DataProvider('dataUntypedBool')]
529+
public function testGetValueBoolOnUntypedValue(string $stored, bool $expected): void {
530+
/** @var AppConfig $config */
531+
$config = $this->generateAppConfig();
532+
$config->setValue('feed', 'untyped-bool', $stored);
533+
534+
$this->assertSame($expected, $config->getValueBool('feed', 'untyped-bool'));
535+
}
536+
537+
public static function dataUntypedBool(): array {
538+
return [
539+
'yes' => ['yes', true],
540+
'no' => ['no', false],
541+
'true' => ['true', true],
542+
'false' => ['false', false],
543+
'on' => ['on', true],
544+
'1' => ['1', true],
545+
'0' => ['0', false],
546+
'empty' => ['', false],
547+
];
548+
}
549+
522550
public function testGetValueBoolOnUnknownAppReturnsDefault(): void {
523551
$config = $this->generateAppConfig();
524552
$this->assertSame(false, $config->getValueBool('typed-1', 'bool', false));

0 commit comments

Comments
 (0)