Skip to content

Commit ce5964c

Browse files
ArtificialOwlbackportbot[bot]
authored andcommitted
fix(userconfig): using api bit functions
Signed-off-by: Maxence Lange <[email protected]>
1 parent 6cc697e commit ce5964c

File tree

6 files changed

+136
-9
lines changed

6 files changed

+136
-9
lines changed

apps/settings/lib/ConfigLexicon.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99
namespace OCA\Settings;
1010

11-
use OC\Config\UserConfig;
11+
use OCP\Config\IUserConfig;
1212
use OCP\Config\Lexicon\Entry;
1313
use OCP\Config\Lexicon\ILexicon;
1414
use OCP\Config\Lexicon\Strictness;
@@ -20,7 +20,7 @@
2020
* Please Add & Manage your Config Keys in that file and keep the Lexicon up to date!
2121
*/
2222
class ConfigLexicon implements ILexicon {
23-
public const USER_SETTINGS_MAIL = 'mail';
23+
public const USER_SETTINGS_EMAIL = 'email';
2424

2525
public function getStrictness(): Strictness {
2626
return Strictness::IGNORE;
@@ -32,7 +32,7 @@ public function getAppConfigs(): array {
3232

3333
public function getUserConfigs(): array {
3434
return [
35-
new Entry(key: self::USER_SETTINGS_MAIL, type: ValueType::STRING, defaultRaw: '', definition: 'account mail address', flags: UserConfig::FLAG_INDEXED),
35+
new Entry(key: self::USER_SETTINGS_EMAIL, type: ValueType::STRING, defaultRaw: '', definition: 'account mail address', flags: IUserConfig::FLAG_INDEXED),
3636
];
3737
}
3838
}

lib/private/Config/ConfigManager.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public function updateLexiconEntries(string $appId): void {
9393
$lexicon = $this->userConfig->getConfigDetailsFromLexicon($appId);
9494
foreach ($lexicon['entries'] as $entry) {
9595
// upgrade based on index flag
96-
$this->userConfig->updateGlobalIndexed($appId, $entry->getKey(), $entry->isFlagged(UserConfig::FLAG_INDEXED));
96+
$this->userConfig->updateGlobalIndexed($appId, $entry->getKey(), $entry->isFlagged(IUserConfig::FLAG_INDEXED));
9797
}
9898
}
9999

lib/private/Config/UserConfig.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ private function searchUsersByTypedValue(string $app, string $key, string|array
479479

480480
$lexiconEntry = $this->getLexiconEntry($app, $key);
481481
if ($lexiconEntry?->isFlagged(self::FLAG_INDEXED) === false) {
482-
$this->logger->notice('UserConfig+Lexicon: using searchUsersByTypedValue on a config key not set as indexed');
482+
$this->logger->notice('UserConfig+Lexicon: using searchUsersByTypedValue on config key ' . $app . '/' . $key . ' which is not set as indexed');
483483
}
484484

485485
$qb = $this->connection->getQueryBuilder();
@@ -1423,18 +1423,30 @@ public function updateGlobalIndexed(string $app, string $key, bool $indexed): vo
14231423
$this->assertParams('', $app, $key, allowEmptyUser: true);
14241424
$this->matchAndApplyLexiconDefinition('', $app, $key);
14251425

1426-
$bitPosition = log(self::FLAG_INDEXED) / log(2); // emulate base-2 logarithm (log2)
1427-
$bitOperation = ($indexed) ? '`flags` | (1 << ' . $bitPosition . ')' : '`flags` & ~(1 << ' . $bitPosition . ')';
1428-
14291426
$update = $this->connection->getQueryBuilder();
14301427
$update->update('preferences')
1431-
->set('flags', $update->createFunction($bitOperation))
1428+
// emptying field 'indexed' if key is not set as indexed anymore
14321429
->set('indexed', ($indexed) ? 'configvalue' : $update->createNamedParameter(''))
14331430
->where(
14341431
$update->expr()->eq('appid', $update->createNamedParameter($app)),
14351432
$update->expr()->eq('configkey', $update->createNamedParameter($key))
14361433
);
14371434

1435+
// switching flags 'indexed' on and off is about adding/removing the bit value on the correct entries
1436+
if ($indexed) {
1437+
$update->set('flags', $update->func()->add('flags', $update->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)));
1438+
$update->andWhere(
1439+
$update->expr()->neq($update->expr()->castColumn(
1440+
$update->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), IQueryBuilder::PARAM_INT), $update->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)
1441+
));
1442+
} else {
1443+
$update->set('flags', $update->func()->subtract('flags', $update->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)));
1444+
$update->andWhere(
1445+
$update->expr()->eq($update->expr()->castColumn(
1446+
$update->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), IQueryBuilder::PARAM_INT), $update->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)
1447+
));
1448+
}
1449+
14381450
$update->executeStatement();
14391451

14401452
// we clear all cache

tests/lib/Config/LexiconTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,15 @@ protected function tearDown(): void {
6060
$this->appConfig->deleteApp(TestLexicon_N::APPID);
6161
$this->appConfig->deleteApp(TestLexicon_W::APPID);
6262
$this->appConfig->deleteApp(TestLexicon_E::APPID);
63+
$this->appConfig->deleteApp(TestLexicon_UserIndexed::APPID);
64+
$this->appConfig->deleteApp(TestLexicon_UserIndexedRemove::APPID);
6365

6466
$this->userConfig->deleteApp(TestConfigLexicon_I::APPID);
6567
$this->userConfig->deleteApp(TestLexicon_N::APPID);
6668
$this->userConfig->deleteApp(TestLexicon_W::APPID);
6769
$this->userConfig->deleteApp(TestLexicon_E::APPID);
70+
$this->userConfig->deleteApp(TestLexicon_UserIndexed::APPID);
71+
$this->userConfig->deleteApp(TestLexicon_UserIndexedRemove::APPID);
6872
}
6973

7074
public function testAppLexiconSetCorrect() {
@@ -234,4 +238,50 @@ public function testUserConfigLexiconPresets() {
234238
$this->presetManager->setLexiconPreset(Preset::FAMILY);
235239
$this->assertSame('family', $this->userConfig->getValueString('user1', TestLexicon_E::APPID, 'key3'));
236240
}
241+
242+
public function testLexiconIndexedUpdate() {
243+
$this->userConfig->setValueString('user1', TestLexicon_UserIndexed::APPID, 'key1', 'abcd');
244+
$this->userConfig->setValueString('user2', TestLexicon_UserIndexed::APPID, 'key1', '1234', flags: 64);
245+
$this->userConfig->setValueString('user3', TestLexicon_UserIndexed::APPID, 'key1', 'qwer', flags: IUserConfig::FLAG_INDEXED);
246+
$this->userConfig->setValueString('user4', TestLexicon_UserIndexed::APPID, 'key1', 'uiop', flags: 64 | IUserConfig::FLAG_INDEXED);
247+
248+
$bootstrapCoordinator = Server::get(Coordinator::class);
249+
$bootstrapCoordinator->getRegistrationContext()?->registerConfigLexicon(TestLexicon_UserIndexed::APPID, TestLexicon_UserIndexed::class);
250+
$this->userConfig->clearCacheAll();
251+
252+
$this->configManager->updateLexiconEntries(TestLexicon_UserIndexed::APPID);
253+
254+
$this->assertTrue($this->userConfig->isIndexed('user1', TestLexicon_UserIndexed::APPID, 'key1'));
255+
$this->assertTrue($this->userConfig->isIndexed('user2', TestLexicon_UserIndexed::APPID, 'key1'));
256+
$this->assertTrue($this->userConfig->isIndexed('user3', TestLexicon_UserIndexed::APPID, 'key1'));
257+
$this->assertTrue($this->userConfig->isIndexed('user4', TestLexicon_UserIndexed::APPID, 'key1'));
258+
259+
$this->assertSame(2, $this->userConfig->getValueFlags('user1', TestLexicon_UserIndexed::APPID, 'key1'));
260+
$this->assertSame(66, $this->userConfig->getValueFlags('user2', TestLexicon_UserIndexed::APPID, 'key1'));
261+
$this->assertSame(2, $this->userConfig->getValueFlags('user3', TestLexicon_UserIndexed::APPID, 'key1'));
262+
$this->assertSame(66, $this->userConfig->getValueFlags('user4', TestLexicon_UserIndexed::APPID, 'key1'));
263+
}
264+
265+
public function testLexiconIndexedUpdateRemove() {
266+
$this->userConfig->setValueString('user1', TestLexicon_UserIndexedRemove::APPID, 'key1', 'abcd');
267+
$this->userConfig->setValueString('user2', TestLexicon_UserIndexedRemove::APPID, 'key1', '1234', flags: 64);
268+
$this->userConfig->setValueString('user3', TestLexicon_UserIndexedRemove::APPID, 'key1', 'qwer', flags: IUserConfig::FLAG_INDEXED);
269+
$this->userConfig->setValueString('user4', TestLexicon_UserIndexedRemove::APPID, 'key1', 'uiop', flags: 64 | IUserConfig::FLAG_INDEXED);
270+
271+
$bootstrapCoordinator = Server::get(Coordinator::class);
272+
$bootstrapCoordinator->getRegistrationContext()?->registerConfigLexicon(TestLexicon_UserIndexedRemove::APPID, TestLexicon_UserIndexedRemove::class);
273+
$this->userConfig->clearCacheAll();
274+
275+
$this->configManager->updateLexiconEntries(TestLexicon_UserIndexedRemove::APPID);
276+
277+
$this->assertFalse($this->userConfig->isIndexed('user1', TestLexicon_UserIndexedRemove::APPID, 'key1'));
278+
$this->assertFalse($this->userConfig->isIndexed('user2', TestLexicon_UserIndexedRemove::APPID, 'key1'));
279+
$this->assertFalse($this->userConfig->isIndexed('user3', TestLexicon_UserIndexedRemove::APPID, 'key1'));
280+
$this->assertFalse($this->userConfig->isIndexed('user4', TestLexicon_UserIndexedRemove::APPID, 'key1'));
281+
282+
$this->assertSame(0, $this->userConfig->getValueFlags('user1', TestLexicon_UserIndexedRemove::APPID, 'key1'));
283+
$this->assertSame(64, $this->userConfig->getValueFlags('user2', TestLexicon_UserIndexedRemove::APPID, 'key1'));
284+
$this->assertSame(0, $this->userConfig->getValueFlags('user3', TestLexicon_UserIndexedRemove::APPID, 'key1'));
285+
$this->assertSame(64, $this->userConfig->getValueFlags('user4', TestLexicon_UserIndexedRemove::APPID, 'key1'));
286+
}
237287
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-only
7+
*/
8+
9+
namespace Tests\lib\Config;
10+
11+
use OCP\Config\IUserConfig;
12+
use OCP\Config\Lexicon\Entry;
13+
use OCP\Config\Lexicon\ILexicon;
14+
use OCP\Config\Lexicon\Strictness;
15+
use OCP\Config\ValueType;
16+
17+
class TestLexicon_UserIndexed implements ILexicon {
18+
public const APPID = 'lexicon_user_indexed';
19+
public function getStrictness(): Strictness {
20+
return Strictness::EXCEPTION;
21+
}
22+
23+
public function getAppConfigs(): array {
24+
return [
25+
];
26+
}
27+
28+
public function getUserConfigs(): array {
29+
return [
30+
new Entry(key: 'key1', type: ValueType::STRING, defaultRaw: '', definition: 'test key', flags: IUserConfig::FLAG_INDEXED),
31+
];
32+
}
33+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-only
7+
*/
8+
9+
namespace Tests\lib\Config;
10+
11+
use OCP\Config\Lexicon\Entry;
12+
use OCP\Config\Lexicon\ILexicon;
13+
use OCP\Config\Lexicon\Strictness;
14+
use OCP\Config\ValueType;
15+
16+
class TestLexicon_UserIndexedRemove implements ILexicon {
17+
public const APPID = 'lexicon_user_not_indexed';
18+
public function getStrictness(): Strictness {
19+
return Strictness::EXCEPTION;
20+
}
21+
22+
public function getAppConfigs(): array {
23+
return [
24+
];
25+
}
26+
27+
public function getUserConfigs(): array {
28+
return [
29+
new Entry(key: 'key1', type: ValueType::STRING, defaultRaw: '', definition: 'test key'),
30+
];
31+
}
32+
}

0 commit comments

Comments
 (0)