fix(provisioning_api): allow clearing display name via editUserMultiField

Map empty string to userId since User::setDisplayName() rejects ""
-e
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
This commit is contained in:
Peter Ringelmann 2026-04-02 18:03:19 +02:00
parent fed1a59f15
commit c8f3c0423e
3 changed files with 38 additions and 1 deletions

View file

@ -1078,7 +1078,9 @@ class UsersController extends AUserDataOCSController
// Apply remaining changes — all fully validated, setters won't throw
if ($displayName !== null) {
$targetUser->setDisplayName($displayName);
// OC\User\User::setDisplayName() rejects empty strings (!empty check),
// so "clear display name" means "reset to userId" — the default.
$targetUser->setDisplayName($displayName !== '' ? $displayName : $userId);
}
if ($email !== null) {

View file

@ -2852,6 +2852,29 @@ class UsersControllerTest extends TestCase {
$this->assertArrayHasKey('language', $result->getData()['errors']);
}
public function testEditUserMultiFieldClearDisplayNameResetsToUserId(): void {
$currentUser = $this->createMock(IUser::class);
$currentUser->method('getUID')->willReturn('admin');
$this->userSession->method('getUser')->willReturn($currentUser);
$targetUser = $this->createMock(IUser::class);
$targetUser->method('getUID')->willReturn('targetuser');
$targetUser->method('canChangeDisplayName')->willReturn(true);
$targetUser->method('getBackend')->willReturn($this->createMock(UserInterface::class));
$this->userManager->method('get')->with('targetuser')->willReturn($targetUser);
$this->groupManager->method('isAdmin')->with('admin')->willReturn(true);
$this->groupManager->method('isDelegatedAdmin')->willReturn(false);
$subAdmin = $this->createMock(ISubAdmin::class);
$this->groupManager->method('getSubAdmin')->willReturn($subAdmin);
// Clearing display name (empty string) should reset to userId
$targetUser->expects($this->once())->method('setDisplayName')->with('targetuser')->willReturn(true);
$result = $this->api->editUserMultiField('targetuser', displayName: '');
$this->assertSame(Http::STATUS_OK, $result->getStatus());
}
public function testDeleteUserNotExistingUser(): void {
$this->expectException(OCSException::class);

View file

@ -153,6 +153,18 @@ describe('diffPayload', () => {
expect(diffPayload(initial, current)).toEqual({ displayName: 'Robert' })
})
it('detects displayName cleared to empty string', () => {
const initial = makeFormData({ displayName: 'Bob' })
const current = makeFormData({ displayName: '' })
expect(diffPayload(initial, current)).toEqual({ displayName: '' })
})
it('detects email cleared to empty string', () => {
const initial = makeFormData({ email: 'bob@example.com' })
const current = makeFormData({ email: '' })
expect(diffPayload(initial, current)).toEqual({ email: '' })
})
it('always includes password when non-empty', () => {
const initial = makeFormData()
const current = makeFormData({ password: 'secret123' })