Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use OCA\Circles\Events\CircleDestroyedEvent;
use OCA\Circles\Events\EditingCircleEvent;
use OCA\Collectives\CacheListener;
use OCA\Collectives\ConfigLexicon;
use OCA\Collectives\Dashboard\RecentPagesWidget;
use OCA\Collectives\Db\CollectiveMapper;
use OCA\Collectives\Db\CollectiveVersionMapper;
Expand Down Expand Up @@ -86,6 +87,8 @@ public function register(IRegistrationContext $context): void {

$context->registerMiddleware(PublicOCSMiddleware::class);

$context->registerConfigLexicon(ConfigLexicon::class);

$context->registerService(MountProvider::class, fn (ContainerInterface $c) => new MountProvider(
$c->get(CollectiveHelper::class),
$c->get(CollectiveFolderManager::class),
Expand Down
97 changes: 97 additions & 0 deletions lib/ConfigLexicon.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Collectives;

use OCP\Config\Lexicon\Entry;
use OCP\Config\Lexicon\ILexicon;
use OCP\Config\Lexicon\Strictness;
use OCP\Config\ValueType;
use OCP\IAppConfig;

/**
* Config Lexicon for collectives.
*
* Please Add & Manage your Config Keys in that file and keep the Lexicon up to date!
*
* {@see ILexicon}
*/
class ConfigLexicon implements ILexicon {
public const DEFAULT_USER_FOLDER = 'default_user_folder';
public const ORPHANED_COLLECTIVES = 'orphaned_collectives';
public const MIGRATED_BACKLINKS = 'migrated_backlinks';
public const MIGRATED_SLUGS = 'migrated_slugs';
public const MIGRATED_USER_FOLDER_SETTINGS = 'migrated_user_folder_settings';

public const USER_FOLDER = 'user_folder';

#[\Override]
public function getStrictness(): Strictness {
return Strictness::IGNORE;
}

#[\Override]
public function getAppConfigs(): array {
return [
new Entry(
self::DEFAULT_USER_FOLDER,
ValueType::STRING,
defaultRaw: '',
definition: 'Default path of the collectives folder in user home directories',
lazy: false,
note: 'Empty means a localized "/Collectives" folder. Users can override it with the user config key user_folder.',
),
new Entry(
self::ORPHANED_COLLECTIVES,
ValueType::ARRAY,
defaultRaw: [],
definition: 'IDs of collectives whose team was missing during the last garbage collection run',
lazy: true,
flags: IAppConfig::FLAG_INTERNAL,
),
new Entry(
self::MIGRATED_BACKLINKS,
ValueType::BOOL,
defaultRaw: false,
definition: 'Whether the backlinks repair step has completed',
lazy: false,
flags: IAppConfig::FLAG_INTERNAL,
),
new Entry(
self::MIGRATED_SLUGS,
ValueType::BOOL,
defaultRaw: false,
definition: 'Whether the slug generation repair step has completed',
lazy: false,
flags: IAppConfig::FLAG_INTERNAL,
),
new Entry(
self::MIGRATED_USER_FOLDER_SETTINGS,
ValueType::BOOL,
defaultRaw: false,
definition: 'Whether the user folder settings repair step has completed',
lazy: false,
flags: IAppConfig::FLAG_INTERNAL,
),
];
}

#[\Override]
public function getUserConfigs(): array {
return [
new Entry(
self::USER_FOLDER,
ValueType::STRING,
definition: 'Path of the collectives folder in the user home directory',
lazy: false,
note: 'No lexicon default on purpose: callers fall back to the app config key default_user_folder.',
),
];
}
}
5 changes: 3 additions & 2 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

namespace OCA\Collectives\Controller;

use OCA\Collectives\ConfigLexicon;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
Expand Down Expand Up @@ -37,7 +38,7 @@ public function __construct(
* @throws OCSBadRequestException
*/
private function validateGetUserSetting(string $setting): void {
if ($setting === 'user_folder') {
if ($setting === ConfigLexicon::USER_FOLDER) {
return;
}

Expand All @@ -52,7 +53,7 @@ private function validateSetUserSetting(string $setting, ?string $value): void {
throw new OCSBadRequestException('Empty value for setting ' . $setting);
}

if ($setting === 'user_folder') {
if ($setting === ConfigLexicon::USER_FOLDER) {
// No root folder, has to start with `/`, not allowed to end with `/`
if ($value === '/'
|| !(str_starts_with($value, '/'))
Expand Down
7 changes: 4 additions & 3 deletions lib/Fs/UserFolderHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace OCA\Collectives\Fs;

use OC_Util;
use OCA\Collectives\ConfigLexicon;
use OCP\Config\IUserConfig;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
Expand All @@ -29,15 +30,15 @@ public function __construct(
}

public function getUserFolderSetting(string $userId): string {
$defaultUserFolder = $this->appConfig->getValueString('collectives', 'default_user_folder', '');
$defaultUserFolder = $this->appConfig->getValueString('collectives', ConfigLexicon::DEFAULT_USER_FOLDER, '');
// Get collectives user folder from settings and default to translated 'Collectives'
$userCollectivesPath = $this->userConfig->getValueString($userId, 'collectives', 'user_folder', $defaultUserFolder);
$userCollectivesPath = $this->userConfig->getValueString($userId, 'collectives', ConfigLexicon::USER_FOLDER, $defaultUserFolder);
if ($userCollectivesPath === '') {
$user = $this->userManager->get($userId);
$userLang = $this->l10nFactory->getUserLanguage($user);
$l10n = $this->l10nFactory->get('collectives', $userLang);
$userCollectivesPath = DIRECTORY_SEPARATOR . '.' . $l10n->t('Collectives');
$this->userConfig->setValueString($userId, 'collectives', 'user_folder', $userCollectivesPath);
$this->userConfig->setValueString($userId, 'collectives', ConfigLexicon::USER_FOLDER, $userCollectivesPath);
}

return $userCollectivesPath;
Expand Down
6 changes: 3 additions & 3 deletions lib/Service/CollectiveGarbageCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@

namespace OCA\Collectives\Service;

use OCA\Collectives\ConfigLexicon;
use OCA\Collectives\Db\Collective;
use OCA\Collectives\Db\CollectiveMapper;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IAppConfig;
use Psr\Log\LoggerInterface;

class CollectiveGarbageCollector {
private const CONFIG_KEY = 'orphaned_collectives';
// Collectives need to be orphaned for at least a week before they get purged
public const GRACE_PERIOD = 60 * 60 * 24 * 7;

Expand Down Expand Up @@ -58,7 +58,7 @@ public function purgeOrphanedCollectives(): int {
}

/** @var array<string, int> $previouslyOrphaned */
$previouslyOrphaned = $this->appConfig->getValueArray('collectives', self::CONFIG_KEY, lazy: true);
$previouslyOrphaned = $this->appConfig->getValueArray('collectives', ConfigLexicon::ORPHANED_COLLECTIVES, lazy: true);
$now = $this->timeFactory->getTime();
$stillOrphaned = [];
$purgeCount = 0;
Expand All @@ -85,7 +85,7 @@ public function purgeOrphanedCollectives(): int {
}

// Only keep collectives that were orphaned in this run
$this->appConfig->setValueArray('collectives', self::CONFIG_KEY, $stillOrphaned, lazy: true);
$this->appConfig->setValueArray('collectives', ConfigLexicon::ORPHANED_COLLECTIVES, $stillOrphaned, lazy: true);

return $purgeCount;
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Settings/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace OCA\Collectives\Settings;

use OCA\Collectives\AppInfo\Application;
use OCA\Collectives\ConfigLexicon;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\IAppConfig;
Expand All @@ -25,7 +26,7 @@ public function __construct(

public function getForm(): TemplateResponse {
$parameters = [
'default_user_folder' => $this->appConfig->getValueString('collectives', 'default_user_folder', ''),
'default_user_folder' => $this->appConfig->getValueString('collectives', ConfigLexicon::DEFAULT_USER_FOLDER, ''),
];
$this->initialState->provideInitialState('adminSettings', $parameters);

Expand Down
38 changes: 38 additions & 0 deletions tests/Unit/ConfigLexiconTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace Unit;

use OCA\Collectives\ConfigLexicon;
use OCP\Config\Lexicon\Entry;
use OCP\Config\Lexicon\Preset;
use Test\TestCase;

class ConfigLexiconTest extends TestCase {
private ConfigLexicon $lexicon;

protected function setUp(): void {
parent::setUp();
$this->lexicon = new ConfigLexicon();
}

public function testAppConfigKeysAreUnique(): void {
$keys = array_map(static fn (Entry $e) => $e->getKey(), $this->lexicon->getAppConfigs());
self::assertSame(array_unique($keys), $keys);
}

public function testUserFolderHasNoLexiconDefault(): void {
$entries = array_filter(
$this->lexicon->getUserConfigs(),
static fn (Entry $e) => $e->getKey() === ConfigLexicon::USER_FOLDER,
);
self::assertCount(1, $entries);
self::assertNull(array_values($entries)[0]->getDefault(Preset::NONE));
}
}
Loading