diff options
Diffstat (limited to 'lib')
486 files changed, 3519 insertions, 1383 deletions
diff --git a/lib/autoloader.php b/lib/autoloader.php deleted file mode 100644 index 7084eb93c89..00000000000 --- a/lib/autoloader.php +++ /dev/null @@ -1,167 +0,0 @@ -<?php - -declare(strict_types=1); -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2013-2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ -namespace OC; - -use OCP\App\AppPathNotFoundException; -use OCP\App\IAppManager; -use OCP\AutoloadNotAllowedException; -use OCP\ICache; -use Psr\Log\LoggerInterface; - -class Autoloader { - /** @var bool */ - private $useGlobalClassPath = true; - /** @var array */ - private $validRoots = []; - - /** - * Optional low-latency memory cache for class to path mapping. - */ - protected ?ICache $memoryCache = null; - - /** - * Autoloader constructor. - * - * @param string[] $validRoots - */ - public function __construct(array $validRoots) { - foreach ($validRoots as $root) { - $this->validRoots[$root] = true; - } - } - - /** - * Add a path to the list of valid php roots for auto loading - * - * @param string $root - */ - public function addValidRoot(string $root): void { - $root = stream_resolve_include_path($root); - $this->validRoots[$root] = true; - } - - /** - * disable the usage of the global classpath \OC::$CLASSPATH - */ - public function disableGlobalClassPath(): void { - $this->useGlobalClassPath = false; - } - - /** - * enable the usage of the global classpath \OC::$CLASSPATH - */ - public function enableGlobalClassPath(): void { - $this->useGlobalClassPath = true; - } - - /** - * get the possible paths for a class - * - * @param string $class - * @return array an array of possible paths - */ - public function findClass(string $class): array { - $class = trim($class, '\\'); - - $paths = []; - if ($this->useGlobalClassPath && array_key_exists($class, \OC::$CLASSPATH)) { - $paths[] = \OC::$CLASSPATH[$class]; - /** - * @TODO: Remove this when necessary - * Remove "apps/" from inclusion path for smooth migration to multi app dir - */ - if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) { - \OCP\Server::get(LoggerInterface::class)->debug('include path for class "' . $class . '" starts with "apps/"', ['app' => 'core']); - $paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]); - } - } elseif (strpos($class, 'OC_') === 0) { - $paths[] = \OC::$SERVERROOT . '/lib/private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php'); - } elseif (strpos($class, 'OCA\\') === 0) { - [, $app, $rest] = explode('\\', $class, 3); - $app = strtolower($app); - try { - $appPath = \OCP\Server::get(IAppManager::class)->getAppPath($app); - if (stream_resolve_include_path($appPath)) { - $paths[] = $appPath . '/' . strtolower(str_replace('\\', '/', $rest) . '.php'); - // If not found in the root of the app directory, insert '/lib' after app id and try again. - $paths[] = $appPath . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php'); - } - } catch (AppPathNotFoundException) { - // App not found, ignore - } - } elseif ($class === 'Test\\TestCase') { - // This File is considered public API, so we make sure that the class - // can still be loaded, although the PSR-4 paths have not been loaded. - $paths[] = \OC::$SERVERROOT . '/tests/lib/TestCase.php'; - } - return $paths; - } - - /** - * @param string $fullPath - * @return bool - * @throws AutoloadNotAllowedException - */ - protected function isValidPath(string $fullPath): bool { - foreach ($this->validRoots as $root => $true) { - if (substr($fullPath, 0, strlen($root) + 1) === $root . '/') { - return true; - } - } - throw new AutoloadNotAllowedException($fullPath); - } - - /** - * Load the specified class - * - * @param string $class - * @return bool - * @throws AutoloadNotAllowedException - */ - public function load(string $class): bool { - if (class_exists($class, false)) { - return false; - } - - $pathsToRequire = null; - if ($this->memoryCache) { - $pathsToRequire = $this->memoryCache->get($class); - } - - if (!is_array($pathsToRequire)) { - // No cache or cache miss - $pathsToRequire = []; - foreach ($this->findClass($class) as $path) { - $fullPath = stream_resolve_include_path($path); - if ($fullPath && $this->isValidPath($fullPath)) { - $pathsToRequire[] = $fullPath; - } - } - - if ($this->memoryCache) { - $this->memoryCache->set($class, $pathsToRequire, 60); // cache 60 sec - } - } - - foreach ($pathsToRequire as $fullPath) { - require_once $fullPath; - } - - return false; - } - - /** - * Sets the optional low-latency cache for class to path mapping. - * - * @param ICache $memoryCache Instance of memory cache. - */ - public function setMemoryCache(?ICache $memoryCache = null): void { - $this->memoryCache = $memoryCache; - } -} diff --git a/lib/base.php b/lib/base.php index ad80df357c5..8613ab62ef1 100644 --- a/lib/base.php +++ b/lib/base.php @@ -40,10 +40,6 @@ require_once 'public/Constants.php'; */ class OC { /** - * Associative array for autoloading. classname => filename - */ - public static array $CLASSPATH = []; - /** * The installation path for Nextcloud on the server (e.g. /srv/http/nextcloud) */ public static string $SERVERROOT = ''; @@ -73,8 +69,6 @@ class OC { */ public static bool $CLI = false; - public static \OC\Autoloader $loader; - public static \Composer\Autoload\ClassLoader $composerAutoloader; public static \OC\Server $server; @@ -147,8 +141,8 @@ class OC { // Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing // slash which is required by URL generation. - if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT && - substr($_SERVER['REQUEST_URI'], -1) !== '/') { + if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT + && substr($_SERVER['REQUEST_URI'], -1) !== '/') { header('Location: ' . \OC::$WEBROOT . '/'); exit(); } @@ -291,8 +285,8 @@ class OC { $tooBig = ($totalUsers > 50); } } - $ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) && - $_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis'; + $ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) + && $_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis'; if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) { // send http status 503 @@ -399,6 +393,12 @@ class OC { $cookie_path = OC::$WEBROOT ? : '/'; ini_set('session.cookie_path', $cookie_path); + // set the cookie domain to the Nextcloud domain + $cookie_domain = self::$config->getValue('cookie_domain', ''); + if ($cookie_domain) { + ini_set('session.cookie_domain', $cookie_domain); + } + // Let the session name be changed in the initSession Hook $sessionName = OC_Util::getInstanceId(); @@ -551,10 +551,10 @@ class OC { $processingScript = explode('/', $requestUri); $processingScript = $processingScript[count($processingScript) - 1]; - // index.php routes are handled in the middleware - // and cron.php does not need any authentication at all - if ($processingScript === 'index.php' - || $processingScript === 'cron.php') { + if ($processingScript === 'index.php' // index.php routes are handled in the middleware + || $processingScript === 'cron.php' // and cron.php does not need any authentication at all + || $processingScript === 'public.php' // For public.php, auth for password protected shares is done in the PublicAuth plugin + ) { return; } @@ -597,15 +597,6 @@ class OC { // register autoloader $loaderStart = microtime(true); - require_once __DIR__ . '/autoloader.php'; - self::$loader = new \OC\Autoloader([ - OC::$SERVERROOT . '/lib/private/legacy', - ]); - if (defined('PHPUNIT_RUN')) { - self::$loader->addValidRoot(OC::$SERVERROOT . '/tests'); - } - spl_autoload_register([self::$loader, 'load']); - $loaderEnd = microtime(true); self::$CLI = (php_sapi_name() == 'cli'); @@ -631,6 +622,10 @@ class OC { print($e->getMessage()); exit(); } + $loaderEnd = microtime(true); + + // Enable lazy loading if activated + \OC\AppFramework\Utility\SimpleContainer::$useLazyObjects = (bool)self::$config->getValue('enable_lazy_objects', true); // setup the basic server self::$server = new \OC\Server(\OC::$WEBROOT, self::$config); @@ -659,9 +654,6 @@ class OC { error_reporting(E_ALL); } - $systemConfig = Server::get(\OC\SystemConfig::class); - self::registerAutoloaderCache($systemConfig); - // initialize intl fallback if necessary OC_Util::isSetLocaleWorking(); @@ -695,6 +687,7 @@ class OC { throw new \OCP\HintException('The PHP SimpleXML/PHP-XML extension is not installed.', 'Install the extension or make sure it is enabled.'); } + $systemConfig = Server::get(\OC\SystemConfig::class); $appManager = Server::get(\OCP\App\IAppManager::class); if ($systemConfig->getValue('installed', false)) { $appManager->loadApps(['session']); @@ -787,8 +780,8 @@ class OC { // Make sure that the application class is not loaded before the database is setup if ($systemConfig->getValue('installed', false)) { $appManager->loadApp('settings'); - /* Build core application to make sure that listeners are registered */ - Server::get(\OC\Core\Application::class); + /* Run core application registration */ + $bootstrapCoordinator->runLazyRegistration('core'); } //make sure temporary files are cleaned up @@ -978,23 +971,6 @@ class OC { } } - protected static function registerAutoloaderCache(\OC\SystemConfig $systemConfig): void { - // The class loader takes an optional low-latency cache, which MUST be - // namespaced. The instanceid is used for namespacing, but might be - // unavailable at this point. Furthermore, it might not be possible to - // generate an instanceid via \OC_Util::getInstanceId() because the - // config file may not be writable. As such, we only register a class - // loader cache if instanceid is available without trying to create one. - $instanceId = $systemConfig->getValue('instanceid', null); - if ($instanceId) { - try { - $memcacheFactory = Server::get(\OCP\ICacheFactory::class); - self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader')); - } catch (\Exception $ex) { - } - } - } - /** * Handle the request */ diff --git a/lib/composer/autoload.php b/lib/composer/autoload.php index b3b39129e7a..7b1481e876c 100644 --- a/lib/composer/autoload.php +++ b/lib/composer/autoload.php @@ -14,10 +14,7 @@ if (PHP_VERSION_ID < 50600) { echo $err; } } - trigger_error( - $err, - E_USER_ERROR - ); + throw new RuntimeException($err); } require_once __DIR__ . '/composer/autoload_real.php'; diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index c65c26af2f2..5300af5242c 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -679,6 +679,7 @@ return array( 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => $baseDir . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', 'OCP\\OCM\\Exceptions\\OCMArgumentException' => $baseDir . '/lib/public/OCM/Exceptions/OCMArgumentException.php', 'OCP\\OCM\\Exceptions\\OCMProviderException' => $baseDir . '/lib/public/OCM/Exceptions/OCMProviderException.php', + 'OCP\\OCM\\ICapabilityAwareOCMProvider' => $baseDir . '/lib/public/OCM/ICapabilityAwareOCMProvider.php', 'OCP\\OCM\\IOCMDiscoveryService' => $baseDir . '/lib/public/OCM/IOCMDiscoveryService.php', 'OCP\\OCM\\IOCMProvider' => $baseDir . '/lib/public/OCM/IOCMProvider.php', 'OCP\\OCM\\IOCMResource' => $baseDir . '/lib/public/OCM/IOCMResource.php', @@ -1049,6 +1050,7 @@ return array( 'OC\\AppScriptDependency' => $baseDir . '/lib/private/AppScriptDependency.php', 'OC\\AppScriptSort' => $baseDir . '/lib/private/AppScriptSort.php', 'OC\\App\\AppManager' => $baseDir . '/lib/private/App/AppManager.php', + 'OC\\App\\AppStore\\AppNotFoundException' => $baseDir . '/lib/private/App/AppStore/AppNotFoundException.php', 'OC\\App\\AppStore\\Bundles\\Bundle' => $baseDir . '/lib/private/App/AppStore/Bundles/Bundle.php', 'OC\\App\\AppStore\\Bundles\\BundleFetcher' => $baseDir . '/lib/private/App/AppStore/Bundles/BundleFetcher.php', 'OC\\App\\AppStore\\Bundles\\EducationBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/EducationBundle.php', @@ -1188,6 +1190,7 @@ return array( 'OC\\Comments\\Manager' => $baseDir . '/lib/private/Comments/Manager.php', 'OC\\Comments\\ManagerFactory' => $baseDir . '/lib/private/Comments/ManagerFactory.php', 'OC\\Config' => $baseDir . '/lib/private/Config.php', + 'OC\\Config\\ConfigManager' => $baseDir . '/lib/private/Config/ConfigManager.php', 'OC\\Config\\Lexicon\\CoreConfigLexicon' => $baseDir . '/lib/private/Config/Lexicon/CoreConfigLexicon.php', 'OC\\Config\\UserConfig' => $baseDir . '/lib/private/Config/UserConfig.php', 'OC\\Console\\Application' => $baseDir . '/lib/private/Console/Application.php', @@ -1202,7 +1205,7 @@ return array( 'OC\\Contacts\\ContactsMenu\\Providers\\EMailProvider' => $baseDir . '/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php', 'OC\\Contacts\\ContactsMenu\\Providers\\LocalTimeProvider' => $baseDir . '/lib/private/Contacts/ContactsMenu/Providers/LocalTimeProvider.php', 'OC\\Contacts\\ContactsMenu\\Providers\\ProfileProvider' => $baseDir . '/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php', - 'OC\\Core\\Application' => $baseDir . '/core/Application.php', + 'OC\\Core\\AppInfo\\Application' => $baseDir . '/core/AppInfo/Application.php', 'OC\\Core\\BackgroundJobs\\BackgroundCleanupUpdaterBackupsJob' => $baseDir . '/core/BackgroundJobs/BackgroundCleanupUpdaterBackupsJob.php', 'OC\\Core\\BackgroundJobs\\CheckForUserCertificates' => $baseDir . '/core/BackgroundJobs/CheckForUserCertificates.php', 'OC\\Core\\BackgroundJobs\\CleanupLoginFlowV2' => $baseDir . '/core/BackgroundJobs/CleanupLoginFlowV2.php', @@ -1231,6 +1234,7 @@ return array( 'OC\\Core\\Command\\Config\\Import' => $baseDir . '/core/Command/Config/Import.php', 'OC\\Core\\Command\\Config\\ListConfigs' => $baseDir . '/core/Command/Config/ListConfigs.php', 'OC\\Core\\Command\\Config\\System\\Base' => $baseDir . '/core/Command/Config/System/Base.php', + 'OC\\Core\\Command\\Config\\System\\CastHelper' => $baseDir . '/core/Command/Config/System/CastHelper.php', 'OC\\Core\\Command\\Config\\System\\DeleteConfig' => $baseDir . '/core/Command/Config/System/DeleteConfig.php', 'OC\\Core\\Command\\Config\\System\\GetConfig' => $baseDir . '/core/Command/Config/System/GetConfig.php', 'OC\\Core\\Command\\Config\\System\\SetConfig' => $baseDir . '/core/Command/Config/System/SetConfig.php', @@ -1289,11 +1293,17 @@ return array( 'OC\\Core\\Command\\Maintenance\\RepairShareOwnership' => $baseDir . '/core/Command/Maintenance/RepairShareOwnership.php', 'OC\\Core\\Command\\Maintenance\\UpdateHtaccess' => $baseDir . '/core/Command/Maintenance/UpdateHtaccess.php', 'OC\\Core\\Command\\Maintenance\\UpdateTheme' => $baseDir . '/core/Command/Maintenance/UpdateTheme.php', + 'OC\\Core\\Command\\Memcache\\DistributedClear' => $baseDir . '/core/Command/Memcache/DistributedClear.php', + 'OC\\Core\\Command\\Memcache\\DistributedDelete' => $baseDir . '/core/Command/Memcache/DistributedDelete.php', + 'OC\\Core\\Command\\Memcache\\DistributedGet' => $baseDir . '/core/Command/Memcache/DistributedGet.php', + 'OC\\Core\\Command\\Memcache\\DistributedSet' => $baseDir . '/core/Command/Memcache/DistributedSet.php', 'OC\\Core\\Command\\Memcache\\RedisCommand' => $baseDir . '/core/Command/Memcache/RedisCommand.php', 'OC\\Core\\Command\\Preview\\Cleanup' => $baseDir . '/core/Command/Preview/Cleanup.php', 'OC\\Core\\Command\\Preview\\Generate' => $baseDir . '/core/Command/Preview/Generate.php', 'OC\\Core\\Command\\Preview\\Repair' => $baseDir . '/core/Command/Preview/Repair.php', 'OC\\Core\\Command\\Preview\\ResetRenderedTexts' => $baseDir . '/core/Command/Preview/ResetRenderedTexts.php', + 'OC\\Core\\Command\\Router\\ListRoutes' => $baseDir . '/core/Command/Router/ListRoutes.php', + 'OC\\Core\\Command\\Router\\MatchRoute' => $baseDir . '/core/Command/Router/MatchRoute.php', 'OC\\Core\\Command\\Security\\BruteforceAttempts' => $baseDir . '/core/Command/Security/BruteforceAttempts.php', 'OC\\Core\\Command\\Security\\BruteforceResetAttempts' => $baseDir . '/core/Command/Security/BruteforceResetAttempts.php', 'OC\\Core\\Command\\Security\\ExportCertificates' => $baseDir . '/core/Command/Security/ExportCertificates.php', @@ -1329,6 +1339,7 @@ return array( 'OC\\Core\\Command\\User\\Keys\\Verify' => $baseDir . '/core/Command/User/Keys/Verify.php', 'OC\\Core\\Command\\User\\LastSeen' => $baseDir . '/core/Command/User/LastSeen.php', 'OC\\Core\\Command\\User\\ListCommand' => $baseDir . '/core/Command/User/ListCommand.php', + 'OC\\Core\\Command\\User\\Profile' => $baseDir . '/core/Command/User/Profile.php', 'OC\\Core\\Command\\User\\Report' => $baseDir . '/core/Command/User/Report.php', 'OC\\Core\\Command\\User\\ResetPassword' => $baseDir . '/core/Command/User/ResetPassword.php', 'OC\\Core\\Command\\User\\Setting' => $baseDir . '/core/Command/User/Setting.php', @@ -1385,8 +1396,11 @@ return array( 'OC\\Core\\Exception\\LoginFlowV2ClientForbiddenException' => $baseDir . '/core/Exception/LoginFlowV2ClientForbiddenException.php', 'OC\\Core\\Exception\\LoginFlowV2NotFoundException' => $baseDir . '/core/Exception/LoginFlowV2NotFoundException.php', 'OC\\Core\\Exception\\ResetPasswordException' => $baseDir . '/core/Exception/ResetPasswordException.php', + 'OC\\Core\\Listener\\AddMissingIndicesListener' => $baseDir . '/core/Listener/AddMissingIndicesListener.php', + 'OC\\Core\\Listener\\AddMissingPrimaryKeyListener' => $baseDir . '/core/Listener/AddMissingPrimaryKeyListener.php', 'OC\\Core\\Listener\\BeforeMessageLoggedEventListener' => $baseDir . '/core/Listener/BeforeMessageLoggedEventListener.php', 'OC\\Core\\Listener\\BeforeTemplateRenderedListener' => $baseDir . '/core/Listener/BeforeTemplateRenderedListener.php', + 'OC\\Core\\Listener\\FeedBackHandler' => $baseDir . '/core/Listener/FeedBackHandler.php', 'OC\\Core\\Middleware\\TwoFactorMiddleware' => $baseDir . '/core/Middleware/TwoFactorMiddleware.php', 'OC\\Core\\Migrations\\Version13000Date20170705121758' => $baseDir . '/core/Migrations/Version13000Date20170705121758.php', 'OC\\Core\\Migrations\\Version13000Date20170718121200' => $baseDir . '/core/Migrations/Version13000Date20170718121200.php', @@ -1466,6 +1480,7 @@ return array( 'OC\\Core\\Migrations\\Version31000Date20240101084401' => $baseDir . '/core/Migrations/Version31000Date20240101084401.php', 'OC\\Core\\Migrations\\Version31000Date20240814184402' => $baseDir . '/core/Migrations/Version31000Date20240814184402.php', 'OC\\Core\\Migrations\\Version31000Date20250213102442' => $baseDir . '/core/Migrations/Version31000Date20250213102442.php', + 'OC\\Core\\Migrations\\Version32000Date20250620081925' => $baseDir . '/core/Migrations/Version32000Date20250620081925.php', 'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php', 'OC\\Core\\ResponseDefinitions' => $baseDir . '/core/ResponseDefinitions.php', 'OC\\Core\\Service\\LoginFlowV2Service' => $baseDir . '/core/Service/LoginFlowV2Service.php', @@ -1643,6 +1658,7 @@ return array( 'OC\\Files\\ObjectStore\\Mapper' => $baseDir . '/lib/private/Files/ObjectStore/Mapper.php', 'OC\\Files\\ObjectStore\\ObjectStoreScanner' => $baseDir . '/lib/private/Files/ObjectStore/ObjectStoreScanner.php', 'OC\\Files\\ObjectStore\\ObjectStoreStorage' => $baseDir . '/lib/private/Files/ObjectStore/ObjectStoreStorage.php', + 'OC\\Files\\ObjectStore\\PrimaryObjectStoreConfig' => $baseDir . '/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php', 'OC\\Files\\ObjectStore\\S3' => $baseDir . '/lib/private/Files/ObjectStore/S3.php', 'OC\\Files\\ObjectStore\\S3ConfigTrait' => $baseDir . '/lib/private/Files/ObjectStore/S3ConfigTrait.php', 'OC\\Files\\ObjectStore\\S3ConnectionTrait' => $baseDir . '/lib/private/Files/ObjectStore/S3ConnectionTrait.php', @@ -1893,6 +1909,7 @@ return array( 'OC\\Repair\\ClearGeneratedAvatarCache' => $baseDir . '/lib/private/Repair/ClearGeneratedAvatarCache.php', 'OC\\Repair\\ClearGeneratedAvatarCacheJob' => $baseDir . '/lib/private/Repair/ClearGeneratedAvatarCacheJob.php', 'OC\\Repair\\Collation' => $baseDir . '/lib/private/Repair/Collation.php', + 'OC\\Repair\\ConfigKeyMigration' => $baseDir . '/lib/private/Repair/ConfigKeyMigration.php', 'OC\\Repair\\Events\\RepairAdvanceEvent' => $baseDir . '/lib/private/Repair/Events/RepairAdvanceEvent.php', 'OC\\Repair\\Events\\RepairErrorEvent' => $baseDir . '/lib/private/Repair/Events/RepairErrorEvent.php', 'OC\\Repair\\Events\\RepairFinishEvent' => $baseDir . '/lib/private/Repair/Events/RepairFinishEvent.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index b1e162bf71e..69231e62689 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -720,6 +720,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => __DIR__ . '/../../..' . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php', 'OCP\\OCM\\Exceptions\\OCMArgumentException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMArgumentException.php', 'OCP\\OCM\\Exceptions\\OCMProviderException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMProviderException.php', + 'OCP\\OCM\\ICapabilityAwareOCMProvider' => __DIR__ . '/../../..' . '/lib/public/OCM/ICapabilityAwareOCMProvider.php', 'OCP\\OCM\\IOCMDiscoveryService' => __DIR__ . '/../../..' . '/lib/public/OCM/IOCMDiscoveryService.php', 'OCP\\OCM\\IOCMProvider' => __DIR__ . '/../../..' . '/lib/public/OCM/IOCMProvider.php', 'OCP\\OCM\\IOCMResource' => __DIR__ . '/../../..' . '/lib/public/OCM/IOCMResource.php', @@ -1090,6 +1091,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\AppScriptDependency' => __DIR__ . '/../../..' . '/lib/private/AppScriptDependency.php', 'OC\\AppScriptSort' => __DIR__ . '/../../..' . '/lib/private/AppScriptSort.php', 'OC\\App\\AppManager' => __DIR__ . '/../../..' . '/lib/private/App/AppManager.php', + 'OC\\App\\AppStore\\AppNotFoundException' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/AppNotFoundException.php', 'OC\\App\\AppStore\\Bundles\\Bundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/Bundle.php', 'OC\\App\\AppStore\\Bundles\\BundleFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/BundleFetcher.php', 'OC\\App\\AppStore\\Bundles\\EducationBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/EducationBundle.php', @@ -1229,6 +1231,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Comments\\Manager' => __DIR__ . '/../../..' . '/lib/private/Comments/Manager.php', 'OC\\Comments\\ManagerFactory' => __DIR__ . '/../../..' . '/lib/private/Comments/ManagerFactory.php', 'OC\\Config' => __DIR__ . '/../../..' . '/lib/private/Config.php', + 'OC\\Config\\ConfigManager' => __DIR__ . '/../../..' . '/lib/private/Config/ConfigManager.php', 'OC\\Config\\Lexicon\\CoreConfigLexicon' => __DIR__ . '/../../..' . '/lib/private/Config/Lexicon/CoreConfigLexicon.php', 'OC\\Config\\UserConfig' => __DIR__ . '/../../..' . '/lib/private/Config/UserConfig.php', 'OC\\Console\\Application' => __DIR__ . '/../../..' . '/lib/private/Console/Application.php', @@ -1243,7 +1246,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Contacts\\ContactsMenu\\Providers\\EMailProvider' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php', 'OC\\Contacts\\ContactsMenu\\Providers\\LocalTimeProvider' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/Providers/LocalTimeProvider.php', 'OC\\Contacts\\ContactsMenu\\Providers\\ProfileProvider' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php', - 'OC\\Core\\Application' => __DIR__ . '/../../..' . '/core/Application.php', + 'OC\\Core\\AppInfo\\Application' => __DIR__ . '/../../..' . '/core/AppInfo/Application.php', 'OC\\Core\\BackgroundJobs\\BackgroundCleanupUpdaterBackupsJob' => __DIR__ . '/../../..' . '/core/BackgroundJobs/BackgroundCleanupUpdaterBackupsJob.php', 'OC\\Core\\BackgroundJobs\\CheckForUserCertificates' => __DIR__ . '/../../..' . '/core/BackgroundJobs/CheckForUserCertificates.php', 'OC\\Core\\BackgroundJobs\\CleanupLoginFlowV2' => __DIR__ . '/../../..' . '/core/BackgroundJobs/CleanupLoginFlowV2.php', @@ -1272,6 +1275,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Command\\Config\\Import' => __DIR__ . '/../../..' . '/core/Command/Config/Import.php', 'OC\\Core\\Command\\Config\\ListConfigs' => __DIR__ . '/../../..' . '/core/Command/Config/ListConfigs.php', 'OC\\Core\\Command\\Config\\System\\Base' => __DIR__ . '/../../..' . '/core/Command/Config/System/Base.php', + 'OC\\Core\\Command\\Config\\System\\CastHelper' => __DIR__ . '/../../..' . '/core/Command/Config/System/CastHelper.php', 'OC\\Core\\Command\\Config\\System\\DeleteConfig' => __DIR__ . '/../../..' . '/core/Command/Config/System/DeleteConfig.php', 'OC\\Core\\Command\\Config\\System\\GetConfig' => __DIR__ . '/../../..' . '/core/Command/Config/System/GetConfig.php', 'OC\\Core\\Command\\Config\\System\\SetConfig' => __DIR__ . '/../../..' . '/core/Command/Config/System/SetConfig.php', @@ -1330,11 +1334,17 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Command\\Maintenance\\RepairShareOwnership' => __DIR__ . '/../../..' . '/core/Command/Maintenance/RepairShareOwnership.php', 'OC\\Core\\Command\\Maintenance\\UpdateHtaccess' => __DIR__ . '/../../..' . '/core/Command/Maintenance/UpdateHtaccess.php', 'OC\\Core\\Command\\Maintenance\\UpdateTheme' => __DIR__ . '/../../..' . '/core/Command/Maintenance/UpdateTheme.php', + 'OC\\Core\\Command\\Memcache\\DistributedClear' => __DIR__ . '/../../..' . '/core/Command/Memcache/DistributedClear.php', + 'OC\\Core\\Command\\Memcache\\DistributedDelete' => __DIR__ . '/../../..' . '/core/Command/Memcache/DistributedDelete.php', + 'OC\\Core\\Command\\Memcache\\DistributedGet' => __DIR__ . '/../../..' . '/core/Command/Memcache/DistributedGet.php', + 'OC\\Core\\Command\\Memcache\\DistributedSet' => __DIR__ . '/../../..' . '/core/Command/Memcache/DistributedSet.php', 'OC\\Core\\Command\\Memcache\\RedisCommand' => __DIR__ . '/../../..' . '/core/Command/Memcache/RedisCommand.php', 'OC\\Core\\Command\\Preview\\Cleanup' => __DIR__ . '/../../..' . '/core/Command/Preview/Cleanup.php', 'OC\\Core\\Command\\Preview\\Generate' => __DIR__ . '/../../..' . '/core/Command/Preview/Generate.php', 'OC\\Core\\Command\\Preview\\Repair' => __DIR__ . '/../../..' . '/core/Command/Preview/Repair.php', 'OC\\Core\\Command\\Preview\\ResetRenderedTexts' => __DIR__ . '/../../..' . '/core/Command/Preview/ResetRenderedTexts.php', + 'OC\\Core\\Command\\Router\\ListRoutes' => __DIR__ . '/../../..' . '/core/Command/Router/ListRoutes.php', + 'OC\\Core\\Command\\Router\\MatchRoute' => __DIR__ . '/../../..' . '/core/Command/Router/MatchRoute.php', 'OC\\Core\\Command\\Security\\BruteforceAttempts' => __DIR__ . '/../../..' . '/core/Command/Security/BruteforceAttempts.php', 'OC\\Core\\Command\\Security\\BruteforceResetAttempts' => __DIR__ . '/../../..' . '/core/Command/Security/BruteforceResetAttempts.php', 'OC\\Core\\Command\\Security\\ExportCertificates' => __DIR__ . '/../../..' . '/core/Command/Security/ExportCertificates.php', @@ -1370,6 +1380,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Command\\User\\Keys\\Verify' => __DIR__ . '/../../..' . '/core/Command/User/Keys/Verify.php', 'OC\\Core\\Command\\User\\LastSeen' => __DIR__ . '/../../..' . '/core/Command/User/LastSeen.php', 'OC\\Core\\Command\\User\\ListCommand' => __DIR__ . '/../../..' . '/core/Command/User/ListCommand.php', + 'OC\\Core\\Command\\User\\Profile' => __DIR__ . '/../../..' . '/core/Command/User/Profile.php', 'OC\\Core\\Command\\User\\Report' => __DIR__ . '/../../..' . '/core/Command/User/Report.php', 'OC\\Core\\Command\\User\\ResetPassword' => __DIR__ . '/../../..' . '/core/Command/User/ResetPassword.php', 'OC\\Core\\Command\\User\\Setting' => __DIR__ . '/../../..' . '/core/Command/User/Setting.php', @@ -1426,8 +1437,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Exception\\LoginFlowV2ClientForbiddenException' => __DIR__ . '/../../..' . '/core/Exception/LoginFlowV2ClientForbiddenException.php', 'OC\\Core\\Exception\\LoginFlowV2NotFoundException' => __DIR__ . '/../../..' . '/core/Exception/LoginFlowV2NotFoundException.php', 'OC\\Core\\Exception\\ResetPasswordException' => __DIR__ . '/../../..' . '/core/Exception/ResetPasswordException.php', + 'OC\\Core\\Listener\\AddMissingIndicesListener' => __DIR__ . '/../../..' . '/core/Listener/AddMissingIndicesListener.php', + 'OC\\Core\\Listener\\AddMissingPrimaryKeyListener' => __DIR__ . '/../../..' . '/core/Listener/AddMissingPrimaryKeyListener.php', 'OC\\Core\\Listener\\BeforeMessageLoggedEventListener' => __DIR__ . '/../../..' . '/core/Listener/BeforeMessageLoggedEventListener.php', 'OC\\Core\\Listener\\BeforeTemplateRenderedListener' => __DIR__ . '/../../..' . '/core/Listener/BeforeTemplateRenderedListener.php', + 'OC\\Core\\Listener\\FeedBackHandler' => __DIR__ . '/../../..' . '/core/Listener/FeedBackHandler.php', 'OC\\Core\\Middleware\\TwoFactorMiddleware' => __DIR__ . '/../../..' . '/core/Middleware/TwoFactorMiddleware.php', 'OC\\Core\\Migrations\\Version13000Date20170705121758' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170705121758.php', 'OC\\Core\\Migrations\\Version13000Date20170718121200' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170718121200.php', @@ -1507,6 +1521,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Migrations\\Version31000Date20240101084401' => __DIR__ . '/../../..' . '/core/Migrations/Version31000Date20240101084401.php', 'OC\\Core\\Migrations\\Version31000Date20240814184402' => __DIR__ . '/../../..' . '/core/Migrations/Version31000Date20240814184402.php', 'OC\\Core\\Migrations\\Version31000Date20250213102442' => __DIR__ . '/../../..' . '/core/Migrations/Version31000Date20250213102442.php', + 'OC\\Core\\Migrations\\Version32000Date20250620081925' => __DIR__ . '/../../..' . '/core/Migrations/Version32000Date20250620081925.php', 'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php', 'OC\\Core\\ResponseDefinitions' => __DIR__ . '/../../..' . '/core/ResponseDefinitions.php', 'OC\\Core\\Service\\LoginFlowV2Service' => __DIR__ . '/../../..' . '/core/Service/LoginFlowV2Service.php', @@ -1684,6 +1699,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Files\\ObjectStore\\Mapper' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/Mapper.php', 'OC\\Files\\ObjectStore\\ObjectStoreScanner' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/ObjectStoreScanner.php', 'OC\\Files\\ObjectStore\\ObjectStoreStorage' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/ObjectStoreStorage.php', + 'OC\\Files\\ObjectStore\\PrimaryObjectStoreConfig' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php', 'OC\\Files\\ObjectStore\\S3' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/S3.php', 'OC\\Files\\ObjectStore\\S3ConfigTrait' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/S3ConfigTrait.php', 'OC\\Files\\ObjectStore\\S3ConnectionTrait' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/S3ConnectionTrait.php', @@ -1934,6 +1950,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Repair\\ClearGeneratedAvatarCache' => __DIR__ . '/../../..' . '/lib/private/Repair/ClearGeneratedAvatarCache.php', 'OC\\Repair\\ClearGeneratedAvatarCacheJob' => __DIR__ . '/../../..' . '/lib/private/Repair/ClearGeneratedAvatarCacheJob.php', 'OC\\Repair\\Collation' => __DIR__ . '/../../..' . '/lib/private/Repair/Collation.php', + 'OC\\Repair\\ConfigKeyMigration' => __DIR__ . '/../../..' . '/lib/private/Repair/ConfigKeyMigration.php', 'OC\\Repair\\Events\\RepairAdvanceEvent' => __DIR__ . '/../../..' . '/lib/private/Repair/Events/RepairAdvanceEvent.php', 'OC\\Repair\\Events\\RepairErrorEvent' => __DIR__ . '/../../..' . '/lib/private/Repair/Events/RepairErrorEvent.php', 'OC\\Repair\\Events\\RepairFinishEvent' => __DIR__ . '/../../..' . '/lib/private/Repair/Events/RepairFinishEvent.php', diff --git a/lib/l10n/ar.js b/lib/l10n/ar.js index 734d8c693d7..4747362aaa8 100644 --- a/lib/l10n/ar.js +++ b/lib/l10n/ar.js @@ -93,6 +93,7 @@ OC.L10N.register( "Destination does not exist" : "المَقصِد غير موجود", "Destination is not creatable" : "المِقصِد لايمكن إنشاؤه", "Dot files are not allowed" : "الملفات النقطية (ملفات ذات أسماء تبدأ بنقطة) غير مسموح بها", + "renamed file" : "ملف معاد تسميته", "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" غير مسموح به أن يكون اسم ملف أو مجلد.", "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" غير مسموح به أن يكون بادئة لاسم ملف أو مجلد.", "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" غير مسموح به أن يكون داخل اسم ملف أو مجلد.", diff --git a/lib/l10n/ar.json b/lib/l10n/ar.json index e53cdc2fd6c..2bc87515bac 100644 --- a/lib/l10n/ar.json +++ b/lib/l10n/ar.json @@ -91,6 +91,7 @@ "Destination does not exist" : "المَقصِد غير موجود", "Destination is not creatable" : "المِقصِد لايمكن إنشاؤه", "Dot files are not allowed" : "الملفات النقطية (ملفات ذات أسماء تبدأ بنقطة) غير مسموح بها", + "renamed file" : "ملف معاد تسميته", "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" غير مسموح به أن يكون اسم ملف أو مجلد.", "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" غير مسموح به أن يكون بادئة لاسم ملف أو مجلد.", "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" غير مسموح به أن يكون داخل اسم ملف أو مجلد.", diff --git a/lib/l10n/bg.js b/lib/l10n/bg.js index 6674c4be2ad..445da4c9626 100644 --- a/lib/l10n/bg.js +++ b/lib/l10n/bg.js @@ -92,6 +92,7 @@ OC.L10N.register( "Administration settings" : "Административни настройки", "Settings" : "Настройки", "Log out" : "Отписване", + "Accounts" : "Профили", "Email" : "Имейл", "Mail %s" : "Поща %s", "Fediverse" : "Fediverse /съвкупност от обединени сървъри/", @@ -103,12 +104,13 @@ OC.L10N.register( "Website" : "Уеб сайт", "Visit %s" : "Посещение %s", "Address" : "Адрес", - "Profile picture" : "Снимка на профила", + "Profile picture" : "Профилна снимка", "About" : "Относно", "Display name" : "Име за визуализация", "Headline" : "Заглавие", "Organisation" : "Организация", "Role" : "Роля", + "Pronouns" : "Обръщение", "Additional settings" : "Допълнителни настройки", "Enter the database name for %s" : "Въведете името на базата данни за %s", "You cannot use dots in the database name %s" : "Не можете да използвате точки в името на базата данни %s", @@ -196,8 +198,8 @@ OC.L10N.register( "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Това обикновено може да бъде оправено като, се даде достъп на уеб сървъра да записва в основната директория. Погледнете %s", "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Права обикновено могат да бъдат оправени когато се даде достъп на уеб сървъра да пише в основната директория. Погледнете %s.", "Your data directory is not writable." : "Вашата директория с данни не е записваема.", - "Setting locale to %s failed." : "Неуспешно задаване на езикова променлива %s.", - "Please install one of these locales on your system and restart your web server." : "Моля, инсталирайте една от тези езикови променливи на вашата система и си рестартирайте уеб сървъра.", + "Setting locale to %s failed." : "Неуспешно задаване на регион %s. ", + "Please install one of these locales on your system and restart your web server." : "Моля, задайте един от следните региони във Вашата система след което рестартирайте сървъра.", "PHP module %s not installed." : "PHP модулът %s не е инсталиран.", "Please ask your server administrator to install the module." : "Моля, помолете вашия администратор да инсталира модула.", "PHP setting \"%s\" is not set to \"%s\"." : "PHP настройка \"%s\" не е зададена на \"%s\".", diff --git a/lib/l10n/bg.json b/lib/l10n/bg.json index 0dfca8ec315..a4bc3162762 100644 --- a/lib/l10n/bg.json +++ b/lib/l10n/bg.json @@ -90,6 +90,7 @@ "Administration settings" : "Административни настройки", "Settings" : "Настройки", "Log out" : "Отписване", + "Accounts" : "Профили", "Email" : "Имейл", "Mail %s" : "Поща %s", "Fediverse" : "Fediverse /съвкупност от обединени сървъри/", @@ -101,12 +102,13 @@ "Website" : "Уеб сайт", "Visit %s" : "Посещение %s", "Address" : "Адрес", - "Profile picture" : "Снимка на профила", + "Profile picture" : "Профилна снимка", "About" : "Относно", "Display name" : "Име за визуализация", "Headline" : "Заглавие", "Organisation" : "Организация", "Role" : "Роля", + "Pronouns" : "Обръщение", "Additional settings" : "Допълнителни настройки", "Enter the database name for %s" : "Въведете името на базата данни за %s", "You cannot use dots in the database name %s" : "Не можете да използвате точки в името на базата данни %s", @@ -194,8 +196,8 @@ "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Това обикновено може да бъде оправено като, се даде достъп на уеб сървъра да записва в основната директория. Погледнете %s", "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Права обикновено могат да бъдат оправени когато се даде достъп на уеб сървъра да пише в основната директория. Погледнете %s.", "Your data directory is not writable." : "Вашата директория с данни не е записваема.", - "Setting locale to %s failed." : "Неуспешно задаване на езикова променлива %s.", - "Please install one of these locales on your system and restart your web server." : "Моля, инсталирайте една от тези езикови променливи на вашата система и си рестартирайте уеб сървъра.", + "Setting locale to %s failed." : "Неуспешно задаване на регион %s. ", + "Please install one of these locales on your system and restart your web server." : "Моля, задайте един от следните региони във Вашата система след което рестартирайте сървъра.", "PHP module %s not installed." : "PHP модулът %s не е инсталиран.", "Please ask your server administrator to install the module." : "Моля, помолете вашия администратор да инсталира модула.", "PHP setting \"%s\" is not set to \"%s\"." : "PHP настройка \"%s\" не е зададена на \"%s\".", diff --git a/lib/l10n/cs.js b/lib/l10n/cs.js index ec1e76e1471..78b1ce3dfe2 100644 --- a/lib/l10n/cs.js +++ b/lib/l10n/cs.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Je třeba zadat platné přihlašovací jméno", "Login contains whitespace at the beginning or at the end" : "Přihlašovací jméno je chybné – na jeho začátku či konci se nachází prázdný znak (mezera, tabulátor, atp.)", "Login must not consist of dots only" : "Přihlašovací jméno se nemůže skládat pouze ze samých teček", - "Login is too long" : "Přihlašovací jméno je příliš dlouhé", + "Username is too long" : "Uživatelské jméno je příliš dlouhé", "Login is invalid because files already exist for this user" : "Přihlašovací jméno není platné, protože protože pro tohoto uživatele už existují soubory", "Account disabled" : "Účet znepřístupněn", "Login canceled by app" : "Přihlášení zrušeno aplikací", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Vytvoří stručný souhrn textu tím, že zkrátí jeho délku aniž by byly ztraceny klíčové informace", "Extracts topics from a text and outputs them separated by commas." : "Vyzíská témata z textu a vypíše je oddělované čárkami.", "File is currently busy, please try again later" : "Soubor je nyní používán, zkuste to později", - "Cannot download file" : "Soubor se nedaří stáhnout" + "Cannot download file" : "Soubor se nedaří stáhnout", + "Login is too long" : "Přihlašovací jméno je příliš dlouhé" }, "nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;"); diff --git a/lib/l10n/cs.json b/lib/l10n/cs.json index 0075e7f087c..aa3b9876ad3 100644 --- a/lib/l10n/cs.json +++ b/lib/l10n/cs.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "Je třeba zadat platné přihlašovací jméno", "Login contains whitespace at the beginning or at the end" : "Přihlašovací jméno je chybné – na jeho začátku či konci se nachází prázdný znak (mezera, tabulátor, atp.)", "Login must not consist of dots only" : "Přihlašovací jméno se nemůže skládat pouze ze samých teček", - "Login is too long" : "Přihlašovací jméno je příliš dlouhé", + "Username is too long" : "Uživatelské jméno je příliš dlouhé", "Login is invalid because files already exist for this user" : "Přihlašovací jméno není platné, protože protože pro tohoto uživatele už existují soubory", "Account disabled" : "Účet znepřístupněn", "Login canceled by app" : "Přihlášení zrušeno aplikací", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Vytvoří stručný souhrn textu tím, že zkrátí jeho délku aniž by byly ztraceny klíčové informace", "Extracts topics from a text and outputs them separated by commas." : "Vyzíská témata z textu a vypíše je oddělované čárkami.", "File is currently busy, please try again later" : "Soubor je nyní používán, zkuste to později", - "Cannot download file" : "Soubor se nedaří stáhnout" + "Cannot download file" : "Soubor se nedaří stáhnout", + "Login is too long" : "Přihlašovací jméno je příliš dlouhé" },"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;" }
\ No newline at end of file diff --git a/lib/l10n/da.js b/lib/l10n/da.js index b7c05641888..e1ed6d62bcd 100644 --- a/lib/l10n/da.js +++ b/lib/l10n/da.js @@ -273,7 +273,6 @@ OC.L10N.register( "A valid Login must be provided" : "Et gyldigt login skal angives", "Login contains whitespace at the beginning or at the end" : "Login indeholder mellemrum i begyndelsen eller slutningen", "Login must not consist of dots only" : "Login må ikke kun bestå af prikker", - "Login is too long" : "Login er for lang", "Login is invalid because files already exist for this user" : "Login er ugyldigt, fordi filer allerede eksisterer for denne bruger", "Account disabled" : "Konto deaktiveret", "Login canceled by app" : "Login annulleret af app", @@ -444,6 +443,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Opsummerer tekst ved at reducere dens længde uden at miste nøgleinformation.", "Extracts topics from a text and outputs them separated by commas." : "Uddrager emner fra en tekst og skriver dem adskilt af kommaer.", "File is currently busy, please try again later" : "Filen er i øjeblikket optaget - forsøg igen senere", - "Cannot download file" : "Kan ikke downloade filen" + "Cannot download file" : "Kan ikke downloade filen", + "Login is too long" : "Login er for lang" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/da.json b/lib/l10n/da.json index 0dd4df01090..36bd40121d8 100644 --- a/lib/l10n/da.json +++ b/lib/l10n/da.json @@ -271,7 +271,6 @@ "A valid Login must be provided" : "Et gyldigt login skal angives", "Login contains whitespace at the beginning or at the end" : "Login indeholder mellemrum i begyndelsen eller slutningen", "Login must not consist of dots only" : "Login må ikke kun bestå af prikker", - "Login is too long" : "Login er for lang", "Login is invalid because files already exist for this user" : "Login er ugyldigt, fordi filer allerede eksisterer for denne bruger", "Account disabled" : "Konto deaktiveret", "Login canceled by app" : "Login annulleret af app", @@ -442,6 +441,7 @@ "Summarizes text by reducing its length without losing key information." : "Opsummerer tekst ved at reducere dens længde uden at miste nøgleinformation.", "Extracts topics from a text and outputs them separated by commas." : "Uddrager emner fra en tekst og skriver dem adskilt af kommaer.", "File is currently busy, please try again later" : "Filen er i øjeblikket optaget - forsøg igen senere", - "Cannot download file" : "Kan ikke downloade filen" + "Cannot download file" : "Kan ikke downloade filen", + "Login is too long" : "Login er for lang" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/de.js b/lib/l10n/de.js index ef4da64d96f..d1090a1d341 100644 --- a/lib/l10n/de.js +++ b/lib/l10n/de.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Ein gültiger Anmeldename muss eingegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", - "Login is too long" : "Die Anmeldung dauert zu lange", + "Username is too long" : "Benutzername ist zu lang", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Konto existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Fasst Text zusammen, indem die Länge reduziert wird, ohne dass wichtige Informationen verloren gehen.", "Extracts topics from a text and outputs them separated by commas." : "Extrahiert Themen aus einem Text und gibt sie durch Kommas getrennt aus.", "File is currently busy, please try again later" : "Die Datei ist in Benutzung, bitte versuche es später noch einmal", - "Cannot download file" : "Datei kann nicht heruntergeladen werden." + "Cannot download file" : "Datei kann nicht heruntergeladen werden.", + "Login is too long" : "Die Anmeldung dauert zu lange" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/de.json b/lib/l10n/de.json index de85210572d..1c5a9e52f3d 100644 --- a/lib/l10n/de.json +++ b/lib/l10n/de.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "Ein gültiger Anmeldename muss eingegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", - "Login is too long" : "Die Anmeldung dauert zu lange", + "Username is too long" : "Benutzername ist zu lang", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Konto existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Fasst Text zusammen, indem die Länge reduziert wird, ohne dass wichtige Informationen verloren gehen.", "Extracts topics from a text and outputs them separated by commas." : "Extrahiert Themen aus einem Text und gibt sie durch Kommas getrennt aus.", "File is currently busy, please try again later" : "Die Datei ist in Benutzung, bitte versuche es später noch einmal", - "Cannot download file" : "Datei kann nicht heruntergeladen werden." + "Cannot download file" : "Datei kann nicht heruntergeladen werden.", + "Login is too long" : "Die Anmeldung dauert zu lange" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/de_DE.js b/lib/l10n/de_DE.js index 835e6af7269..d8599c0262f 100644 --- a/lib/l10n/de_DE.js +++ b/lib/l10n/de_DE.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Ein gültiger Anmeldename muss angegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", - "Login is too long" : "Der Kontenname ist zu lang", + "Username is too long" : "Benutzername ist zu lang", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Benutzer existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Fasst Text zusammen, indem die Länge reduziert wird, ohne dass wichtige Informationen verloren gehen.", "Extracts topics from a text and outputs them separated by commas." : "Extrahiert Themen aus einem Text und gibt sie durch Kommas getrennt aus.", "File is currently busy, please try again later" : "Die Datei ist in Benutzung, bitte später erneut versuchen.", - "Cannot download file" : "Datei kann nicht heruntergeladen werden" + "Cannot download file" : "Datei kann nicht heruntergeladen werden", + "Login is too long" : "Der Kontenname ist zu lang" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/de_DE.json b/lib/l10n/de_DE.json index 6225e659833..5149f3f2d97 100644 --- a/lib/l10n/de_DE.json +++ b/lib/l10n/de_DE.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "Ein gültiger Anmeldename muss angegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", - "Login is too long" : "Der Kontenname ist zu lang", + "Username is too long" : "Benutzername ist zu lang", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Benutzer existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Fasst Text zusammen, indem die Länge reduziert wird, ohne dass wichtige Informationen verloren gehen.", "Extracts topics from a text and outputs them separated by commas." : "Extrahiert Themen aus einem Text und gibt sie durch Kommas getrennt aus.", "File is currently busy, please try again later" : "Die Datei ist in Benutzung, bitte später erneut versuchen.", - "Cannot download file" : "Datei kann nicht heruntergeladen werden" + "Cannot download file" : "Datei kann nicht heruntergeladen werden", + "Login is too long" : "Der Kontenname ist zu lang" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/en_GB.js b/lib/l10n/en_GB.js index 21731cb3516..b1a73cec9ad 100644 --- a/lib/l10n/en_GB.js +++ b/lib/l10n/en_GB.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "A valid Login must be provided", "Login contains whitespace at the beginning or at the end" : "Login contains whitespace at the beginning or at the end", "Login must not consist of dots only" : "Login must not consist of dots only", - "Login is too long" : "Login is too long", + "Username is too long" : "Username is too long", "Login is invalid because files already exist for this user" : "Login is invalid because files already exist for this user", "Account disabled" : "Account disabled", "Login canceled by app" : "Login cancelled by app", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Summarizes text by reducing its length without losing key information.", "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", "File is currently busy, please try again later" : "File is currently busy, please try again later", - "Cannot download file" : "Cannot download file" + "Cannot download file" : "Cannot download file", + "Login is too long" : "Login is too long" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/en_GB.json b/lib/l10n/en_GB.json index 043cb98581e..fb477ccbca3 100644 --- a/lib/l10n/en_GB.json +++ b/lib/l10n/en_GB.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "A valid Login must be provided", "Login contains whitespace at the beginning or at the end" : "Login contains whitespace at the beginning or at the end", "Login must not consist of dots only" : "Login must not consist of dots only", - "Login is too long" : "Login is too long", + "Username is too long" : "Username is too long", "Login is invalid because files already exist for this user" : "Login is invalid because files already exist for this user", "Account disabled" : "Account disabled", "Login canceled by app" : "Login cancelled by app", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Summarizes text by reducing its length without losing key information.", "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", "File is currently busy, please try again later" : "File is currently busy, please try again later", - "Cannot download file" : "Cannot download file" + "Cannot download file" : "Cannot download file", + "Login is too long" : "Login is too long" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/es.js b/lib/l10n/es.js index 4346343d733..f53ec599a0b 100644 --- a/lib/l10n/es.js +++ b/lib/l10n/es.js @@ -275,7 +275,6 @@ OC.L10N.register( "A valid Login must be provided" : "Se debe proporcionar un usuario válido", "Login contains whitespace at the beginning or at the end" : "El usuario contiene espacios en blanco al inicio o al final", "Login must not consist of dots only" : "El usuario no debe consistir sólo de puntos", - "Login is too long" : "El nombre de inicio de sesión es demasiado largo", "Login is invalid because files already exist for this user" : "El nombre de inicio de sesión es inválido porque ya existen archivos para este usuario", "Account disabled" : "Cuenta deshabilitada", "Login canceled by app" : "Login cancelado por la app", @@ -451,6 +450,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Resume el texto reduciendo su longitud sin perder información clave.", "Extracts topics from a text and outputs them separated by commas." : "Extrae los tópicos de un texto y genera una salida separada por comas. ", "File is currently busy, please try again later" : "El archivo se encuentra actualmente ocupado, por favor inténtelo de nuevo más tarde", - "Cannot download file" : "No se puede descargar el archivo" + "Cannot download file" : "No se puede descargar el archivo", + "Login is too long" : "El nombre de inicio de sesión es demasiado largo" }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es.json b/lib/l10n/es.json index 03fab3069cd..a88b6c22513 100644 --- a/lib/l10n/es.json +++ b/lib/l10n/es.json @@ -273,7 +273,6 @@ "A valid Login must be provided" : "Se debe proporcionar un usuario válido", "Login contains whitespace at the beginning or at the end" : "El usuario contiene espacios en blanco al inicio o al final", "Login must not consist of dots only" : "El usuario no debe consistir sólo de puntos", - "Login is too long" : "El nombre de inicio de sesión es demasiado largo", "Login is invalid because files already exist for this user" : "El nombre de inicio de sesión es inválido porque ya existen archivos para este usuario", "Account disabled" : "Cuenta deshabilitada", "Login canceled by app" : "Login cancelado por la app", @@ -449,6 +448,7 @@ "Summarizes text by reducing its length without losing key information." : "Resume el texto reduciendo su longitud sin perder información clave.", "Extracts topics from a text and outputs them separated by commas." : "Extrae los tópicos de un texto y genera una salida separada por comas. ", "File is currently busy, please try again later" : "El archivo se encuentra actualmente ocupado, por favor inténtelo de nuevo más tarde", - "Cannot download file" : "No se puede descargar el archivo" + "Cannot download file" : "No se puede descargar el archivo", + "Login is too long" : "El nombre de inicio de sesión es demasiado largo" },"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" }
\ No newline at end of file diff --git a/lib/l10n/et_EE.js b/lib/l10n/et_EE.js index 6039d601449..e2092211637 100644 --- a/lib/l10n/et_EE.js +++ b/lib/l10n/et_EE.js @@ -261,14 +261,14 @@ OC.L10N.register( "Oct." : "Okt.", "Nov." : "Nov.", "Dec." : "Dets.", - "A valid password must be provided" : "Sisesta nõuetele vastav parool", + "A valid password must be provided" : "Sisesta nõuetele vastav salasõna", "The Login is already being used" : "See kasutajanimi on juba kasutusel", "Could not create account" : "Kasutajakonto loomine ei õnnestunud", "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kasutajanimes on lubatud ainult järgmised tähemärgid: „a-z“, „A-Z“, „0-9“, ja „_.@-'“", "A valid Login must be provided" : "Palun sisesta korrektne kasutajanimi", "Login contains whitespace at the beginning or at the end" : "Kasutajanime alguses või lõpus on tühik", "Login must not consist of dots only" : "Kasutajanimi ei tohi koosneda ainult punktidest", - "Login is too long" : "Kasutajanimi on liiga pikk", + "Username is too long" : "Kasutajanimi on liiga pikk", "Login is invalid because files already exist for this user" : "See kasutajanimi ei sobi, kuna sellise kasutaja faile on juba olemas", "Account disabled" : "Konto pole kasutusel", "Login canceled by app" : "Rakendus katkestas sisselogimise", @@ -401,6 +401,7 @@ OC.L10N.register( "Result" : "Tulemus", "The translated text" : "Tõlgitud tekst", "File is currently busy, please try again later" : "Fail on hetkel kasutuses, proovi hiljem uuesti", - "Cannot download file" : "Faili pole võimalik alla laadida" + "Cannot download file" : "Faili pole võimalik alla laadida", + "Login is too long" : "Kasutajanimi on liiga pikk" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/et_EE.json b/lib/l10n/et_EE.json index 4f41a7963b0..78bbd2a7591 100644 --- a/lib/l10n/et_EE.json +++ b/lib/l10n/et_EE.json @@ -259,14 +259,14 @@ "Oct." : "Okt.", "Nov." : "Nov.", "Dec." : "Dets.", - "A valid password must be provided" : "Sisesta nõuetele vastav parool", + "A valid password must be provided" : "Sisesta nõuetele vastav salasõna", "The Login is already being used" : "See kasutajanimi on juba kasutusel", "Could not create account" : "Kasutajakonto loomine ei õnnestunud", "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kasutajanimes on lubatud ainult järgmised tähemärgid: „a-z“, „A-Z“, „0-9“, ja „_.@-'“", "A valid Login must be provided" : "Palun sisesta korrektne kasutajanimi", "Login contains whitespace at the beginning or at the end" : "Kasutajanime alguses või lõpus on tühik", "Login must not consist of dots only" : "Kasutajanimi ei tohi koosneda ainult punktidest", - "Login is too long" : "Kasutajanimi on liiga pikk", + "Username is too long" : "Kasutajanimi on liiga pikk", "Login is invalid because files already exist for this user" : "See kasutajanimi ei sobi, kuna sellise kasutaja faile on juba olemas", "Account disabled" : "Konto pole kasutusel", "Login canceled by app" : "Rakendus katkestas sisselogimise", @@ -399,6 +399,7 @@ "Result" : "Tulemus", "The translated text" : "Tõlgitud tekst", "File is currently busy, please try again later" : "Fail on hetkel kasutuses, proovi hiljem uuesti", - "Cannot download file" : "Faili pole võimalik alla laadida" + "Cannot download file" : "Faili pole võimalik alla laadida", + "Login is too long" : "Kasutajanimi on liiga pikk" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/fa.js b/lib/l10n/fa.js index 0c3e496c42d..da77202e434 100644 --- a/lib/l10n/fa.js +++ b/lib/l10n/fa.js @@ -2,26 +2,28 @@ OC.L10N.register( "lib", { "Cannot write into \"config\" directory!" : "نمیتوانید داخل دایرکتوری \"config\" تغییراتی ایجاد کنید", - "This can usually be fixed by giving the web server write access to the config directory." : "This can usually be fixed by giving the web server write access to the config directory.", - "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it.", + "This can usually be fixed by giving the web server write access to the config directory." : "این مشکل معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری پیکربندی قابل رفع است.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "اما، اگر ترجیح میدهید فایل config.php فقط خواندنی باشد، گزینه \"config_is_read_only\" را در آن به true تنظیم کنید.", "See %s" : "مشاهده %s", - "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory.", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "برنامه %1$s موجود نیست یا نسخهای ناسازگار با این سرور دارد. لطفاً دایرکتوری برنامهها را بررسی کنید.", "Sample configuration detected" : "فایل پیکربندی نمونه پیدا شد", "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "تشخیص داده شده است که پیکربندی نمونه کپی شده است. این می تواند نصب شما را خراب کند و پشتیبانی نمی شود. لطفاً قبل از انجام تغییرات در config.php ، اسناد را بخوانید", - "The page could not be found on the server." : "The page could not be found on the server.", - "%s email verification" : "%s email verification", - "Email verification" : "Email verification", - "Click the following button to confirm your email." : "Click the following button to confirm your email.", - "Click the following link to confirm your email." : "Click the following link to confirm your email.", - "Confirm your email" : "Confirm your email", + "The page could not be found on the server." : "صفحه در سرور یافت نشد.", + "%s email verification" : "تأیید ایمیل %s", + "Email verification" : "تأیید ایمیل", + "Click the following button to confirm your email." : "برای تأیید ایمیل خود روی دکمه زیر کلیک کنید.", + "Click the following link to confirm your email." : "برای تأیید ایمیل خود روی لینک زیر کلیک کنید.", + "Confirm your email" : "ایمیل خود را تأیید کنید", "Other activities" : "سایر فعالیت ها", - "%1$s and %2$s" : "%1$sو%2$s", - "%1$s, %2$s and %3$s" : "%1$s،%2$sو%3$s", - "%1$s, %2$s, %3$s and %4$s" : "%1$s،%2$s،%3$sو%4$s", - "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s،%2$s،%3$s،%4$sو%5$s", + "%1$s and %2$s" : "%1$s و %2$s", + "%1$s, %2$s and %3$s" : "%1$s، %2$s و %3$s", + "%1$s, %2$s, %3$s and %4$s" : "%1$s، %2$s، %3$s و %4$s", + "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s، %2$s، %3$s، %4$s و %5$s", + "Education bundle" : "بسته آموزشی", "Enterprise bundle" : "بستهٔ سازمانی", "Groupware bundle" : "بستهٔ کار گروهی", "Hub bundle" : "بستهٔ هستهای", + "Public sector bundle" : "بسته بخش عمومی", "Social sharing bundle" : "بستهٔ همرسانی اجتماعی", "PHP %s or higher is required." : "PHP نسخهی %s یا بالاتر نیاز است.", "PHP with a version lower than %s is required." : "نیاز به نگارش پایینتر از %s پیاچپی.", @@ -35,26 +37,34 @@ OC.L10N.register( "The following platforms are supported: %s" : "بنسازههای زیر پشتیبانی میشوند: %s", "Server version %s or higher is required." : "نیاز به کارساز با نگارش %s یا بالاتر.", "Server version %s or lower is required." : "نیاز به کارساز با نگارش %s یا پایینتر.", - "Wiping of device %s has started" : "پاک کردن دستگاه%s شروع شده است", - "Wiping of device »%s« has started" : "پاک کردن دستگاه%s شروع شده است", - "»%s« started remote wipe" : "%sپاک کردن از راه دور", - "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "دستگاه یا برنامه%s فرآیند پاک کردن از راه دور را آغاز کرده است. پس از اتمام مراحل ، ایمیل دیگری دریافت خواهید کرد", - "Wiping of device %s has finished" : "پاک کردن دستگاه %sبه پایان رسیده است", - "Wiping of device »%s« has finished" : "پاک کردن دستگاه %sبه پایان رسیده است", - "»%s« finished remote wipe" : "%sپاک کردن از راه دور", - "Device or application »%s« has finished the remote wipe process." : "دستگاه یا برنامه %sفرآیند پاک کردن از راه دور را به پایان رسانده است.", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "حساب وارد شده باید یک مدیر، یک مدیر فرعی یا دارای حق دسترسی ویژه برای دسترسی به این تنظیم باشد", + "Your current IP address doesn't allow you to perform admin actions" : "آدرس IP فعلی شما اجازه انجام اقدامات مدیریتی را به شما نمیدهد", + "Logged in account must be an admin or sub admin" : "حساب وارد شده باید یک مدیر یا مدیر فرعی باشد", + "Logged in account must be an admin" : "حساب وارد شده باید یک مدیر باشد", + "Wiping of device %s has started" : "پاک کردن دستگاه %s آغاز شد", + "Wiping of device »%s« has started" : "پاک کردن دستگاه «%s» آغاز شد", + "»%s« started remote wipe" : "«%s» پاک کردن از راه دور را آغاز کرد", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "دستگاه یا برنامه «%s» فرآیند پاک کردن از راه دور را آغاز کرده است. پس از اتمام مراحل، ایمیل دیگری دریافت خواهید کرد.", + "Wiping of device %s has finished" : "پاک کردن دستگاه %s به پایان رسید", + "Wiping of device »%s« has finished" : "پاک کردن دستگاه «%s» به پایان رسید", + "»%s« finished remote wipe" : "«%s» پاک کردن از راه دور را به پایان رساند", + "Device or application »%s« has finished the remote wipe process." : "دستگاه یا برنامه «%s» فرآیند پاک کردن از راه دور را به پایان رسانده است.", "Remote wipe started" : "پاک کردن از راه دور شروع شد", - "A remote wipe was started on device %s" : "پاک کردن از راه دور روی دستگاه شروع شد%s", + "A remote wipe was started on device %s" : "پاک کردن از راه دور روی دستگاه %s شروع شد", "Remote wipe finished" : "پاک کردن از راه دور به پایان رسید", - "The remote wipe on %s has finished" : "پاک کردن از راه دور روی%s کار تمام شد", + "The remote wipe on %s has finished" : "پاک کردن از راه دور روی %s کار تمام شد", "Authentication" : "احراز هویت", "Unknown filetype" : "نوع فایل ناشناخته", "Invalid image" : "عکس نامعتبر", "Avatar image is not square" : "تصویر آواتار مربع نیست", "Files" : "پوشهها", "View profile" : "مشاهدهٔ نمایه", - "_%nh_::_%nh_" : ["%nh","%nh"], - "Local time: %s" : "Local time: %s", + "same time" : "همزمان", + "_%nh_::_%nh_" : ["%n ساعت","%n ساعت"], + "_%nm_::_%nm_" : ["%n دقیقه","%n دقیقه"], + "%s ahead" : "%s جلوتر", + "%s behind" : "%s عقبتر", + "Local time: %s" : "زمان محلی: %s", "today" : "امروز", "tomorrow" : "فردا", "yesterday" : "دیروز", @@ -75,13 +85,37 @@ OC.L10N.register( "in a few seconds" : "در چند ثانیه", "seconds ago" : "ثانیهها پیش", "Empty file" : "پروندهٔ خالی", - "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "ماژول با شناسه:%s وجود ندارد. لطفاً آن را در تنظیمات برنامه خود فعال کنید یا با سرپرست خود تماس بگیرید", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "ماژول با شناسه: %s وجود ندارد. لطفاً آن را در تنظیمات برنامه خود فعال کنید یا با سرپرست خود تماس بگیرید.", + "No file conversion providers available" : "ارائهدهنده تبدیل فایل در دسترس نیست", + "File is too large to convert" : "فایل برای تبدیل خیلی بزرگ است", + "Destination does not match conversion extension" : "مقصد با پسوند تبدیل مطابقت ندارد", + "Could not convert file" : "فایل قابل تبدیل نبود", + "Destination does not exist" : "مقصد وجود ندارد", + "Destination is not creatable" : "مقصد قابل ایجاد نیست", "Dot files are not allowed" : "پروندههای نقطهدار مجاز نیستند", + "%1$s (renamed)" : "%1$s (تغییر نام داده شد)", + "renamed file" : "فایل تغییر نام داده شد", + "\"%1$s\" is a forbidden file or folder name." : "«%1$s» یک نام فایل یا پوشه ممنوع است.", + "\"%1$s\" is a forbidden prefix for file or folder names." : "«%1$s» یک پیشوند ممنوع برای نام فایل یا پوشه است.", + "\"%1$s\" is not allowed inside a file or folder name." : "«%1$s» در نام فایل یا پوشه مجاز نیست.", + "\"%1$s\" is a forbidden file type." : "«%1$s» یک نوع فایل ممنوع است.", + "Filenames must not end with \"%1$s\"." : "نام فایلها نباید با «%1$s» به پایان برسند.", + "Invalid parent path" : "مسیر والد نامعتبر", "File already exists" : "پرونده از پیش موجود است", "Invalid path" : "مسیر نامعتبر", "Failed to create file from template" : "شکست در ایجاد پرونده از قالب", "Templates" : "قالبها", + "Storage %s cannot be moved" : "حافظه %s قابل جابجایی نیست", + "Moving a share (%s) into a shared folder is not allowed" : "انتقال یک اشتراک (%s) به یک پوشه مشترک مجاز نیست", + "Moving a storage (%s) into a shared folder is not allowed" : "انتقال یک حافظه (%s) به یک پوشه مشترک مجاز نیست", + "Moving a share (%s) into another share (%s) is not allowed" : "انتقال یک اشتراک (%s) به اشتراک دیگر (%s) مجاز نیست", + "Moving a share (%s) into another storage (%s) is not allowed" : "انتقال یک اشتراک (%s) به حافظه دیگر (%s) مجاز نیست", + "Moving a storage (%s) into a share (%s) is not allowed" : "انتقال یک حافظه (%s) به یک اشتراک (%s) مجاز نیست", + "Moving a storage (%s) into another storage (%s) is not allowed" : "انتقال یک حافظه (%s) به حافظه دیگر (%s) مجاز نیست", + "Path contains invalid segments" : "مسیر شامل بخشهای نامعتبر است", + "Filename is a reserved word" : "نام فایل یک کلمه رزرو شده است", "Filename contains at least one invalid character" : "نام فایل حداقل دارای یک کاراکتر نامعتبر است", + "Filename is too long" : "نام فایل بیش از حد طولانی است", "Empty filename is not allowed" : "نام فایل نمیتواند خالی باشد", "App \"%s\" cannot be installed because appinfo file cannot be read." : "کارهٔ «%s» به دلیل ناتوانی در خواندن پروندهٔ appinfo نمیتواند نصب شود.", "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "کارهٔ «%s» به دلیل سازگار نبودن با این نگارش از کارساز نمیتواند نصب شود.", @@ -97,8 +131,8 @@ OC.L10N.register( "Accounts" : "حسابها", "Email" : "رایانامه", "Mail %s" : "نامه به %s", - "Fediverse" : "Fediverse", - "View %s on the fediverse" : "View %s on the fediverse", + "Fediverse" : "فدیورس", + "View %s on the fediverse" : "مشاهده %s در فدیورس", "Phone" : "تلفن", "Call %s" : "تماس با %s", "Twitter" : "توییتر", @@ -108,35 +142,87 @@ OC.L10N.register( "Address" : "نشانی", "Profile picture" : "تصویر نمایه", "About" : "درباره", - "Display name" : "Display name", + "Display name" : "نام نمایشی", "Headline" : "عنوان", "Organisation" : "سازمان", "Role" : "نقش", + "Pronouns" : "ضمایر", + "Unknown account" : "حساب ناشناخته", "Additional settings" : "تنظیمات اضافی", + "Enter the database Login and name for %s" : "نام کاربری و نام پایگاه داده را برای %s وارد کنید", + "Enter the database Login for %s" : "نام کاربری پایگاه داده را برای %s وارد کنید", "Enter the database name for %s" : "ورود نام پایگاه داده برای %s", "You cannot use dots in the database name %s" : "نمیتوانید در در نام پایگاه دادهٔ %s از نقطه استفاده کنید", + "MySQL Login and/or password not valid" : "نام کاربری و/یا رمز عبور MySQL نامعتبر است", "You need to enter details of an existing account." : "لازم است جزییات یک حساب موحود را وارد کنید.", "Oracle connection could not be established" : "ارتباط اراکل نمیتواند برقرار باشد.", + "Oracle Login and/or password not valid" : "نام کاربری و/یا رمز عبور Oracle نامعتبر است", + "PostgreSQL Login and/or password not valid" : "نام کاربری و/یا رمز عبور PostgreSQL نامعتبر است", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk!" : "Mac OS X پشتیبانی نمیشود و %s روی این پلتفرم به درستی کار نخواهد کرد. با مسئولیت خودتان از آن استفاده کنید!", "For the best results, please consider using a GNU/Linux server instead." : "برای بهترین نتیجه، استفاده از یک کارساز گنو/لینوکسی را در نظر داشته باشید.", - "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "به نظر می رسد%s که این نمونه در یک محیط PHP 32 بیتی در حال اجرا است و open_baseir در php.ini پیکربندی شده است. این مسئله به پرونده هایی با بیش از 4 گیگ منجر می شود و بسیار دلسرد می شود", - "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "لطفاً تنظیمات open_baseir را درون php.ini خود حذف کنید یا به PHP 64 بیتی تغییر دهید.", + "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "به نظر می رسد %s که این نمونه در یک محیط PHP 32 بیتی در حال اجرا است و open_basedir در php.ini پیکربندی شده است. این مسئله به پرونده هایی با بیش از 4 گیگ منجر می شود و بسیار دلسرد می شود.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "لطفاً تنظیمات open_basedir را درون php.ini خود حذف کنید یا به PHP 64 بیتی تغییر دهید.", + "Set an admin Login." : "یک نام کاربری برای مدیر تنظیم کنید.", "Set an admin password." : "یک رمزعبور برای مدیر تنظیم نمایید.", - "Cannot create or write into the data directory %s" : "Cannot create or write into the data directory %s", - "Sharing backend %s must implement the interface OCP\\Share_Backend" : "به اشتراک گذاشتن باطن باید رابط OCP \\ Share_Backend %sرا پیاده سازی کند", - "Sharing backend %s not found" : "به اشتراک گذاشتن باطن%s یافت نشد", - "Sharing backend for %s not found" : "به اشتراک گذاشتن باطن برای%s یافت نشد", + "Cannot create or write into the data directory %s" : "نمیتوان در دایرکتوری داده %s ایجاد یا نوشت", + "Sharing backend %s must implement the interface OCP\\Share_Backend" : "بکاند اشتراکگذاری %s باید رابط OCP\\Share_Backend را پیادهسازی کند", + "Sharing backend %s not found" : "بکاند اشتراکگذاری %s یافت نشد", + "Sharing backend for %s not found" : "بکاند اشتراکگذاری برای %s یافت نشد", + "%1$s shared %2$s with you" : "%1$s %2$s را با شما به اشتراک گذاشت", + "Open %s" : "باز کردن %s", "%1$s via %2$s" : "%1$s از طریق %2$s", + "%1$s shared %2$s with you and wants to add:" : "%1$s %2$s را با شما به اشتراک گذاشت و میخواهد اضافه کند:", + "%1$s shared %2$s with you and wants to add" : "%1$s %2$s را با شما به اشتراک گذاشت و میخواهد اضافه کند", + "%s added a note to a file shared with you" : "%s یک یادداشت به فایلی که با شما به اشتراک گذاشته شده است اضافه کرد", + "Passwords are enforced for link and mail shares" : "رمزهای عبور برای اشتراکگذاری لینک و ایمیل اجباری هستند", + "Share recipient is not a valid user" : "گیرنده اشتراک یک کاربر معتبر نیست", + "Share recipient is not a valid group" : "گیرنده اشتراک یک گروه معتبر نیست", + "Share recipient should be empty" : "گیرنده اشتراک باید خالی باشد", + "Share recipient should not be empty" : "گیرنده اشتراک نباید خالی باشد", + "Share recipient is not a valid circle" : "گیرنده اشتراک یک دایره معتبر نیست", "Unknown share type" : "نوع اشتراک ناشناخته", - "You are not allowed to share %s" : "شما مجاز به اشتراک گذاری نیستید%s", - "Cannot increase permissions of %s" : "Cannot increase permissions of %s", - "Files cannot be shared with delete permissions" : "Files cannot be shared with delete permissions", - "Files cannot be shared with create permissions" : "Files cannot be shared with create permissions", + "Share initiator must be set" : "شروعکننده اشتراک باید تنظیم شود", + "Cannot share with yourself" : "نمیتوانید با خودتان به اشتراک بگذارید", + "Shared path must be set" : "مسیر مشترک باید تنظیم شود", + "Shared path must be either a file or a folder" : "مسیر مشترک باید یک فایل یا یک پوشه باشد", + "You cannot share your root folder" : "نمیتوانید پوشه ریشه خود را به اشتراک بگذارید", + "You are not allowed to share %s" : "شما مجاز به اشتراک گذاری %s نیستید", + "Valid permissions are required for sharing" : "مجوزهای معتبر برای اشتراکگذاری لازم است", + "File shares cannot have create or delete permissions" : "اشتراکگذاری فایلها نمیتواند مجوزهای ایجاد یا حذف داشته باشد", + "Cannot increase permissions of %s" : "نمیتوان مجوزهای %s را افزایش داد", + "Shares need at least read permissions" : "اشتراکگذاریها حداقل به مجوزهای خواندن نیاز دارند", + "Files cannot be shared with delete permissions" : "فایلها را نمیتوان با مجوزهای حذف به اشتراک گذاشت", + "Files cannot be shared with create permissions" : "فایلها را نمیتوان با مجوزهای ایجاد به اشتراک گذاشت", "Expiration date is in the past" : "تاریخ انقضا در گذشته است", - "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Cannot set expiration date more than %n day in the future","Cannot set expiration date more than %n days in the future"], - "Sharing is only allowed with group members" : "Sharing is only allowed with group members", + "Expiration date is enforced" : "تاریخ انقضا اجباری است", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["نمیتوان تاریخ انقضا را بیش از %n روز در آینده تنظیم کرد","نمیتوان تاریخ انقضا را بیش از %n روز در آینده تنظیم کرد"], + "Sharing is only allowed with group members" : "اشتراکگذاری فقط با اعضای گروه مجاز است", + "Sharing %s failed, because this item is already shared with the account %s" : "اشتراکگذاری %s ناموفق بود، زیرا این مورد قبلاً با حساب %s به اشتراک گذاشته شده است", + "Group sharing is now allowed" : "اشتراکگذاری گروهی اکنون مجاز است", + "Sharing is only allowed within your own groups" : "اشتراکگذاری فقط در گروههای خودتان مجاز است", + "Path is already shared with this group" : "این مسیر قبلاً با این گروه به اشتراک گذاشته شده است", + "Link sharing is not allowed" : "اشتراکگذاری لینک مجاز نیست", + "Public upload is not allowed" : "بارگذاری عمومی مجاز نیست", + "You cannot share a folder that contains other shares" : "نمیتوانید پوشهای را به اشتراک بگذارید که حاوی اشتراکهای دیگر است", + "Sharing is disabled" : "اشتراکگذاری غیرفعال است", + "Sharing is disabled for you" : "اشتراکگذاری برای شما غیرفعال است", + "Cannot share with the share owner" : "نمیتوان با صاحب اشتراک به اشتراک گذاشت", + "Share does not have a full ID" : "اشتراک شناسه کامل ندارد", + "Cannot change share type" : "نمیتوان نوع اشتراک را تغییر داد", + "Can only update recipient on user shares" : "فقط میتوان گیرنده را در اشتراکهای کاربر بهروزرسانی کرد", + "Cannot enable sending the password by Talk with an empty password" : "نمیتوان ارسال رمز عبور از طریق Talk را با رمز عبور خالی فعال کرد", + "Cannot enable sending the password by Talk without setting a new password" : "نمیتوان ارسال رمز عبور از طریق Talk را بدون تنظیم رمز عبور جدید فعال کرد", + "Cannot disable sending the password by Talk without setting a new password" : "نمیتوان ارسال رمز عبور از طریق Talk را بدون تنظیم رمز عبور جدید غیرفعال کرد", + "Share provider does not support accepting" : "ارائهدهنده اشتراک از پذیرش پشتیبانی نمیکند", + "Cannot change target of link share" : "نمیتوان مقصد اشتراک لینک را تغییر داد", + "Invalid share recipient" : "گیرنده اشتراک نامعتبر است", + "Group \"%s\" does not exist" : "گروه «%s» وجود ندارد", "The requested share does not exist anymore" : "سهم درخواست شده دیگر وجود ندارد", - "The user was not created because the user limit has been reached. Check your notifications to learn more." : "The user was not created because the user limit has been reached. Check your notifications to learn more.", + "The requested share comes from a disabled user" : "اشتراک درخواستی از یک کاربر غیرفعال است", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "کاربر ایجاد نشد زیرا محدودیت کاربر به پایان رسیده است. برای اطلاعات بیشتر اعلانهای خود را بررسی کنید.", "Could not find category \"%s\"" : "دسته بندی %s یافت نشد", + "Input text" : "متن ورودی", + "The input text" : "متن ورودی", "Sunday" : "یکشنبه", "Monday" : "دوشنبه", "Tuesday" : "سهشنبه", @@ -183,6 +269,15 @@ OC.L10N.register( "Nov." : "نو.", "Dec." : "دس.", "A valid password must be provided" : "رمز عبور صحیح باید وارد شود", + "The Login is already being used" : "نام کاربری قبلاً استفاده شده است", + "Could not create account" : "حساب کاربری ایجاد نشد", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "فقط کاراکترهای زیر در نام کاربری مجاز هستند: \"a-z\", \"A-Z\", \"0-9\", فاصله و \"_.@-'\"", + "A valid Login must be provided" : "یک نام کاربری معتبر باید ارائه شود", + "Login contains whitespace at the beginning or at the end" : "نام کاربری حاوی فاصله در ابتدا یا انتها است", + "Login must not consist of dots only" : "نام کاربری نباید فقط از نقطه تشکیل شده باشد", + "Username is too long" : "نام کاربری بیش از حد طولانی است", + "Login is invalid because files already exist for this user" : "نام کاربری نامعتبر است زیرا فایلها برای این کاربر از قبل وجود دارند", + "Account disabled" : "حساب کاربری غیرفعال است", "Login canceled by app" : "ورود به دست کاره لغو شد", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "کارهٔ «%1$s» نمیتواند نصب شود؛ چرا که وابستگی زیر تأمین نشده: %2$s", "a safe home for all your data" : "خانهای امن برای تمامی دادههایتان", @@ -190,60 +285,173 @@ OC.L10N.register( "Authentication error" : "خطا در اعتبار سنجی", "Token expired. Please reload page." : "Token منقضی شده است. لطفا دوباره صفحه را بارگذاری نمایید.", "No database drivers (sqlite, mysql, or postgresql) installed." : "هیچ درایور پایگاه داده (sqlite ، mysql یا postgresql) نصب نشده است.", - "Cannot write into \"config\" directory." : "Cannot write into \"config\" directory.", - "This can usually be fixed by giving the web server write access to the config directory. See %s" : "This can usually be fixed by giving the web server write access to the config directory. See %s", - "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "یا اگر ترجیح می دهید پرونده config.php را فقط بخوانید ، گزینه \"config_is_read_only\" را در آن تنظیم کنید. دیدن%s", - "Cannot write into \"apps\" directory." : "Cannot write into \"apps\" directory.", - "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file." : "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file.", - "Cannot create \"data\" directory." : "Cannot create \"data\" directory.", - "This can usually be fixed by giving the web server write access to the root directory. See %s" : "This can usually be fixed by giving the web server write access to the root directory. See %s", - "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Permissions can usually be fixed by giving the web server write access to the root directory. See %s.", - "Your data directory is not writable." : "Your data directory is not writable.", - "Setting locale to %s failed." : "Setting locale to %s failed.", - "Please install one of these locales on your system and restart your web server." : "Please install one of these locales on your system and restart your web server.", + "Cannot write into \"config\" directory." : "نمیتوان در دایرکتوری «config» نوشت.", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "این مشکل معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری پیکربندی قابل رفع است. مشاهده %s", + "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "یا اگر ترجیح میدهید فایل config.php فقط خواندنی باشد، گزینه \"config_is_read_only\" را در آن به true تنظیم کنید. مشاهده %s", + "Cannot write into \"apps\" directory." : "نمیتوان در دایرکتوری «apps» نوشت.", + "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file." : "این مشکل معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری برنامهها یا غیرفعال کردن فروشگاه برنامه در فایل پیکربندی قابل رفع است.", + "Cannot create \"data\" directory." : "نمیتوان دایرکتوری «data» را ایجاد کرد.", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "این مشکل معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری ریشه قابل رفع است. مشاهده %s", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "مجوزها معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری ریشه قابل رفع هستند. مشاهده %s.", + "Your data directory is not writable." : "دایرکتوری داده شما قابل نوشتن نیست.", + "Setting locale to %s failed." : "تنظیم محلی به %s ناموفق بود.", + "Please install one of these locales on your system and restart your web server." : "لطفاً یکی از این محلیها را روی سیستم خود نصب کرده و وبسرور خود را مجدداً راهاندازی کنید.", "PHP module %s not installed." : "ماژول PHP %s نصب نشده است.", "Please ask your server administrator to install the module." : "لطفا از مدیر سیستم بخواهید تا ماژول را نصب کند.", - "PHP setting \"%s\" is not set to \"%s\"." : "تنظیمات PHP%s تنظیم نشده است%s", + "PHP setting \"%s\" is not set to \"%s\"." : "تنظیمات PHP «%s» روی «%s» تنظیم نشده است.", "Adjusting this setting in php.ini will make Nextcloud run again" : "تنظیم این تنظیمات در php.ini باعث می شود Nextcloud دوباره اجرا شود", - "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>.", - "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.", - "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP ظاهراً برای خنثی کردن بلوک های اسناد درون خطی تنظیم شده است. این کار چندین برنامه اصلی را غیرقابل دسترسی خواهد کرد.", - "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "این احتمالاً توسط حافظه پنهان / کش مانند Zend OPcache یا eAccelerator ایجاد شده است.", - "PHP modules have been installed, but they are still listed as missing?" : "ماژول های پی اچ پی نصب شده اند ، اما هنوز هم به عنوان مفقود شده ذکر شده اند؟", - "Please ask your server administrator to restart the web server." : "لطفاً از سرور سرور خود بخواهید که وب سرور را مجدداً راه اندازی کند.", - "The required %s config variable is not configured in the config.php file." : "The required %s config variable is not configured in the config.php file.", - "Please ask your server administrator to check the Nextcloud configuration." : "Please ask your server administrator to check the Nextcloud configuration.", - "Your data directory must be an absolute path." : "Your data directory must be an absolute path.", - "Check the value of \"datadirectory\" in your configuration." : "Check the value of \"datadirectory\" in your configuration.", - "Your data directory is invalid." : "Your data directory is invalid.", - "Action \"%s\" not supported or implemented." : "عملی%s پشتیبانی یا اجرا نشده است.", - "Authentication failed, wrong token or provider ID given" : "تأیید اعتبار انجام نشد ، نشانه اشتباه یا شناسه ارائه دهنده داده شد", - "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "پارامترهای موجود برای تکمیل درخواست. پارامترهای موجود نیست%s", - "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "شناسه%1$s قبلاً توسط ارائه دهنده فدراسیون ابر استفاده شده است%2$s", - "Cloud Federation Provider with ID: \"%s\" does not exist." : "ارائه دهنده فدراسیون Cloud با شناسه:%s وجود ندارد.", - "Could not obtain lock type %d on \"%s\"." : "نمی توان نوع%d قفل را به دست آورد%s", - "Storage unauthorized. %s" : "ذخیره سازی غیر مجاز.%s", - "Storage incomplete configuration. %s" : "پیکربندی ناقص ذخیره سازی.%s<br>", - "Storage connection error. %s" : "خطای اتصال ذخیره سازی%s", - "Storage is temporarily not available" : "ذخیره سازی به طور موقت در دسترس نیست", - "Storage connection timeout. %s" : "مدت زمان اتصال ذخیره سازی%s", - "Confirmation" : "Confirmation", - "Prompt" : "Prompt", - "Chat" : "Chat", - "Generates a possible headline for a text." : "Generates a possible headline for a text.", + "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> به جای مقدار مورد انتظار <code>0</code> روی <code>%s</code> تنظیم شده است.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "برای رفع این مشکل، <code>mbstring.func_overload</code> را در php.ini خود روی <code>0</code> تنظیم کنید.", + "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP ظاهراً برای حذف بلوکهای مستندات درونخطی تنظیم شده است. این کار چندین برنامه اصلی را غیرقابل دسترس خواهد کرد.", + "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "این احتمالاً توسط حافظه پنهان/شتابدهندهای مانند Zend OPcache یا eAccelerator ایجاد شده است.", + "PHP modules have been installed, but they are still listed as missing?" : "ماژولهای PHP نصب شدهاند، اما همچنان به عنوان گمشده لیست شدهاند؟", + "Please ask your server administrator to restart the web server." : "لطفاً از مدیر سرور خود بخواهید که وبسرور را مجدداً راهاندازی کند.", + "The required %s config variable is not configured in the config.php file." : "متغیر پیکربندی مورد نیاز %s در فایل config.php پیکربندی نشده است.", + "Please ask your server administrator to check the Nextcloud configuration." : "لطفاً از مدیر سرور خود بخواهید پیکربندی Nextcloud را بررسی کند.", + "Your data directory is readable by other people." : "دایرکتوری داده شما برای دیگران قابل خواندن است.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "لطفاً مجوزها را به 0770 تغییر دهید تا دایرکتوری توسط افراد دیگر قابل فهرست شدن نباشد.", + "Your data directory must be an absolute path." : "دایرکتوری داده شما باید یک مسیر مطلق باشد.", + "Check the value of \"datadirectory\" in your configuration." : "مقدار \"datadirectory\" را در پیکربندی خود بررسی کنید.", + "Your data directory is invalid." : "دایرکتوری داده شما نامعتبر است.", + "Ensure there is a file called \"%1$s\" in the root of the data directory. It should have the content: \"%2$s\"" : "اطمینان حاصل کنید که فایلی به نام «%1$s» در ریشه دایرکتوری داده وجود دارد. این فایل باید حاوی: «%2$s» باشد", + "Action \"%s\" not supported or implemented." : "عملیات «%s» پشتیبانی یا اجرا نشده است.", + "Authentication failed, wrong token or provider ID given" : "تأیید اعتبار انجام نشد، نشانه اشتباه یا شناسه ارائه دهنده داده شد", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "پارامترهای مورد نیاز برای تکمیل درخواست وجود ندارند. پارامترهای از دست رفته: «%s»", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "شناسه «%1$s» قبلاً توسط ارائهدهنده فدراسیون ابری «%2$s» استفاده شده است", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "ارائهدهنده فدراسیون ابری با شناسه: «%s» وجود ندارد.", + "Could not obtain lock type %d on \"%s\"." : "نمیتوان قفل از نوع %d را روی «%s» به دست آورد.", + "Storage unauthorized. %s" : "دسترسی به حافظه غیرمجاز است. %s", + "Storage incomplete configuration. %s" : "پیکربندی حافظه ناقص است. %s", + "Storage connection error. %s" : "خطای اتصال حافظه. %s", + "Storage is temporarily not available" : "حافظه به طور موقت در دسترس نیست", + "Storage connection timeout. %s" : "مهلت اتصال حافظه به پایان رسید. %s", + "To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule." : "برای اجرای این بررسی، باید مطمئن شوید که وبسرور شما میتواند به خودش متصل شود. بنابراین باید بتواند حداقل یکی از `trusted_domains` یا `overwrite.cli.url` خود را حل و به آن متصل شود. این خطا ممکن است نتیجه عدم تطابق DNS سمت سرور یا قانون فایروال خروجی باشد.", + "Transcribe audio" : "رونوشت صوتی", + "Transcribe the things said in an audio" : "رونوشت چیزهای گفته شده در یک فایل صوتی", + "Audio input" : "ورودی صوتی", + "The audio to transcribe" : "فایل صوتی برای رونوشت", + "Transcription" : "رونوشت", + "The transcribed text" : "متن رونوشت شده", + "Chat with an agent" : "چت با یک عامل", + "Chat message" : "پیام چت", + "A chat message to send to the agent." : "یک پیام چت برای ارسال به عامل.", + "Confirmation" : "تأیید", + "Whether to confirm previously requested actions: 0 for denial and 1 for confirmation." : "آیا اقدامات قبلاً درخواست شده را تأیید کنید: 0 برای رد و 1 برای تأیید.", + "Conversation token" : "توکن مکالمه", + "A token representing the conversation." : "یک توکن نماینده مکالمه.", + "Generated response" : "پاسخ تولید شده", + "The response from the chat model." : "پاسخ از مدل چت.", + "The new conversation token" : "توکن مکالمه جدید", + "Send this along with the next interaction." : "این را همراه با تعامل بعدی ارسال کنید.", + "Requested actions by the agent" : "اقدامات درخواستی توسط عامل", + "Actions that the agent would like to carry out in JSON format." : "اقدامات که عامل مایل به انجام آنها در قالب JSON است.", + "Context write" : "نوشتن متنی", + "Writes text in a given style based on the provided source material." : "متن را با سبکی مشخص بر اساس محتوای منبع ارائه شده مینویسد.", + "Writing style" : "سبک نگارش", + "Demonstrate a writing style that you would like to immitate" : "یک سبک نگارش را که میخواهید تقلید کنید، نشان دهید", + "Source material" : "محتوای منبع", + "The content that would like to be rewritten in the new writing style" : "محتوایی که میخواهید با سبک نگارش جدید بازنویسی شود", + "Generated text" : "متن تولید شده", + "The generated text with content from the source material in the given style" : "متن تولید شده با محتوای منبع در سبک مشخص شده", + "Emoji generator" : "تولیدکننده اموجی", + "Takes text and generates a representative emoji for it." : "متن را دریافت کرده و یک اموجی مناسب برای آن تولید میکند.", + "The text to generate an emoji for" : "متنی که میخواهید برای آن اموجی تولید شود", + "Generated emoji" : "اموجی تولید شده", + "The generated emoji based on the input text" : "اموجی تولید شده بر اساس متن ورودی", + "Generate image" : "تولید تصویر", + "Generate an image from a text prompt" : "تولید تصویر از یک متن ورودی", + "Prompt" : "درخواست", + "Describe the image you want to generate" : "تصویری که میخواهید تولید شود را توصیف کنید", + "Number of images" : "تعداد تصاویر", + "How many images to generate" : "چه تعداد تصویر تولید شود", + "Output images" : "تصاویر خروجی", + "The generated images" : "تصاویر تولید شده", + "Generate speech" : "تولید گفتار", + "Generate speech from a transcript" : "تولید گفتار از یک رونوشت", + "Write transcript that you want the assistant to generate speech from" : "رونوشتی را بنویسید که میخواهید دستیار از آن گفتار تولید کند", + "Output speech" : "گفتار خروجی", + "The generated speech" : "گفتار تولید شده", + "Free text to text prompt" : "درخواست متن به متن آزاد", + "Runs an arbitrary prompt through a language model that returns a reply" : "یک درخواست دلخواه را از طریق یک مدل زبانی اجرا میکند که پاسخی را برمیگرداند", + "Describe a task that you want the assistant to do or ask a question" : "وظیفهای که میخواهید دستیار انجام دهد را توصیف کنید یا سؤالی بپرسید", + "Generated reply" : "پاسخ تولید شده", + "The generated text from the assistant" : "متن تولید شده توسط دستیار", + "Change Tone" : "تغییر لحن", + "Change the tone of a piece of text." : "لحن یک قطعه متن را تغییر دهید.", + "Write a text that you want the assistant to rewrite in another tone." : "متنی را بنویسید که میخواهید دستیار آن را با لحن دیگری بازنویسی کند.", + "Desired tone" : "لحن مورد نظر", + "In which tone should your text be rewritten?" : "متن شما با چه لحنی بازنویسی شود؟", + "The rewritten text in the desired tone, written by the assistant:" : "متن بازنویسی شده با لحن مورد نظر، نوشته شده توسط دستیار:", + "Chat" : "چت", + "Chat with the assistant" : "چت با دستیار", + "System prompt" : "درخواست سیستمی", + "Define rules and assumptions that the assistant should follow during the conversation." : "قوانین و فرضیاتی را که دستیار باید در طول مکالمه رعایت کند، تعریف کنید.", + "Chat history" : "تاریخچه چت", + "The history of chat messages before the current message, starting with a message by the user" : "تاریخچه پیامهای چت قبل از پیام فعلی، با شروع از یک پیام توسط کاربر", + "Response message" : "پیام پاسخ", + "The generated response as part of the conversation" : "پاسخ تولید شده به عنوان بخشی از مکالمه", + "Chat with tools" : "چت با ابزارها", + "Chat with the language model with tool calling support." : "چت با مدل زبانی با پشتیبانی از فراخوانی ابزار.", + "Tool message" : "پیام ابزار", + "The result of tool calls in the last interaction" : "نتیجه فراخوانی ابزارها در تعامل قبلی", + "Available tools" : "ابزارهای موجود", + "The available tools in JSON format" : "ابزارهای موجود در قالب JSON", + "The response from the chat model" : "پاسخ از مدل چت", + "Tool calls" : "فراخوانی ابزار", + "Tools call instructions from the model in JSON format" : "دستورالعملهای فراخوانی ابزار از مدل در قالب JSON", + "Formalize text" : "رسمی کردن متن", + "Takes a text and makes it sound more formal" : "یک متن را دریافت کرده و آن را رسمیتر میکند", + "Write a text that you want the assistant to formalize" : "متنی را بنویسید که میخواهید دستیار آن را رسمی کند", + "Formalized text" : "متن رسمی شده", + "The formalized text" : "متن رسمی شده", + "Generate a headline" : "تولید یک عنوان", + "Generates a possible headline for a text." : "یک عنوان احتمالی برای یک متن تولید میکند.", + "Original text" : "متن اصلی", + "The original text to generate a headline for" : "متن اصلی برای تولید عنوان", + "The generated headline" : "عنوان تولید شده", + "Proofread" : "ویرایش", + "Proofreads a text and lists corrections" : "یک متن را ویرایش کرده و اصلاحات را لیست میکند", "Text" : "متن", - "Summarize" : "Summarize", + "The text to proofread" : "متن برای ویرایش", + "Corrections" : "اصلاحات", + "The corrections that should be made in your text" : "اصلاحاتی که باید در متن شما انجام شود", + "Reformulate text" : "بازنویسی متن", + "Takes a text and reformulates it" : "یک متن را دریافت کرده و آن را بازنویسی میکند", + "Write a text that you want the assistant to reformulate" : "متنی را بنویسید که میخواهید دستیار آن را بازنویسی کند", + "Reformulated text" : "متن بازنویسی شده", + "The reformulated text, written by the assistant" : "متن بازنویسی شده، نوشته شده توسط دستیار", + "Simplify text" : "سادهسازی متن", + "Takes a text and simplifies it" : "یک متن را دریافت کرده و آن را ساده میکند", + "Write a text that you want the assistant to simplify" : "متنی را بنویسید که میخواهید دستیار آن را ساده کند", + "Simplified text" : "متن ساده شده", + "The simplified text" : "متن ساده شده", + "Summarize" : "خلاصهسازی", + "Summarizes a text" : "یک متن را خلاصهسازی میکند", + "The original text to summarize" : "متن اصلی برای خلاصهسازی", "Summary" : "چکیده", - "Extract topics" : "Extract topics", + "The generated summary" : "خلاصه تولید شده", + "Extract topics" : "استخراج موضوعات", + "Extracts topics from a text and outputs them separated by commas" : "موضوعات را از یک متن استخراج کرده و با کاما جدا شده خروجی میدهد", + "The original text to extract topics from" : "متن اصلی برای استخراج موضوعات", + "Topics" : "موضوعات", + "The list of extracted topics" : "لیست موضوعات استخراج شده", "Translate" : "ترجمه", - "Target language" : "Target language", - "Result" : "شروع به اسکنیک", - "Free prompt" : "Free prompt", - "Runs an arbitrary prompt through the language model." : "Runs an arbitrary prompt through the language model.", - "Generate headline" : "Generate headline", - "Summarizes text by reducing its length without losing key information." : "Summarizes text by reducing its length without losing key information.", - "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", + "Translate text from one language to another" : "ترجمه متن از یک زبان به زبان دیگر", + "Origin text" : "متن مبدأ", + "The text to translate" : "متن برای ترجمه", + "Origin language" : "زبان مبدأ", + "The language of the origin text" : "زبان متن مبدأ", + "Target language" : "زبان مقصد", + "The desired language to translate the origin text in" : "زبان مورد نظر برای ترجمه متن مبدأ", + "Result" : "نتیجه", + "The translated text" : "متن ترجمه شده", + "Free prompt" : "درخواست آزاد", + "Runs an arbitrary prompt through the language model." : "یک درخواست دلخواه را از طریق مدل زبانی اجرا میکند.", + "Generate headline" : "تولید عنوان", + "Summarizes text by reducing its length without losing key information." : "متن را با کاهش طول آن و بدون از دست دادن اطلاعات کلیدی، خلاصهسازی میکند.", + "Extracts topics from a text and outputs them separated by commas." : "موضوعات را از یک متن استخراج کرده و با کاما جدا شده خروجی میدهد.", "File is currently busy, please try again later" : "فایل در حال حاضر مشغول است، لطفا مجددا تلاش کنید", - "Cannot download file" : "نمیتوان پرونده را بارگرفت" + "Cannot download file" : "نمیتوان پرونده را بارگرفت", + "Login is too long" : "نام کاربری بیش از حد طولانی است" }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/fa.json b/lib/l10n/fa.json index a16f86e6522..7fda24b1e51 100644 --- a/lib/l10n/fa.json +++ b/lib/l10n/fa.json @@ -1,25 +1,27 @@ { "translations": { "Cannot write into \"config\" directory!" : "نمیتوانید داخل دایرکتوری \"config\" تغییراتی ایجاد کنید", - "This can usually be fixed by giving the web server write access to the config directory." : "This can usually be fixed by giving the web server write access to the config directory.", - "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it.", + "This can usually be fixed by giving the web server write access to the config directory." : "این مشکل معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری پیکربندی قابل رفع است.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "اما، اگر ترجیح میدهید فایل config.php فقط خواندنی باشد، گزینه \"config_is_read_only\" را در آن به true تنظیم کنید.", "See %s" : "مشاهده %s", - "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory.", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "برنامه %1$s موجود نیست یا نسخهای ناسازگار با این سرور دارد. لطفاً دایرکتوری برنامهها را بررسی کنید.", "Sample configuration detected" : "فایل پیکربندی نمونه پیدا شد", "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "تشخیص داده شده است که پیکربندی نمونه کپی شده است. این می تواند نصب شما را خراب کند و پشتیبانی نمی شود. لطفاً قبل از انجام تغییرات در config.php ، اسناد را بخوانید", - "The page could not be found on the server." : "The page could not be found on the server.", - "%s email verification" : "%s email verification", - "Email verification" : "Email verification", - "Click the following button to confirm your email." : "Click the following button to confirm your email.", - "Click the following link to confirm your email." : "Click the following link to confirm your email.", - "Confirm your email" : "Confirm your email", + "The page could not be found on the server." : "صفحه در سرور یافت نشد.", + "%s email verification" : "تأیید ایمیل %s", + "Email verification" : "تأیید ایمیل", + "Click the following button to confirm your email." : "برای تأیید ایمیل خود روی دکمه زیر کلیک کنید.", + "Click the following link to confirm your email." : "برای تأیید ایمیل خود روی لینک زیر کلیک کنید.", + "Confirm your email" : "ایمیل خود را تأیید کنید", "Other activities" : "سایر فعالیت ها", - "%1$s and %2$s" : "%1$sو%2$s", - "%1$s, %2$s and %3$s" : "%1$s،%2$sو%3$s", - "%1$s, %2$s, %3$s and %4$s" : "%1$s،%2$s،%3$sو%4$s", - "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s،%2$s،%3$s،%4$sو%5$s", + "%1$s and %2$s" : "%1$s و %2$s", + "%1$s, %2$s and %3$s" : "%1$s، %2$s و %3$s", + "%1$s, %2$s, %3$s and %4$s" : "%1$s، %2$s، %3$s و %4$s", + "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s، %2$s، %3$s، %4$s و %5$s", + "Education bundle" : "بسته آموزشی", "Enterprise bundle" : "بستهٔ سازمانی", "Groupware bundle" : "بستهٔ کار گروهی", "Hub bundle" : "بستهٔ هستهای", + "Public sector bundle" : "بسته بخش عمومی", "Social sharing bundle" : "بستهٔ همرسانی اجتماعی", "PHP %s or higher is required." : "PHP نسخهی %s یا بالاتر نیاز است.", "PHP with a version lower than %s is required." : "نیاز به نگارش پایینتر از %s پیاچپی.", @@ -33,26 +35,34 @@ "The following platforms are supported: %s" : "بنسازههای زیر پشتیبانی میشوند: %s", "Server version %s or higher is required." : "نیاز به کارساز با نگارش %s یا بالاتر.", "Server version %s or lower is required." : "نیاز به کارساز با نگارش %s یا پایینتر.", - "Wiping of device %s has started" : "پاک کردن دستگاه%s شروع شده است", - "Wiping of device »%s« has started" : "پاک کردن دستگاه%s شروع شده است", - "»%s« started remote wipe" : "%sپاک کردن از راه دور", - "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "دستگاه یا برنامه%s فرآیند پاک کردن از راه دور را آغاز کرده است. پس از اتمام مراحل ، ایمیل دیگری دریافت خواهید کرد", - "Wiping of device %s has finished" : "پاک کردن دستگاه %sبه پایان رسیده است", - "Wiping of device »%s« has finished" : "پاک کردن دستگاه %sبه پایان رسیده است", - "»%s« finished remote wipe" : "%sپاک کردن از راه دور", - "Device or application »%s« has finished the remote wipe process." : "دستگاه یا برنامه %sفرآیند پاک کردن از راه دور را به پایان رسانده است.", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "حساب وارد شده باید یک مدیر، یک مدیر فرعی یا دارای حق دسترسی ویژه برای دسترسی به این تنظیم باشد", + "Your current IP address doesn't allow you to perform admin actions" : "آدرس IP فعلی شما اجازه انجام اقدامات مدیریتی را به شما نمیدهد", + "Logged in account must be an admin or sub admin" : "حساب وارد شده باید یک مدیر یا مدیر فرعی باشد", + "Logged in account must be an admin" : "حساب وارد شده باید یک مدیر باشد", + "Wiping of device %s has started" : "پاک کردن دستگاه %s آغاز شد", + "Wiping of device »%s« has started" : "پاک کردن دستگاه «%s» آغاز شد", + "»%s« started remote wipe" : "«%s» پاک کردن از راه دور را آغاز کرد", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "دستگاه یا برنامه «%s» فرآیند پاک کردن از راه دور را آغاز کرده است. پس از اتمام مراحل، ایمیل دیگری دریافت خواهید کرد.", + "Wiping of device %s has finished" : "پاک کردن دستگاه %s به پایان رسید", + "Wiping of device »%s« has finished" : "پاک کردن دستگاه «%s» به پایان رسید", + "»%s« finished remote wipe" : "«%s» پاک کردن از راه دور را به پایان رساند", + "Device or application »%s« has finished the remote wipe process." : "دستگاه یا برنامه «%s» فرآیند پاک کردن از راه دور را به پایان رسانده است.", "Remote wipe started" : "پاک کردن از راه دور شروع شد", - "A remote wipe was started on device %s" : "پاک کردن از راه دور روی دستگاه شروع شد%s", + "A remote wipe was started on device %s" : "پاک کردن از راه دور روی دستگاه %s شروع شد", "Remote wipe finished" : "پاک کردن از راه دور به پایان رسید", - "The remote wipe on %s has finished" : "پاک کردن از راه دور روی%s کار تمام شد", + "The remote wipe on %s has finished" : "پاک کردن از راه دور روی %s کار تمام شد", "Authentication" : "احراز هویت", "Unknown filetype" : "نوع فایل ناشناخته", "Invalid image" : "عکس نامعتبر", "Avatar image is not square" : "تصویر آواتار مربع نیست", "Files" : "پوشهها", "View profile" : "مشاهدهٔ نمایه", - "_%nh_::_%nh_" : ["%nh","%nh"], - "Local time: %s" : "Local time: %s", + "same time" : "همزمان", + "_%nh_::_%nh_" : ["%n ساعت","%n ساعت"], + "_%nm_::_%nm_" : ["%n دقیقه","%n دقیقه"], + "%s ahead" : "%s جلوتر", + "%s behind" : "%s عقبتر", + "Local time: %s" : "زمان محلی: %s", "today" : "امروز", "tomorrow" : "فردا", "yesterday" : "دیروز", @@ -73,13 +83,37 @@ "in a few seconds" : "در چند ثانیه", "seconds ago" : "ثانیهها پیش", "Empty file" : "پروندهٔ خالی", - "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "ماژول با شناسه:%s وجود ندارد. لطفاً آن را در تنظیمات برنامه خود فعال کنید یا با سرپرست خود تماس بگیرید", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "ماژول با شناسه: %s وجود ندارد. لطفاً آن را در تنظیمات برنامه خود فعال کنید یا با سرپرست خود تماس بگیرید.", + "No file conversion providers available" : "ارائهدهنده تبدیل فایل در دسترس نیست", + "File is too large to convert" : "فایل برای تبدیل خیلی بزرگ است", + "Destination does not match conversion extension" : "مقصد با پسوند تبدیل مطابقت ندارد", + "Could not convert file" : "فایل قابل تبدیل نبود", + "Destination does not exist" : "مقصد وجود ندارد", + "Destination is not creatable" : "مقصد قابل ایجاد نیست", "Dot files are not allowed" : "پروندههای نقطهدار مجاز نیستند", + "%1$s (renamed)" : "%1$s (تغییر نام داده شد)", + "renamed file" : "فایل تغییر نام داده شد", + "\"%1$s\" is a forbidden file or folder name." : "«%1$s» یک نام فایل یا پوشه ممنوع است.", + "\"%1$s\" is a forbidden prefix for file or folder names." : "«%1$s» یک پیشوند ممنوع برای نام فایل یا پوشه است.", + "\"%1$s\" is not allowed inside a file or folder name." : "«%1$s» در نام فایل یا پوشه مجاز نیست.", + "\"%1$s\" is a forbidden file type." : "«%1$s» یک نوع فایل ممنوع است.", + "Filenames must not end with \"%1$s\"." : "نام فایلها نباید با «%1$s» به پایان برسند.", + "Invalid parent path" : "مسیر والد نامعتبر", "File already exists" : "پرونده از پیش موجود است", "Invalid path" : "مسیر نامعتبر", "Failed to create file from template" : "شکست در ایجاد پرونده از قالب", "Templates" : "قالبها", + "Storage %s cannot be moved" : "حافظه %s قابل جابجایی نیست", + "Moving a share (%s) into a shared folder is not allowed" : "انتقال یک اشتراک (%s) به یک پوشه مشترک مجاز نیست", + "Moving a storage (%s) into a shared folder is not allowed" : "انتقال یک حافظه (%s) به یک پوشه مشترک مجاز نیست", + "Moving a share (%s) into another share (%s) is not allowed" : "انتقال یک اشتراک (%s) به اشتراک دیگر (%s) مجاز نیست", + "Moving a share (%s) into another storage (%s) is not allowed" : "انتقال یک اشتراک (%s) به حافظه دیگر (%s) مجاز نیست", + "Moving a storage (%s) into a share (%s) is not allowed" : "انتقال یک حافظه (%s) به یک اشتراک (%s) مجاز نیست", + "Moving a storage (%s) into another storage (%s) is not allowed" : "انتقال یک حافظه (%s) به حافظه دیگر (%s) مجاز نیست", + "Path contains invalid segments" : "مسیر شامل بخشهای نامعتبر است", + "Filename is a reserved word" : "نام فایل یک کلمه رزرو شده است", "Filename contains at least one invalid character" : "نام فایل حداقل دارای یک کاراکتر نامعتبر است", + "Filename is too long" : "نام فایل بیش از حد طولانی است", "Empty filename is not allowed" : "نام فایل نمیتواند خالی باشد", "App \"%s\" cannot be installed because appinfo file cannot be read." : "کارهٔ «%s» به دلیل ناتوانی در خواندن پروندهٔ appinfo نمیتواند نصب شود.", "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "کارهٔ «%s» به دلیل سازگار نبودن با این نگارش از کارساز نمیتواند نصب شود.", @@ -95,8 +129,8 @@ "Accounts" : "حسابها", "Email" : "رایانامه", "Mail %s" : "نامه به %s", - "Fediverse" : "Fediverse", - "View %s on the fediverse" : "View %s on the fediverse", + "Fediverse" : "فدیورس", + "View %s on the fediverse" : "مشاهده %s در فدیورس", "Phone" : "تلفن", "Call %s" : "تماس با %s", "Twitter" : "توییتر", @@ -106,35 +140,87 @@ "Address" : "نشانی", "Profile picture" : "تصویر نمایه", "About" : "درباره", - "Display name" : "Display name", + "Display name" : "نام نمایشی", "Headline" : "عنوان", "Organisation" : "سازمان", "Role" : "نقش", + "Pronouns" : "ضمایر", + "Unknown account" : "حساب ناشناخته", "Additional settings" : "تنظیمات اضافی", + "Enter the database Login and name for %s" : "نام کاربری و نام پایگاه داده را برای %s وارد کنید", + "Enter the database Login for %s" : "نام کاربری پایگاه داده را برای %s وارد کنید", "Enter the database name for %s" : "ورود نام پایگاه داده برای %s", "You cannot use dots in the database name %s" : "نمیتوانید در در نام پایگاه دادهٔ %s از نقطه استفاده کنید", + "MySQL Login and/or password not valid" : "نام کاربری و/یا رمز عبور MySQL نامعتبر است", "You need to enter details of an existing account." : "لازم است جزییات یک حساب موحود را وارد کنید.", "Oracle connection could not be established" : "ارتباط اراکل نمیتواند برقرار باشد.", + "Oracle Login and/or password not valid" : "نام کاربری و/یا رمز عبور Oracle نامعتبر است", + "PostgreSQL Login and/or password not valid" : "نام کاربری و/یا رمز عبور PostgreSQL نامعتبر است", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk!" : "Mac OS X پشتیبانی نمیشود و %s روی این پلتفرم به درستی کار نخواهد کرد. با مسئولیت خودتان از آن استفاده کنید!", "For the best results, please consider using a GNU/Linux server instead." : "برای بهترین نتیجه، استفاده از یک کارساز گنو/لینوکسی را در نظر داشته باشید.", - "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "به نظر می رسد%s که این نمونه در یک محیط PHP 32 بیتی در حال اجرا است و open_baseir در php.ini پیکربندی شده است. این مسئله به پرونده هایی با بیش از 4 گیگ منجر می شود و بسیار دلسرد می شود", - "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "لطفاً تنظیمات open_baseir را درون php.ini خود حذف کنید یا به PHP 64 بیتی تغییر دهید.", + "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "به نظر می رسد %s که این نمونه در یک محیط PHP 32 بیتی در حال اجرا است و open_basedir در php.ini پیکربندی شده است. این مسئله به پرونده هایی با بیش از 4 گیگ منجر می شود و بسیار دلسرد می شود.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "لطفاً تنظیمات open_basedir را درون php.ini خود حذف کنید یا به PHP 64 بیتی تغییر دهید.", + "Set an admin Login." : "یک نام کاربری برای مدیر تنظیم کنید.", "Set an admin password." : "یک رمزعبور برای مدیر تنظیم نمایید.", - "Cannot create or write into the data directory %s" : "Cannot create or write into the data directory %s", - "Sharing backend %s must implement the interface OCP\\Share_Backend" : "به اشتراک گذاشتن باطن باید رابط OCP \\ Share_Backend %sرا پیاده سازی کند", - "Sharing backend %s not found" : "به اشتراک گذاشتن باطن%s یافت نشد", - "Sharing backend for %s not found" : "به اشتراک گذاشتن باطن برای%s یافت نشد", + "Cannot create or write into the data directory %s" : "نمیتوان در دایرکتوری داده %s ایجاد یا نوشت", + "Sharing backend %s must implement the interface OCP\\Share_Backend" : "بکاند اشتراکگذاری %s باید رابط OCP\\Share_Backend را پیادهسازی کند", + "Sharing backend %s not found" : "بکاند اشتراکگذاری %s یافت نشد", + "Sharing backend for %s not found" : "بکاند اشتراکگذاری برای %s یافت نشد", + "%1$s shared %2$s with you" : "%1$s %2$s را با شما به اشتراک گذاشت", + "Open %s" : "باز کردن %s", "%1$s via %2$s" : "%1$s از طریق %2$s", + "%1$s shared %2$s with you and wants to add:" : "%1$s %2$s را با شما به اشتراک گذاشت و میخواهد اضافه کند:", + "%1$s shared %2$s with you and wants to add" : "%1$s %2$s را با شما به اشتراک گذاشت و میخواهد اضافه کند", + "%s added a note to a file shared with you" : "%s یک یادداشت به فایلی که با شما به اشتراک گذاشته شده است اضافه کرد", + "Passwords are enforced for link and mail shares" : "رمزهای عبور برای اشتراکگذاری لینک و ایمیل اجباری هستند", + "Share recipient is not a valid user" : "گیرنده اشتراک یک کاربر معتبر نیست", + "Share recipient is not a valid group" : "گیرنده اشتراک یک گروه معتبر نیست", + "Share recipient should be empty" : "گیرنده اشتراک باید خالی باشد", + "Share recipient should not be empty" : "گیرنده اشتراک نباید خالی باشد", + "Share recipient is not a valid circle" : "گیرنده اشتراک یک دایره معتبر نیست", "Unknown share type" : "نوع اشتراک ناشناخته", - "You are not allowed to share %s" : "شما مجاز به اشتراک گذاری نیستید%s", - "Cannot increase permissions of %s" : "Cannot increase permissions of %s", - "Files cannot be shared with delete permissions" : "Files cannot be shared with delete permissions", - "Files cannot be shared with create permissions" : "Files cannot be shared with create permissions", + "Share initiator must be set" : "شروعکننده اشتراک باید تنظیم شود", + "Cannot share with yourself" : "نمیتوانید با خودتان به اشتراک بگذارید", + "Shared path must be set" : "مسیر مشترک باید تنظیم شود", + "Shared path must be either a file or a folder" : "مسیر مشترک باید یک فایل یا یک پوشه باشد", + "You cannot share your root folder" : "نمیتوانید پوشه ریشه خود را به اشتراک بگذارید", + "You are not allowed to share %s" : "شما مجاز به اشتراک گذاری %s نیستید", + "Valid permissions are required for sharing" : "مجوزهای معتبر برای اشتراکگذاری لازم است", + "File shares cannot have create or delete permissions" : "اشتراکگذاری فایلها نمیتواند مجوزهای ایجاد یا حذف داشته باشد", + "Cannot increase permissions of %s" : "نمیتوان مجوزهای %s را افزایش داد", + "Shares need at least read permissions" : "اشتراکگذاریها حداقل به مجوزهای خواندن نیاز دارند", + "Files cannot be shared with delete permissions" : "فایلها را نمیتوان با مجوزهای حذف به اشتراک گذاشت", + "Files cannot be shared with create permissions" : "فایلها را نمیتوان با مجوزهای ایجاد به اشتراک گذاشت", "Expiration date is in the past" : "تاریخ انقضا در گذشته است", - "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Cannot set expiration date more than %n day in the future","Cannot set expiration date more than %n days in the future"], - "Sharing is only allowed with group members" : "Sharing is only allowed with group members", + "Expiration date is enforced" : "تاریخ انقضا اجباری است", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["نمیتوان تاریخ انقضا را بیش از %n روز در آینده تنظیم کرد","نمیتوان تاریخ انقضا را بیش از %n روز در آینده تنظیم کرد"], + "Sharing is only allowed with group members" : "اشتراکگذاری فقط با اعضای گروه مجاز است", + "Sharing %s failed, because this item is already shared with the account %s" : "اشتراکگذاری %s ناموفق بود، زیرا این مورد قبلاً با حساب %s به اشتراک گذاشته شده است", + "Group sharing is now allowed" : "اشتراکگذاری گروهی اکنون مجاز است", + "Sharing is only allowed within your own groups" : "اشتراکگذاری فقط در گروههای خودتان مجاز است", + "Path is already shared with this group" : "این مسیر قبلاً با این گروه به اشتراک گذاشته شده است", + "Link sharing is not allowed" : "اشتراکگذاری لینک مجاز نیست", + "Public upload is not allowed" : "بارگذاری عمومی مجاز نیست", + "You cannot share a folder that contains other shares" : "نمیتوانید پوشهای را به اشتراک بگذارید که حاوی اشتراکهای دیگر است", + "Sharing is disabled" : "اشتراکگذاری غیرفعال است", + "Sharing is disabled for you" : "اشتراکگذاری برای شما غیرفعال است", + "Cannot share with the share owner" : "نمیتوان با صاحب اشتراک به اشتراک گذاشت", + "Share does not have a full ID" : "اشتراک شناسه کامل ندارد", + "Cannot change share type" : "نمیتوان نوع اشتراک را تغییر داد", + "Can only update recipient on user shares" : "فقط میتوان گیرنده را در اشتراکهای کاربر بهروزرسانی کرد", + "Cannot enable sending the password by Talk with an empty password" : "نمیتوان ارسال رمز عبور از طریق Talk را با رمز عبور خالی فعال کرد", + "Cannot enable sending the password by Talk without setting a new password" : "نمیتوان ارسال رمز عبور از طریق Talk را بدون تنظیم رمز عبور جدید فعال کرد", + "Cannot disable sending the password by Talk without setting a new password" : "نمیتوان ارسال رمز عبور از طریق Talk را بدون تنظیم رمز عبور جدید غیرفعال کرد", + "Share provider does not support accepting" : "ارائهدهنده اشتراک از پذیرش پشتیبانی نمیکند", + "Cannot change target of link share" : "نمیتوان مقصد اشتراک لینک را تغییر داد", + "Invalid share recipient" : "گیرنده اشتراک نامعتبر است", + "Group \"%s\" does not exist" : "گروه «%s» وجود ندارد", "The requested share does not exist anymore" : "سهم درخواست شده دیگر وجود ندارد", - "The user was not created because the user limit has been reached. Check your notifications to learn more." : "The user was not created because the user limit has been reached. Check your notifications to learn more.", + "The requested share comes from a disabled user" : "اشتراک درخواستی از یک کاربر غیرفعال است", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "کاربر ایجاد نشد زیرا محدودیت کاربر به پایان رسیده است. برای اطلاعات بیشتر اعلانهای خود را بررسی کنید.", "Could not find category \"%s\"" : "دسته بندی %s یافت نشد", + "Input text" : "متن ورودی", + "The input text" : "متن ورودی", "Sunday" : "یکشنبه", "Monday" : "دوشنبه", "Tuesday" : "سهشنبه", @@ -181,6 +267,15 @@ "Nov." : "نو.", "Dec." : "دس.", "A valid password must be provided" : "رمز عبور صحیح باید وارد شود", + "The Login is already being used" : "نام کاربری قبلاً استفاده شده است", + "Could not create account" : "حساب کاربری ایجاد نشد", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "فقط کاراکترهای زیر در نام کاربری مجاز هستند: \"a-z\", \"A-Z\", \"0-9\", فاصله و \"_.@-'\"", + "A valid Login must be provided" : "یک نام کاربری معتبر باید ارائه شود", + "Login contains whitespace at the beginning or at the end" : "نام کاربری حاوی فاصله در ابتدا یا انتها است", + "Login must not consist of dots only" : "نام کاربری نباید فقط از نقطه تشکیل شده باشد", + "Username is too long" : "نام کاربری بیش از حد طولانی است", + "Login is invalid because files already exist for this user" : "نام کاربری نامعتبر است زیرا فایلها برای این کاربر از قبل وجود دارند", + "Account disabled" : "حساب کاربری غیرفعال است", "Login canceled by app" : "ورود به دست کاره لغو شد", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "کارهٔ «%1$s» نمیتواند نصب شود؛ چرا که وابستگی زیر تأمین نشده: %2$s", "a safe home for all your data" : "خانهای امن برای تمامی دادههایتان", @@ -188,60 +283,173 @@ "Authentication error" : "خطا در اعتبار سنجی", "Token expired. Please reload page." : "Token منقضی شده است. لطفا دوباره صفحه را بارگذاری نمایید.", "No database drivers (sqlite, mysql, or postgresql) installed." : "هیچ درایور پایگاه داده (sqlite ، mysql یا postgresql) نصب نشده است.", - "Cannot write into \"config\" directory." : "Cannot write into \"config\" directory.", - "This can usually be fixed by giving the web server write access to the config directory. See %s" : "This can usually be fixed by giving the web server write access to the config directory. See %s", - "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "یا اگر ترجیح می دهید پرونده config.php را فقط بخوانید ، گزینه \"config_is_read_only\" را در آن تنظیم کنید. دیدن%s", - "Cannot write into \"apps\" directory." : "Cannot write into \"apps\" directory.", - "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file." : "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file.", - "Cannot create \"data\" directory." : "Cannot create \"data\" directory.", - "This can usually be fixed by giving the web server write access to the root directory. See %s" : "This can usually be fixed by giving the web server write access to the root directory. See %s", - "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Permissions can usually be fixed by giving the web server write access to the root directory. See %s.", - "Your data directory is not writable." : "Your data directory is not writable.", - "Setting locale to %s failed." : "Setting locale to %s failed.", - "Please install one of these locales on your system and restart your web server." : "Please install one of these locales on your system and restart your web server.", + "Cannot write into \"config\" directory." : "نمیتوان در دایرکتوری «config» نوشت.", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "این مشکل معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری پیکربندی قابل رفع است. مشاهده %s", + "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "یا اگر ترجیح میدهید فایل config.php فقط خواندنی باشد، گزینه \"config_is_read_only\" را در آن به true تنظیم کنید. مشاهده %s", + "Cannot write into \"apps\" directory." : "نمیتوان در دایرکتوری «apps» نوشت.", + "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file." : "این مشکل معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری برنامهها یا غیرفعال کردن فروشگاه برنامه در فایل پیکربندی قابل رفع است.", + "Cannot create \"data\" directory." : "نمیتوان دایرکتوری «data» را ایجاد کرد.", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "این مشکل معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری ریشه قابل رفع است. مشاهده %s", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "مجوزها معمولاً با دادن دسترسی نوشتن به وبسرور در دایرکتوری ریشه قابل رفع هستند. مشاهده %s.", + "Your data directory is not writable." : "دایرکتوری داده شما قابل نوشتن نیست.", + "Setting locale to %s failed." : "تنظیم محلی به %s ناموفق بود.", + "Please install one of these locales on your system and restart your web server." : "لطفاً یکی از این محلیها را روی سیستم خود نصب کرده و وبسرور خود را مجدداً راهاندازی کنید.", "PHP module %s not installed." : "ماژول PHP %s نصب نشده است.", "Please ask your server administrator to install the module." : "لطفا از مدیر سیستم بخواهید تا ماژول را نصب کند.", - "PHP setting \"%s\" is not set to \"%s\"." : "تنظیمات PHP%s تنظیم نشده است%s", + "PHP setting \"%s\" is not set to \"%s\"." : "تنظیمات PHP «%s» روی «%s» تنظیم نشده است.", "Adjusting this setting in php.ini will make Nextcloud run again" : "تنظیم این تنظیمات در php.ini باعث می شود Nextcloud دوباره اجرا شود", - "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>.", - "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.", - "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP ظاهراً برای خنثی کردن بلوک های اسناد درون خطی تنظیم شده است. این کار چندین برنامه اصلی را غیرقابل دسترسی خواهد کرد.", - "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "این احتمالاً توسط حافظه پنهان / کش مانند Zend OPcache یا eAccelerator ایجاد شده است.", - "PHP modules have been installed, but they are still listed as missing?" : "ماژول های پی اچ پی نصب شده اند ، اما هنوز هم به عنوان مفقود شده ذکر شده اند؟", - "Please ask your server administrator to restart the web server." : "لطفاً از سرور سرور خود بخواهید که وب سرور را مجدداً راه اندازی کند.", - "The required %s config variable is not configured in the config.php file." : "The required %s config variable is not configured in the config.php file.", - "Please ask your server administrator to check the Nextcloud configuration." : "Please ask your server administrator to check the Nextcloud configuration.", - "Your data directory must be an absolute path." : "Your data directory must be an absolute path.", - "Check the value of \"datadirectory\" in your configuration." : "Check the value of \"datadirectory\" in your configuration.", - "Your data directory is invalid." : "Your data directory is invalid.", - "Action \"%s\" not supported or implemented." : "عملی%s پشتیبانی یا اجرا نشده است.", - "Authentication failed, wrong token or provider ID given" : "تأیید اعتبار انجام نشد ، نشانه اشتباه یا شناسه ارائه دهنده داده شد", - "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "پارامترهای موجود برای تکمیل درخواست. پارامترهای موجود نیست%s", - "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "شناسه%1$s قبلاً توسط ارائه دهنده فدراسیون ابر استفاده شده است%2$s", - "Cloud Federation Provider with ID: \"%s\" does not exist." : "ارائه دهنده فدراسیون Cloud با شناسه:%s وجود ندارد.", - "Could not obtain lock type %d on \"%s\"." : "نمی توان نوع%d قفل را به دست آورد%s", - "Storage unauthorized. %s" : "ذخیره سازی غیر مجاز.%s", - "Storage incomplete configuration. %s" : "پیکربندی ناقص ذخیره سازی.%s<br>", - "Storage connection error. %s" : "خطای اتصال ذخیره سازی%s", - "Storage is temporarily not available" : "ذخیره سازی به طور موقت در دسترس نیست", - "Storage connection timeout. %s" : "مدت زمان اتصال ذخیره سازی%s", - "Confirmation" : "Confirmation", - "Prompt" : "Prompt", - "Chat" : "Chat", - "Generates a possible headline for a text." : "Generates a possible headline for a text.", + "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> به جای مقدار مورد انتظار <code>0</code> روی <code>%s</code> تنظیم شده است.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "برای رفع این مشکل، <code>mbstring.func_overload</code> را در php.ini خود روی <code>0</code> تنظیم کنید.", + "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP ظاهراً برای حذف بلوکهای مستندات درونخطی تنظیم شده است. این کار چندین برنامه اصلی را غیرقابل دسترس خواهد کرد.", + "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "این احتمالاً توسط حافظه پنهان/شتابدهندهای مانند Zend OPcache یا eAccelerator ایجاد شده است.", + "PHP modules have been installed, but they are still listed as missing?" : "ماژولهای PHP نصب شدهاند، اما همچنان به عنوان گمشده لیست شدهاند؟", + "Please ask your server administrator to restart the web server." : "لطفاً از مدیر سرور خود بخواهید که وبسرور را مجدداً راهاندازی کند.", + "The required %s config variable is not configured in the config.php file." : "متغیر پیکربندی مورد نیاز %s در فایل config.php پیکربندی نشده است.", + "Please ask your server administrator to check the Nextcloud configuration." : "لطفاً از مدیر سرور خود بخواهید پیکربندی Nextcloud را بررسی کند.", + "Your data directory is readable by other people." : "دایرکتوری داده شما برای دیگران قابل خواندن است.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "لطفاً مجوزها را به 0770 تغییر دهید تا دایرکتوری توسط افراد دیگر قابل فهرست شدن نباشد.", + "Your data directory must be an absolute path." : "دایرکتوری داده شما باید یک مسیر مطلق باشد.", + "Check the value of \"datadirectory\" in your configuration." : "مقدار \"datadirectory\" را در پیکربندی خود بررسی کنید.", + "Your data directory is invalid." : "دایرکتوری داده شما نامعتبر است.", + "Ensure there is a file called \"%1$s\" in the root of the data directory. It should have the content: \"%2$s\"" : "اطمینان حاصل کنید که فایلی به نام «%1$s» در ریشه دایرکتوری داده وجود دارد. این فایل باید حاوی: «%2$s» باشد", + "Action \"%s\" not supported or implemented." : "عملیات «%s» پشتیبانی یا اجرا نشده است.", + "Authentication failed, wrong token or provider ID given" : "تأیید اعتبار انجام نشد، نشانه اشتباه یا شناسه ارائه دهنده داده شد", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "پارامترهای مورد نیاز برای تکمیل درخواست وجود ندارند. پارامترهای از دست رفته: «%s»", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "شناسه «%1$s» قبلاً توسط ارائهدهنده فدراسیون ابری «%2$s» استفاده شده است", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "ارائهدهنده فدراسیون ابری با شناسه: «%s» وجود ندارد.", + "Could not obtain lock type %d on \"%s\"." : "نمیتوان قفل از نوع %d را روی «%s» به دست آورد.", + "Storage unauthorized. %s" : "دسترسی به حافظه غیرمجاز است. %s", + "Storage incomplete configuration. %s" : "پیکربندی حافظه ناقص است. %s", + "Storage connection error. %s" : "خطای اتصال حافظه. %s", + "Storage is temporarily not available" : "حافظه به طور موقت در دسترس نیست", + "Storage connection timeout. %s" : "مهلت اتصال حافظه به پایان رسید. %s", + "To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule." : "برای اجرای این بررسی، باید مطمئن شوید که وبسرور شما میتواند به خودش متصل شود. بنابراین باید بتواند حداقل یکی از `trusted_domains` یا `overwrite.cli.url` خود را حل و به آن متصل شود. این خطا ممکن است نتیجه عدم تطابق DNS سمت سرور یا قانون فایروال خروجی باشد.", + "Transcribe audio" : "رونوشت صوتی", + "Transcribe the things said in an audio" : "رونوشت چیزهای گفته شده در یک فایل صوتی", + "Audio input" : "ورودی صوتی", + "The audio to transcribe" : "فایل صوتی برای رونوشت", + "Transcription" : "رونوشت", + "The transcribed text" : "متن رونوشت شده", + "Chat with an agent" : "چت با یک عامل", + "Chat message" : "پیام چت", + "A chat message to send to the agent." : "یک پیام چت برای ارسال به عامل.", + "Confirmation" : "تأیید", + "Whether to confirm previously requested actions: 0 for denial and 1 for confirmation." : "آیا اقدامات قبلاً درخواست شده را تأیید کنید: 0 برای رد و 1 برای تأیید.", + "Conversation token" : "توکن مکالمه", + "A token representing the conversation." : "یک توکن نماینده مکالمه.", + "Generated response" : "پاسخ تولید شده", + "The response from the chat model." : "پاسخ از مدل چت.", + "The new conversation token" : "توکن مکالمه جدید", + "Send this along with the next interaction." : "این را همراه با تعامل بعدی ارسال کنید.", + "Requested actions by the agent" : "اقدامات درخواستی توسط عامل", + "Actions that the agent would like to carry out in JSON format." : "اقدامات که عامل مایل به انجام آنها در قالب JSON است.", + "Context write" : "نوشتن متنی", + "Writes text in a given style based on the provided source material." : "متن را با سبکی مشخص بر اساس محتوای منبع ارائه شده مینویسد.", + "Writing style" : "سبک نگارش", + "Demonstrate a writing style that you would like to immitate" : "یک سبک نگارش را که میخواهید تقلید کنید، نشان دهید", + "Source material" : "محتوای منبع", + "The content that would like to be rewritten in the new writing style" : "محتوایی که میخواهید با سبک نگارش جدید بازنویسی شود", + "Generated text" : "متن تولید شده", + "The generated text with content from the source material in the given style" : "متن تولید شده با محتوای منبع در سبک مشخص شده", + "Emoji generator" : "تولیدکننده اموجی", + "Takes text and generates a representative emoji for it." : "متن را دریافت کرده و یک اموجی مناسب برای آن تولید میکند.", + "The text to generate an emoji for" : "متنی که میخواهید برای آن اموجی تولید شود", + "Generated emoji" : "اموجی تولید شده", + "The generated emoji based on the input text" : "اموجی تولید شده بر اساس متن ورودی", + "Generate image" : "تولید تصویر", + "Generate an image from a text prompt" : "تولید تصویر از یک متن ورودی", + "Prompt" : "درخواست", + "Describe the image you want to generate" : "تصویری که میخواهید تولید شود را توصیف کنید", + "Number of images" : "تعداد تصاویر", + "How many images to generate" : "چه تعداد تصویر تولید شود", + "Output images" : "تصاویر خروجی", + "The generated images" : "تصاویر تولید شده", + "Generate speech" : "تولید گفتار", + "Generate speech from a transcript" : "تولید گفتار از یک رونوشت", + "Write transcript that you want the assistant to generate speech from" : "رونوشتی را بنویسید که میخواهید دستیار از آن گفتار تولید کند", + "Output speech" : "گفتار خروجی", + "The generated speech" : "گفتار تولید شده", + "Free text to text prompt" : "درخواست متن به متن آزاد", + "Runs an arbitrary prompt through a language model that returns a reply" : "یک درخواست دلخواه را از طریق یک مدل زبانی اجرا میکند که پاسخی را برمیگرداند", + "Describe a task that you want the assistant to do or ask a question" : "وظیفهای که میخواهید دستیار انجام دهد را توصیف کنید یا سؤالی بپرسید", + "Generated reply" : "پاسخ تولید شده", + "The generated text from the assistant" : "متن تولید شده توسط دستیار", + "Change Tone" : "تغییر لحن", + "Change the tone of a piece of text." : "لحن یک قطعه متن را تغییر دهید.", + "Write a text that you want the assistant to rewrite in another tone." : "متنی را بنویسید که میخواهید دستیار آن را با لحن دیگری بازنویسی کند.", + "Desired tone" : "لحن مورد نظر", + "In which tone should your text be rewritten?" : "متن شما با چه لحنی بازنویسی شود؟", + "The rewritten text in the desired tone, written by the assistant:" : "متن بازنویسی شده با لحن مورد نظر، نوشته شده توسط دستیار:", + "Chat" : "چت", + "Chat with the assistant" : "چت با دستیار", + "System prompt" : "درخواست سیستمی", + "Define rules and assumptions that the assistant should follow during the conversation." : "قوانین و فرضیاتی را که دستیار باید در طول مکالمه رعایت کند، تعریف کنید.", + "Chat history" : "تاریخچه چت", + "The history of chat messages before the current message, starting with a message by the user" : "تاریخچه پیامهای چت قبل از پیام فعلی، با شروع از یک پیام توسط کاربر", + "Response message" : "پیام پاسخ", + "The generated response as part of the conversation" : "پاسخ تولید شده به عنوان بخشی از مکالمه", + "Chat with tools" : "چت با ابزارها", + "Chat with the language model with tool calling support." : "چت با مدل زبانی با پشتیبانی از فراخوانی ابزار.", + "Tool message" : "پیام ابزار", + "The result of tool calls in the last interaction" : "نتیجه فراخوانی ابزارها در تعامل قبلی", + "Available tools" : "ابزارهای موجود", + "The available tools in JSON format" : "ابزارهای موجود در قالب JSON", + "The response from the chat model" : "پاسخ از مدل چت", + "Tool calls" : "فراخوانی ابزار", + "Tools call instructions from the model in JSON format" : "دستورالعملهای فراخوانی ابزار از مدل در قالب JSON", + "Formalize text" : "رسمی کردن متن", + "Takes a text and makes it sound more formal" : "یک متن را دریافت کرده و آن را رسمیتر میکند", + "Write a text that you want the assistant to formalize" : "متنی را بنویسید که میخواهید دستیار آن را رسمی کند", + "Formalized text" : "متن رسمی شده", + "The formalized text" : "متن رسمی شده", + "Generate a headline" : "تولید یک عنوان", + "Generates a possible headline for a text." : "یک عنوان احتمالی برای یک متن تولید میکند.", + "Original text" : "متن اصلی", + "The original text to generate a headline for" : "متن اصلی برای تولید عنوان", + "The generated headline" : "عنوان تولید شده", + "Proofread" : "ویرایش", + "Proofreads a text and lists corrections" : "یک متن را ویرایش کرده و اصلاحات را لیست میکند", "Text" : "متن", - "Summarize" : "Summarize", + "The text to proofread" : "متن برای ویرایش", + "Corrections" : "اصلاحات", + "The corrections that should be made in your text" : "اصلاحاتی که باید در متن شما انجام شود", + "Reformulate text" : "بازنویسی متن", + "Takes a text and reformulates it" : "یک متن را دریافت کرده و آن را بازنویسی میکند", + "Write a text that you want the assistant to reformulate" : "متنی را بنویسید که میخواهید دستیار آن را بازنویسی کند", + "Reformulated text" : "متن بازنویسی شده", + "The reformulated text, written by the assistant" : "متن بازنویسی شده، نوشته شده توسط دستیار", + "Simplify text" : "سادهسازی متن", + "Takes a text and simplifies it" : "یک متن را دریافت کرده و آن را ساده میکند", + "Write a text that you want the assistant to simplify" : "متنی را بنویسید که میخواهید دستیار آن را ساده کند", + "Simplified text" : "متن ساده شده", + "The simplified text" : "متن ساده شده", + "Summarize" : "خلاصهسازی", + "Summarizes a text" : "یک متن را خلاصهسازی میکند", + "The original text to summarize" : "متن اصلی برای خلاصهسازی", "Summary" : "چکیده", - "Extract topics" : "Extract topics", + "The generated summary" : "خلاصه تولید شده", + "Extract topics" : "استخراج موضوعات", + "Extracts topics from a text and outputs them separated by commas" : "موضوعات را از یک متن استخراج کرده و با کاما جدا شده خروجی میدهد", + "The original text to extract topics from" : "متن اصلی برای استخراج موضوعات", + "Topics" : "موضوعات", + "The list of extracted topics" : "لیست موضوعات استخراج شده", "Translate" : "ترجمه", - "Target language" : "Target language", - "Result" : "شروع به اسکنیک", - "Free prompt" : "Free prompt", - "Runs an arbitrary prompt through the language model." : "Runs an arbitrary prompt through the language model.", - "Generate headline" : "Generate headline", - "Summarizes text by reducing its length without losing key information." : "Summarizes text by reducing its length without losing key information.", - "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", + "Translate text from one language to another" : "ترجمه متن از یک زبان به زبان دیگر", + "Origin text" : "متن مبدأ", + "The text to translate" : "متن برای ترجمه", + "Origin language" : "زبان مبدأ", + "The language of the origin text" : "زبان متن مبدأ", + "Target language" : "زبان مقصد", + "The desired language to translate the origin text in" : "زبان مورد نظر برای ترجمه متن مبدأ", + "Result" : "نتیجه", + "The translated text" : "متن ترجمه شده", + "Free prompt" : "درخواست آزاد", + "Runs an arbitrary prompt through the language model." : "یک درخواست دلخواه را از طریق مدل زبانی اجرا میکند.", + "Generate headline" : "تولید عنوان", + "Summarizes text by reducing its length without losing key information." : "متن را با کاهش طول آن و بدون از دست دادن اطلاعات کلیدی، خلاصهسازی میکند.", + "Extracts topics from a text and outputs them separated by commas." : "موضوعات را از یک متن استخراج کرده و با کاما جدا شده خروجی میدهد.", "File is currently busy, please try again later" : "فایل در حال حاضر مشغول است، لطفا مجددا تلاش کنید", - "Cannot download file" : "نمیتوان پرونده را بارگرفت" + "Cannot download file" : "نمیتوان پرونده را بارگرفت", + "Login is too long" : "نام کاربری بیش از حد طولانی است" },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/lib/l10n/fi.js b/lib/l10n/fi.js index 593c9c3465d..fdabc59a9e1 100644 --- a/lib/l10n/fi.js +++ b/lib/l10n/fi.js @@ -67,6 +67,7 @@ OC.L10N.register( "seconds ago" : "sekunteja sitten", "Empty file" : "Tyhjä tiedosto", "Dot files are not allowed" : "Pistetiedostot eivät ole sallittuja", + "%1$s (renamed)" : "%1$s (nimetty uudelleen)", "File already exists" : "Tiedosto on jo olemassa", "Invalid path" : "Virheellinen polku", "Failed to create file from template" : "Tiedoston luominen mallipohjasta epäonnistui", diff --git a/lib/l10n/fi.json b/lib/l10n/fi.json index e938dc41405..a2b35c13827 100644 --- a/lib/l10n/fi.json +++ b/lib/l10n/fi.json @@ -65,6 +65,7 @@ "seconds ago" : "sekunteja sitten", "Empty file" : "Tyhjä tiedosto", "Dot files are not allowed" : "Pistetiedostot eivät ole sallittuja", + "%1$s (renamed)" : "%1$s (nimetty uudelleen)", "File already exists" : "Tiedosto on jo olemassa", "Invalid path" : "Virheellinen polku", "Failed to create file from template" : "Tiedoston luominen mallipohjasta epäonnistui", diff --git a/lib/l10n/fr.js b/lib/l10n/fr.js index 4c531b76411..bcdeeeabd83 100644 --- a/lib/l10n/fr.js +++ b/lib/l10n/fr.js @@ -203,6 +203,7 @@ OC.L10N.register( "Path is already shared with this group" : "Le chemin est déjà partagé avec ce groupe", "Link sharing is not allowed" : "Le partage de liens n'est pas autorisé", "Public upload is not allowed" : "Le téléversement public n'est pas autorisé", + "You cannot share a folder that contains other shares" : "Vous ne pouvez pas partager un dossier qui contient déjà d'autres partages.", "Sharing is disabled" : "Le partage est désactivé", "Sharing is disabled for you" : "Le partage est désactivé pour vous", "Cannot share with the share owner" : "Impossible de partager avec le propriétaire de l'action", @@ -274,6 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Un identifiant valide doit être saisi", "Login contains whitespace at the beginning or at the end" : "L'identifiant contient des espaces au début ou à la fin", "Login must not consist of dots only" : "L'identifiant ne doit pas être composé uniquement de points", + "Username is too long" : "Le nom d'utilisateur est trop long", "Login is invalid because files already exist for this user" : "L’identifiant n'est pas valide car des fichiers existent déjà pour cet utilisateur", "Account disabled" : "Compte désactivé", "Login canceled by app" : "L'authentification a été annulée par l'application", @@ -364,6 +366,11 @@ OC.L10N.register( "How many images to generate" : "Nombre d'images à générer", "Output images" : "Images de sortie", "The generated images" : "Les images générées", + "Generate speech" : "Générer la vocalisation", + "Generate speech from a transcript" : "Générer la vocalisation à partir d'une transcription", + "Write transcript that you want the assistant to generate speech from" : "Écrire la transcription à partir de laquelle vous voulez générer la vocalisation", + "Output speech" : "Sortie de la vocalisation", + "The generated speech" : "La vocalisation générée", "Free text to text prompt" : "Texte libre à texte libre", "Runs an arbitrary prompt through a language model that returns a reply" : "Exécute une commande arbitraire à l'aide d'un modèle linguistique qui génère une réponse", "Describe a task that you want the assistant to do or ask a question" : "Décrivez une tâche que vous voulez que l'assistant effectue ou posez une question", @@ -444,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Résume un texte en réduisant sa longueur sans perdre d’informations essentielles.", "Extracts topics from a text and outputs them separated by commas." : "Extrait les thèmes d'un texte et les restitue séparés par des virgules.", "File is currently busy, please try again later" : "Le fichier est actuellement utilisé, veuillez réessayer plus tard", - "Cannot download file" : "Impossible de télécharger le fichier" + "Cannot download file" : "Impossible de télécharger le fichier", + "Login is too long" : "L'authentification est trop longue" }, "nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/fr.json b/lib/l10n/fr.json index b7fb111568a..e6d19d589f0 100644 --- a/lib/l10n/fr.json +++ b/lib/l10n/fr.json @@ -201,6 +201,7 @@ "Path is already shared with this group" : "Le chemin est déjà partagé avec ce groupe", "Link sharing is not allowed" : "Le partage de liens n'est pas autorisé", "Public upload is not allowed" : "Le téléversement public n'est pas autorisé", + "You cannot share a folder that contains other shares" : "Vous ne pouvez pas partager un dossier qui contient déjà d'autres partages.", "Sharing is disabled" : "Le partage est désactivé", "Sharing is disabled for you" : "Le partage est désactivé pour vous", "Cannot share with the share owner" : "Impossible de partager avec le propriétaire de l'action", @@ -272,6 +273,7 @@ "A valid Login must be provided" : "Un identifiant valide doit être saisi", "Login contains whitespace at the beginning or at the end" : "L'identifiant contient des espaces au début ou à la fin", "Login must not consist of dots only" : "L'identifiant ne doit pas être composé uniquement de points", + "Username is too long" : "Le nom d'utilisateur est trop long", "Login is invalid because files already exist for this user" : "L’identifiant n'est pas valide car des fichiers existent déjà pour cet utilisateur", "Account disabled" : "Compte désactivé", "Login canceled by app" : "L'authentification a été annulée par l'application", @@ -362,6 +364,11 @@ "How many images to generate" : "Nombre d'images à générer", "Output images" : "Images de sortie", "The generated images" : "Les images générées", + "Generate speech" : "Générer la vocalisation", + "Generate speech from a transcript" : "Générer la vocalisation à partir d'une transcription", + "Write transcript that you want the assistant to generate speech from" : "Écrire la transcription à partir de laquelle vous voulez générer la vocalisation", + "Output speech" : "Sortie de la vocalisation", + "The generated speech" : "La vocalisation générée", "Free text to text prompt" : "Texte libre à texte libre", "Runs an arbitrary prompt through a language model that returns a reply" : "Exécute une commande arbitraire à l'aide d'un modèle linguistique qui génère une réponse", "Describe a task that you want the assistant to do or ask a question" : "Décrivez une tâche que vous voulez que l'assistant effectue ou posez une question", @@ -442,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Résume un texte en réduisant sa longueur sans perdre d’informations essentielles.", "Extracts topics from a text and outputs them separated by commas." : "Extrait les thèmes d'un texte et les restitue séparés par des virgules.", "File is currently busy, please try again later" : "Le fichier est actuellement utilisé, veuillez réessayer plus tard", - "Cannot download file" : "Impossible de télécharger le fichier" + "Cannot download file" : "Impossible de télécharger le fichier", + "Login is too long" : "L'authentification est trop longue" },"pluralForm" :"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" }
\ No newline at end of file diff --git a/lib/l10n/ga.js b/lib/l10n/ga.js index 42607da43bc..481a89b9f06 100644 --- a/lib/l10n/ga.js +++ b/lib/l10n/ga.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Ní mór Logáil Isteach bailí a sholáthar", "Login contains whitespace at the beginning or at the end" : "Tá spás bán sa logáil isteach ag an tús nó ag an deireadh", "Login must not consist of dots only" : "Níor cheart go gcuimseodh logáil isteach poncanna amháin", - "Login is too long" : "Tá logáil isteach ró-fhada", + "Username is too long" : "Tá an t-ainm úsáideora rófhada", "Login is invalid because files already exist for this user" : "Tá logáil isteach neamhbhailí toisc go bhfuil comhaid ann cheana don úsáideoir seo", "Account disabled" : "Díchumasaíodh an cuntas", "Login canceled by app" : "Cealaíodh logáil isteach ag an aip", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Déanann sé achoimre ar théacs trína fhad a laghdú gan eochairfhaisnéis a chailliúint.", "Extracts topics from a text and outputs them separated by commas." : "Sliocht topaicí as téacs agus aschuir iad scartha le camóga.", "File is currently busy, please try again later" : "Tá an comhad gnóthach faoi láthair, bain triail eile as ar ball le do thoil", - "Cannot download file" : "Ní féidir an comhad a íoslódáil" + "Cannot download file" : "Ní féidir an comhad a íoslódáil", + "Login is too long" : "Tá logáil isteach ró-fhada" }, "nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);"); diff --git a/lib/l10n/ga.json b/lib/l10n/ga.json index e1367c8b5bd..669754526c2 100644 --- a/lib/l10n/ga.json +++ b/lib/l10n/ga.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "Ní mór Logáil Isteach bailí a sholáthar", "Login contains whitespace at the beginning or at the end" : "Tá spás bán sa logáil isteach ag an tús nó ag an deireadh", "Login must not consist of dots only" : "Níor cheart go gcuimseodh logáil isteach poncanna amháin", - "Login is too long" : "Tá logáil isteach ró-fhada", + "Username is too long" : "Tá an t-ainm úsáideora rófhada", "Login is invalid because files already exist for this user" : "Tá logáil isteach neamhbhailí toisc go bhfuil comhaid ann cheana don úsáideoir seo", "Account disabled" : "Díchumasaíodh an cuntas", "Login canceled by app" : "Cealaíodh logáil isteach ag an aip", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Déanann sé achoimre ar théacs trína fhad a laghdú gan eochairfhaisnéis a chailliúint.", "Extracts topics from a text and outputs them separated by commas." : "Sliocht topaicí as téacs agus aschuir iad scartha le camóga.", "File is currently busy, please try again later" : "Tá an comhad gnóthach faoi láthair, bain triail eile as ar ball le do thoil", - "Cannot download file" : "Ní féidir an comhad a íoslódáil" + "Cannot download file" : "Ní féidir an comhad a íoslódáil", + "Login is too long" : "Tá logáil isteach ró-fhada" },"pluralForm" :"nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);" }
\ No newline at end of file diff --git a/lib/l10n/gl.js b/lib/l10n/gl.js index b38c1963b4e..adcd145ae66 100644 --- a/lib/l10n/gl.js +++ b/lib/l10n/gl.js @@ -112,7 +112,7 @@ OC.L10N.register( "Moving a storage (%s) into another storage (%s) is not allowed" : "Non está permitido mover un almacenamento (%s) cara a outro almacenamento (%s)", "Path contains invalid segments" : "A ruta contén segmentos non válidos", "Filename is a reserved word" : "O nome de ficheiro é unha palabra reservada", - "Filename contains at least one invalid character" : "O nome de ficheiro contén algún carácter incorrecto", + "Filename contains at least one invalid character" : "O nome de ficheiro contén algún carácter non aceptado", "Filename is too long" : "O nome de ficheiro é longo de máis", "Empty filename is not allowed" : "Non está permitido deixar baleiro o nome de ficheiro", "App \"%s\" cannot be installed because appinfo file cannot be read." : "Non é posíbel instalar a aplicación «%s» por mor de non poder ler o ficheiro appinfo.", diff --git a/lib/l10n/gl.json b/lib/l10n/gl.json index 9c8d0e65999..ea8fc00b36c 100644 --- a/lib/l10n/gl.json +++ b/lib/l10n/gl.json @@ -110,7 +110,7 @@ "Moving a storage (%s) into another storage (%s) is not allowed" : "Non está permitido mover un almacenamento (%s) cara a outro almacenamento (%s)", "Path contains invalid segments" : "A ruta contén segmentos non válidos", "Filename is a reserved word" : "O nome de ficheiro é unha palabra reservada", - "Filename contains at least one invalid character" : "O nome de ficheiro contén algún carácter incorrecto", + "Filename contains at least one invalid character" : "O nome de ficheiro contén algún carácter non aceptado", "Filename is too long" : "O nome de ficheiro é longo de máis", "Empty filename is not allowed" : "Non está permitido deixar baleiro o nome de ficheiro", "App \"%s\" cannot be installed because appinfo file cannot be read." : "Non é posíbel instalar a aplicación «%s» por mor de non poder ler o ficheiro appinfo.", diff --git a/lib/l10n/hu.js b/lib/l10n/hu.js index a4d342fb56f..21d0f6b986f 100644 --- a/lib/l10n/hu.js +++ b/lib/l10n/hu.js @@ -77,6 +77,8 @@ OC.L10N.register( "Empty file" : "Üres fájl", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "A(z) %s azonosítójú modul nem létezik. Engedélyezze az alkalmazásbeállításokban, vagy lépjen kapcsolatba a rendszergazdával.", "Dot files are not allowed" : "A ponttal kezdődő fájlok nem engedélyezettek", + "%1$s (renamed)" : "%1$s (átnevezve)", + "renamed file" : "átnevezett fájl", "Filenames must not end with \"%1$s\"." : "Fájlnév nem végződhet így: „%1$s”.", "File already exists" : "A fájl már létezik", "Invalid path" : "Érvénytelen útvonal", diff --git a/lib/l10n/hu.json b/lib/l10n/hu.json index 54c0297d8e9..e40d8174716 100644 --- a/lib/l10n/hu.json +++ b/lib/l10n/hu.json @@ -75,6 +75,8 @@ "Empty file" : "Üres fájl", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "A(z) %s azonosítójú modul nem létezik. Engedélyezze az alkalmazásbeállításokban, vagy lépjen kapcsolatba a rendszergazdával.", "Dot files are not allowed" : "A ponttal kezdődő fájlok nem engedélyezettek", + "%1$s (renamed)" : "%1$s (átnevezve)", + "renamed file" : "átnevezett fájl", "Filenames must not end with \"%1$s\"." : "Fájlnév nem végződhet így: „%1$s”.", "File already exists" : "A fájl már létezik", "Invalid path" : "Érvénytelen útvonal", diff --git a/lib/l10n/ja.js b/lib/l10n/ja.js index 56a3f7327fc..72a4b6f133b 100644 --- a/lib/l10n/ja.js +++ b/lib/l10n/ja.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "ログイン名を提供する必要があります", "Login contains whitespace at the beginning or at the end" : "ログイン名の最初か最後に空白が含まれています", "Login must not consist of dots only" : "ログイン名はドットのみで構成されてはいけません", - "Login is too long" : "ログインが長すぎます", + "Username is too long" : "ユーザー名が長すぎます", "Login is invalid because files already exist for this user" : "このユーザのファイルが既に存在するため、このログイン名は使用できません", "Account disabled" : "アカウントは無効", "Login canceled by app" : "アプリによりログインが中止されました", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "重要な情報を失わずにテキストの長さを要約して短縮する。", "Extracts topics from a text and outputs them separated by commas." : "テキストからトピックを抽出し、カンマ区切りで出力します。", "File is currently busy, please try again later" : "現在ファイルはビジーです。後でもう一度試してください。", - "Cannot download file" : "ファイルをダウンロードできません" + "Cannot download file" : "ファイルをダウンロードできません", + "Login is too long" : "ログインが長すぎます" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/ja.json b/lib/l10n/ja.json index ea04d3f522b..5a6af204f01 100644 --- a/lib/l10n/ja.json +++ b/lib/l10n/ja.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "ログイン名を提供する必要があります", "Login contains whitespace at the beginning or at the end" : "ログイン名の最初か最後に空白が含まれています", "Login must not consist of dots only" : "ログイン名はドットのみで構成されてはいけません", - "Login is too long" : "ログインが長すぎます", + "Username is too long" : "ユーザー名が長すぎます", "Login is invalid because files already exist for this user" : "このユーザのファイルが既に存在するため、このログイン名は使用できません", "Account disabled" : "アカウントは無効", "Login canceled by app" : "アプリによりログインが中止されました", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "重要な情報を失わずにテキストの長さを要約して短縮する。", "Extracts topics from a text and outputs them separated by commas." : "テキストからトピックを抽出し、カンマ区切りで出力します。", "File is currently busy, please try again later" : "現在ファイルはビジーです。後でもう一度試してください。", - "Cannot download file" : "ファイルをダウンロードできません" + "Cannot download file" : "ファイルをダウンロードできません", + "Login is too long" : "ログインが長すぎます" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/ko.js b/lib/l10n/ko.js index 2ae40fc9454..41178d953f3 100644 --- a/lib/l10n/ko.js +++ b/lib/l10n/ko.js @@ -140,6 +140,7 @@ OC.L10N.register( "The requested share comes from a disabled user" : "요청한 공유가 비활성화된 사용자로부터 수신되었습니다", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "사용자 수 제한에 도달하여 사용자를 만들 수 없습니다. 더 자세한 정보는 알림을 참조하십시오.", "Could not find category \"%s\"" : "분류 \"%s\"을(를) 찾을 수 없습니다", + "Input text" : "텍스트를 입력", "Sunday" : "일요일", "Monday" : "월요일", "Tuesday" : "화요일", @@ -234,12 +235,18 @@ OC.L10N.register( "Storage connection timeout. %s" : "저장소 연결 시간이 초과되었습니다. %s", "Audio input" : "음성 입력", "Confirmation" : "확인", + "Generated response" : "생성된 응답", "Context write" : "컨텍스트 쓰기", "Writes text in a given style based on the provided source material." : "제공된 소스 자료를 기반으로 특정 스타일로 텍스트를 작성합니다.", "Writing style" : "작문 스타일", "Source material" : "소스 자료", "Generate image" : "이미지 생성", "Prompt" : "프롬프트", + "Change Tone" : "톤을 변경", + "Write a text that you want the assistant to rewrite in another tone." : "어시스턴트에 다른 톤으로 다시 쓰고 싶은 텍스트를 쓰기", + "Desired tone" : "희망하는 톤", + "In which tone should your text be rewritten?" : "텍스트를 어떤 어조로 다시 씁니까?", + "The rewritten text in the desired tone, written by the assistant:" : "원하는 톤으로 어시스턴트에 의해서 다시 쓴 텍스트:", "Chat" : "대화", "Generates a possible headline for a text." : "내용에 대한 헤드라인을 생성하십시오.", "Text" : "텍스트", diff --git a/lib/l10n/ko.json b/lib/l10n/ko.json index 2c2001dcc04..409bc07408d 100644 --- a/lib/l10n/ko.json +++ b/lib/l10n/ko.json @@ -138,6 +138,7 @@ "The requested share comes from a disabled user" : "요청한 공유가 비활성화된 사용자로부터 수신되었습니다", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "사용자 수 제한에 도달하여 사용자를 만들 수 없습니다. 더 자세한 정보는 알림을 참조하십시오.", "Could not find category \"%s\"" : "분류 \"%s\"을(를) 찾을 수 없습니다", + "Input text" : "텍스트를 입력", "Sunday" : "일요일", "Monday" : "월요일", "Tuesday" : "화요일", @@ -232,12 +233,18 @@ "Storage connection timeout. %s" : "저장소 연결 시간이 초과되었습니다. %s", "Audio input" : "음성 입력", "Confirmation" : "확인", + "Generated response" : "생성된 응답", "Context write" : "컨텍스트 쓰기", "Writes text in a given style based on the provided source material." : "제공된 소스 자료를 기반으로 특정 스타일로 텍스트를 작성합니다.", "Writing style" : "작문 스타일", "Source material" : "소스 자료", "Generate image" : "이미지 생성", "Prompt" : "프롬프트", + "Change Tone" : "톤을 변경", + "Write a text that you want the assistant to rewrite in another tone." : "어시스턴트에 다른 톤으로 다시 쓰고 싶은 텍스트를 쓰기", + "Desired tone" : "희망하는 톤", + "In which tone should your text be rewritten?" : "텍스트를 어떤 어조로 다시 씁니까?", + "The rewritten text in the desired tone, written by the assistant:" : "원하는 톤으로 어시스턴트에 의해서 다시 쓴 텍스트:", "Chat" : "대화", "Generates a possible headline for a text." : "내용에 대한 헤드라인을 생성하십시오.", "Text" : "텍스트", diff --git a/lib/l10n/lv.js b/lib/l10n/lv.js index f0ffc6f3235..d70b713b15f 100644 --- a/lib/l10n/lv.js +++ b/lib/l10n/lv.js @@ -5,7 +5,7 @@ OC.L10N.register( "See %s" : "Skatīt %s", "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Lietotne %1$s nav pieejama vai tai ir ar šo serveri nesaderīga versija. Lūgums pārbaudīt lietotņu mapi.", "Sample configuration detected" : "Atrasta konfigurācijas paraugs", - "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Konstatēts, ka paraug konfigurācija ir nokopēta. Tas var izjaukt jūsu instalāciju un nav atbalstīts. Lūdzu, izlasiet dokumentāciju, pirms veicat izmaiņas config.php", + "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Tika noteikts, ka tika kopēta paraugkonfigurācija. Tas var salauzt uzstādīto un netiek atbalstīts. Lūgums pirms izmaiņu veikšanas config.php izlasīt dokumentāciju", "%s email verification" : "%s e-pasta pārbaude", "Email verification" : "E-pasta pārbaude", "Click the following button to confirm your email." : "Jāklikšķina zemā esošā poga, lai apstiprinātu savu e-pasta adresi.", @@ -40,6 +40,8 @@ OC.L10N.register( "_%n minute ago_::_%n minutes ago_" : ["pirms %n minūtēm","pirms %n minūtes","pirms %n minūtēm"], "seconds ago" : "pirms vairākām sekundēm", "Empty file" : "Tukša datne", + "%1$s (renamed)" : "%1$s (pārdēvēta)", + "renamed file" : "pārdēvēja datni", "File already exists" : "Datne jau pastāv", "Filename contains at least one invalid character" : "Datnes nosaukums satur vismaz vienu nederīgu rakstzīmi", "Empty filename is not allowed" : "Tukšs datnes nosaukums nav atļauts", @@ -68,7 +70,7 @@ OC.L10N.register( "Set an admin password." : "Iestatīt pārvaldītāja paroli.", "Open %s" : "Atvērt %s", "Unknown share type" : "Nezināms kopīgošanas veids", - "You are not allowed to share %s" : "Tev nav ļauts dalīties ar %s", + "You are not allowed to share %s" : "Tev nav ļauts kopīgot %s", "Could not find category \"%s\"" : "Nevarēja atrast kategoriju “%s”", "Sunday" : "Svētdiena", "Monday" : "Pirmdiena", diff --git a/lib/l10n/lv.json b/lib/l10n/lv.json index 5400ea39460..985ca12e30a 100644 --- a/lib/l10n/lv.json +++ b/lib/l10n/lv.json @@ -3,7 +3,7 @@ "See %s" : "Skatīt %s", "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Lietotne %1$s nav pieejama vai tai ir ar šo serveri nesaderīga versija. Lūgums pārbaudīt lietotņu mapi.", "Sample configuration detected" : "Atrasta konfigurācijas paraugs", - "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Konstatēts, ka paraug konfigurācija ir nokopēta. Tas var izjaukt jūsu instalāciju un nav atbalstīts. Lūdzu, izlasiet dokumentāciju, pirms veicat izmaiņas config.php", + "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Tika noteikts, ka tika kopēta paraugkonfigurācija. Tas var salauzt uzstādīto un netiek atbalstīts. Lūgums pirms izmaiņu veikšanas config.php izlasīt dokumentāciju", "%s email verification" : "%s e-pasta pārbaude", "Email verification" : "E-pasta pārbaude", "Click the following button to confirm your email." : "Jāklikšķina zemā esošā poga, lai apstiprinātu savu e-pasta adresi.", @@ -38,6 +38,8 @@ "_%n minute ago_::_%n minutes ago_" : ["pirms %n minūtēm","pirms %n minūtes","pirms %n minūtēm"], "seconds ago" : "pirms vairākām sekundēm", "Empty file" : "Tukša datne", + "%1$s (renamed)" : "%1$s (pārdēvēta)", + "renamed file" : "pārdēvēja datni", "File already exists" : "Datne jau pastāv", "Filename contains at least one invalid character" : "Datnes nosaukums satur vismaz vienu nederīgu rakstzīmi", "Empty filename is not allowed" : "Tukšs datnes nosaukums nav atļauts", @@ -66,7 +68,7 @@ "Set an admin password." : "Iestatīt pārvaldītāja paroli.", "Open %s" : "Atvērt %s", "Unknown share type" : "Nezināms kopīgošanas veids", - "You are not allowed to share %s" : "Tev nav ļauts dalīties ar %s", + "You are not allowed to share %s" : "Tev nav ļauts kopīgot %s", "Could not find category \"%s\"" : "Nevarēja atrast kategoriju “%s”", "Sunday" : "Svētdiena", "Monday" : "Pirmdiena", diff --git a/lib/l10n/nl.js b/lib/l10n/nl.js index 7d9c078ad71..66af2d8ba2b 100644 --- a/lib/l10n/nl.js +++ b/lib/l10n/nl.js @@ -53,6 +53,7 @@ OC.L10N.register( "Files" : "Bestanden", "View profile" : "Bekijk profiel", "_%nh_::_%nh_" : ["%nh","%nh"], + "Local time: %s" : "Lokale tijd: %s", "today" : "vandaag", "tomorrow" : "morgen", "yesterday" : "gisteren", @@ -75,6 +76,8 @@ OC.L10N.register( "Empty file" : "Leeg bestand", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Module met ID: %s bestaat niet. Schakel die in binnen de app-instellingen of neem contact op met je beheerder.", "Dot files are not allowed" : "Punt-bestanden zijn niet toegestaan", + "%1$s (renamed)" : "%1$s (hernoemd)", + "renamed file" : "bestand hernoemd", "File already exists" : "Bestand bestaat al", "Invalid path" : "Ongeldig pad", "Failed to create file from template" : "Kon geen bestand van het sjabloon maken", @@ -103,6 +106,7 @@ OC.L10N.register( "Address" : "Adres", "Profile picture" : "Profielafbeelding", "About" : "Over", + "Display name" : "Weergave naam", "Headline" : "Hoofdlijn", "Organisation" : "Organisatie", "Role" : "Rol", @@ -117,7 +121,12 @@ OC.L10N.register( "Sharing backend %s must implement the interface OCP\\Share_Backend" : "De gedeelde achtergrond %s moet de OCP\\Share_Backend interface implementeren", "Sharing backend %s not found" : "De gedeelde backend %s is niet gevonden", "Sharing backend for %s not found" : "De gedeelde backend voor %s is niet gevonden", + "%1$s shared %2$s with you" : "%1$s deelde %2$s met jou", + "Open %s" : "%s openen", "%1$s via %2$s" : "%1$s via %2$s", + "%1$s shared %2$s with you and wants to add:" : "%1$s deelde %2$s met jou en wil toevoegen:", + "%1$s shared %2$s with you and wants to add" : "%1$s deelde %2$s met jou en wil toevoegen", + "%s added a note to a file shared with you" : "%s heeft een notitie toegevoegd aan een bestand dat met jou werd gedeeld", "Unknown share type" : "Onbekend type gedeelde folder", "You are not allowed to share %s" : "Je bent niet bevoegd om %s te delen", "Cannot increase permissions of %s" : "Kan de machtiging van %s niet verhogen.", @@ -126,6 +135,7 @@ OC.L10N.register( "Expiration date is in the past" : "De vervaldatum ligt in het verleden", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Kan de vervaldatum niet meer dan %s dag in de toekomst instellen","Kan de vervaldatum niet meer dan %s dagen in de toekomst instellen"], "Sharing is only allowed with group members" : "Delen kan alleen met groepsleden", + "Sharing %s failed, because this item is already shared with the account %s" : "Het delen van%s is mislukt, omdat dit item al gedeeld wordt met het account %s", "The requested share does not exist anymore" : "De toegang tot de gedeelde folder bestaat niet meer", "Could not find category \"%s\"" : "Kan categorie \"%s\" niet vinden", "Sunday" : "Zondag", diff --git a/lib/l10n/nl.json b/lib/l10n/nl.json index 0d11433dc52..c2bb3c5831b 100644 --- a/lib/l10n/nl.json +++ b/lib/l10n/nl.json @@ -51,6 +51,7 @@ "Files" : "Bestanden", "View profile" : "Bekijk profiel", "_%nh_::_%nh_" : ["%nh","%nh"], + "Local time: %s" : "Lokale tijd: %s", "today" : "vandaag", "tomorrow" : "morgen", "yesterday" : "gisteren", @@ -73,6 +74,8 @@ "Empty file" : "Leeg bestand", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Module met ID: %s bestaat niet. Schakel die in binnen de app-instellingen of neem contact op met je beheerder.", "Dot files are not allowed" : "Punt-bestanden zijn niet toegestaan", + "%1$s (renamed)" : "%1$s (hernoemd)", + "renamed file" : "bestand hernoemd", "File already exists" : "Bestand bestaat al", "Invalid path" : "Ongeldig pad", "Failed to create file from template" : "Kon geen bestand van het sjabloon maken", @@ -101,6 +104,7 @@ "Address" : "Adres", "Profile picture" : "Profielafbeelding", "About" : "Over", + "Display name" : "Weergave naam", "Headline" : "Hoofdlijn", "Organisation" : "Organisatie", "Role" : "Rol", @@ -115,7 +119,12 @@ "Sharing backend %s must implement the interface OCP\\Share_Backend" : "De gedeelde achtergrond %s moet de OCP\\Share_Backend interface implementeren", "Sharing backend %s not found" : "De gedeelde backend %s is niet gevonden", "Sharing backend for %s not found" : "De gedeelde backend voor %s is niet gevonden", + "%1$s shared %2$s with you" : "%1$s deelde %2$s met jou", + "Open %s" : "%s openen", "%1$s via %2$s" : "%1$s via %2$s", + "%1$s shared %2$s with you and wants to add:" : "%1$s deelde %2$s met jou en wil toevoegen:", + "%1$s shared %2$s with you and wants to add" : "%1$s deelde %2$s met jou en wil toevoegen", + "%s added a note to a file shared with you" : "%s heeft een notitie toegevoegd aan een bestand dat met jou werd gedeeld", "Unknown share type" : "Onbekend type gedeelde folder", "You are not allowed to share %s" : "Je bent niet bevoegd om %s te delen", "Cannot increase permissions of %s" : "Kan de machtiging van %s niet verhogen.", @@ -124,6 +133,7 @@ "Expiration date is in the past" : "De vervaldatum ligt in het verleden", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Kan de vervaldatum niet meer dan %s dag in de toekomst instellen","Kan de vervaldatum niet meer dan %s dagen in de toekomst instellen"], "Sharing is only allowed with group members" : "Delen kan alleen met groepsleden", + "Sharing %s failed, because this item is already shared with the account %s" : "Het delen van%s is mislukt, omdat dit item al gedeeld wordt met het account %s", "The requested share does not exist anymore" : "De toegang tot de gedeelde folder bestaat niet meer", "Could not find category \"%s\"" : "Kan categorie \"%s\" niet vinden", "Sunday" : "Zondag", diff --git a/lib/l10n/pl.js b/lib/l10n/pl.js index 4b551782476..884ae246664 100644 --- a/lib/l10n/pl.js +++ b/lib/l10n/pl.js @@ -38,6 +38,7 @@ OC.L10N.register( "Server version %s or higher is required." : "Wymagana jest wersja serwera %s lub wyższa.", "Server version %s or lower is required." : "Wymagana jest wersja serwera %s lub niższa.", "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Zalogowane konto musi być administratorem, subadministratorem lub posiadać specjalne uprawnienia, aby uzyskać dostęp do tego ustawienia", + "Your current IP address doesn't allow you to perform admin actions" : "Twój obecny adres IP nie pozwala na wykonywanie działań administracyjnych", "Logged in account must be an admin or sub admin" : "Zalogowane konto musi być administratorem lub subadministratorem", "Logged in account must be an admin" : "Zalogowane konto musi być administratorem", "Wiping of device %s has started" : "Rozpoczęto czyszczenie urządzenia %s", @@ -58,7 +59,11 @@ OC.L10N.register( "Avatar image is not square" : "Obraz awatara nie jest kwadratowy", "Files" : "Pliki", "View profile" : "Zobacz profil", + "same time" : "jednocześnie", "_%nh_::_%nh_" : ["%nh","%nh","%nh","%ngodz."], + "_%nm_::_%nm_" : ["%nmin","%nmin","%nmin","%nmin"], + "%s ahead" : "o %s wcześniej", + "%s behind" : "o %s później", "Local time: %s" : "Czas lokalny: %s", "today" : "dzisiaj", "tomorrow" : "jutro", @@ -81,14 +86,32 @@ OC.L10N.register( "seconds ago" : "przed chwilą", "Empty file" : "Pusty plik", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Moduł o ID: %s nie istnieje. Włącz go w ustawieniach aplikacji lub skontaktuj się z administratorem.", + "No file conversion providers available" : "Brak dostępnych usług konwersji plików.", + "File is too large to convert" : "Plik jest zbyt duży, aby go przekonwertować.", + "Destination does not match conversion extension" : "Docelowy format nie odpowiada rozszerzeniu konwersji", + "Could not convert file" : "Nie można przekonwertować pliku", + "Destination does not exist" : "Folder docelowy nie istnieje", + "Destination is not creatable" : "Nie można utworzyć folderu docelowego", "Dot files are not allowed" : "Pliki z kropką są niedozwolone", "%1$s (renamed)" : "%1$s (zmieniona nazwa)", "renamed file" : "zmieniona nazwa pliku", + "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" jest zabronioną nazwą pliku lub folderu.", + "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" jest zabronionym przedrostkiem dla nazw plików lub folderów.", + "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" nie jest dozwolone w nazwie pliku ani folderu.", + "\"%1$s\" is a forbidden file type." : "\"%1$s\" jest zabronionym typem pliku.", + "Filenames must not end with \"%1$s\"." : "Nazwa pliku nie może być zakończona znakiem \"%1$s\"", "Invalid parent path" : "Nieprawidłowa ścieżka nadrzędna", "File already exists" : "Plik już istnieje", "Invalid path" : "Niewłaściwa ścieżka", "Failed to create file from template" : "Nie udało się utworzyć pliku z szablonu", "Templates" : "Szablony", + "Storage %s cannot be moved" : "Magazynu %s nie można przenieść", + "Moving a share (%s) into a shared folder is not allowed" : "Przenoszenie udziału (%s) do folderu współdzielonego jest niedozwolone", + "Moving a storage (%s) into a shared folder is not allowed" : "Przenoszenie magazynu (%s) do folderu współdzielonego jest niedozwolone", + "Moving a share (%s) into another share (%s) is not allowed" : "Przenoszenie udziału (%s) do innego udziału (%s) jest niedozwolone", + "Moving a share (%s) into another storage (%s) is not allowed" : "Przenoszenie udziału (%s) do innego magazynu (%s) jest niedozwolone", + "Moving a storage (%s) into a share (%s) is not allowed" : "Przenoszenie magazynu (%s) do udziału (%s) jest niedozwolone", + "Moving a storage (%s) into another storage (%s) is not allowed" : "Przenoszenie magazynu (%s) do innego magazynu (%s) jest niedozwolone", "Path contains invalid segments" : "Ścieżka zawiera nieprawidłowe segmenty", "Filename is a reserved word" : "Nazwa pliku jest słowem zastrzeżonym", "Filename contains at least one invalid character" : "Nazwa pliku zawiera co najmniej jeden nieprawidłowy znak", @@ -130,8 +153,12 @@ OC.L10N.register( "Enter the database Login for %s" : "Wpisz logowanie do bazy danych dla %s", "Enter the database name for %s" : "Podaj nazwę bazy danych dla %s", "You cannot use dots in the database name %s" : "Nie można używać kropek w nazwie bazy danych %s", + "MySQL Login and/or password not valid" : "Nieprawidłowy login i/lub hasło do MySQL", "You need to enter details of an existing account." : "Musisz wprowadzić szczegółowe dane dla istniejącego konta.", "Oracle connection could not be established" : "Nie można nawiązać połączenia z bazą danych Oracle", + "Oracle Login and/or password not valid" : "Nieprawidłowy login i/lub hasło do Oracle", + "PostgreSQL Login and/or password not valid" : "Nieprawidłowy login i/lub hasło do PostgreSQL", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk!" : "Mac OS X nie jest obsługiwany i %s może nie działać poprawnie na tej platformie. Używasz na własne ryzyko!", "For the best results, please consider using a GNU/Linux server instead." : "Aby uzyskać najlepszy efekt, rozważ użycie serwera GNU/Linux.", "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "Wydaje się, że ta instancja %s używa PHP dla 32-bitowego środowiska, ponieważ open_basedir został tak skonfigurowany w php.ini. Doprowadzi to do problemów z plikami powyżej 4 GB i jest bardzo niezalecane.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Usuń ustawienie open_basedir w php.ini lub przełącz na PHP 64-bitowe.", @@ -154,12 +181,14 @@ OC.L10N.register( "Share recipient should not be empty" : "Odbiorca udostępnienia nie powinien być pusty", "Share recipient is not a valid circle" : "Odbiorca udostępnienia nie jest prawidłowym kręgiem", "Unknown share type" : "Nieznany typ udostępnienia", + "Share initiator must be set" : "Należy ustawić inicjatora współdzielenia", "Cannot share with yourself" : "Nie można dzielić się ze sobą", "Shared path must be set" : "Należy ustawić ścieżkę współdzieloną", "Shared path must be either a file or a folder" : "Udostępniona ścieżka musi być plikiem lub katalogiem", "You cannot share your root folder" : "Nie możesz udostępnić swojego katalogu głównego root", "You are not allowed to share %s" : "Nie możesz udostępnić %s", "Valid permissions are required for sharing" : "Do udostępniania wymagane są ważne uprawnienia", + "File shares cannot have create or delete permissions" : "Udostępnione pliki nie mogą mieć uprawnień do tworzenia ani usuwania", "Cannot increase permissions of %s" : "Nie można zwiększyć uprawnień %s", "Shares need at least read permissions" : "Udostępnianie wymaga co najmniej uprawnień do odczytu", "Files cannot be shared with delete permissions" : "Pliki nie mogą zostać udostępnione z prawem do usuwania", @@ -168,18 +197,26 @@ OC.L10N.register( "Expiration date is enforced" : "Obowiązuje data ważności", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Nie można utworzyć daty wygaśnięcia na %n dzień do przodu","Nie można utworzyć daty wygaśnięcia na %n dni do przodu","Nie można utworzyć daty wygaśnięcia na %n dni do przodu","Nie można utworzyć daty wygaśnięcia na %n dni do przodu"], "Sharing is only allowed with group members" : "Udostępnianie jest dozwolone tylko członkom grupy", + "Sharing %s failed, because this item is already shared with the account %s" : "Udostępnianie %s nie powiodło się, ponieważ ten element jest już współdzielony z kontem %s", "Group sharing is now allowed" : "Udostępnianie grupowe jest teraz dozwolone", "Sharing is only allowed within your own groups" : "Udostępnianie jest dozwolone wyłącznie w obrębie własnych grup", "Path is already shared with this group" : "Ścieżka jest już udostępniona tej grupie", "Link sharing is not allowed" : "Udostępnianie odnośników jest niedozwolone", "Public upload is not allowed" : "Przesyłanie publiczne nie jest dozwolone", + "You cannot share a folder that contains other shares" : "Nie można udostępnić folderu zawierającego inne udostępnienia", "Sharing is disabled" : "Udostępnianie jest wyłączone", "Sharing is disabled for you" : "Udostępnianie jest dla Ciebie wyłączone", "Cannot share with the share owner" : "Nie można udostępnić właścicielowi udziału", "Share does not have a full ID" : "Udział nie ma pełnego identyfikatora", "Cannot change share type" : "Nie można zmienić typu udziału", "Can only update recipient on user shares" : "Może aktualizować odbiorców tylko w przypadku udziałów użytkownika", + "Cannot enable sending the password by Talk with an empty password" : "Nie można włączyć wysyłania hasła przez Talk przy pustym haśle", + "Cannot enable sending the password by Talk without setting a new password" : "Nie można włączyć wysyłania hasła przez Talk bez ustawienia nowego hasła", + "Cannot disable sending the password by Talk without setting a new password" : "Nie można wyłączyć wysyłania hasła przez Talk bez ustawienia nowego hasła", + "Share provider does not support accepting" : "Dostawca współdzielenia nie obsługuje przyjmowania", + "Cannot change target of link share" : "Nie można zmienić celu współdzielonego linku", "Invalid share recipient" : "Nieprawidłowy odbiorca udostępnienia", + "Group \"%s\" does not exist" : "Grupa \"%s\" nie istnieje", "The requested share does not exist anymore" : "Żądane udostępnienie już nie istnieje", "The requested share comes from a disabled user" : "Żądane udostępnienie pochodzi od wyłączonego użytkownika", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Użytkownik nie został utworzony, ponieważ osiągnięto limit użytkowników. Sprawdź swoje powiadomienia, aby dowiedzieć się więcej.", @@ -238,6 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Należy podać poprawny login", "Login contains whitespace at the beginning or at the end" : "Login zawiera spacje na początku lub na końcu", "Login must not consist of dots only" : "Login nie może składać się wyłącznie z kropek", + "Username is too long" : "Nazwa użytkownika jest zbyt długa", "Login is invalid because files already exist for this user" : "Login jest nieprawidłowy, ponieważ dla tego użytkownika istnieją już pliki", "Account disabled" : "Konto wyłączone", "Login canceled by app" : "Logowanie anulowane przez aplikację", @@ -275,6 +313,7 @@ OC.L10N.register( "Your data directory must be an absolute path." : "Katalog danych musi mieć ścieżkę absolutną.", "Check the value of \"datadirectory\" in your configuration." : "Sprawdź wartość \"datadirectory\" w swojej konfiguracji.", "Your data directory is invalid." : "Katalog danych jest nieprawidłowy.", + "Ensure there is a file called \"%1$s\" in the root of the data directory. It should have the content: \"%2$s\"" : "Upewnij się, że w katalogu głównym danych znajduje się plik o nazwie \"%1$s\". Powinien on zawierać: \"%2$s\"", "Action \"%s\" not supported or implemented." : "Akcja \"%s\" jest niewspierana lub niezaimplementowana.", "Authentication failed, wrong token or provider ID given" : "Uwierzytelnienie nie powiodło się, podano nieprawidłowy token lub ID dostawcy", "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Brak parametrów w celu uzupełnienia żądania. Brakujące parametry: \"%s\"", @@ -286,34 +325,114 @@ OC.L10N.register( "Storage connection error. %s" : "Błąd połączenia z magazynem. %s", "Storage is temporarily not available" : "Magazyn jest tymczasowo niedostępny", "Storage connection timeout. %s" : "Limit czasu połączenia do magazynu. %s", + "To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule." : "Aby umożliwić wykonanie tego sprawdzenia, upewnij się, że serwer WWW może połączyć się sam ze sobą. Musi on być w stanie rozpoznać i połączyć się przynajmniej z jedną z wartości 'trusted_domains' lub 'overwrite.cli.url'. Błąd ten może być wynikiem niezgodności DNS po stronie serwera lub reguły zapory sieciowej wychodzącej.", "Transcribe audio" : "Transkrypcja dźwięku", "Transcribe the things said in an audio" : "Transkrypcja wypowiedzi w formie audio", "Audio input" : "Wejście dźwięku", "The audio to transcribe" : "Dźwięk do transkrypcji", "Transcription" : "Transkrypcja", "The transcribed text" : "Tekst transkrypcji", + "Chat with an agent" : "Czat z agentem", + "Chat message" : "Wiadomość czatu", + "A chat message to send to the agent." : "Wiadomość czatu do wysłania do agenta.", "Confirmation" : "Potwierdzenie", + "Whether to confirm previously requested actions: 0 for denial and 1 for confirmation." : "Czy potwierdzić wcześniej żądane działania: 0 — odmowa, 1 — potwierdzenie.", + "Conversation token" : "Token konwersacji", + "A token representing the conversation." : "Token reprezentujący konwersację.", "Generated response" : "Wygenerowana odpowiedź", + "The response from the chat model." : "Odpowiedź z modelu czatu.", + "The new conversation token" : "Nowy token konwersacji", + "Send this along with the next interaction." : "Wyślij to razem z następną interakcją.", + "Requested actions by the agent" : "Żądane działania agenta", + "Actions that the agent would like to carry out in JSON format." : "Działania, które agent chciałby wykonać w formacie JSON.", + "Context write" : "Zapis kontekstu", + "Writes text in a given style based on the provided source material." : "Tworzy tekst w określonym stylu na podstawie dostarczonego materiału źródłowego.", "Writing style" : "Styl pisania", + "Demonstrate a writing style that you would like to immitate" : "Zaprezentuj styl pisania, który chciałbyś naśladować", "Source material" : "Materiał źródłowy", + "The content that would like to be rewritten in the new writing style" : "Treść, która ma zostać przepisana w nowym stylu pisania", + "Generated text" : "Wygenerowany tekst", + "The generated text with content from the source material in the given style" : "Wygenerowany tekst z treścią z materiału źródłowego w określonym stylu", + "Emoji generator" : "Generator emoji", + "Takes text and generates a representative emoji for it." : "Przyjmuje tekst i generuje pasującą emoji.", + "The text to generate an emoji for" : "Tekst, dla którego ma zostać wygenerowana emoji", + "Generated emoji" : "Wygenerowane emoji", + "The generated emoji based on the input text" : "Wygenerowana emoji na podstawie wprowadzonego tekstu", + "Generate image" : "Generuj obraz", + "Generate an image from a text prompt" : "Wygeneruj obraz z opisu tekstowego", + "Prompt" : "Polecenie", "Describe the image you want to generate" : "Opisz obraz, który chcesz wygenerować", "Number of images" : "Liczba obrazów", "How many images to generate" : "Ile obrazów wygenerować", "Output images" : "Obrazy wyjściowe", "The generated images" : "Wygenerowane obrazy", + "Generate speech" : "Generuj mowę", + "Generate speech from a transcript" : "Wygeneruj mowę z transkryptu", + "Write transcript that you want the assistant to generate speech from" : "Napisz transkrypt, na podstawie którego asystent ma wygenerować mowę", + "Output speech" : "Wygenerowana mowa", + "The generated speech" : "Wygenerowana mowa", + "Free text to text prompt" : "Dowolny tekst jako polecenie wejściowe", + "Runs an arbitrary prompt through a language model that returns a reply" : "Przetwarza dowolne polecenie za pomocą modelu językowego, który zwraca odpowiedź", + "Describe a task that you want the assistant to do or ask a question" : "Opisz zadanie, które ma wykonać asystent, lub zadaj pytanie", + "Generated reply" : "Wygenerowana odpowiedź", + "The generated text from the assistant" : "Wygenerowany tekst od asystenta", "Change Tone" : "Zmień ton wypowiedzi", + "Change the tone of a piece of text." : "Zmień ton fragmentu tekstu", "Write a text that you want the assistant to rewrite in another tone." : "Napisz tekst, który chcesz, aby asystent napisał inaczej.", "Desired tone" : "Pożądany ton wypowiedzi", "In which tone should your text be rewritten?" : "W jakim tonie powinien zostać napisany Twój tekst?", "The rewritten text in the desired tone, written by the assistant:" : "Przepisany tekst w pożądanym tonie, napisany przez asystenta:", "Chat" : "Rozmowa", + "Chat with the assistant" : "Czat z asystentem", + "System prompt" : "Polecenie systemowe", + "Define rules and assumptions that the assistant should follow during the conversation." : "Określ zasady i założenia, których asystent powinien przestrzegać podczas rozmowy", "Chat history" : "Historia rozmów", + "The history of chat messages before the current message, starting with a message by the user" : "Historia wiadomości czatu przed bieżącą wiadomością, zaczynając od wiadomości użytkownika", + "Response message" : "Wiadomość odpowiedzi", + "The generated response as part of the conversation" : "Wygenerowana odpowiedź jako część rozmowy", + "Chat with tools" : "Czat z użyciem narzędzi", + "Chat with the language model with tool calling support." : "Czat z modelem językowym z obsługą wywoływania narzędzi", + "Tool message" : "Wiadomość narzędzia", + "The result of tool calls in the last interaction" : "Wynik wywołań narzędzi w ostatniej interakcji", + "Available tools" : "Dostępne narzędzia", + "The available tools in JSON format" : "Dostępne narzędzia w formacie JSON", + "The response from the chat model" : "Odpowiedź z modelu czatu", + "Tool calls" : "Wywołania narzędzi", + "Tools call instructions from the model in JSON format" : "Instrukcje wywołań narzędzi z modelu w formacie JSON", + "Formalize text" : "Sformalizuj tekst", + "Takes a text and makes it sound more formal" : "Pobiera tekst i sprawia, że brzmi bardziej formalnie", + "Write a text that you want the assistant to formalize" : "Napisz tekst, który chcesz, aby asystent sformalizował", + "Formalized text" : "Sformalizowany tekst", + "The formalized text" : "Sformalizowany tekst", + "Generate a headline" : "Wygeneruj nagłówek", "Generates a possible headline for a text." : "Generuje możliwy nagłówek tekstu.", "Original text" : "Tekst oryginalny", + "The original text to generate a headline for" : "Oryginalny tekst, do którego ma zostać wygenerowany nagłówek", + "The generated headline" : "Wygenerowany nagłówek", + "Proofread" : "Korekta", + "Proofreads a text and lists corrections" : "Sprawdza tekst i podaje poprawki", "Text" : "Tekst", + "The text to proofread" : "Tekst do korekty", + "Corrections" : "Poprawki", + "The corrections that should be made in your text" : "Poprawki, które należy wprowadzić w Twoim tekście", + "Reformulate text" : "Przekształć tekst", + "Takes a text and reformulates it" : "Pobiera tekst i przekształca go", + "Write a text that you want the assistant to reformulate" : "Napisz tekst, który chcesz, aby asystent przekształcił", + "Reformulated text" : "Przekształcony tekst", + "The reformulated text, written by the assistant" : "Przekształcony tekst napisany przez asystenta", + "Simplify text" : "Uprość tekst", + "Takes a text and simplifies it" : "Pobiera tekst i upraszcza go", + "Write a text that you want the assistant to simplify" : "Napisz tekst, który chcesz, aby asystent uprościł", + "Simplified text" : "Uproszczony tekst", + "The simplified text" : "Uproszczony tekst", "Summarize" : "Podsumuj", + "Summarizes a text" : "Tworzy podsumowanie tekstu", + "The original text to summarize" : "Oryginalny tekst do podsumowania", "Summary" : "Podsumowanie", + "The generated summary" : "Wygenerowane podsumowanie", "Extract topics" : "Wyodrębnij tematy", + "Extracts topics from a text and outputs them separated by commas" : "Wydobywa tematy z tekstu i zwraca je oddzielone przecinkami", + "The original text to extract topics from" : "Oryginalny tekst, z którego mają zostać wydobyte tematy", "Topics" : "Tematy", "The list of extracted topics" : "Lista wyodrębnionych tematów", "Translate" : "Tłumaczenie", @@ -332,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Podsumowuje tekst, zmniejszając jego długość bez utraty kluczowych informacji.", "Extracts topics from a text and outputs them separated by commas." : "Wyodrębnia tematy z tekstu i wyświetla je oddzielone przecinkami.", "File is currently busy, please try again later" : "Plik jest obecnie niedostępny, spróbuj później", - "Cannot download file" : "Nie można pobrać pliku" + "Cannot download file" : "Nie można pobrać pliku", + "Login is too long" : "Login jest zbyt długi" }, "nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);"); diff --git a/lib/l10n/pl.json b/lib/l10n/pl.json index ee8cd672e0e..cfdcc25a3a3 100644 --- a/lib/l10n/pl.json +++ b/lib/l10n/pl.json @@ -36,6 +36,7 @@ "Server version %s or higher is required." : "Wymagana jest wersja serwera %s lub wyższa.", "Server version %s or lower is required." : "Wymagana jest wersja serwera %s lub niższa.", "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Zalogowane konto musi być administratorem, subadministratorem lub posiadać specjalne uprawnienia, aby uzyskać dostęp do tego ustawienia", + "Your current IP address doesn't allow you to perform admin actions" : "Twój obecny adres IP nie pozwala na wykonywanie działań administracyjnych", "Logged in account must be an admin or sub admin" : "Zalogowane konto musi być administratorem lub subadministratorem", "Logged in account must be an admin" : "Zalogowane konto musi być administratorem", "Wiping of device %s has started" : "Rozpoczęto czyszczenie urządzenia %s", @@ -56,7 +57,11 @@ "Avatar image is not square" : "Obraz awatara nie jest kwadratowy", "Files" : "Pliki", "View profile" : "Zobacz profil", + "same time" : "jednocześnie", "_%nh_::_%nh_" : ["%nh","%nh","%nh","%ngodz."], + "_%nm_::_%nm_" : ["%nmin","%nmin","%nmin","%nmin"], + "%s ahead" : "o %s wcześniej", + "%s behind" : "o %s później", "Local time: %s" : "Czas lokalny: %s", "today" : "dzisiaj", "tomorrow" : "jutro", @@ -79,14 +84,32 @@ "seconds ago" : "przed chwilą", "Empty file" : "Pusty plik", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Moduł o ID: %s nie istnieje. Włącz go w ustawieniach aplikacji lub skontaktuj się z administratorem.", + "No file conversion providers available" : "Brak dostępnych usług konwersji plików.", + "File is too large to convert" : "Plik jest zbyt duży, aby go przekonwertować.", + "Destination does not match conversion extension" : "Docelowy format nie odpowiada rozszerzeniu konwersji", + "Could not convert file" : "Nie można przekonwertować pliku", + "Destination does not exist" : "Folder docelowy nie istnieje", + "Destination is not creatable" : "Nie można utworzyć folderu docelowego", "Dot files are not allowed" : "Pliki z kropką są niedozwolone", "%1$s (renamed)" : "%1$s (zmieniona nazwa)", "renamed file" : "zmieniona nazwa pliku", + "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" jest zabronioną nazwą pliku lub folderu.", + "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" jest zabronionym przedrostkiem dla nazw plików lub folderów.", + "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" nie jest dozwolone w nazwie pliku ani folderu.", + "\"%1$s\" is a forbidden file type." : "\"%1$s\" jest zabronionym typem pliku.", + "Filenames must not end with \"%1$s\"." : "Nazwa pliku nie może być zakończona znakiem \"%1$s\"", "Invalid parent path" : "Nieprawidłowa ścieżka nadrzędna", "File already exists" : "Plik już istnieje", "Invalid path" : "Niewłaściwa ścieżka", "Failed to create file from template" : "Nie udało się utworzyć pliku z szablonu", "Templates" : "Szablony", + "Storage %s cannot be moved" : "Magazynu %s nie można przenieść", + "Moving a share (%s) into a shared folder is not allowed" : "Przenoszenie udziału (%s) do folderu współdzielonego jest niedozwolone", + "Moving a storage (%s) into a shared folder is not allowed" : "Przenoszenie magazynu (%s) do folderu współdzielonego jest niedozwolone", + "Moving a share (%s) into another share (%s) is not allowed" : "Przenoszenie udziału (%s) do innego udziału (%s) jest niedozwolone", + "Moving a share (%s) into another storage (%s) is not allowed" : "Przenoszenie udziału (%s) do innego magazynu (%s) jest niedozwolone", + "Moving a storage (%s) into a share (%s) is not allowed" : "Przenoszenie magazynu (%s) do udziału (%s) jest niedozwolone", + "Moving a storage (%s) into another storage (%s) is not allowed" : "Przenoszenie magazynu (%s) do innego magazynu (%s) jest niedozwolone", "Path contains invalid segments" : "Ścieżka zawiera nieprawidłowe segmenty", "Filename is a reserved word" : "Nazwa pliku jest słowem zastrzeżonym", "Filename contains at least one invalid character" : "Nazwa pliku zawiera co najmniej jeden nieprawidłowy znak", @@ -128,8 +151,12 @@ "Enter the database Login for %s" : "Wpisz logowanie do bazy danych dla %s", "Enter the database name for %s" : "Podaj nazwę bazy danych dla %s", "You cannot use dots in the database name %s" : "Nie można używać kropek w nazwie bazy danych %s", + "MySQL Login and/or password not valid" : "Nieprawidłowy login i/lub hasło do MySQL", "You need to enter details of an existing account." : "Musisz wprowadzić szczegółowe dane dla istniejącego konta.", "Oracle connection could not be established" : "Nie można nawiązać połączenia z bazą danych Oracle", + "Oracle Login and/or password not valid" : "Nieprawidłowy login i/lub hasło do Oracle", + "PostgreSQL Login and/or password not valid" : "Nieprawidłowy login i/lub hasło do PostgreSQL", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk!" : "Mac OS X nie jest obsługiwany i %s może nie działać poprawnie na tej platformie. Używasz na własne ryzyko!", "For the best results, please consider using a GNU/Linux server instead." : "Aby uzyskać najlepszy efekt, rozważ użycie serwera GNU/Linux.", "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "Wydaje się, że ta instancja %s używa PHP dla 32-bitowego środowiska, ponieważ open_basedir został tak skonfigurowany w php.ini. Doprowadzi to do problemów z plikami powyżej 4 GB i jest bardzo niezalecane.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Usuń ustawienie open_basedir w php.ini lub przełącz na PHP 64-bitowe.", @@ -152,12 +179,14 @@ "Share recipient should not be empty" : "Odbiorca udostępnienia nie powinien być pusty", "Share recipient is not a valid circle" : "Odbiorca udostępnienia nie jest prawidłowym kręgiem", "Unknown share type" : "Nieznany typ udostępnienia", + "Share initiator must be set" : "Należy ustawić inicjatora współdzielenia", "Cannot share with yourself" : "Nie można dzielić się ze sobą", "Shared path must be set" : "Należy ustawić ścieżkę współdzieloną", "Shared path must be either a file or a folder" : "Udostępniona ścieżka musi być plikiem lub katalogiem", "You cannot share your root folder" : "Nie możesz udostępnić swojego katalogu głównego root", "You are not allowed to share %s" : "Nie możesz udostępnić %s", "Valid permissions are required for sharing" : "Do udostępniania wymagane są ważne uprawnienia", + "File shares cannot have create or delete permissions" : "Udostępnione pliki nie mogą mieć uprawnień do tworzenia ani usuwania", "Cannot increase permissions of %s" : "Nie można zwiększyć uprawnień %s", "Shares need at least read permissions" : "Udostępnianie wymaga co najmniej uprawnień do odczytu", "Files cannot be shared with delete permissions" : "Pliki nie mogą zostać udostępnione z prawem do usuwania", @@ -166,18 +195,26 @@ "Expiration date is enforced" : "Obowiązuje data ważności", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Nie można utworzyć daty wygaśnięcia na %n dzień do przodu","Nie można utworzyć daty wygaśnięcia na %n dni do przodu","Nie można utworzyć daty wygaśnięcia na %n dni do przodu","Nie można utworzyć daty wygaśnięcia na %n dni do przodu"], "Sharing is only allowed with group members" : "Udostępnianie jest dozwolone tylko członkom grupy", + "Sharing %s failed, because this item is already shared with the account %s" : "Udostępnianie %s nie powiodło się, ponieważ ten element jest już współdzielony z kontem %s", "Group sharing is now allowed" : "Udostępnianie grupowe jest teraz dozwolone", "Sharing is only allowed within your own groups" : "Udostępnianie jest dozwolone wyłącznie w obrębie własnych grup", "Path is already shared with this group" : "Ścieżka jest już udostępniona tej grupie", "Link sharing is not allowed" : "Udostępnianie odnośników jest niedozwolone", "Public upload is not allowed" : "Przesyłanie publiczne nie jest dozwolone", + "You cannot share a folder that contains other shares" : "Nie można udostępnić folderu zawierającego inne udostępnienia", "Sharing is disabled" : "Udostępnianie jest wyłączone", "Sharing is disabled for you" : "Udostępnianie jest dla Ciebie wyłączone", "Cannot share with the share owner" : "Nie można udostępnić właścicielowi udziału", "Share does not have a full ID" : "Udział nie ma pełnego identyfikatora", "Cannot change share type" : "Nie można zmienić typu udziału", "Can only update recipient on user shares" : "Może aktualizować odbiorców tylko w przypadku udziałów użytkownika", + "Cannot enable sending the password by Talk with an empty password" : "Nie można włączyć wysyłania hasła przez Talk przy pustym haśle", + "Cannot enable sending the password by Talk without setting a new password" : "Nie można włączyć wysyłania hasła przez Talk bez ustawienia nowego hasła", + "Cannot disable sending the password by Talk without setting a new password" : "Nie można wyłączyć wysyłania hasła przez Talk bez ustawienia nowego hasła", + "Share provider does not support accepting" : "Dostawca współdzielenia nie obsługuje przyjmowania", + "Cannot change target of link share" : "Nie można zmienić celu współdzielonego linku", "Invalid share recipient" : "Nieprawidłowy odbiorca udostępnienia", + "Group \"%s\" does not exist" : "Grupa \"%s\" nie istnieje", "The requested share does not exist anymore" : "Żądane udostępnienie już nie istnieje", "The requested share comes from a disabled user" : "Żądane udostępnienie pochodzi od wyłączonego użytkownika", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Użytkownik nie został utworzony, ponieważ osiągnięto limit użytkowników. Sprawdź swoje powiadomienia, aby dowiedzieć się więcej.", @@ -236,6 +273,7 @@ "A valid Login must be provided" : "Należy podać poprawny login", "Login contains whitespace at the beginning or at the end" : "Login zawiera spacje na początku lub na końcu", "Login must not consist of dots only" : "Login nie może składać się wyłącznie z kropek", + "Username is too long" : "Nazwa użytkownika jest zbyt długa", "Login is invalid because files already exist for this user" : "Login jest nieprawidłowy, ponieważ dla tego użytkownika istnieją już pliki", "Account disabled" : "Konto wyłączone", "Login canceled by app" : "Logowanie anulowane przez aplikację", @@ -273,6 +311,7 @@ "Your data directory must be an absolute path." : "Katalog danych musi mieć ścieżkę absolutną.", "Check the value of \"datadirectory\" in your configuration." : "Sprawdź wartość \"datadirectory\" w swojej konfiguracji.", "Your data directory is invalid." : "Katalog danych jest nieprawidłowy.", + "Ensure there is a file called \"%1$s\" in the root of the data directory. It should have the content: \"%2$s\"" : "Upewnij się, że w katalogu głównym danych znajduje się plik o nazwie \"%1$s\". Powinien on zawierać: \"%2$s\"", "Action \"%s\" not supported or implemented." : "Akcja \"%s\" jest niewspierana lub niezaimplementowana.", "Authentication failed, wrong token or provider ID given" : "Uwierzytelnienie nie powiodło się, podano nieprawidłowy token lub ID dostawcy", "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Brak parametrów w celu uzupełnienia żądania. Brakujące parametry: \"%s\"", @@ -284,34 +323,114 @@ "Storage connection error. %s" : "Błąd połączenia z magazynem. %s", "Storage is temporarily not available" : "Magazyn jest tymczasowo niedostępny", "Storage connection timeout. %s" : "Limit czasu połączenia do magazynu. %s", + "To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule." : "Aby umożliwić wykonanie tego sprawdzenia, upewnij się, że serwer WWW może połączyć się sam ze sobą. Musi on być w stanie rozpoznać i połączyć się przynajmniej z jedną z wartości 'trusted_domains' lub 'overwrite.cli.url'. Błąd ten może być wynikiem niezgodności DNS po stronie serwera lub reguły zapory sieciowej wychodzącej.", "Transcribe audio" : "Transkrypcja dźwięku", "Transcribe the things said in an audio" : "Transkrypcja wypowiedzi w formie audio", "Audio input" : "Wejście dźwięku", "The audio to transcribe" : "Dźwięk do transkrypcji", "Transcription" : "Transkrypcja", "The transcribed text" : "Tekst transkrypcji", + "Chat with an agent" : "Czat z agentem", + "Chat message" : "Wiadomość czatu", + "A chat message to send to the agent." : "Wiadomość czatu do wysłania do agenta.", "Confirmation" : "Potwierdzenie", + "Whether to confirm previously requested actions: 0 for denial and 1 for confirmation." : "Czy potwierdzić wcześniej żądane działania: 0 — odmowa, 1 — potwierdzenie.", + "Conversation token" : "Token konwersacji", + "A token representing the conversation." : "Token reprezentujący konwersację.", "Generated response" : "Wygenerowana odpowiedź", + "The response from the chat model." : "Odpowiedź z modelu czatu.", + "The new conversation token" : "Nowy token konwersacji", + "Send this along with the next interaction." : "Wyślij to razem z następną interakcją.", + "Requested actions by the agent" : "Żądane działania agenta", + "Actions that the agent would like to carry out in JSON format." : "Działania, które agent chciałby wykonać w formacie JSON.", + "Context write" : "Zapis kontekstu", + "Writes text in a given style based on the provided source material." : "Tworzy tekst w określonym stylu na podstawie dostarczonego materiału źródłowego.", "Writing style" : "Styl pisania", + "Demonstrate a writing style that you would like to immitate" : "Zaprezentuj styl pisania, który chciałbyś naśladować", "Source material" : "Materiał źródłowy", + "The content that would like to be rewritten in the new writing style" : "Treść, która ma zostać przepisana w nowym stylu pisania", + "Generated text" : "Wygenerowany tekst", + "The generated text with content from the source material in the given style" : "Wygenerowany tekst z treścią z materiału źródłowego w określonym stylu", + "Emoji generator" : "Generator emoji", + "Takes text and generates a representative emoji for it." : "Przyjmuje tekst i generuje pasującą emoji.", + "The text to generate an emoji for" : "Tekst, dla którego ma zostać wygenerowana emoji", + "Generated emoji" : "Wygenerowane emoji", + "The generated emoji based on the input text" : "Wygenerowana emoji na podstawie wprowadzonego tekstu", + "Generate image" : "Generuj obraz", + "Generate an image from a text prompt" : "Wygeneruj obraz z opisu tekstowego", + "Prompt" : "Polecenie", "Describe the image you want to generate" : "Opisz obraz, który chcesz wygenerować", "Number of images" : "Liczba obrazów", "How many images to generate" : "Ile obrazów wygenerować", "Output images" : "Obrazy wyjściowe", "The generated images" : "Wygenerowane obrazy", + "Generate speech" : "Generuj mowę", + "Generate speech from a transcript" : "Wygeneruj mowę z transkryptu", + "Write transcript that you want the assistant to generate speech from" : "Napisz transkrypt, na podstawie którego asystent ma wygenerować mowę", + "Output speech" : "Wygenerowana mowa", + "The generated speech" : "Wygenerowana mowa", + "Free text to text prompt" : "Dowolny tekst jako polecenie wejściowe", + "Runs an arbitrary prompt through a language model that returns a reply" : "Przetwarza dowolne polecenie za pomocą modelu językowego, który zwraca odpowiedź", + "Describe a task that you want the assistant to do or ask a question" : "Opisz zadanie, które ma wykonać asystent, lub zadaj pytanie", + "Generated reply" : "Wygenerowana odpowiedź", + "The generated text from the assistant" : "Wygenerowany tekst od asystenta", "Change Tone" : "Zmień ton wypowiedzi", + "Change the tone of a piece of text." : "Zmień ton fragmentu tekstu", "Write a text that you want the assistant to rewrite in another tone." : "Napisz tekst, który chcesz, aby asystent napisał inaczej.", "Desired tone" : "Pożądany ton wypowiedzi", "In which tone should your text be rewritten?" : "W jakim tonie powinien zostać napisany Twój tekst?", "The rewritten text in the desired tone, written by the assistant:" : "Przepisany tekst w pożądanym tonie, napisany przez asystenta:", "Chat" : "Rozmowa", + "Chat with the assistant" : "Czat z asystentem", + "System prompt" : "Polecenie systemowe", + "Define rules and assumptions that the assistant should follow during the conversation." : "Określ zasady i założenia, których asystent powinien przestrzegać podczas rozmowy", "Chat history" : "Historia rozmów", + "The history of chat messages before the current message, starting with a message by the user" : "Historia wiadomości czatu przed bieżącą wiadomością, zaczynając od wiadomości użytkownika", + "Response message" : "Wiadomość odpowiedzi", + "The generated response as part of the conversation" : "Wygenerowana odpowiedź jako część rozmowy", + "Chat with tools" : "Czat z użyciem narzędzi", + "Chat with the language model with tool calling support." : "Czat z modelem językowym z obsługą wywoływania narzędzi", + "Tool message" : "Wiadomość narzędzia", + "The result of tool calls in the last interaction" : "Wynik wywołań narzędzi w ostatniej interakcji", + "Available tools" : "Dostępne narzędzia", + "The available tools in JSON format" : "Dostępne narzędzia w formacie JSON", + "The response from the chat model" : "Odpowiedź z modelu czatu", + "Tool calls" : "Wywołania narzędzi", + "Tools call instructions from the model in JSON format" : "Instrukcje wywołań narzędzi z modelu w formacie JSON", + "Formalize text" : "Sformalizuj tekst", + "Takes a text and makes it sound more formal" : "Pobiera tekst i sprawia, że brzmi bardziej formalnie", + "Write a text that you want the assistant to formalize" : "Napisz tekst, który chcesz, aby asystent sformalizował", + "Formalized text" : "Sformalizowany tekst", + "The formalized text" : "Sformalizowany tekst", + "Generate a headline" : "Wygeneruj nagłówek", "Generates a possible headline for a text." : "Generuje możliwy nagłówek tekstu.", "Original text" : "Tekst oryginalny", + "The original text to generate a headline for" : "Oryginalny tekst, do którego ma zostać wygenerowany nagłówek", + "The generated headline" : "Wygenerowany nagłówek", + "Proofread" : "Korekta", + "Proofreads a text and lists corrections" : "Sprawdza tekst i podaje poprawki", "Text" : "Tekst", + "The text to proofread" : "Tekst do korekty", + "Corrections" : "Poprawki", + "The corrections that should be made in your text" : "Poprawki, które należy wprowadzić w Twoim tekście", + "Reformulate text" : "Przekształć tekst", + "Takes a text and reformulates it" : "Pobiera tekst i przekształca go", + "Write a text that you want the assistant to reformulate" : "Napisz tekst, który chcesz, aby asystent przekształcił", + "Reformulated text" : "Przekształcony tekst", + "The reformulated text, written by the assistant" : "Przekształcony tekst napisany przez asystenta", + "Simplify text" : "Uprość tekst", + "Takes a text and simplifies it" : "Pobiera tekst i upraszcza go", + "Write a text that you want the assistant to simplify" : "Napisz tekst, który chcesz, aby asystent uprościł", + "Simplified text" : "Uproszczony tekst", + "The simplified text" : "Uproszczony tekst", "Summarize" : "Podsumuj", + "Summarizes a text" : "Tworzy podsumowanie tekstu", + "The original text to summarize" : "Oryginalny tekst do podsumowania", "Summary" : "Podsumowanie", + "The generated summary" : "Wygenerowane podsumowanie", "Extract topics" : "Wyodrębnij tematy", + "Extracts topics from a text and outputs them separated by commas" : "Wydobywa tematy z tekstu i zwraca je oddzielone przecinkami", + "The original text to extract topics from" : "Oryginalny tekst, z którego mają zostać wydobyte tematy", "Topics" : "Tematy", "The list of extracted topics" : "Lista wyodrębnionych tematów", "Translate" : "Tłumaczenie", @@ -330,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Podsumowuje tekst, zmniejszając jego długość bez utraty kluczowych informacji.", "Extracts topics from a text and outputs them separated by commas." : "Wyodrębnia tematy z tekstu i wyświetla je oddzielone przecinkami.", "File is currently busy, please try again later" : "Plik jest obecnie niedostępny, spróbuj później", - "Cannot download file" : "Nie można pobrać pliku" + "Cannot download file" : "Nie można pobrać pliku", + "Login is too long" : "Login jest zbyt długi" },"pluralForm" :"nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);" }
\ No newline at end of file diff --git a/lib/l10n/pt_BR.js b/lib/l10n/pt_BR.js index 3c654ddd844..af2d50b9d1c 100644 --- a/lib/l10n/pt_BR.js +++ b/lib/l10n/pt_BR.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Um Login válido deve ser fornecido", "Login contains whitespace at the beginning or at the end" : "O login contém espaços em branco no início ou no final", "Login must not consist of dots only" : "O login não deve consistir apenas de pontos", - "Login is too long" : "Login é muito longo", + "Username is too long" : "O nome de usuário é muito longo", "Login is invalid because files already exist for this user" : "O login é inválido porque já existem arquivos para este usuário", "Account disabled" : "Conta desativada", "Login canceled by app" : "Login cancelado pelo aplicativo", @@ -301,7 +301,7 @@ OC.L10N.register( "PHP setting \"%s\" is not set to \"%s\"." : "Configuração PHP \"%s\" não está configurado para \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ajustar a configuração no php.ini fará com que o Nextcloud execute novamente", "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> está configurado para <code>%s</code> em vez do valor esperado <code>0</code>.", - "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para corrigir este conjunto de problemas <code>mbstring.func_overload</code> para <code>0</code> no seu php.ini.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para corrigir esse problema, defina <code>mbstring.func_overload</code> como <code>0</code> em seu php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP aparentemente está configurado para retirar blocos doc inline. Isso fará com que vários aplicativos do núcleo fiquem inacessíveis.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isso provavelmente é causado por um cache/acelerador, como Zend OPcache ou eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Módulos do PHP foram instalados, mas eles ainda estão listados como faltantes?", @@ -325,9 +325,9 @@ OC.L10N.register( "Storage connection error. %s" : "Erro na conexão de armazenamento. %s", "Storage is temporarily not available" : "Armazenamento temporariamente indisponível", "Storage connection timeout. %s" : "Atingido o tempo limite de conexão ao armazenamento. %s", - "To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule." : "Para permitir que esta verificação seja executada, você deve certificar-se de que seu servidor Web pode se conectar a si mesmo. Portanto, ele deve ser capaz de resolver e conectar-se a pelo menos um de seus `trusted_domains` ou `overwrite.cli.url`. Essa falha pode ser o resultado de uma incompatibilidade de DNS no servidor ou de uma regra de firewall de saída.", + "To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule." : "Para permitir que esta verificação seja executada, você deve certificar-se de que seu servidor web pode se conectar a si mesmo. Portanto, ele deve ser capaz de resolver e conectar a pelo menos um de seus `trusted_domains` ou `overwrite.cli.url`. Esta falha pode ser o resultado de uma incompatibilidade de DNS no servidor ou de uma regra de firewall de saída.", "Transcribe audio" : "Transcrever áudio", - "Transcribe the things said in an audio" : "Transcreva as coisas ditas em um áudio", + "Transcribe the things said in an audio" : "Transcrever o que foi dito em um áudio", "Audio input" : "Entrada de áudio", "The audio to transcribe" : "O áudio a ser transcrito", "Transcription" : "Transcrição", @@ -345,7 +345,7 @@ OC.L10N.register( "Send this along with the next interaction." : "Envie isso junto com a próxima interação.", "Requested actions by the agent" : "Ações solicitadas pelo agente", "Actions that the agent would like to carry out in JSON format." : "Ações que o agente gostaria de realizar no formato JSON.", - "Context write" : "Gravação de contexto", + "Context write" : "Escrita contextual", "Writes text in a given style based on the provided source material." : "Escreve texto em um determinado estilo com base no material de origem fornecido.", "Writing style" : "Estilo de escrita", "Demonstrate a writing style that you would like to immitate" : "Demonstre um estilo de escrita que você gostaria de imitar", @@ -355,7 +355,7 @@ OC.L10N.register( "The generated text with content from the source material in the given style" : "O texto gerado com conteúdo do material de origem no estilo determinado", "Emoji generator" : "Gerador de emojis", "Takes text and generates a representative emoji for it." : "Pega texto e gera um emoji representativo para ele.", - "The text to generate an emoji for" : "O texto para gerar um emoji para", + "The text to generate an emoji for" : "O texto para o qual gerar um emoji", "Generated emoji" : "Emoji gerado", "The generated emoji based on the input text" : "O emoji gerado com base no texto de entrada", "Generate image" : "Gerar imagem", @@ -363,7 +363,7 @@ OC.L10N.register( "Prompt" : "Prompt", "Describe the image you want to generate" : "Descreva a imagem que você deseja gerar", "Number of images" : "Número de imagens", - "How many images to generate" : "Quantas imagens gerar", + "How many images to generate" : "Quantas imagens devem ser geradas", "Output images" : "Imagens de saída", "The generated images" : "As imagens geradas", "Generate speech" : "Gerar fala", @@ -382,7 +382,7 @@ OC.L10N.register( "Desired tone" : "Tom desejado", "In which tone should your text be rewritten?" : "Em qual tom seu texto deve ser reescrito?", "The rewritten text in the desired tone, written by the assistant:" : "O texto reescrito no tom desejado, escrito pelo assistente:", - "Chat" : "Conversa", + "Chat" : "Bate-papo", "Chat with the assistant" : "Converse com o assistente", "System prompt" : "Prompt do sistema", "Define rules and assumptions that the assistant should follow during the conversation." : "Defina regras e suposições que o assistente deve seguir durante a conversa.", @@ -393,12 +393,12 @@ OC.L10N.register( "Chat with tools" : "Conversar com ferramentas", "Chat with the language model with tool calling support." : "Converse com o modelo de linguagem com suporte a tool calling (\"chamadas a ferramentas\").", "Tool message" : "Mensagem da ferramenta", - "The result of tool calls in the last interaction" : "O resultado das chamadas de ferramentas na última interação", + "The result of tool calls in the last interaction" : "O resultado das chamadas a ferramentas na última interação", "Available tools" : "Ferramentas disponíveis", "The available tools in JSON format" : "As ferramentas disponíveis em formato JSON", "The response from the chat model" : "A resposta do modelo de bate-papo", - "Tool calls" : "Chamadas de ferramentas", - "Tools call instructions from the model in JSON format" : "Instruções de chamada de ferramentas do modelo no formato JSON", + "Tool calls" : "Chamadas a ferramentas", + "Tools call instructions from the model in JSON format" : "Instruções para chamadas a ferramentas do modelo no formato JSON", "Formalize text" : "Formalizar texto", "Takes a text and makes it sound more formal" : "Pega um texto e o faz parecer mais formal", "Write a text that you want the assistant to formalize" : "Escreva um texto que você deseja que o assistente formalize", @@ -407,7 +407,7 @@ OC.L10N.register( "Generate a headline" : "Gere um título", "Generates a possible headline for a text." : "Gera um possível título para um texto.", "Original text" : "Texto original", - "The original text to generate a headline for" : "O texto original para gerar um título para", + "The original text to generate a headline for" : "O texto original para gerar um título", "The generated headline" : "O título gerado", "Proofread" : "Revisar", "Proofreads a text and lists corrections" : "Revisa um texto e lista as correções", @@ -417,11 +417,11 @@ OC.L10N.register( "The corrections that should be made in your text" : "As correções que devem ser feitas em seu texto", "Reformulate text" : "Reformular texto", "Takes a text and reformulates it" : "Pega um texto e o reformula", - "Write a text that you want the assistant to reformulate" : "Escrever um texto que você deseja que o assistente reformule", + "Write a text that you want the assistant to reformulate" : "Escreva um texto que você deseja que o assistente reformule", "Reformulated text" : "Texto reformulado", - "The reformulated text, written by the assistant" : "O texto reformulado, escrito pela assistente", + "The reformulated text, written by the assistant" : "O texto reformulado, escrito pelo assistente", "Simplify text" : "Simplificar texto", - "Takes a text and simplifies it" : "Pega e simplifica um texto", + "Takes a text and simplifies it" : "Pega um texto e o simplifica", "Write a text that you want the assistant to simplify" : "Escreva um texto que você deseja que o assistente simplifique", "Simplified text" : "Texto simplificado", "The simplified text" : "O texto simplificado", @@ -430,11 +430,11 @@ OC.L10N.register( "The original text to summarize" : "O texto original para resumir", "Summary" : "Resumo", "The generated summary" : "O resumo gerado", - "Extract topics" : "Extrair tópicos", - "Extracts topics from a text and outputs them separated by commas" : "Extrai tópicos de um texto e os exibe separados por vírgulas", - "The original text to extract topics from" : "O texto original para extrair tópicos de", - "Topics" : "Tópicos", - "The list of extracted topics" : "A lista de tópicos extraídos", + "Extract topics" : "Extrair temas", + "Extracts topics from a text and outputs them separated by commas" : "Extrai temas de um texto e os exibe separados por vírgulas", + "The original text to extract topics from" : "O texto original do qual extrair temas", + "Topics" : "Temas", + "The list of extracted topics" : "A lista de temas extraídos", "Translate" : "Traduzir", "Translate text from one language to another" : "Traduzir um texto de um idioma para outro", "Origin text" : "Texto original", @@ -446,11 +446,12 @@ OC.L10N.register( "Result" : "Resultado", "The translated text" : "O texto traduzido", "Free prompt" : "Prompt livre", - "Runs an arbitrary prompt through the language model." : "Executa um prompt arbitrário por meio do modelo de idioma.", + "Runs an arbitrary prompt through the language model." : "Executa um prompt arbitrário por meio do modelo de linguagem.", "Generate headline" : "Gerar título", "Summarizes text by reducing its length without losing key information." : "Resume o texto reduzindo seu comprimento sem perder informações importantes.", - "Extracts topics from a text and outputs them separated by commas." : "Extrai tópicos de um texto e os gera separados por vírgulas.", + "Extracts topics from a text and outputs them separated by commas." : "Extrai temas de um texto e os exibe separados por vírgulas.", "File is currently busy, please try again later" : "O arquivo está ocupado, tente novamente mais tarde", - "Cannot download file" : "Não é possível baixar o arquivo" + "Cannot download file" : "Não é possível baixar o arquivo", + "Login is too long" : "Login é muito longo" }, "nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/pt_BR.json b/lib/l10n/pt_BR.json index cf58327d3ee..3c28e56e91d 100644 --- a/lib/l10n/pt_BR.json +++ b/lib/l10n/pt_BR.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "Um Login válido deve ser fornecido", "Login contains whitespace at the beginning or at the end" : "O login contém espaços em branco no início ou no final", "Login must not consist of dots only" : "O login não deve consistir apenas de pontos", - "Login is too long" : "Login é muito longo", + "Username is too long" : "O nome de usuário é muito longo", "Login is invalid because files already exist for this user" : "O login é inválido porque já existem arquivos para este usuário", "Account disabled" : "Conta desativada", "Login canceled by app" : "Login cancelado pelo aplicativo", @@ -299,7 +299,7 @@ "PHP setting \"%s\" is not set to \"%s\"." : "Configuração PHP \"%s\" não está configurado para \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ajustar a configuração no php.ini fará com que o Nextcloud execute novamente", "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> está configurado para <code>%s</code> em vez do valor esperado <code>0</code>.", - "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para corrigir este conjunto de problemas <code>mbstring.func_overload</code> para <code>0</code> no seu php.ini.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para corrigir esse problema, defina <code>mbstring.func_overload</code> como <code>0</code> em seu php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP aparentemente está configurado para retirar blocos doc inline. Isso fará com que vários aplicativos do núcleo fiquem inacessíveis.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isso provavelmente é causado por um cache/acelerador, como Zend OPcache ou eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Módulos do PHP foram instalados, mas eles ainda estão listados como faltantes?", @@ -323,9 +323,9 @@ "Storage connection error. %s" : "Erro na conexão de armazenamento. %s", "Storage is temporarily not available" : "Armazenamento temporariamente indisponível", "Storage connection timeout. %s" : "Atingido o tempo limite de conexão ao armazenamento. %s", - "To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule." : "Para permitir que esta verificação seja executada, você deve certificar-se de que seu servidor Web pode se conectar a si mesmo. Portanto, ele deve ser capaz de resolver e conectar-se a pelo menos um de seus `trusted_domains` ou `overwrite.cli.url`. Essa falha pode ser o resultado de uma incompatibilidade de DNS no servidor ou de uma regra de firewall de saída.", + "To allow this check to run you have to make sure that your Web server can connect to itself. Therefore it must be able to resolve and connect to at least one of its `trusted_domains` or the `overwrite.cli.url`. This failure may be the result of a server-side DNS mismatch or outbound firewall rule." : "Para permitir que esta verificação seja executada, você deve certificar-se de que seu servidor web pode se conectar a si mesmo. Portanto, ele deve ser capaz de resolver e conectar a pelo menos um de seus `trusted_domains` ou `overwrite.cli.url`. Esta falha pode ser o resultado de uma incompatibilidade de DNS no servidor ou de uma regra de firewall de saída.", "Transcribe audio" : "Transcrever áudio", - "Transcribe the things said in an audio" : "Transcreva as coisas ditas em um áudio", + "Transcribe the things said in an audio" : "Transcrever o que foi dito em um áudio", "Audio input" : "Entrada de áudio", "The audio to transcribe" : "O áudio a ser transcrito", "Transcription" : "Transcrição", @@ -343,7 +343,7 @@ "Send this along with the next interaction." : "Envie isso junto com a próxima interação.", "Requested actions by the agent" : "Ações solicitadas pelo agente", "Actions that the agent would like to carry out in JSON format." : "Ações que o agente gostaria de realizar no formato JSON.", - "Context write" : "Gravação de contexto", + "Context write" : "Escrita contextual", "Writes text in a given style based on the provided source material." : "Escreve texto em um determinado estilo com base no material de origem fornecido.", "Writing style" : "Estilo de escrita", "Demonstrate a writing style that you would like to immitate" : "Demonstre um estilo de escrita que você gostaria de imitar", @@ -353,7 +353,7 @@ "The generated text with content from the source material in the given style" : "O texto gerado com conteúdo do material de origem no estilo determinado", "Emoji generator" : "Gerador de emojis", "Takes text and generates a representative emoji for it." : "Pega texto e gera um emoji representativo para ele.", - "The text to generate an emoji for" : "O texto para gerar um emoji para", + "The text to generate an emoji for" : "O texto para o qual gerar um emoji", "Generated emoji" : "Emoji gerado", "The generated emoji based on the input text" : "O emoji gerado com base no texto de entrada", "Generate image" : "Gerar imagem", @@ -361,7 +361,7 @@ "Prompt" : "Prompt", "Describe the image you want to generate" : "Descreva a imagem que você deseja gerar", "Number of images" : "Número de imagens", - "How many images to generate" : "Quantas imagens gerar", + "How many images to generate" : "Quantas imagens devem ser geradas", "Output images" : "Imagens de saída", "The generated images" : "As imagens geradas", "Generate speech" : "Gerar fala", @@ -380,7 +380,7 @@ "Desired tone" : "Tom desejado", "In which tone should your text be rewritten?" : "Em qual tom seu texto deve ser reescrito?", "The rewritten text in the desired tone, written by the assistant:" : "O texto reescrito no tom desejado, escrito pelo assistente:", - "Chat" : "Conversa", + "Chat" : "Bate-papo", "Chat with the assistant" : "Converse com o assistente", "System prompt" : "Prompt do sistema", "Define rules and assumptions that the assistant should follow during the conversation." : "Defina regras e suposições que o assistente deve seguir durante a conversa.", @@ -391,12 +391,12 @@ "Chat with tools" : "Conversar com ferramentas", "Chat with the language model with tool calling support." : "Converse com o modelo de linguagem com suporte a tool calling (\"chamadas a ferramentas\").", "Tool message" : "Mensagem da ferramenta", - "The result of tool calls in the last interaction" : "O resultado das chamadas de ferramentas na última interação", + "The result of tool calls in the last interaction" : "O resultado das chamadas a ferramentas na última interação", "Available tools" : "Ferramentas disponíveis", "The available tools in JSON format" : "As ferramentas disponíveis em formato JSON", "The response from the chat model" : "A resposta do modelo de bate-papo", - "Tool calls" : "Chamadas de ferramentas", - "Tools call instructions from the model in JSON format" : "Instruções de chamada de ferramentas do modelo no formato JSON", + "Tool calls" : "Chamadas a ferramentas", + "Tools call instructions from the model in JSON format" : "Instruções para chamadas a ferramentas do modelo no formato JSON", "Formalize text" : "Formalizar texto", "Takes a text and makes it sound more formal" : "Pega um texto e o faz parecer mais formal", "Write a text that you want the assistant to formalize" : "Escreva um texto que você deseja que o assistente formalize", @@ -405,7 +405,7 @@ "Generate a headline" : "Gere um título", "Generates a possible headline for a text." : "Gera um possível título para um texto.", "Original text" : "Texto original", - "The original text to generate a headline for" : "O texto original para gerar um título para", + "The original text to generate a headline for" : "O texto original para gerar um título", "The generated headline" : "O título gerado", "Proofread" : "Revisar", "Proofreads a text and lists corrections" : "Revisa um texto e lista as correções", @@ -415,11 +415,11 @@ "The corrections that should be made in your text" : "As correções que devem ser feitas em seu texto", "Reformulate text" : "Reformular texto", "Takes a text and reformulates it" : "Pega um texto e o reformula", - "Write a text that you want the assistant to reformulate" : "Escrever um texto que você deseja que o assistente reformule", + "Write a text that you want the assistant to reformulate" : "Escreva um texto que você deseja que o assistente reformule", "Reformulated text" : "Texto reformulado", - "The reformulated text, written by the assistant" : "O texto reformulado, escrito pela assistente", + "The reformulated text, written by the assistant" : "O texto reformulado, escrito pelo assistente", "Simplify text" : "Simplificar texto", - "Takes a text and simplifies it" : "Pega e simplifica um texto", + "Takes a text and simplifies it" : "Pega um texto e o simplifica", "Write a text that you want the assistant to simplify" : "Escreva um texto que você deseja que o assistente simplifique", "Simplified text" : "Texto simplificado", "The simplified text" : "O texto simplificado", @@ -428,11 +428,11 @@ "The original text to summarize" : "O texto original para resumir", "Summary" : "Resumo", "The generated summary" : "O resumo gerado", - "Extract topics" : "Extrair tópicos", - "Extracts topics from a text and outputs them separated by commas" : "Extrai tópicos de um texto e os exibe separados por vírgulas", - "The original text to extract topics from" : "O texto original para extrair tópicos de", - "Topics" : "Tópicos", - "The list of extracted topics" : "A lista de tópicos extraídos", + "Extract topics" : "Extrair temas", + "Extracts topics from a text and outputs them separated by commas" : "Extrai temas de um texto e os exibe separados por vírgulas", + "The original text to extract topics from" : "O texto original do qual extrair temas", + "Topics" : "Temas", + "The list of extracted topics" : "A lista de temas extraídos", "Translate" : "Traduzir", "Translate text from one language to another" : "Traduzir um texto de um idioma para outro", "Origin text" : "Texto original", @@ -444,11 +444,12 @@ "Result" : "Resultado", "The translated text" : "O texto traduzido", "Free prompt" : "Prompt livre", - "Runs an arbitrary prompt through the language model." : "Executa um prompt arbitrário por meio do modelo de idioma.", + "Runs an arbitrary prompt through the language model." : "Executa um prompt arbitrário por meio do modelo de linguagem.", "Generate headline" : "Gerar título", "Summarizes text by reducing its length without losing key information." : "Resume o texto reduzindo seu comprimento sem perder informações importantes.", - "Extracts topics from a text and outputs them separated by commas." : "Extrai tópicos de um texto e os gera separados por vírgulas.", + "Extracts topics from a text and outputs them separated by commas." : "Extrai temas de um texto e os exibe separados por vírgulas.", "File is currently busy, please try again later" : "O arquivo está ocupado, tente novamente mais tarde", - "Cannot download file" : "Não é possível baixar o arquivo" + "Cannot download file" : "Não é possível baixar o arquivo", + "Login is too long" : "Login é muito longo" },"pluralForm" :"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" }
\ No newline at end of file diff --git a/lib/l10n/pt_PT.js b/lib/l10n/pt_PT.js index dabcf027355..937cd4b983a 100644 --- a/lib/l10n/pt_PT.js +++ b/lib/l10n/pt_PT.js @@ -56,6 +56,8 @@ OC.L10N.register( "Empty file" : "Ficheiro vazio", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Módulo com ID: %s não existe. Por favor ative-o nas definições da aplicação ou contacte o administrador.", "Dot files are not allowed" : "Ficheiros dot não são permitidos", + "%1$s (renamed)" : "%1$s (renomeado)", + "renamed file" : "ficheiro renomeado", "File already exists" : "O ficheiro já existe", "Invalid path" : "Caminho inválido!", "Failed to create file from template" : "Erro ao criar o ficheiro a partir do modelo", @@ -69,6 +71,7 @@ OC.L10N.register( "Apps" : "Apps", "Settings" : "Definições", "Log out" : "Sair", + "Accounts" : "Contas", "Email" : "E-mail", "Mail %s" : "Mensagem para %s", "Phone" : "Telefone", diff --git a/lib/l10n/pt_PT.json b/lib/l10n/pt_PT.json index 6aeeff65c0b..d8955a0796a 100644 --- a/lib/l10n/pt_PT.json +++ b/lib/l10n/pt_PT.json @@ -54,6 +54,8 @@ "Empty file" : "Ficheiro vazio", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Módulo com ID: %s não existe. Por favor ative-o nas definições da aplicação ou contacte o administrador.", "Dot files are not allowed" : "Ficheiros dot não são permitidos", + "%1$s (renamed)" : "%1$s (renomeado)", + "renamed file" : "ficheiro renomeado", "File already exists" : "O ficheiro já existe", "Invalid path" : "Caminho inválido!", "Failed to create file from template" : "Erro ao criar o ficheiro a partir do modelo", @@ -67,6 +69,7 @@ "Apps" : "Apps", "Settings" : "Definições", "Log out" : "Sair", + "Accounts" : "Contas", "Email" : "E-mail", "Mail %s" : "Mensagem para %s", "Phone" : "Telefone", diff --git a/lib/l10n/ru.js b/lib/l10n/ru.js index 1fa28c281be..92337e27833 100644 --- a/lib/l10n/ru.js +++ b/lib/l10n/ru.js @@ -38,6 +38,7 @@ OC.L10N.register( "Server version %s or higher is required." : "Требуется сервер версии %s или выше.", "Server version %s or lower is required." : "Требуется сервер версии %s или ниже.", "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Для доступа к этой настройке зарегистрированная учетная запись должна быть администратором, субадминистратором или иметь специальные права", + "Your current IP address doesn't allow you to perform admin actions" : "Ваш текущий IP-адрес не позволяет вам выполнять действия администратора.", "Logged in account must be an admin or sub admin" : "Зарегистрированная учетная запись должна быть администратором или субадминистратором", "Logged in account must be an admin" : "Вошедший в систему пользователь должен быть администратором", "Wiping of device %s has started" : "Удаление данных с устройства «%s».", @@ -58,7 +59,11 @@ OC.L10N.register( "Avatar image is not square" : "Изображение аватара не квадратное", "Files" : "Файлы", "View profile" : "Открыть профиль", + "same time" : "в то же время", "_%nh_::_%nh_" : ["%nч","%nч","%nч","%nч"], + "_%nm_::_%nm_" : ["%nм","%nм","%n м","%n м"], + "%s ahead" : "%s вперёд", + "%s behind" : "%s позади", "Local time: %s" : "Местное время: %s", "today" : "сегодня", "tomorrow" : "завтра", @@ -86,7 +91,10 @@ OC.L10N.register( "Destination does not match conversion extension" : "Назначение не соответствует расширению преобразования", "Could not convert file" : "Не удалось преобразовать файл", "Destination does not exist" : "Пункт назначения не существует", + "Destination is not creatable" : "Место назначения не может быть создано", "Dot files are not allowed" : "Файлы начинающиеся с точки не допускаются", + "%1$s (renamed)" : "%1$s (переименовано)", + "renamed file" : "переименованный файл", "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" это запрещенное имя файла или папки.", "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" является запрещенным префиксом для имен файлов или папок.", "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" не допускается указывать имя файла или папки внутри него.", @@ -97,6 +105,13 @@ OC.L10N.register( "Invalid path" : "Некорректный путь", "Failed to create file from template" : "Не удалось создать файл на основе шаблона", "Templates" : "Шаблоны", + "Storage %s cannot be moved" : "Хранилище %s не может быть перемещено", + "Moving a share (%s) into a shared folder is not allowed" : "Перемещение общего ресурса (%s) в общую папку запрещено", + "Moving a storage (%s) into a shared folder is not allowed" : "Перемещение хранилища (%s) в общую папку запрещено", + "Moving a share (%s) into another share (%s) is not allowed" : "Перемещение общего ресурса (%s) в другой общий ресурс (%s) запрещено", + "Moving a share (%s) into another storage (%s) is not allowed" : "Перемещение общего ресурса (%s) в другое хранилище (%s) запрещено", + "Moving a storage (%s) into a share (%s) is not allowed" : "Перемещение хранилища (%s) в общий ресурс (%s) запрещено", + "Moving a storage (%s) into another storage (%s) is not allowed" : "Перемещение хранилища (%s) в другое хранилище (%s) запрещено", "Path contains invalid segments" : "Путь содержит недопустимые сегменты", "Filename is a reserved word" : "Имя файла - это зарезервированное слово", "Filename contains at least one invalid character" : "Имя файла содержит как минимум один недопустимый символ", @@ -143,6 +158,7 @@ OC.L10N.register( "Oracle connection could not be established" : "Соединение с Oracle не может быть установлено", "Oracle Login and/or password not valid" : "Неверный логин и/или пароль Oracle", "PostgreSQL Login and/or password not valid" : "Неверный логин и/или пароль для PostgreSQL", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk!" : "Mac OS X не поддерживается, и %s может работать некорректно на этой платформе. Используйте на свой страх и риск!", "For the best results, please consider using a GNU/Linux server instead." : "Для достижения наилучших результатов, рассмотрите вариант использования сервера на GNU/Linux.", "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "Кажется что экземпляр этого %s работает в 32-битной среде PHP и в php.ini был настроен open_basedir. Это приведёт к проблемам с файлами более 4 ГБ и настоятельно не рекомендуется.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Удалите директиву open_basedir из файла php.ini или смените PHP на 64-разрядную сборку.", @@ -152,13 +168,27 @@ OC.L10N.register( "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Бэкенд общего доступа %s должен реализовывать интерфейс OCP\\Share_Backend", "Sharing backend %s not found" : "Механизм предоставления общего доступа %s не найден", "Sharing backend for %s not found" : "Не найден механизм предоставления общего доступа для %s ", + "%1$s shared %2$s with you" : "%1$s поделился(ась) %2$s с вами", "Open %s" : "Открыть %s", "%1$s via %2$s" : "%1$s через %2$s", + "%1$s shared %2$s with you and wants to add:" : "%1$s поделился(ась) %2$s с вами и хочет добавить:", + "%1$s shared %2$s with you and wants to add" : "%1$s поделился(ась) %2$s с вами и хочет добавить", + "%s added a note to a file shared with you" : "%s добавил(а) заметку к файлу, которым поделился(ась) с вами", "Passwords are enforced for link and mail shares" : "Для общих ссылок и почтовых рассылок применяются пароли", + "Share recipient is not a valid user" : "Получатель общего ресурса — некорректный пользователь", + "Share recipient is not a valid group" : "Получатель общего ресурса — некорректная группа", + "Share recipient should be empty" : "Получатель общего ресурса должен быть пустым", + "Share recipient should not be empty" : "Получатель общего ресурса не должен быть пустым", + "Share recipient is not a valid circle" : "Получатель общего ресурса — некорректный круг", "Unknown share type" : "Общий доступ неизвестного типа", + "Share initiator must be set" : "Должен быть задан инициатор общего ресурса", "Cannot share with yourself" : "Не могу поделиться с самим собой", + "Shared path must be set" : "Должен быть указан путь к общему ресурсу", + "Shared path must be either a file or a folder" : "Путь должен указывать на файл или папку", "You cannot share your root folder" : "Вы не можете предоставить общий доступ к своей корневой папке", "You are not allowed to share %s" : "Вам не разрешено делиться %s", + "Valid permissions are required for sharing" : "Для общего ресурса необходимы корректные права", + "File shares cannot have create or delete permissions" : "Для файловых общих ресурсов нельзя задавать права доступа на создание или удаление", "Cannot increase permissions of %s" : "Не удалось повысить права доступа %s", "Shares need at least read permissions" : "Общим ресурсам требуются как минимум разрешения на чтение", "Files cannot be shared with delete permissions" : "Права на удаление файлов не позволяют открывать общий доступ к ним", @@ -173,6 +203,7 @@ OC.L10N.register( "Path is already shared with this group" : "Путь уже является общим для этой группы", "Link sharing is not allowed" : "Обмен ссылками запрещен", "Public upload is not allowed" : "Публичная загрузка данных запрещена", + "You cannot share a folder that contains other shares" : "Нельзя делиться папкой, содержащей другие общие ресурсы", "Sharing is disabled" : "Общий доступ отключен", "Sharing is disabled for you" : "Общий доступ для вас отключен", "Cannot share with the share owner" : "Невозможно поделиться с владельцем общего доступа", @@ -184,6 +215,7 @@ OC.L10N.register( "Cannot disable sending the password by Talk without setting a new password" : "Невозможно отключить отправку пароля по телефону без установки нового пароля", "Share provider does not support accepting" : "Поставщик общего доступа не поддерживает прием", "Cannot change target of link share" : "Невозможно изменить цель публикации ссылки", + "Invalid share recipient" : "Некорректный получатель общего ресурса", "Group \"%s\" does not exist" : "Группа \"%s\" не существует", "The requested share does not exist anymore" : "Запрошенный общий ресурс более не существует.", "The requested share comes from a disabled user" : "Запрос на общий доступ поступает от отключенного пользователя", @@ -243,6 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Необходимо указать действительный логин для входа в систему", "Login contains whitespace at the beginning or at the end" : "Имя пользователя содержит пробелы в начале или в конце", "Login must not consist of dots only" : "Логин не должен состоять только из точек", + "Username is too long" : "Имя пользователя слишком длинное", "Login is invalid because files already exist for this user" : "Логин недействителен, поскольку файлы для этого пользователя уже существуют", "Account disabled" : "Учетная запись отключена", "Login canceled by app" : "Вход отменен приложением", @@ -299,10 +332,19 @@ OC.L10N.register( "The audio to transcribe" : "Аудио для расшифровки", "Transcription" : "Транскрипция", "The transcribed text" : "Расшифрованный текст", + "Chat with an agent" : "Чат с агентом", "Chat message" : "Сообщение в чате", + "A chat message to send to the agent." : "Сообщение для отправки агенту", "Confirmation" : "Подтверждение", + "Whether to confirm previously requested actions: 0 for denial and 1 for confirmation." : "Подтвердить ранее запрошенные действия: 0 — отказ, 1 — подтверждение.", + "Conversation token" : "Токен беседы", + "A token representing the conversation." : "Токен, представляющий беседу.", "Generated response" : "Сгенерированный ответ", "The response from the chat model." : "Ответ от модели чата.", + "The new conversation token" : "Новый токен беседы", + "Send this along with the next interaction." : "Отправьте его при следующем взаимодействии.", + "Requested actions by the agent" : "Запрошенные действия от агента", + "Actions that the agent would like to carry out in JSON format." : "Действия, которые агент хотел бы выполнить в формате JSON.", "Context write" : "Контекстная запись", "Writes text in a given style based on the provided source material." : "Пишет текст в заданном стиле на основе предоставленного исходного материала.", "Writing style" : "Стиль письма", @@ -313,18 +355,33 @@ OC.L10N.register( "The generated text with content from the source material in the given style" : "Сгенерированный текст с содержимым из исходного материала в заданном стиле", "Emoji generator" : "Генератор Emoji", "Takes text and generates a representative emoji for it." : "Берет текст и генерирует для него репрезентативный смайлик.", + "The text to generate an emoji for" : "Текст для создания эмодзи", + "Generated emoji" : "Созданный эмодзи", + "The generated emoji based on the input text" : "Эмодзи, созданный на основе введённого текста", "Generate image" : "Генерировать изображение", "Generate an image from a text prompt" : "Создайте изображение из текстовой подсказки", + "Prompt" : "Подсказка", "Describe the image you want to generate" : "Опишите изображение, которое вы хотите создать", "Number of images" : "Количество изображений", "How many images to generate" : "Сколько изображений генерировать", "Output images" : "Выходные изображения", "The generated images" : "Сгенерированные изображения", + "Generate speech" : "Сгенерировать речь", + "Generate speech from a transcript" : "Сгенерировать речь из транскрипта", + "Write transcript that you want the assistant to generate speech from" : "Введите транскрипт, по которому ассистент должен сгенерировать речь", + "Output speech" : "Выходное аудио", + "The generated speech" : "Сгенерированная речь", "Free text to text prompt" : "Произвольное преобразование текста в текстовую подсказку", "Runs an arbitrary prompt through a language model that returns a reply" : "Запускает произвольный запрос с помощью языковой модели, которая возвращает ответ", "Describe a task that you want the assistant to do or ask a question" : "Опишите задачу, которую вы хотите поручить ассистенту, или задайте вопрос", "Generated reply" : "Сгенерированный ответ", "The generated text from the assistant" : "Сгенерированный текст от помощника", + "Change Tone" : "Сменить тон", + "Change the tone of a piece of text." : "Изменить тон текста", + "Write a text that you want the assistant to rewrite in another tone." : "Напишите текст, чтобы ассистент переписал его в другом тоне.", + "Desired tone" : "Желаемый тон", + "In which tone should your text be rewritten?" : "В каком тоне следует переписать ваш текст?", + "The rewritten text in the desired tone, written by the assistant:" : "Переписанный текст в нужном тоне, написанный ассистентом:", "Chat" : "Разговор", "Chat with the assistant" : "Пообщайтесь с ассистентом", "System prompt" : "Системная подсказка", @@ -333,7 +390,15 @@ OC.L10N.register( "The history of chat messages before the current message, starting with a message by the user" : "История сообщений в чате до текущего сообщения, начиная с сообщения пользователя", "Response message" : "Ответное сообщение", "The generated response as part of the conversation" : "Сгенерированный ответ в ходе беседы", + "Chat with tools" : "Чат с инструментами", + "Chat with the language model with tool calling support." : "Чат с языковой моделью с поддержкой вызова инструментов.", + "Tool message" : "Сообщение инструмента", + "The result of tool calls in the last interaction" : "Результат вызова инструментов в последнем взаимодействии", + "Available tools" : "Доступные инструменты", + "The available tools in JSON format" : "Доступные инструменты в формате JSON", "The response from the chat model" : "Ответ от чат-модели", + "Tool calls" : "Вызовы инструментов", + "Tools call instructions from the model in JSON format" : "Инструкции по вызову инструментов от модели в формате JSON", "Formalize text" : "Формализовать текст", "Takes a text and makes it sound more formal" : "Берется текст и делает его звучание более формальным", "Write a text that you want the assistant to formalize" : "Напишите текст, который вы хотите, чтобы ассистент оформил официально", @@ -344,7 +409,12 @@ OC.L10N.register( "Original text" : "Оригинальный текст", "The original text to generate a headline for" : "Исходный текст для создания заголовка для", "The generated headline" : "Сгенерированный заголовок", + "Proofread" : "Проверка правописания", + "Proofreads a text and lists corrections" : "Проверяет текст и показывает исправления", "Text" : "Текст", + "The text to proofread" : "Текст для проверки", + "Corrections" : "Исправления", + "The corrections that should be made in your text" : "Исправления, которые следует внести в ваш текст", "Reformulate text" : "Переформулировать текст", "Takes a text and reformulates it" : "Берет текст и переформулирует его", "Write a text that you want the assistant to reformulate" : "Напишите текст, который вы хотите, чтобы ассистент переформулировал", @@ -381,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Обобщает текст, сокращая его длину без потери ключевой информации.", "Extracts topics from a text and outputs them separated by commas." : "Извлекает темы из текста и выводит их через запятую.", "File is currently busy, please try again later" : "Файл в данный момент используется, повторите попытку позже.", - "Cannot download file" : "Не удалось скачать файл" + "Cannot download file" : "Не удалось скачать файл", + "Login is too long" : "Имя пользователя слишком длинное" }, "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"); diff --git a/lib/l10n/ru.json b/lib/l10n/ru.json index 3266d0f6088..590ad80b5b7 100644 --- a/lib/l10n/ru.json +++ b/lib/l10n/ru.json @@ -36,6 +36,7 @@ "Server version %s or higher is required." : "Требуется сервер версии %s или выше.", "Server version %s or lower is required." : "Требуется сервер версии %s или ниже.", "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Для доступа к этой настройке зарегистрированная учетная запись должна быть администратором, субадминистратором или иметь специальные права", + "Your current IP address doesn't allow you to perform admin actions" : "Ваш текущий IP-адрес не позволяет вам выполнять действия администратора.", "Logged in account must be an admin or sub admin" : "Зарегистрированная учетная запись должна быть администратором или субадминистратором", "Logged in account must be an admin" : "Вошедший в систему пользователь должен быть администратором", "Wiping of device %s has started" : "Удаление данных с устройства «%s».", @@ -56,7 +57,11 @@ "Avatar image is not square" : "Изображение аватара не квадратное", "Files" : "Файлы", "View profile" : "Открыть профиль", + "same time" : "в то же время", "_%nh_::_%nh_" : ["%nч","%nч","%nч","%nч"], + "_%nm_::_%nm_" : ["%nм","%nм","%n м","%n м"], + "%s ahead" : "%s вперёд", + "%s behind" : "%s позади", "Local time: %s" : "Местное время: %s", "today" : "сегодня", "tomorrow" : "завтра", @@ -84,7 +89,10 @@ "Destination does not match conversion extension" : "Назначение не соответствует расширению преобразования", "Could not convert file" : "Не удалось преобразовать файл", "Destination does not exist" : "Пункт назначения не существует", + "Destination is not creatable" : "Место назначения не может быть создано", "Dot files are not allowed" : "Файлы начинающиеся с точки не допускаются", + "%1$s (renamed)" : "%1$s (переименовано)", + "renamed file" : "переименованный файл", "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" это запрещенное имя файла или папки.", "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" является запрещенным префиксом для имен файлов или папок.", "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" не допускается указывать имя файла или папки внутри него.", @@ -95,6 +103,13 @@ "Invalid path" : "Некорректный путь", "Failed to create file from template" : "Не удалось создать файл на основе шаблона", "Templates" : "Шаблоны", + "Storage %s cannot be moved" : "Хранилище %s не может быть перемещено", + "Moving a share (%s) into a shared folder is not allowed" : "Перемещение общего ресурса (%s) в общую папку запрещено", + "Moving a storage (%s) into a shared folder is not allowed" : "Перемещение хранилища (%s) в общую папку запрещено", + "Moving a share (%s) into another share (%s) is not allowed" : "Перемещение общего ресурса (%s) в другой общий ресурс (%s) запрещено", + "Moving a share (%s) into another storage (%s) is not allowed" : "Перемещение общего ресурса (%s) в другое хранилище (%s) запрещено", + "Moving a storage (%s) into a share (%s) is not allowed" : "Перемещение хранилища (%s) в общий ресурс (%s) запрещено", + "Moving a storage (%s) into another storage (%s) is not allowed" : "Перемещение хранилища (%s) в другое хранилище (%s) запрещено", "Path contains invalid segments" : "Путь содержит недопустимые сегменты", "Filename is a reserved word" : "Имя файла - это зарезервированное слово", "Filename contains at least one invalid character" : "Имя файла содержит как минимум один недопустимый символ", @@ -141,6 +156,7 @@ "Oracle connection could not be established" : "Соединение с Oracle не может быть установлено", "Oracle Login and/or password not valid" : "Неверный логин и/или пароль Oracle", "PostgreSQL Login and/or password not valid" : "Неверный логин и/или пароль для PostgreSQL", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk!" : "Mac OS X не поддерживается, и %s может работать некорректно на этой платформе. Используйте на свой страх и риск!", "For the best results, please consider using a GNU/Linux server instead." : "Для достижения наилучших результатов, рассмотрите вариант использования сервера на GNU/Linux.", "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "Кажется что экземпляр этого %s работает в 32-битной среде PHP и в php.ini был настроен open_basedir. Это приведёт к проблемам с файлами более 4 ГБ и настоятельно не рекомендуется.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Удалите директиву open_basedir из файла php.ini или смените PHP на 64-разрядную сборку.", @@ -150,13 +166,27 @@ "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Бэкенд общего доступа %s должен реализовывать интерфейс OCP\\Share_Backend", "Sharing backend %s not found" : "Механизм предоставления общего доступа %s не найден", "Sharing backend for %s not found" : "Не найден механизм предоставления общего доступа для %s ", + "%1$s shared %2$s with you" : "%1$s поделился(ась) %2$s с вами", "Open %s" : "Открыть %s", "%1$s via %2$s" : "%1$s через %2$s", + "%1$s shared %2$s with you and wants to add:" : "%1$s поделился(ась) %2$s с вами и хочет добавить:", + "%1$s shared %2$s with you and wants to add" : "%1$s поделился(ась) %2$s с вами и хочет добавить", + "%s added a note to a file shared with you" : "%s добавил(а) заметку к файлу, которым поделился(ась) с вами", "Passwords are enforced for link and mail shares" : "Для общих ссылок и почтовых рассылок применяются пароли", + "Share recipient is not a valid user" : "Получатель общего ресурса — некорректный пользователь", + "Share recipient is not a valid group" : "Получатель общего ресурса — некорректная группа", + "Share recipient should be empty" : "Получатель общего ресурса должен быть пустым", + "Share recipient should not be empty" : "Получатель общего ресурса не должен быть пустым", + "Share recipient is not a valid circle" : "Получатель общего ресурса — некорректный круг", "Unknown share type" : "Общий доступ неизвестного типа", + "Share initiator must be set" : "Должен быть задан инициатор общего ресурса", "Cannot share with yourself" : "Не могу поделиться с самим собой", + "Shared path must be set" : "Должен быть указан путь к общему ресурсу", + "Shared path must be either a file or a folder" : "Путь должен указывать на файл или папку", "You cannot share your root folder" : "Вы не можете предоставить общий доступ к своей корневой папке", "You are not allowed to share %s" : "Вам не разрешено делиться %s", + "Valid permissions are required for sharing" : "Для общего ресурса необходимы корректные права", + "File shares cannot have create or delete permissions" : "Для файловых общих ресурсов нельзя задавать права доступа на создание или удаление", "Cannot increase permissions of %s" : "Не удалось повысить права доступа %s", "Shares need at least read permissions" : "Общим ресурсам требуются как минимум разрешения на чтение", "Files cannot be shared with delete permissions" : "Права на удаление файлов не позволяют открывать общий доступ к ним", @@ -171,6 +201,7 @@ "Path is already shared with this group" : "Путь уже является общим для этой группы", "Link sharing is not allowed" : "Обмен ссылками запрещен", "Public upload is not allowed" : "Публичная загрузка данных запрещена", + "You cannot share a folder that contains other shares" : "Нельзя делиться папкой, содержащей другие общие ресурсы", "Sharing is disabled" : "Общий доступ отключен", "Sharing is disabled for you" : "Общий доступ для вас отключен", "Cannot share with the share owner" : "Невозможно поделиться с владельцем общего доступа", @@ -182,6 +213,7 @@ "Cannot disable sending the password by Talk without setting a new password" : "Невозможно отключить отправку пароля по телефону без установки нового пароля", "Share provider does not support accepting" : "Поставщик общего доступа не поддерживает прием", "Cannot change target of link share" : "Невозможно изменить цель публикации ссылки", + "Invalid share recipient" : "Некорректный получатель общего ресурса", "Group \"%s\" does not exist" : "Группа \"%s\" не существует", "The requested share does not exist anymore" : "Запрошенный общий ресурс более не существует.", "The requested share comes from a disabled user" : "Запрос на общий доступ поступает от отключенного пользователя", @@ -241,6 +273,7 @@ "A valid Login must be provided" : "Необходимо указать действительный логин для входа в систему", "Login contains whitespace at the beginning or at the end" : "Имя пользователя содержит пробелы в начале или в конце", "Login must not consist of dots only" : "Логин не должен состоять только из точек", + "Username is too long" : "Имя пользователя слишком длинное", "Login is invalid because files already exist for this user" : "Логин недействителен, поскольку файлы для этого пользователя уже существуют", "Account disabled" : "Учетная запись отключена", "Login canceled by app" : "Вход отменен приложением", @@ -297,10 +330,19 @@ "The audio to transcribe" : "Аудио для расшифровки", "Transcription" : "Транскрипция", "The transcribed text" : "Расшифрованный текст", + "Chat with an agent" : "Чат с агентом", "Chat message" : "Сообщение в чате", + "A chat message to send to the agent." : "Сообщение для отправки агенту", "Confirmation" : "Подтверждение", + "Whether to confirm previously requested actions: 0 for denial and 1 for confirmation." : "Подтвердить ранее запрошенные действия: 0 — отказ, 1 — подтверждение.", + "Conversation token" : "Токен беседы", + "A token representing the conversation." : "Токен, представляющий беседу.", "Generated response" : "Сгенерированный ответ", "The response from the chat model." : "Ответ от модели чата.", + "The new conversation token" : "Новый токен беседы", + "Send this along with the next interaction." : "Отправьте его при следующем взаимодействии.", + "Requested actions by the agent" : "Запрошенные действия от агента", + "Actions that the agent would like to carry out in JSON format." : "Действия, которые агент хотел бы выполнить в формате JSON.", "Context write" : "Контекстная запись", "Writes text in a given style based on the provided source material." : "Пишет текст в заданном стиле на основе предоставленного исходного материала.", "Writing style" : "Стиль письма", @@ -311,18 +353,33 @@ "The generated text with content from the source material in the given style" : "Сгенерированный текст с содержимым из исходного материала в заданном стиле", "Emoji generator" : "Генератор Emoji", "Takes text and generates a representative emoji for it." : "Берет текст и генерирует для него репрезентативный смайлик.", + "The text to generate an emoji for" : "Текст для создания эмодзи", + "Generated emoji" : "Созданный эмодзи", + "The generated emoji based on the input text" : "Эмодзи, созданный на основе введённого текста", "Generate image" : "Генерировать изображение", "Generate an image from a text prompt" : "Создайте изображение из текстовой подсказки", + "Prompt" : "Подсказка", "Describe the image you want to generate" : "Опишите изображение, которое вы хотите создать", "Number of images" : "Количество изображений", "How many images to generate" : "Сколько изображений генерировать", "Output images" : "Выходные изображения", "The generated images" : "Сгенерированные изображения", + "Generate speech" : "Сгенерировать речь", + "Generate speech from a transcript" : "Сгенерировать речь из транскрипта", + "Write transcript that you want the assistant to generate speech from" : "Введите транскрипт, по которому ассистент должен сгенерировать речь", + "Output speech" : "Выходное аудио", + "The generated speech" : "Сгенерированная речь", "Free text to text prompt" : "Произвольное преобразование текста в текстовую подсказку", "Runs an arbitrary prompt through a language model that returns a reply" : "Запускает произвольный запрос с помощью языковой модели, которая возвращает ответ", "Describe a task that you want the assistant to do or ask a question" : "Опишите задачу, которую вы хотите поручить ассистенту, или задайте вопрос", "Generated reply" : "Сгенерированный ответ", "The generated text from the assistant" : "Сгенерированный текст от помощника", + "Change Tone" : "Сменить тон", + "Change the tone of a piece of text." : "Изменить тон текста", + "Write a text that you want the assistant to rewrite in another tone." : "Напишите текст, чтобы ассистент переписал его в другом тоне.", + "Desired tone" : "Желаемый тон", + "In which tone should your text be rewritten?" : "В каком тоне следует переписать ваш текст?", + "The rewritten text in the desired tone, written by the assistant:" : "Переписанный текст в нужном тоне, написанный ассистентом:", "Chat" : "Разговор", "Chat with the assistant" : "Пообщайтесь с ассистентом", "System prompt" : "Системная подсказка", @@ -331,7 +388,15 @@ "The history of chat messages before the current message, starting with a message by the user" : "История сообщений в чате до текущего сообщения, начиная с сообщения пользователя", "Response message" : "Ответное сообщение", "The generated response as part of the conversation" : "Сгенерированный ответ в ходе беседы", + "Chat with tools" : "Чат с инструментами", + "Chat with the language model with tool calling support." : "Чат с языковой моделью с поддержкой вызова инструментов.", + "Tool message" : "Сообщение инструмента", + "The result of tool calls in the last interaction" : "Результат вызова инструментов в последнем взаимодействии", + "Available tools" : "Доступные инструменты", + "The available tools in JSON format" : "Доступные инструменты в формате JSON", "The response from the chat model" : "Ответ от чат-модели", + "Tool calls" : "Вызовы инструментов", + "Tools call instructions from the model in JSON format" : "Инструкции по вызову инструментов от модели в формате JSON", "Formalize text" : "Формализовать текст", "Takes a text and makes it sound more formal" : "Берется текст и делает его звучание более формальным", "Write a text that you want the assistant to formalize" : "Напишите текст, который вы хотите, чтобы ассистент оформил официально", @@ -342,7 +407,12 @@ "Original text" : "Оригинальный текст", "The original text to generate a headline for" : "Исходный текст для создания заголовка для", "The generated headline" : "Сгенерированный заголовок", + "Proofread" : "Проверка правописания", + "Proofreads a text and lists corrections" : "Проверяет текст и показывает исправления", "Text" : "Текст", + "The text to proofread" : "Текст для проверки", + "Corrections" : "Исправления", + "The corrections that should be made in your text" : "Исправления, которые следует внести в ваш текст", "Reformulate text" : "Переформулировать текст", "Takes a text and reformulates it" : "Берет текст и переформулирует его", "Write a text that you want the assistant to reformulate" : "Напишите текст, который вы хотите, чтобы ассистент переформулировал", @@ -379,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Обобщает текст, сокращая его длину без потери ключевой информации.", "Extracts topics from a text and outputs them separated by commas." : "Извлекает темы из текста и выводит их через запятую.", "File is currently busy, please try again later" : "Файл в данный момент используется, повторите попытку позже.", - "Cannot download file" : "Не удалось скачать файл" + "Cannot download file" : "Не удалось скачать файл", + "Login is too long" : "Имя пользователя слишком длинное" },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);" }
\ No newline at end of file diff --git a/lib/l10n/sr.js b/lib/l10n/sr.js index 6760be8e4a9..bea3ea369a6 100644 --- a/lib/l10n/sr.js +++ b/lib/l10n/sr.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Морате да унесете исправно име за пријаву", "Login contains whitespace at the beginning or at the end" : "Име за пријаву садржи белине на почетку или на крају", "Login must not consist of dots only" : "Име за пријаву не може да се састоји само од тачака", - "Login is too long" : "Име за пријаву је сувише дугачко", + "Username is too long" : "Корисничко име је сувише дугачко", "Login is invalid because files already exist for this user" : "Име за пријаву није исправно пошто већ постоје фајлови овог корисника", "Account disabled" : "Налог је искључен", "Login canceled by app" : "Пријава отказана од стране апликације", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Резимира текст тако што га скраћује без губитка кључних информација.", "Extracts topics from a text and outputs them separated by commas." : "Издваја теме из текста и исписује их раздвојене запетама.", "File is currently busy, please try again later" : "Фајл је тренутно заузет, покушајте поново касније", - "Cannot download file" : "Фајл не може да се преузме" + "Cannot download file" : "Фајл не може да се преузме", + "Login is too long" : "Име за пријаву је сувише дугачко" }, "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"); diff --git a/lib/l10n/sr.json b/lib/l10n/sr.json index 42ad00dc46d..a9b9e940482 100644 --- a/lib/l10n/sr.json +++ b/lib/l10n/sr.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "Морате да унесете исправно име за пријаву", "Login contains whitespace at the beginning or at the end" : "Име за пријаву садржи белине на почетку или на крају", "Login must not consist of dots only" : "Име за пријаву не може да се састоји само од тачака", - "Login is too long" : "Име за пријаву је сувише дугачко", + "Username is too long" : "Корисничко име је сувише дугачко", "Login is invalid because files already exist for this user" : "Име за пријаву није исправно пошто већ постоје фајлови овог корисника", "Account disabled" : "Налог је искључен", "Login canceled by app" : "Пријава отказана од стране апликације", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Резимира текст тако што га скраћује без губитка кључних информација.", "Extracts topics from a text and outputs them separated by commas." : "Издваја теме из текста и исписује их раздвојене запетама.", "File is currently busy, please try again later" : "Фајл је тренутно заузет, покушајте поново касније", - "Cannot download file" : "Фајл не може да се преузме" + "Cannot download file" : "Фајл не може да се преузме", + "Login is too long" : "Име за пријаву је сувише дугачко" },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }
\ No newline at end of file diff --git a/lib/l10n/sv.js b/lib/l10n/sv.js index 121a87b137b..77c836b42d3 100644 --- a/lib/l10n/sv.js +++ b/lib/l10n/sv.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "En giltig inloggning måste anges", "Login contains whitespace at the beginning or at the end" : "Inloggningen innehåller blanksteg i början eller slutet", "Login must not consist of dots only" : "Inloggningen får inte innehålla enbart punkter", - "Login is too long" : "Inloggningen är för lång", + "Username is too long" : "Användarnamnet är för långt", "Login is invalid because files already exist for this user" : "Inloggningen är ogiltigt eftersom det redan finns filer för den här användaren", "Account disabled" : "Konto inaktiverat", "Login canceled by app" : "Inloggningen avbruten av appen", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Sammanfattar text genom att minska dess längd utan att förlora viktig information.", "Extracts topics from a text and outputs them separated by commas." : "Extraherar ämnen från en text och matar ut dem separerade med kommatecken.", "File is currently busy, please try again later" : "Filen är för tillfället upptagen, försök igen senare", - "Cannot download file" : "Kan inte ladda ner fil" + "Cannot download file" : "Kan inte ladda ner fil", + "Login is too long" : "Inloggningen är för lång" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/sv.json b/lib/l10n/sv.json index 7c44fef111a..f4eb5f933f3 100644 --- a/lib/l10n/sv.json +++ b/lib/l10n/sv.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "En giltig inloggning måste anges", "Login contains whitespace at the beginning or at the end" : "Inloggningen innehåller blanksteg i början eller slutet", "Login must not consist of dots only" : "Inloggningen får inte innehålla enbart punkter", - "Login is too long" : "Inloggningen är för lång", + "Username is too long" : "Användarnamnet är för långt", "Login is invalid because files already exist for this user" : "Inloggningen är ogiltigt eftersom det redan finns filer för den här användaren", "Account disabled" : "Konto inaktiverat", "Login canceled by app" : "Inloggningen avbruten av appen", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Sammanfattar text genom att minska dess längd utan att förlora viktig information.", "Extracts topics from a text and outputs them separated by commas." : "Extraherar ämnen från en text och matar ut dem separerade med kommatecken.", "File is currently busy, please try again later" : "Filen är för tillfället upptagen, försök igen senare", - "Cannot download file" : "Kan inte ladda ner fil" + "Cannot download file" : "Kan inte ladda ner fil", + "Login is too long" : "Inloggningen är för lång" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/sw.js b/lib/l10n/sw.js new file mode 100644 index 00000000000..1e14a7e863a --- /dev/null +++ b/lib/l10n/sw.js @@ -0,0 +1,41 @@ +OC.L10N.register( + "lib", + { + "Authentication" : "Uthibitisho", + "Unknown filetype" : "Aina ya faili haijulikani", + "Invalid image" : "Taswira si halisi", + "Files" : "Mafaili", + "View profile" : "Angalia wasifu", + "Local time: %s" : "Muda wa kawaida: %s", + "_%n year ago_::_%n years ago_" : ["%n year ago","%n years ago"], + "seconds ago" : "sukunde zilizopita", + "%1$s (renamed)" : "%1$s (iliyopew jina jipya)", + "renamed file" : "Faili iliyopewa jina jipya", + "Filenames must not end with \"%1$s\"." : "Majina ya faili hayapaswi kuishia na \"%1$s\"", + "File already exists" : "Faili lipo tayari", + "Templates" : "Violezo", + "Apps" : "Maombi", + "Settings" : "Mipangilio", + "Log out" : "Ondoka", + "Accounts" : "Akaunti", + "Email" : "Barua pepe", + "Phone" : "Simu", + "Twitter" : "Twitter", + "Website" : "Wavuti", + "Address" : "Anwani", + "About" : "Kuhusu", + "Additional settings" : "Mipangilio ya nyongeza", + "Sunday" : "Jumapili", + "Monday" : "Jumatatu", + "Tuesday" : "Jumanne", + "Wednesday" : "Jumatano", + "Thursday" : "Alhamisi", + "Friday" : "Ijumaa", + "Saturday" : "Jumamosi", + "Storage is temporarily not available" : "Uhifadhi haupo kwa muda", + "Confirmation" : "Uthibitisho", + "Text" : "Maandishi", + "Summary" : "Muhtasari", + "Translate" : "Tafsiri" +}, +"nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/sw.json b/lib/l10n/sw.json new file mode 100644 index 00000000000..a4d0bdc97d8 --- /dev/null +++ b/lib/l10n/sw.json @@ -0,0 +1,39 @@ +{ "translations": { + "Authentication" : "Uthibitisho", + "Unknown filetype" : "Aina ya faili haijulikani", + "Invalid image" : "Taswira si halisi", + "Files" : "Mafaili", + "View profile" : "Angalia wasifu", + "Local time: %s" : "Muda wa kawaida: %s", + "_%n year ago_::_%n years ago_" : ["%n year ago","%n years ago"], + "seconds ago" : "sukunde zilizopita", + "%1$s (renamed)" : "%1$s (iliyopew jina jipya)", + "renamed file" : "Faili iliyopewa jina jipya", + "Filenames must not end with \"%1$s\"." : "Majina ya faili hayapaswi kuishia na \"%1$s\"", + "File already exists" : "Faili lipo tayari", + "Templates" : "Violezo", + "Apps" : "Maombi", + "Settings" : "Mipangilio", + "Log out" : "Ondoka", + "Accounts" : "Akaunti", + "Email" : "Barua pepe", + "Phone" : "Simu", + "Twitter" : "Twitter", + "Website" : "Wavuti", + "Address" : "Anwani", + "About" : "Kuhusu", + "Additional settings" : "Mipangilio ya nyongeza", + "Sunday" : "Jumapili", + "Monday" : "Jumatatu", + "Tuesday" : "Jumanne", + "Wednesday" : "Jumatano", + "Thursday" : "Alhamisi", + "Friday" : "Ijumaa", + "Saturday" : "Jumamosi", + "Storage is temporarily not available" : "Uhifadhi haupo kwa muda", + "Confirmation" : "Uthibitisho", + "Text" : "Maandishi", + "Summary" : "Muhtasari", + "Translate" : "Tafsiri" +},"pluralForm" :"nplurals=2; plural=(n != 1);" +}
\ No newline at end of file diff --git a/lib/l10n/tr.js b/lib/l10n/tr.js index 76f8d0b1e1b..5f28ef658ab 100644 --- a/lib/l10n/tr.js +++ b/lib/l10n/tr.js @@ -83,7 +83,7 @@ OC.L10N.register( "_in %n minute_::_in %n minutes_" : ["%n dakika içinde","%n dakika içinde"], "_%n minute ago_::_%n minutes ago_" : ["%n dakika önce","%n dakika önce"], "in a few seconds" : "bir kaç saniye içinde", - "seconds ago" : "saniyeler önce", + "seconds ago" : "saniye önce", "Empty file" : "Dosya boş", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "%s kimlikli modül bulunamadı. Lütfen uygulamalarınız içinden modülü kullanıma alın ya da BT yöneticiniz ile görüşün.", "No file conversion providers available" : "Kullanılabilecek bir dosya dönüştürücü hizmeti sağlayıcı yok", @@ -93,6 +93,8 @@ OC.L10N.register( "Destination does not exist" : "Hedef bulunamadı", "Destination is not creatable" : "Hedef oluşturulamadı", "Dot files are not allowed" : "Nokta dosyalarına izin verilmiyor", + "%1$s (renamed)" : "%1$s (yeniden adlandırıldı)", + "renamed file" : "dosyayı yeniden adlandırdı", "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" dosya ya da klasör adı olarak kullanılamaz.", "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" dosya ya da klasör adı ön eki olarak kullanılamaz.", "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" bir dosya ya da klasör adında kullanılamaz.", @@ -163,16 +165,16 @@ OC.L10N.register( "Set an admin Login." : "Bir yönetici kullanıcı adı yazın.", "Set an admin password." : "Bir yönetici parolası yazın.", "Cannot create or write into the data directory %s" : "%s veri klasörü oluşturulamadı ya da içine yazılamadı", - "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Paylaşım arka ucu %s OCP\\Share_Backend arayüzünü desteklemeli", - "Sharing backend %s not found" : "%s paylaşım arka ucu bulunamadı", - "Sharing backend for %s not found" : "%s için paylaşım arka ucu bulunamadı", + "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Paylaşım arka yüzü %s OCP\\Share_Backend arayüzünü desteklemeli", + "Sharing backend %s not found" : "%s paylaşım arka yüzü bulunamadı", + "Sharing backend for %s not found" : "%s için paylaşım arka yüzü bulunamadı", "%1$s shared %2$s with you" : "%1$s, sizinle %2$s ögesini paylaştı", "Open %s" : "%s ögesini aç", "%1$s via %2$s" : "%1$s, %2$s aracılığıyla", "%1$s shared %2$s with you and wants to add:" : "%1$s sizinle %2$s ögesini paylaştı ve eklemenizi istiyor:", "%1$s shared %2$s with you and wants to add" : "%1$s sizinle %2$s ögesini paylaştı ve eklemenizi istiyor", "%s added a note to a file shared with you" : "%s sizinle paylaştığı bir dosyaya bir not ekledi", - "Passwords are enforced for link and mail shares" : "Bağlantı ve e-posta paylaşımları için parolalar zorunludur", + "Passwords are enforced for link and mail shares" : "Bağlantı ve e-posta paylaşımları için parola kullanılması zorunlu kılınmış", "Share recipient is not a valid user" : "Paylaşım alıcısı geçerli bir kullanıcı değil", "Share recipient is not a valid group" : "Paylaşım alıcısı geçerli bir grup değil", "Share recipient should be empty" : "Paylaşım alıcısı boş olmalı", @@ -192,7 +194,7 @@ OC.L10N.register( "Files cannot be shared with delete permissions" : "Silme izni ile dosya paylaşılamaz", "Files cannot be shared with create permissions" : "Ekleme izni ile dosya paylaşılamaz", "Expiration date is in the past" : "Geçerlilik sonu tarihi geçmişte", - "Expiration date is enforced" : "Geçerlilik sonu tarihi dayatılıyor", + "Expiration date is enforced" : "Geçerlilik sonu tarihi zorunlu kılınmış", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Paylaşımların geçerlilik süreleri, gelecekte %n günden fazla olamaz","Paylaşımların geçerlilik süreleri, gelecekte %n günden fazla olamaz"], "Sharing is only allowed with group members" : "Paylaşım yalnızca grup üyeleri ile yapılabilir", "Sharing %s failed, because this item is already shared with the account %s" : "%s paylaşılamadı. Bu öge zaten %s hesabı ile paylaşılmış", @@ -208,9 +210,9 @@ OC.L10N.register( "Share does not have a full ID" : "Paylaşımın tam kimliği yok", "Cannot change share type" : "Paylaşım türü değiştirilemez", "Can only update recipient on user shares" : "Yalnızca kullanıcı paylaşımlarındaki alıcıyı güncelleyebilir", - "Cannot enable sending the password by Talk with an empty password" : "Boş bir parola ile Sohbet uygulaması ile parola gönderme özelliği kullanıma alınamaz", - "Cannot enable sending the password by Talk without setting a new password" : "Yeni bir parola ayarlanmadan Sohbet uygulaması ile parola gönderme özelliği kullanıma alınamaz", - "Cannot disable sending the password by Talk without setting a new password" : "Yeni bir parola ayarlanmadan Sohbet uygulaması ile parola gönderme kullanımdan kaldırılamaz", + "Cannot enable sending the password by Talk with an empty password" : "Boş bir parola kullanarak Konuş uygulaması ile parola gönderme özelliği açılamaz", + "Cannot enable sending the password by Talk without setting a new password" : "Yeni bir parola ayarlanmadan Konuş uygulaması ile parola gönderme özelliği açılamaz", + "Cannot disable sending the password by Talk without setting a new password" : "Yeni bir parola ayarlanmadan Konuş uygulaması ile parola gönderme özelliği kapatılamaz", "Share provider does not support accepting" : "Paylaşım hizmeti sağlayıcısı kabul etmeyi desteklemiyor", "Cannot change target of link share" : "Bağlantı paylaşımının hedefi değiştirilemedi", "Invalid share recipient" : "Paylaşım alıcısı geçersiz", @@ -273,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Geçerli bir kullanıcı adı yazmalısınız", "Login contains whitespace at the beginning or at the end" : "Kullanıcı adının başında ya da sonunda boşluk var", "Login must not consist of dots only" : "Kullanıcı adı yalnızca noktalardan oluşamaz", - "Login is too long" : "Kullanıcı adı çok uzun", + "Username is too long" : "Kullanıcı adı çok uzun", "Login is invalid because files already exist for this user" : "Kullanıcı adı geçersiz, bu kullanıcı için zaten bazı dosyalar var", "Account disabled" : "Hesap kullanımdan kaldırılmış", "Login canceled by app" : "Oturum açma uygulama tarafından iptal edildi", @@ -364,6 +366,11 @@ OC.L10N.register( "How many images to generate" : "Oluşturulacak görsel sayısı", "Output images" : "Çıktı görselleri", "The generated images" : "Oluşturulan görseller", + "Generate speech" : "Konuşma oluştur", + "Generate speech from a transcript" : "Bir yazıya dönüştürmeden konuşma oluştur", + "Write transcript that you want the assistant to generate speech from" : "Yardımcının konuşma oluşturmasını istediğiniz yazı dönüştürmesini yazın", + "Output speech" : "Konuşma çıktısı", + "The generated speech" : "Oluşturulan konuşma", "Free text to text prompt" : "Ücretsiz yazıdan yazıya istemi", "Runs an arbitrary prompt through a language model that returns a reply" : "Dil modeli ile bir yanıt döndüren isteğe bağlı bir bilgi istemi çalıştırır", "Describe a task that you want the assistant to do or ask a question" : "Yardımcının yapmasını istediğiniz bir görevi tanımlayın ya da bir soru sorun", @@ -444,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Temel içeriği kaybetmeden uzunluğunu kısaltarak metni özetler.", "Extracts topics from a text and outputs them separated by commas." : "Bir metindeki konuları ayıklar ve bunları virgül ile ayırarak sıralar.", "File is currently busy, please try again later" : "Dosya şu anda meşgul. Lütfen bir süre sonra yeniden deneyin", - "Cannot download file" : "Dosya indirilemedi" + "Cannot download file" : "Dosya indirilemedi", + "Login is too long" : "Kullanıcı adı çok uzun" }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/tr.json b/lib/l10n/tr.json index 5161808df23..2e46571c57f 100644 --- a/lib/l10n/tr.json +++ b/lib/l10n/tr.json @@ -81,7 +81,7 @@ "_in %n minute_::_in %n minutes_" : ["%n dakika içinde","%n dakika içinde"], "_%n minute ago_::_%n minutes ago_" : ["%n dakika önce","%n dakika önce"], "in a few seconds" : "bir kaç saniye içinde", - "seconds ago" : "saniyeler önce", + "seconds ago" : "saniye önce", "Empty file" : "Dosya boş", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "%s kimlikli modül bulunamadı. Lütfen uygulamalarınız içinden modülü kullanıma alın ya da BT yöneticiniz ile görüşün.", "No file conversion providers available" : "Kullanılabilecek bir dosya dönüştürücü hizmeti sağlayıcı yok", @@ -91,6 +91,8 @@ "Destination does not exist" : "Hedef bulunamadı", "Destination is not creatable" : "Hedef oluşturulamadı", "Dot files are not allowed" : "Nokta dosyalarına izin verilmiyor", + "%1$s (renamed)" : "%1$s (yeniden adlandırıldı)", + "renamed file" : "dosyayı yeniden adlandırdı", "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" dosya ya da klasör adı olarak kullanılamaz.", "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" dosya ya da klasör adı ön eki olarak kullanılamaz.", "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" bir dosya ya da klasör adında kullanılamaz.", @@ -161,16 +163,16 @@ "Set an admin Login." : "Bir yönetici kullanıcı adı yazın.", "Set an admin password." : "Bir yönetici parolası yazın.", "Cannot create or write into the data directory %s" : "%s veri klasörü oluşturulamadı ya da içine yazılamadı", - "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Paylaşım arka ucu %s OCP\\Share_Backend arayüzünü desteklemeli", - "Sharing backend %s not found" : "%s paylaşım arka ucu bulunamadı", - "Sharing backend for %s not found" : "%s için paylaşım arka ucu bulunamadı", + "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Paylaşım arka yüzü %s OCP\\Share_Backend arayüzünü desteklemeli", + "Sharing backend %s not found" : "%s paylaşım arka yüzü bulunamadı", + "Sharing backend for %s not found" : "%s için paylaşım arka yüzü bulunamadı", "%1$s shared %2$s with you" : "%1$s, sizinle %2$s ögesini paylaştı", "Open %s" : "%s ögesini aç", "%1$s via %2$s" : "%1$s, %2$s aracılığıyla", "%1$s shared %2$s with you and wants to add:" : "%1$s sizinle %2$s ögesini paylaştı ve eklemenizi istiyor:", "%1$s shared %2$s with you and wants to add" : "%1$s sizinle %2$s ögesini paylaştı ve eklemenizi istiyor", "%s added a note to a file shared with you" : "%s sizinle paylaştığı bir dosyaya bir not ekledi", - "Passwords are enforced for link and mail shares" : "Bağlantı ve e-posta paylaşımları için parolalar zorunludur", + "Passwords are enforced for link and mail shares" : "Bağlantı ve e-posta paylaşımları için parola kullanılması zorunlu kılınmış", "Share recipient is not a valid user" : "Paylaşım alıcısı geçerli bir kullanıcı değil", "Share recipient is not a valid group" : "Paylaşım alıcısı geçerli bir grup değil", "Share recipient should be empty" : "Paylaşım alıcısı boş olmalı", @@ -190,7 +192,7 @@ "Files cannot be shared with delete permissions" : "Silme izni ile dosya paylaşılamaz", "Files cannot be shared with create permissions" : "Ekleme izni ile dosya paylaşılamaz", "Expiration date is in the past" : "Geçerlilik sonu tarihi geçmişte", - "Expiration date is enforced" : "Geçerlilik sonu tarihi dayatılıyor", + "Expiration date is enforced" : "Geçerlilik sonu tarihi zorunlu kılınmış", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Paylaşımların geçerlilik süreleri, gelecekte %n günden fazla olamaz","Paylaşımların geçerlilik süreleri, gelecekte %n günden fazla olamaz"], "Sharing is only allowed with group members" : "Paylaşım yalnızca grup üyeleri ile yapılabilir", "Sharing %s failed, because this item is already shared with the account %s" : "%s paylaşılamadı. Bu öge zaten %s hesabı ile paylaşılmış", @@ -206,9 +208,9 @@ "Share does not have a full ID" : "Paylaşımın tam kimliği yok", "Cannot change share type" : "Paylaşım türü değiştirilemez", "Can only update recipient on user shares" : "Yalnızca kullanıcı paylaşımlarındaki alıcıyı güncelleyebilir", - "Cannot enable sending the password by Talk with an empty password" : "Boş bir parola ile Sohbet uygulaması ile parola gönderme özelliği kullanıma alınamaz", - "Cannot enable sending the password by Talk without setting a new password" : "Yeni bir parola ayarlanmadan Sohbet uygulaması ile parola gönderme özelliği kullanıma alınamaz", - "Cannot disable sending the password by Talk without setting a new password" : "Yeni bir parola ayarlanmadan Sohbet uygulaması ile parola gönderme kullanımdan kaldırılamaz", + "Cannot enable sending the password by Talk with an empty password" : "Boş bir parola kullanarak Konuş uygulaması ile parola gönderme özelliği açılamaz", + "Cannot enable sending the password by Talk without setting a new password" : "Yeni bir parola ayarlanmadan Konuş uygulaması ile parola gönderme özelliği açılamaz", + "Cannot disable sending the password by Talk without setting a new password" : "Yeni bir parola ayarlanmadan Konuş uygulaması ile parola gönderme özelliği kapatılamaz", "Share provider does not support accepting" : "Paylaşım hizmeti sağlayıcısı kabul etmeyi desteklemiyor", "Cannot change target of link share" : "Bağlantı paylaşımının hedefi değiştirilemedi", "Invalid share recipient" : "Paylaşım alıcısı geçersiz", @@ -271,7 +273,7 @@ "A valid Login must be provided" : "Geçerli bir kullanıcı adı yazmalısınız", "Login contains whitespace at the beginning or at the end" : "Kullanıcı adının başında ya da sonunda boşluk var", "Login must not consist of dots only" : "Kullanıcı adı yalnızca noktalardan oluşamaz", - "Login is too long" : "Kullanıcı adı çok uzun", + "Username is too long" : "Kullanıcı adı çok uzun", "Login is invalid because files already exist for this user" : "Kullanıcı adı geçersiz, bu kullanıcı için zaten bazı dosyalar var", "Account disabled" : "Hesap kullanımdan kaldırılmış", "Login canceled by app" : "Oturum açma uygulama tarafından iptal edildi", @@ -362,6 +364,11 @@ "How many images to generate" : "Oluşturulacak görsel sayısı", "Output images" : "Çıktı görselleri", "The generated images" : "Oluşturulan görseller", + "Generate speech" : "Konuşma oluştur", + "Generate speech from a transcript" : "Bir yazıya dönüştürmeden konuşma oluştur", + "Write transcript that you want the assistant to generate speech from" : "Yardımcının konuşma oluşturmasını istediğiniz yazı dönüştürmesini yazın", + "Output speech" : "Konuşma çıktısı", + "The generated speech" : "Oluşturulan konuşma", "Free text to text prompt" : "Ücretsiz yazıdan yazıya istemi", "Runs an arbitrary prompt through a language model that returns a reply" : "Dil modeli ile bir yanıt döndüren isteğe bağlı bir bilgi istemi çalıştırır", "Describe a task that you want the assistant to do or ask a question" : "Yardımcının yapmasını istediğiniz bir görevi tanımlayın ya da bir soru sorun", @@ -442,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "Temel içeriği kaybetmeden uzunluğunu kısaltarak metni özetler.", "Extracts topics from a text and outputs them separated by commas." : "Bir metindeki konuları ayıklar ve bunları virgül ile ayırarak sıralar.", "File is currently busy, please try again later" : "Dosya şu anda meşgul. Lütfen bir süre sonra yeniden deneyin", - "Cannot download file" : "Dosya indirilemedi" + "Cannot download file" : "Dosya indirilemedi", + "Login is too long" : "Kullanıcı adı çok uzun" },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/lib/l10n/uk.js b/lib/l10n/uk.js index 21ba04ce6dc..b92f38a5f57 100644 --- a/lib/l10n/uk.js +++ b/lib/l10n/uk.js @@ -93,6 +93,8 @@ OC.L10N.register( "Destination does not exist" : "Призначення відсутнє", "Destination is not creatable" : "Неможливо створити призначення", "Dot files are not allowed" : "Файли які починаються з крапки не допустимі", + "%1$s (renamed)" : "%1$s (перейменовано)", + "renamed file" : "перейменовано файл", "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" є недозволеним ім'ям файлів або каталогів.", "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" є недозволеним префіксом у іменах файлів або каталоів.", "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" не дозволено всередині імени файлів або каталогів.", @@ -273,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "Зазначте дійсне ім'я користувача", "Login contains whitespace at the beginning or at the end" : "Ім'я користувача містить символ пробілу на початку або наприкінці", "Login must not consist of dots only" : "Ім'я користувача не може складатися лише з крапок", - "Login is too long" : "Ім'я користувача для авторизації задовге", + "Username is too long" : "Ім'я користувача задовге", "Login is invalid because files already exist for this user" : "Недійсне ім'я облікового запису, оскільки файли для цього користувача вже присутні", "Account disabled" : "Обліковий запис вимкнено", "Login canceled by app" : "Вхід скасовано застосунком", @@ -355,6 +357,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Викокремлює головне у тексті шляхом зменшення довжини тексту без втрати ключової інформації.", "Extracts topics from a text and outputs them separated by commas." : "Виділяє теми, які висвітлює текст, зводить їх у перелік, що розділено комами.", "File is currently busy, please try again later" : "Файл на разі зайнятий, будь ласка, спробуйте пізніше", - "Cannot download file" : "Неможливо звантажити файл" + "Cannot download file" : "Неможливо звантажити файл", + "Login is too long" : "Ім'я користувача для авторизації задовге" }, "nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);"); diff --git a/lib/l10n/uk.json b/lib/l10n/uk.json index 208494144e3..e091c070aa7 100644 --- a/lib/l10n/uk.json +++ b/lib/l10n/uk.json @@ -91,6 +91,8 @@ "Destination does not exist" : "Призначення відсутнє", "Destination is not creatable" : "Неможливо створити призначення", "Dot files are not allowed" : "Файли які починаються з крапки не допустимі", + "%1$s (renamed)" : "%1$s (перейменовано)", + "renamed file" : "перейменовано файл", "\"%1$s\" is a forbidden file or folder name." : "\"%1$s\" є недозволеним ім'ям файлів або каталогів.", "\"%1$s\" is a forbidden prefix for file or folder names." : "\"%1$s\" є недозволеним префіксом у іменах файлів або каталоів.", "\"%1$s\" is not allowed inside a file or folder name." : "\"%1$s\" не дозволено всередині імени файлів або каталогів.", @@ -271,7 +273,7 @@ "A valid Login must be provided" : "Зазначте дійсне ім'я користувача", "Login contains whitespace at the beginning or at the end" : "Ім'я користувача містить символ пробілу на початку або наприкінці", "Login must not consist of dots only" : "Ім'я користувача не може складатися лише з крапок", - "Login is too long" : "Ім'я користувача для авторизації задовге", + "Username is too long" : "Ім'я користувача задовге", "Login is invalid because files already exist for this user" : "Недійсне ім'я облікового запису, оскільки файли для цього користувача вже присутні", "Account disabled" : "Обліковий запис вимкнено", "Login canceled by app" : "Вхід скасовано застосунком", @@ -353,6 +355,7 @@ "Summarizes text by reducing its length without losing key information." : "Викокремлює головне у тексті шляхом зменшення довжини тексту без втрати ключової інформації.", "Extracts topics from a text and outputs them separated by commas." : "Виділяє теми, які висвітлює текст, зводить їх у перелік, що розділено комами.", "File is currently busy, please try again later" : "Файл на разі зайнятий, будь ласка, спробуйте пізніше", - "Cannot download file" : "Неможливо звантажити файл" + "Cannot download file" : "Неможливо звантажити файл", + "Login is too long" : "Ім'я користувача для авторизації задовге" },"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);" }
\ No newline at end of file diff --git a/lib/l10n/zh_CN.js b/lib/l10n/zh_CN.js index d4684c4b96a..7a2f7cca2a4 100644 --- a/lib/l10n/zh_CN.js +++ b/lib/l10n/zh_CN.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "必须提供有效的登录名", "Login contains whitespace at the beginning or at the end" : "登录名开头或结尾包含空格", "Login must not consist of dots only" : "登录名不能仅由点组成", - "Login is too long" : "登录名太长", + "Username is too long" : "用户名太长", "Login is invalid because files already exist for this user" : "登录无效,因为此用户的文件已存在", "Account disabled" : "帐户已禁用", "Login canceled by app" : "已通过应用取消登录", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "总结一段文本以减少长度而不丢失关键信息", "Extracts topics from a text and outputs them separated by commas." : "从文本中摘出主题,输出逗号分隔的结果", "File is currently busy, please try again later" : "文件当前正忙,请稍后再试", - "Cannot download file" : "无法下载文件" + "Cannot download file" : "无法下载文件", + "Login is too long" : "登录名太长" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/zh_CN.json b/lib/l10n/zh_CN.json index 75250cad139..1727656ae7d 100644 --- a/lib/l10n/zh_CN.json +++ b/lib/l10n/zh_CN.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "必须提供有效的登录名", "Login contains whitespace at the beginning or at the end" : "登录名开头或结尾包含空格", "Login must not consist of dots only" : "登录名不能仅由点组成", - "Login is too long" : "登录名太长", + "Username is too long" : "用户名太长", "Login is invalid because files already exist for this user" : "登录无效,因为此用户的文件已存在", "Account disabled" : "帐户已禁用", "Login canceled by app" : "已通过应用取消登录", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "总结一段文本以减少长度而不丢失关键信息", "Extracts topics from a text and outputs them separated by commas." : "从文本中摘出主题,输出逗号分隔的结果", "File is currently busy, please try again later" : "文件当前正忙,请稍后再试", - "Cannot download file" : "无法下载文件" + "Cannot download file" : "无法下载文件", + "Login is too long" : "登录名太长" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/zh_HK.js b/lib/l10n/zh_HK.js index 7e94d5fb9cc..17c629aba08 100644 --- a/lib/l10n/zh_HK.js +++ b/lib/l10n/zh_HK.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "必須提供有效帳戶", "Login contains whitespace at the beginning or at the end" : "帳戶的開頭或結尾有空白", "Login must not consist of dots only" : "帳戶不能只包含小數點", - "Login is too long" : "帳號太長了", + "Username is too long" : "用戶名稱太長", "Login is invalid because files already exist for this user" : "帳戶無效,因為此用戶的檔案已經存在", "Account disabled" : "帳戶已停用", "Login canceled by app" : "登入已被應用程式取消", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "通過減少文字長度來總結而不丟失關鍵資訊。", "Extracts topics from a text and outputs them separated by commas." : "從文字中提取主題並輸出,並用逗號分隔。", "File is currently busy, please try again later" : "檔案目前忙碌中,請稍候再試", - "Cannot download file" : "無法下載檔案" + "Cannot download file" : "無法下載檔案", + "Login is too long" : "帳號太長了" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/zh_HK.json b/lib/l10n/zh_HK.json index fd28486dccb..b2ef29118b8 100644 --- a/lib/l10n/zh_HK.json +++ b/lib/l10n/zh_HK.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "必須提供有效帳戶", "Login contains whitespace at the beginning or at the end" : "帳戶的開頭或結尾有空白", "Login must not consist of dots only" : "帳戶不能只包含小數點", - "Login is too long" : "帳號太長了", + "Username is too long" : "用戶名稱太長", "Login is invalid because files already exist for this user" : "帳戶無效,因為此用戶的檔案已經存在", "Account disabled" : "帳戶已停用", "Login canceled by app" : "登入已被應用程式取消", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "通過減少文字長度來總結而不丟失關鍵資訊。", "Extracts topics from a text and outputs them separated by commas." : "從文字中提取主題並輸出,並用逗號分隔。", "File is currently busy, please try again later" : "檔案目前忙碌中,請稍候再試", - "Cannot download file" : "無法下載檔案" + "Cannot download file" : "無法下載檔案", + "Login is too long" : "帳號太長了" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/zh_TW.js b/lib/l10n/zh_TW.js index 39bf221f009..196cb52767f 100644 --- a/lib/l10n/zh_TW.js +++ b/lib/l10n/zh_TW.js @@ -275,7 +275,7 @@ OC.L10N.register( "A valid Login must be provided" : "必須提供有效帳號", "Login contains whitespace at the beginning or at the end" : "帳號的開頭或結尾有空白", "Login must not consist of dots only" : "帳號不能只包含小數點", - "Login is too long" : "帳號太長了", + "Username is too long" : "使用者名稱太長了", "Login is invalid because files already exist for this user" : "帳號無效,因為使用者的檔案已經存在", "Account disabled" : "帳號已停用", "Login canceled by app" : "應用程式取消了登入", @@ -451,6 +451,7 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "寫成摘要,減少文字長度而不丟失關鍵資訊。", "Extracts topics from a text and outputs them separated by commas." : "從文字中取出涵蓋的主題並輸出,然後用逗號分隔。", "File is currently busy, please try again later" : "檔案目前忙碌中,請稍候再試", - "Cannot download file" : "無法下載檔案" + "Cannot download file" : "無法下載檔案", + "Login is too long" : "帳號太長了" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/zh_TW.json b/lib/l10n/zh_TW.json index 101da41381b..5bde18ad24d 100644 --- a/lib/l10n/zh_TW.json +++ b/lib/l10n/zh_TW.json @@ -273,7 +273,7 @@ "A valid Login must be provided" : "必須提供有效帳號", "Login contains whitespace at the beginning or at the end" : "帳號的開頭或結尾有空白", "Login must not consist of dots only" : "帳號不能只包含小數點", - "Login is too long" : "帳號太長了", + "Username is too long" : "使用者名稱太長了", "Login is invalid because files already exist for this user" : "帳號無效,因為使用者的檔案已經存在", "Account disabled" : "帳號已停用", "Login canceled by app" : "應用程式取消了登入", @@ -449,6 +449,7 @@ "Summarizes text by reducing its length without losing key information." : "寫成摘要,減少文字長度而不丟失關鍵資訊。", "Extracts topics from a text and outputs them separated by commas." : "從文字中取出涵蓋的主題並輸出,然後用逗號分隔。", "File is currently busy, please try again later" : "檔案目前忙碌中,請稍候再試", - "Cannot download file" : "無法下載檔案" + "Cannot download file" : "無法下載檔案", + "Login is too long" : "帳號太長了" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/private/Accounts/Hooks.php b/lib/private/Accounts/Hooks.php index 0235879e8e7..12f2b4777f8 100644 --- a/lib/private/Accounts/Hooks.php +++ b/lib/private/Accounts/Hooks.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Activity/Event.php b/lib/private/Activity/Event.php index 54274acea6b..39cdc12b3fb 100644 --- a/lib/private/Activity/Event.php +++ b/lib/private/Activity/Event.php @@ -415,8 +415,7 @@ class Event implements IEvent { public function isValid(): bool { return $this->isValidCommon() - && - $this->getSubject() !== '' + && $this->getSubject() !== '' ; } @@ -443,20 +442,16 @@ class Event implements IEvent { return $this->isValidCommon() - && - $this->getParsedSubject() !== '' + && $this->getParsedSubject() !== '' ; } protected function isValidCommon(): bool { return $this->getApp() !== '' - && - $this->getType() !== '' - && - $this->getAffectedUser() !== '' - && - $this->getTimestamp() !== 0 + && $this->getType() !== '' + && $this->getAffectedUser() !== '' + && $this->getTimestamp() !== 0 /** * Disabled for BC with old activities * && diff --git a/lib/private/Activity/EventMerger.php b/lib/private/Activity/EventMerger.php index 504f9088f24..0e7d318103a 100644 --- a/lib/private/Activity/EventMerger.php +++ b/lib/private/Activity/EventMerger.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Activity/Manager.php b/lib/private/Activity/Manager.php index 5c306fe6399..4e10f8a0c1a 100644 --- a/lib/private/Activity/Manager.php +++ b/lib/private/Activity/Manager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/AllConfig.php b/lib/private/AllConfig.php index 72af6c960a5..8a6bb5a4723 100644 --- a/lib/private/AllConfig.php +++ b/lib/private/AllConfig.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index f6494fa946d..1911bce12bf 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -8,6 +9,7 @@ namespace OC\App; use OC\AppConfig; use OC\AppFramework\Bootstrap\Coordinator; +use OC\Config\ConfigManager; use OCP\Activity\IManager as IActivityManager; use OCP\App\AppPathNotFoundException; use OCP\App\Events\AppDisableEvent; @@ -18,6 +20,7 @@ use OCP\Collaboration\AutoComplete\IManager as IAutoCompleteManager; use OCP\Collaboration\Collaborators\ISearch as ICollaboratorSearch; use OCP\Diagnostics\IEventLogger; use OCP\EventDispatcher\IEventDispatcher; +use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IConfig; use OCP\IGroup; @@ -26,6 +29,7 @@ use OCP\INavigationManager; use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserSession; +use OCP\Server; use OCP\ServerVersion; use OCP\Settings\IManager as ISettingsManager; use Psr\Log\LoggerInterface; @@ -81,12 +85,13 @@ class AppManager implements IAppManager { private IEventDispatcher $dispatcher, private LoggerInterface $logger, private ServerVersion $serverVersion, + private ConfigManager $configManager, ) { } private function getNavigationManager(): INavigationManager { if ($this->navigationManager === null) { - $this->navigationManager = \OCP\Server::get(INavigationManager::class); + $this->navigationManager = Server::get(INavigationManager::class); } return $this->navigationManager; } @@ -112,7 +117,7 @@ class AppManager implements IAppManager { if (!$this->config->getSystemValueBool('installed', false)) { throw new \Exception('Nextcloud is not installed yet, AppConfig is not available'); } - $this->appConfig = \OCP\Server::get(AppConfig::class); + $this->appConfig = Server::get(AppConfig::class); return $this->appConfig; } @@ -123,7 +128,7 @@ class AppManager implements IAppManager { if (!$this->config->getSystemValueBool('installed', false)) { throw new \Exception('Nextcloud is not installed yet, AppConfig is not available'); } - $this->urlGenerator = \OCP\Server::get(IURLGenerator::class); + $this->urlGenerator = Server::get(IURLGenerator::class); return $this->urlGenerator; } @@ -134,7 +139,8 @@ class AppManager implements IAppManager { */ private function getEnabledAppsValues(): array { if (!$this->enabledAppsCache) { - $values = $this->getAppConfig()->getValues(false, 'enabled'); + /** @var array<string,string> */ + $values = $this->getAppConfig()->searchValues('enabled', false, IAppConfig::VALUE_STRING); $alwaysEnabledApps = $this->getAlwaysEnabledApps(); foreach ($alwaysEnabledApps as $appId) { @@ -185,9 +191,9 @@ class AppManager implements IAppManager { if (is_resource($dh)) { while (($file = readdir($dh)) !== false) { if ( - $file[0] != '.' && - is_dir($apps_dir['path'] . '/' . $file) && - is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml') + $file[0] != '.' + && is_dir($apps_dir['path'] . '/' . $file) + && is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml') ) { $apps[] = $file; } @@ -202,7 +208,7 @@ class AppManager implements IAppManager { * List all apps enabled for a user * * @param \OCP\IUser $user - * @return string[] + * @return list<string> */ public function getEnabledAppsForUser(IUser $user) { $apps = $this->getEnabledAppsValues(); @@ -457,7 +463,7 @@ class AppManager implements IAppManager { ]); } - $coordinator = \OCP\Server::get(Coordinator::class); + $coordinator = Server::get(Coordinator::class); $coordinator->bootApp($app); $eventLogger->start("bootstrap:load_app:$app:info", "Load info.xml for $app and register any services defined in it"); @@ -507,8 +513,8 @@ class AppManager implements IAppManager { if (!empty($info['collaboration']['plugins'])) { // deal with one or many plugin entries - $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ? - [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin']; + $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) + ? [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin']; $collaboratorSearch = null; $autoCompleteManager = null; foreach ($plugins as $plugin) { @@ -545,11 +551,16 @@ class AppManager implements IAppManager { * @param string $appId * @param bool $forceEnable * @throws AppPathNotFoundException + * @throws \InvalidArgumentException if the application is not installed yet */ public function enableApp(string $appId, bool $forceEnable = false): void { // Check if app exists $this->getAppPath($appId); + if ($this->config->getAppValue($appId, 'installed_version', '') === '') { + throw new \InvalidArgumentException("$appId is not installed, cannot be enabled."); + } + if ($forceEnable) { $this->overwriteNextcloudRequirement($appId); } @@ -561,6 +572,8 @@ class AppManager implements IAppManager { ManagerEvent::EVENT_APP_ENABLE, $appId )); $this->clearAppsCache(); + + $this->configManager->migrateConfigLexiconKeys($appId); } /** @@ -596,6 +609,10 @@ class AppManager implements IAppManager { throw new \InvalidArgumentException("$appId can't be enabled for groups."); } + if ($this->config->getAppValue($appId, 'installed_version', '') === '') { + throw new \InvalidArgumentException("$appId is not installed, cannot be enabled."); + } + if ($forceEnable) { $this->overwriteNextcloudRequirement($appId); } @@ -615,6 +632,8 @@ class AppManager implements IAppManager { ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, $appId, $groups )); $this->clearAppsCache(); + + $this->configManager->migrateConfigLexiconKeys($appId); } /** @@ -775,8 +794,8 @@ class AppManager implements IAppManager { * * @return array<string, string> */ - public function getAppInstalledVersions(): array { - return $this->getAppConfig()->getAppInstalledVersions(); + public function getAppInstalledVersions(bool $onlyEnabled = false): array { + return $this->getAppConfig()->getAppInstalledVersions($onlyEnabled); } /** @@ -812,6 +831,10 @@ class AppManager implements IAppManager { } private function isAlwaysEnabled(string $appId): bool { + if ($appId === 'core') { + return true; + } + $alwaysEnabled = $this->getAlwaysEnabledApps(); return in_array($appId, $alwaysEnabled, true); } diff --git a/lib/private/App/AppStore/AppNotFoundException.php b/lib/private/App/AppStore/AppNotFoundException.php new file mode 100644 index 00000000000..79ceebb4423 --- /dev/null +++ b/lib/private/App/AppStore/AppNotFoundException.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OC\App\AppStore; + +class AppNotFoundException extends \Exception { +} diff --git a/lib/private/App/AppStore/Bundles/Bundle.php b/lib/private/App/AppStore/Bundles/Bundle.php index 62f09b82f79..1443be81e92 100644 --- a/lib/private/App/AppStore/Bundles/Bundle.php +++ b/lib/private/App/AppStore/Bundles/Bundle.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Bundles/BundleFetcher.php b/lib/private/App/AppStore/Bundles/BundleFetcher.php index 01325699e2c..4ff53b0c70b 100644 --- a/lib/private/App/AppStore/Bundles/BundleFetcher.php +++ b/lib/private/App/AppStore/Bundles/BundleFetcher.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Bundles/EducationBundle.php b/lib/private/App/AppStore/Bundles/EducationBundle.php index 6770d4a7091..23681ec7416 100644 --- a/lib/private/App/AppStore/Bundles/EducationBundle.php +++ b/lib/private/App/AppStore/Bundles/EducationBundle.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Bundles/EnterpriseBundle.php b/lib/private/App/AppStore/Bundles/EnterpriseBundle.php index 88a9ec60a00..fc2d43e0388 100644 --- a/lib/private/App/AppStore/Bundles/EnterpriseBundle.php +++ b/lib/private/App/AppStore/Bundles/EnterpriseBundle.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Bundles/GroupwareBundle.php b/lib/private/App/AppStore/Bundles/GroupwareBundle.php index 7c7b74ff53d..93fa70268cd 100644 --- a/lib/private/App/AppStore/Bundles/GroupwareBundle.php +++ b/lib/private/App/AppStore/Bundles/GroupwareBundle.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Bundles/PublicSectorBundle.php b/lib/private/App/AppStore/Bundles/PublicSectorBundle.php index 158d525bdcc..106a6353029 100644 --- a/lib/private/App/AppStore/Bundles/PublicSectorBundle.php +++ b/lib/private/App/AppStore/Bundles/PublicSectorBundle.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Bundles/SocialSharingBundle.php b/lib/private/App/AppStore/Bundles/SocialSharingBundle.php index 7f925688ca3..40f0fb15977 100644 --- a/lib/private/App/AppStore/Bundles/SocialSharingBundle.php +++ b/lib/private/App/AppStore/Bundles/SocialSharingBundle.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php b/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php index 2537d1dcec9..8389e525750 100644 --- a/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php +++ b/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Fetcher/AppFetcher.php b/lib/private/App/AppStore/Fetcher/AppFetcher.php index 352646c3f5e..bbf4b00245b 100644 --- a/lib/private/App/AppStore/Fetcher/AppFetcher.php +++ b/lib/private/App/AppStore/Fetcher/AppFetcher.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -78,8 +79,8 @@ class AppFetcher extends Fetcher { $minServerVersion = $serverVersion->getMinimumVersion(); $maxServerVersion = $serverVersion->getMaximumVersion(); $minFulfilled = $this->compareVersion->isCompatible($ncVersion, $minServerVersion, '>='); - $maxFulfilled = $maxServerVersion !== '' && - $this->compareVersion->isCompatible($ncVersion, $maxServerVersion, '<='); + $maxFulfilled = $maxServerVersion !== '' + && $this->compareVersion->isCompatible($ncVersion, $maxServerVersion, '<='); $isPhpCompatible = true; if (($release['rawPhpVersionSpec'] ?? '*') !== '*') { $phpVersion = $versionParser->getVersion($release['rawPhpVersionSpec']); diff --git a/lib/private/App/AppStore/Fetcher/CategoryFetcher.php b/lib/private/App/AppStore/Fetcher/CategoryFetcher.php index d72f8fa7e24..d7857d41bee 100644 --- a/lib/private/App/AppStore/Fetcher/CategoryFetcher.php +++ b/lib/private/App/AppStore/Fetcher/CategoryFetcher.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Fetcher/Fetcher.php b/lib/private/App/AppStore/Fetcher/Fetcher.php index f998c9e2023..2e949fedb51 100644 --- a/lib/private/App/AppStore/Fetcher/Fetcher.php +++ b/lib/private/App/AppStore/Fetcher/Fetcher.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Version/Version.php b/lib/private/App/AppStore/Version/Version.php index b7e679d250a..2d169a291f1 100644 --- a/lib/private/App/AppStore/Version/Version.php +++ b/lib/private/App/AppStore/Version/Version.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/AppStore/Version/VersionParser.php b/lib/private/App/AppStore/Version/VersionParser.php index 59715c8d385..8976f28837f 100644 --- a/lib/private/App/AppStore/Version/VersionParser.php +++ b/lib/private/App/AppStore/Version/VersionParser.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/App/DependencyAnalyzer.php b/lib/private/App/DependencyAnalyzer.php index 72b38ca12c7..1e56612132b 100644 --- a/lib/private/App/DependencyAnalyzer.php +++ b/lib/private/App/DependencyAnalyzer.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/App/InfoParser.php b/lib/private/App/InfoParser.php index 6610121f446..e7a75afdf0b 100644 --- a/lib/private/App/InfoParser.php +++ b/lib/private/App/InfoParser.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/App/Platform.php b/lib/private/App/Platform.php index c2c059220c8..80e4cefed64 100644 --- a/lib/private/App/Platform.php +++ b/lib/private/App/Platform.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/App/PlatformRepository.php b/lib/private/App/PlatformRepository.php index 6d9a9cd011a..faed8b07feb 100644 --- a/lib/private/App/PlatformRepository.php +++ b/lib/private/App/PlatformRepository.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php index a8a6f689ffa..476adbb93e0 100644 --- a/lib/private/AppConfig.php +++ b/lib/private/AppConfig.php @@ -15,6 +15,7 @@ use NCU\Config\Lexicon\ConfigLexiconEntry; use NCU\Config\Lexicon\ConfigLexiconStrictness; use NCU\Config\Lexicon\IConfigLexicon; use OC\AppFramework\Bootstrap\Coordinator; +use OC\Config\ConfigManager; use OCP\DB\Exception as DBException; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Exceptions\AppConfigIncorrectTypeException; @@ -24,6 +25,7 @@ use OCP\IAppConfig; use OCP\IConfig; use OCP\IDBConnection; use OCP\Security\ICrypto; +use OCP\Server; use Psr\Log\LoggerInterface; /** @@ -59,8 +61,9 @@ class AppConfig implements IAppConfig { private array $valueTypes = []; // type for all config values private bool $fastLoaded = false; private bool $lazyLoaded = false; - /** @var array<array-key, array{entries: array<array-key, ConfigLexiconEntry>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */ + /** @var array<string, array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */ private array $configLexiconDetails = []; + private bool $ignoreLexiconAliases = false; /** @var ?array<string, string> */ private ?array $appVersionsCache = null; @@ -117,6 +120,7 @@ class AppConfig implements IAppConfig { public function hasKey(string $app, string $key, ?bool $lazy = false): bool { $this->assertParams($app, $key); $this->loadConfig($app, $lazy); + $this->matchAndApplyLexiconDefinition($app, $key); if ($lazy === null) { $appCache = $this->getAllValues($app); @@ -142,6 +146,7 @@ class AppConfig implements IAppConfig { public function isSensitive(string $app, string $key, ?bool $lazy = false): bool { $this->assertParams($app, $key); $this->loadConfig(null, $lazy); + $this->matchAndApplyLexiconDefinition($app, $key); if (!isset($this->valueTypes[$app][$key])) { throw new AppConfigUnknownKeyException('unknown config key'); @@ -162,6 +167,9 @@ class AppConfig implements IAppConfig { * @since 29.0.0 */ public function isLazy(string $app, string $key): bool { + $this->assertParams($app, $key); + $this->matchAndApplyLexiconDefinition($app, $key); + // there is a huge probability the non-lazy config are already loaded if ($this->hasKey($app, $key, false)) { return false; @@ -284,7 +292,7 @@ class AppConfig implements IAppConfig { ): string { try { $lazy = ($lazy === null) ? $this->isLazy($app, $key) : $lazy; - } catch (AppConfigUnknownKeyException $e) { + } catch (AppConfigUnknownKeyException) { return $default; } @@ -429,6 +437,7 @@ class AppConfig implements IAppConfig { int $type, ): string { $this->assertParams($app, $key, valueType: $type); + $origKey = $key; if (!$this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type, $default)) { return $default; // returns default if strictness of lexicon is set to WARNING (block and report) } @@ -469,6 +478,14 @@ class AppConfig implements IAppConfig { $value = $this->crypto->decrypt(substr($value, self::ENCRYPTION_PREFIX_LENGTH)); } + // in case the key was modified while running matchAndApplyLexiconDefinition() we are + // interested to check options in case a modification of the value is needed + // ie inverting value from previous key when using lexicon option RENAME_INVERT_BOOLEAN + if ($origKey !== $key && $type === self::VALUE_BOOL) { + $configManager = Server::get(ConfigManager::class); + $value = ($configManager->convertToBool($value, $this->getLexiconEntry($app, $key))) ? '1' : '0'; + } + return $value; } @@ -798,8 +815,8 @@ class AppConfig implements IAppConfig { * we only accept a different type from the one stored in database * if the one stored in database is not-defined (VALUE_MIXED) */ - if (!$this->isTyped(self::VALUE_MIXED, $currType) && - ($type | self::VALUE_SENSITIVE) !== ($currType | self::VALUE_SENSITIVE)) { + if (!$this->isTyped(self::VALUE_MIXED, $currType) + && ($type | self::VALUE_SENSITIVE) !== ($currType | self::VALUE_SENSITIVE)) { try { $currType = $this->convertTypeToString($currType); $type = $this->convertTypeToString($type); @@ -863,7 +880,8 @@ class AppConfig implements IAppConfig { public function updateType(string $app, string $key, int $type = self::VALUE_MIXED): bool { $this->assertParams($app, $key); $this->loadConfigAll(); - $lazy = $this->isLazy($app, $key); + $this->matchAndApplyLexiconDefinition($app, $key); + $this->isLazy($app, $key); // confirm key exists // type can only be one type if (!in_array($type, [self::VALUE_MIXED, self::VALUE_STRING, self::VALUE_INT, self::VALUE_FLOAT, self::VALUE_BOOL, self::VALUE_ARRAY])) { @@ -905,6 +923,7 @@ class AppConfig implements IAppConfig { public function updateSensitive(string $app, string $key, bool $sensitive): bool { $this->assertParams($app, $key); $this->loadConfigAll(); + $this->matchAndApplyLexiconDefinition($app, $key); try { if ($sensitive === $this->isSensitive($app, $key, null)) { @@ -964,6 +983,7 @@ class AppConfig implements IAppConfig { public function updateLazy(string $app, string $key, bool $lazy): bool { $this->assertParams($app, $key); $this->loadConfigAll(); + $this->matchAndApplyLexiconDefinition($app, $key); try { if ($lazy === $this->isLazy($app, $key)) { @@ -999,6 +1019,7 @@ class AppConfig implements IAppConfig { public function getDetails(string $app, string $key): array { $this->assertParams($app, $key); $this->loadConfigAll(); + $this->matchAndApplyLexiconDefinition($app, $key); $lazy = $this->isLazy($app, $key); if ($lazy) { @@ -1086,6 +1107,8 @@ class AppConfig implements IAppConfig { */ public function deleteKey(string $app, string $key): void { $this->assertParams($app, $key); + $this->matchAndApplyLexiconDefinition($app, $key); + $qb = $this->connection->getQueryBuilder(); $qb->delete('appconfig') ->where($qb->expr()->eq('appid', $qb->createNamedParameter($app))) @@ -1293,6 +1316,7 @@ class AppConfig implements IAppConfig { */ public function getValue($app, $key, $default = null) { $this->loadConfig($app); + $this->matchAndApplyLexiconDefinition($app, $key); return $this->fastCache[$app][$key] ?? $default; } @@ -1372,7 +1396,7 @@ class AppConfig implements IAppConfig { foreach ($values as $key => $value) { try { $type = $this->getValueType($app, $key, $lazy); - } catch (AppConfigUnknownKeyException $e) { + } catch (AppConfigUnknownKeyException) { continue; } @@ -1556,7 +1580,8 @@ class AppConfig implements IAppConfig { } /** - * match and apply current use of config values with defined lexicon + * Match and apply current use of config values with defined lexicon. + * Set $lazy to NULL only if only interested into checking that $key is alias. * * @throws AppConfigUnknownKeyException * @throws AppConfigTypeConflictException @@ -1564,9 +1589,9 @@ class AppConfig implements IAppConfig { */ private function matchAndApplyLexiconDefinition( string $app, - string $key, - bool &$lazy, - int &$type, + string &$key, + ?bool &$lazy = null, + int &$type = self::VALUE_MIXED, string &$default = '', ): bool { if (in_array($key, @@ -1578,11 +1603,18 @@ class AppConfig implements IAppConfig { return true; // we don't break stuff for this list of config keys. } $configDetails = $this->getConfigDetailsFromLexicon($app); + if (array_key_exists($key, $configDetails['aliases']) && !$this->ignoreLexiconAliases) { + // in case '$rename' is set in ConfigLexiconEntry, we use the new config key + $key = $configDetails['aliases'][$key]; + } + if (!array_key_exists($key, $configDetails['entries'])) { - return $this->applyLexiconStrictness( - $configDetails['strictness'], - 'The app config key ' . $app . '/' . $key . ' is not defined in the config lexicon' - ); + return $this->applyLexiconStrictness($configDetails['strictness'], 'The app config key ' . $app . '/' . $key . ' is not defined in the config lexicon'); + } + + // if lazy is NULL, we ignore all check on the type/lazyness/default from Lexicon + if ($lazy === null) { + return true; } /** @var ConfigLexiconEntry $configValue */ @@ -1644,20 +1676,25 @@ class AppConfig implements IAppConfig { * extract details from registered $appId's config lexicon * * @param string $appId + * @internal * - * @return array{entries: array<array-key, ConfigLexiconEntry>, strictness: ConfigLexiconStrictness} + * @return array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness} */ - private function getConfigDetailsFromLexicon(string $appId): array { + public function getConfigDetailsFromLexicon(string $appId): array { if (!array_key_exists($appId, $this->configLexiconDetails)) { - $entries = []; + $entries = $aliases = []; $bootstrapCoordinator = \OCP\Server::get(Coordinator::class); $configLexicon = $bootstrapCoordinator->getRegistrationContext()?->getConfigLexicon($appId); foreach ($configLexicon?->getAppConfigs() ?? [] as $configEntry) { $entries[$configEntry->getKey()] = $configEntry; + if ($configEntry->getRename() !== null) { + $aliases[$configEntry->getRename()] = $configEntry->getKey(); + } } $this->configLexiconDetails[$appId] = [ 'entries' => $entries, + 'aliases' => $aliases, 'strictness' => $configLexicon?->getStrictness() ?? ConfigLexiconStrictness::IGNORE ]; } @@ -1665,16 +1702,36 @@ class AppConfig implements IAppConfig { return $this->configLexiconDetails[$appId]; } + private function getLexiconEntry(string $appId, string $key): ?ConfigLexiconEntry { + return $this->getConfigDetailsFromLexicon($appId)['entries'][$key] ?? null; + } + + /** + * if set to TRUE, ignore aliases defined in Config Lexicon during the use of the methods of this class + * + * @internal + */ + public function ignoreLexiconAliases(bool $ignore): void { + $this->ignoreLexiconAliases = $ignore; + } + /** * Returns the installed versions of all apps * * @return array<string, string> */ - public function getAppInstalledVersions(): array { + public function getAppInstalledVersions(bool $onlyEnabled = false): array { if ($this->appVersionsCache === null) { /** @var array<string, string> */ $this->appVersionsCache = $this->searchValues('installed_version', false, IAppConfig::VALUE_STRING); } + if ($onlyEnabled) { + return array_filter( + $this->appVersionsCache, + fn (string $app): bool => $this->getValueString($app, 'enabled', 'no') !== 'no', + ARRAY_FILTER_USE_KEY + ); + } return $this->appVersionsCache; } } diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php index 4e613703dec..64e3dbfd928 100644 --- a/lib/private/AppFramework/Bootstrap/Coordinator.php +++ b/lib/private/AppFramework/Bootstrap/Coordinator.php @@ -20,6 +20,7 @@ use OCP\Dashboard\IManager; use OCP\Diagnostics\IEventLogger; use OCP\EventDispatcher\IEventDispatcher; use OCP\IServerContainer; +use Psr\Container\ContainerExceptionInterface; use Psr\Log\LoggerInterface; use Throwable; use function class_exists; @@ -69,19 +70,24 @@ class Coordinator { */ try { $path = $this->appManager->getAppPath($appId); + OC_App::registerAutoloading($appId, $path); } catch (AppPathNotFoundException) { // Ignore continue; } - OC_App::registerAutoloading($appId, $path); $this->eventLogger->end("bootstrap:register_app:$appId:autoloader"); /* * Next we check if there is an application class, and it implements * the \OCP\AppFramework\Bootstrap\IBootstrap interface */ - $appNameSpace = App::buildAppNamespace($appId); + if ($appId === 'core') { + $appNameSpace = 'OC\\Core'; + } else { + $appNameSpace = App::buildAppNamespace($appId); + } $applicationClassName = $appNameSpace . '\\AppInfo\\Application'; + try { if (class_exists($applicationClassName) && is_a($applicationClassName, IBootstrap::class, true)) { $this->eventLogger->start("bootstrap:register_app:$appId:application", "Load `Application` instance for $appId"); @@ -89,7 +95,7 @@ class Coordinator { /** @var IBootstrap&App $application */ $application = $this->serverContainer->query($applicationClassName); $apps[$appId] = $application; - } catch (QueryException $e) { + } catch (ContainerExceptionInterface $e) { // Weird, but ok $this->eventLogger->end("bootstrap:register_app:$appId"); continue; @@ -172,7 +178,7 @@ class Coordinator { public function isBootable(string $appId) { $appNameSpace = App::buildAppNamespace($appId); $applicationClassName = $appNameSpace . '\\AppInfo\\Application'; - return class_exists($applicationClassName) && - in_array(IBootstrap::class, class_implements($applicationClassName), true); + return class_exists($applicationClassName) + && in_array(IBootstrap::class, class_implements($applicationClassName), true); } } diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php index c3b829825c2..95ad129c466 100644 --- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -157,7 +157,7 @@ class RegistrationContext { /** @var ServiceRegistration<\OCP\Files\Conversion\IConversionProvider>[] */ private array $fileConversionProviders = []; - + /** @var ServiceRegistration<IMailProvider>[] */ private $mailProviders = []; diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index b6e2df4ce7b..87361a9d1ea 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -440,7 +441,7 @@ class DIContainer extends SimpleContainer implements IAppContainer { return parent::query($name); } - throw new QueryException('Could not resolve ' . $name . '!' . - ' Class can not be instantiated', 1); + throw new QueryException('Could not resolve ' . $name . '!' + . ' Class can not be instantiated', 1); } } diff --git a/lib/private/AppFramework/Http.php b/lib/private/AppFramework/Http.php index 3c3e19692bf..08d6259c2a2 100644 --- a/lib/private/AppFramework/Http.php +++ b/lib/private/AppFramework/Http.php @@ -102,7 +102,7 @@ class Http extends BaseHttp { $status = self::STATUS_FOUND; } - return $this->protocolVersion . ' ' . $status . ' ' . - $this->headers[$status]; + return $this->protocolVersion . ' ' . $status . ' ' + . $this->headers[$status]; } } diff --git a/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php b/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php index c30855a0e98..e4571dfc50e 100644 --- a/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php +++ b/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php @@ -33,8 +33,8 @@ class FlowV2EphemeralSessionsMiddleware extends Middleware { } if ( - $controller instanceof ClientFlowLoginV2Controller && - ($methodName === 'grantPage' || $methodName === 'generateAppPassword') + $controller instanceof ClientFlowLoginV2Controller + && ($methodName === 'grantPage' || $methodName === 'generateAppPassword') ) { return; } diff --git a/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php b/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php index 17b423164f6..08b30092155 100644 --- a/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php +++ b/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php @@ -29,7 +29,7 @@ class NotModifiedMiddleware extends Middleware { } $modifiedSinceHeader = $this->request->getHeader('IF_MODIFIED_SINCE'); - if ($modifiedSinceHeader !== '' && $response->getLastModified() !== null && trim($modifiedSinceHeader) === $response->getLastModified()->format(\DateTimeInterface::RFC2822)) { + if ($modifiedSinceHeader !== '' && $response->getLastModified() !== null && trim($modifiedSinceHeader) === $response->getLastModified()->format(\DateTimeInterface::RFC7231)) { $response->setStatus(Http::STATUS_NOT_MODIFIED); return $response; } diff --git a/lib/private/AppFramework/Middleware/OCSMiddleware.php b/lib/private/AppFramework/Middleware/OCSMiddleware.php index 46612bf0d29..64f4b0054de 100644 --- a/lib/private/AppFramework/Middleware/OCSMiddleware.php +++ b/lib/private/AppFramework/Middleware/OCSMiddleware.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/AppFramework/Middleware/PublicShare/Exceptions/NeedAuthenticationException.php b/lib/private/AppFramework/Middleware/PublicShare/Exceptions/NeedAuthenticationException.php index c80d06c90ae..5df4009b094 100644 --- a/lib/private/AppFramework/Middleware/PublicShare/Exceptions/NeedAuthenticationException.php +++ b/lib/private/AppFramework/Middleware/PublicShare/Exceptions/NeedAuthenticationException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php b/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php index b3040673d0f..83e799e3d3b 100644 --- a/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php +++ b/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php index 40af67739d6..4453f5a7d4b 100644 --- a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php @@ -68,8 +68,8 @@ class CORSMiddleware extends Middleware { // ensure that @CORS annotated API routes are not used in conjunction // with session authentication since this enables CSRF attack vectors - if ($this->hasAnnotationOrAttribute($reflectionMethod, 'CORS', CORS::class) && - (!$this->hasAnnotationOrAttribute($reflectionMethod, 'PublicPage', PublicPage::class) || $this->session->isLoggedIn())) { + if ($this->hasAnnotationOrAttribute($reflectionMethod, 'CORS', CORS::class) + && (!$this->hasAnnotationOrAttribute($reflectionMethod, 'PublicPage', PublicPage::class) || $this->session->isLoggedIn())) { $user = array_key_exists('PHP_AUTH_USER', $this->request->server) ? $this->request->server['PHP_AUTH_USER'] : null; $pass = array_key_exists('PHP_AUTH_PW', $this->request->server) ? $this->request->server['PHP_AUTH_PW'] : null; @@ -134,10 +134,10 @@ class CORSMiddleware extends Middleware { // allow credentials headers must not be true or CSRF is possible // otherwise foreach ($response->getHeaders() as $header => $value) { - if (strtolower($header) === 'access-control-allow-credentials' && - strtolower(trim($value)) === 'true') { - $msg = 'Access-Control-Allow-Credentials must not be ' . - 'set to true in order to prevent CSRF'; + if (strtolower($header) === 'access-control-allow-credentials' + && strtolower(trim($value)) === 'true') { + $msg = 'Access-Control-Allow-Credentials must not be ' + . 'set to true in order to prevent CSRF'; throw new SecurityException($msg); } } diff --git a/lib/private/AppFramework/Middleware/Security/Exceptions/AppNotEnabledException.php b/lib/private/AppFramework/Middleware/Security/Exceptions/AppNotEnabledException.php index 646a5240bfc..53fbaaf5ed2 100644 --- a/lib/private/AppFramework/Middleware/Security/Exceptions/AppNotEnabledException.php +++ b/lib/private/AppFramework/Middleware/Security/Exceptions/AppNotEnabledException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/AppFramework/Middleware/Security/Exceptions/LaxSameSiteCookieFailedException.php b/lib/private/AppFramework/Middleware/Security/Exceptions/LaxSameSiteCookieFailedException.php index 91f1dba874d..0380c6781aa 100644 --- a/lib/private/AppFramework/Middleware/Security/Exceptions/LaxSameSiteCookieFailedException.php +++ b/lib/private/AppFramework/Middleware/Security/Exceptions/LaxSameSiteCookieFailedException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/AppFramework/Middleware/Security/Exceptions/NotConfirmedException.php b/lib/private/AppFramework/Middleware/Security/Exceptions/NotConfirmedException.php index 7e950f2c976..ca30f736fbc 100644 --- a/lib/private/AppFramework/Middleware/Security/Exceptions/NotConfirmedException.php +++ b/lib/private/AppFramework/Middleware/Security/Exceptions/NotConfirmedException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -14,7 +15,7 @@ use OCP\AppFramework\Http; * @package OC\AppFramework\Middleware\Security\Exceptions */ class NotConfirmedException extends SecurityException { - public function __construct() { - parent::__construct('Password confirmation is required', Http::STATUS_FORBIDDEN); + public function __construct(string $message = 'Password confirmation is required') { + parent::__construct($message, Http::STATUS_FORBIDDEN); } } diff --git a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php index d00840084a3..0facbffe504 100644 --- a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -79,6 +80,9 @@ class PasswordConfirmationMiddleware extends Middleware { if ($this->isPasswordConfirmationStrict($reflectionMethod)) { $authHeader = $this->request->getHeader('Authorization'); + if (!str_starts_with(strtolower($authHeader), 'basic ')) { + throw new NotConfirmedException('Required authorization header missing'); + } [, $password] = explode(':', base64_decode(substr($authHeader, 6)), 2); $loginName = $this->session->get('loginname'); $loginResult = $this->userManager->checkPassword($loginName, $password); diff --git a/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php b/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php index efe56e0b124..ed3bb232023 100644 --- a/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php index 6b054b03f44..e3a293e0fd9 100644 --- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php @@ -184,8 +184,8 @@ class SecurityMiddleware extends Middleware { } // Check for strict cookie requirement - if ($this->hasAnnotationOrAttribute($reflectionMethod, 'StrictCookieRequired', StrictCookiesRequired::class) || - !$this->hasAnnotationOrAttribute($reflectionMethod, 'NoCSRFRequired', NoCSRFRequired::class)) { + if ($this->hasAnnotationOrAttribute($reflectionMethod, 'StrictCookieRequired', StrictCookiesRequired::class) + || !$this->hasAnnotationOrAttribute($reflectionMethod, 'NoCSRFRequired', NoCSRFRequired::class)) { if (!$this->request->passesStrictCookieCheck()) { throw new StrictCookieMissingException(); } diff --git a/lib/private/AppFramework/OCS/BaseResponse.php b/lib/private/AppFramework/OCS/BaseResponse.php index 5929a3993ec..05ce133db24 100644 --- a/lib/private/AppFramework/OCS/BaseResponse.php +++ b/lib/private/AppFramework/OCS/BaseResponse.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -83,9 +84,9 @@ abstract class BaseResponse extends Response { */ protected function renderResult(array $meta): string { $status = $this->getStatus(); - if ($status === Http::STATUS_NO_CONTENT || - $status === Http::STATUS_NOT_MODIFIED || - ($status >= 100 && $status <= 199)) { + if ($status === Http::STATUS_NO_CONTENT + || $status === Http::STATUS_NOT_MODIFIED + || ($status >= 100 && $status <= 199)) { // Those status codes are not supposed to have a body: // https://stackoverflow.com/q/8628725 return ''; diff --git a/lib/private/AppFramework/OCS/V1Response.php b/lib/private/AppFramework/OCS/V1Response.php index 131ca22ff24..1c2c25f5cb0 100644 --- a/lib/private/AppFramework/OCS/V1Response.php +++ b/lib/private/AppFramework/OCS/V1Response.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/AppFramework/OCS/V2Response.php b/lib/private/AppFramework/OCS/V2Response.php index 47cf0f60200..efc9348eb37 100644 --- a/lib/private/AppFramework/OCS/V2Response.php +++ b/lib/private/AppFramework/OCS/V2Response.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/AppFramework/Services/AppConfig.php b/lib/private/AppFramework/Services/AppConfig.php index 77c5ea4de0c..04d97738483 100644 --- a/lib/private/AppFramework/Services/AppConfig.php +++ b/lib/private/AppFramework/Services/AppConfig.php @@ -343,7 +343,7 @@ class AppConfig implements IAppConfig { * * @return array<string, string> */ - public function getAppInstalledVersions(): array { - return $this->appConfig->getAppInstalledVersions(); + public function getAppInstalledVersions(bool $onlyEnabled = false): array { + return $this->appConfig->getAppInstalledVersions($onlyEnabled); } } diff --git a/lib/private/AppFramework/Utility/SimpleContainer.php b/lib/private/AppFramework/Utility/SimpleContainer.php index 9af65a37ab8..1d77c277b02 100644 --- a/lib/private/AppFramework/Utility/SimpleContainer.php +++ b/lib/private/AppFramework/Utility/SimpleContainer.php @@ -12,6 +12,7 @@ use Closure; use OCP\AppFramework\QueryException; use OCP\IContainer; use Pimple\Container; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use ReflectionClass; use ReflectionException; @@ -23,8 +24,9 @@ use function class_exists; * SimpleContainer is a simple implementation of a container on basis of Pimple */ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer { - /** @var Container */ - private $container; + public static bool $useLazyObjects = false; + + private Container $container; public function __construct() { $this->container = new Container(); @@ -49,16 +51,29 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer { /** * @param ReflectionClass $class the class to instantiate - * @return \stdClass the created class + * @return object the created class * @suppress PhanUndeclaredClassInstanceof */ - private function buildClass(ReflectionClass $class) { + private function buildClass(ReflectionClass $class): object { $constructor = $class->getConstructor(); if ($constructor === null) { + /* No constructor, return a instance directly */ return $class->newInstance(); } + if (PHP_VERSION_ID >= 80400 && self::$useLazyObjects) { + /* For PHP>=8.4, use a lazy ghost to delay constructor and dependency resolving */ + /** @psalm-suppress UndefinedMethod */ + return $class->newLazyGhost(function (object $object) use ($constructor): void { + /** @psalm-suppress DirectConstructorCall For lazy ghosts we have to call the constructor directly */ + $object->__construct(...$this->buildClassConstructorParameters($constructor)); + }); + } else { + return $class->newInstanceArgs($this->buildClassConstructorParameters($constructor)); + } + } - return $class->newInstanceArgs(array_map(function (ReflectionParameter $parameter) { + private function buildClassConstructorParameters(\ReflectionMethod $constructor): array { + return array_map(function (ReflectionParameter $parameter) { $parameterType = $parameter->getType(); $resolveName = $parameter->getName(); @@ -69,10 +84,10 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer { } try { - $builtIn = $parameter->hasType() && ($parameter->getType() instanceof ReflectionNamedType) - && $parameter->getType()->isBuiltin(); + $builtIn = $parameterType !== null && ($parameterType instanceof ReflectionNamedType) + && $parameterType->isBuiltin(); return $this->query($resolveName, !$builtIn); - } catch (QueryException $e) { + } catch (ContainerExceptionInterface $e) { // Service not found, use the default value when available if ($parameter->isDefaultValueAvailable()) { return $parameter->getDefaultValue(); @@ -82,7 +97,7 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer { $resolveName = $parameter->getName(); try { return $this->query($resolveName); - } catch (QueryException $e2) { + } catch (ContainerExceptionInterface $e2) { // Pass null if typed and nullable if ($parameter->allowsNull() && ($parameterType instanceof ReflectionNamedType)) { return null; @@ -95,7 +110,7 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer { throw $e; } - }, $constructor->getParameters())); + }, $constructor->getParameters()); } public function resolve($name) { @@ -105,8 +120,8 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer { if ($class->isInstantiable()) { return $this->buildClass($class); } else { - throw new QueryException($baseMsg . - ' Class can not be instantiated'); + throw new QueryException($baseMsg + . ' Class can not be instantiated'); } } catch (ReflectionException $e) { // Class does not exist diff --git a/lib/private/AppScriptDependency.php b/lib/private/AppScriptDependency.php index 380816f21ac..cc5ded0d011 100644 --- a/lib/private/AppScriptDependency.php +++ b/lib/private/AppScriptDependency.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/AppScriptSort.php b/lib/private/AppScriptSort.php index eda41e97445..134dad100dc 100644 --- a/lib/private/AppScriptSort.php +++ b/lib/private/AppScriptSort.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Authentication/LoginCredentials/Credentials.php b/lib/private/Authentication/LoginCredentials/Credentials.php index 2d7ed3adfd0..3414034b33c 100644 --- a/lib/private/Authentication/LoginCredentials/Credentials.php +++ b/lib/private/Authentication/LoginCredentials/Credentials.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Authentication/Token/TokenCleanupJob.php b/lib/private/Authentication/Token/TokenCleanupJob.php index 041d2e8a5e2..e6d1e69e9b4 100644 --- a/lib/private/Authentication/Token/TokenCleanupJob.php +++ b/lib/private/Authentication/Token/TokenCleanupJob.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-only diff --git a/lib/private/Authentication/TwoFactorAuth/Manager.php b/lib/private/Authentication/TwoFactorAuth/Manager.php index 1b22300e317..07aa98610ed 100644 --- a/lib/private/Authentication/TwoFactorAuth/Manager.php +++ b/lib/private/Authentication/TwoFactorAuth/Manager.php @@ -308,8 +308,8 @@ class Manager { // First check if the session tells us we should do 2FA (99% case) if (!$this->session->exists(self::SESSION_UID_KEY)) { // Check if the session tells us it is 2FA authenticated already - if ($this->session->exists(self::SESSION_UID_DONE) && - $this->session->get(self::SESSION_UID_DONE) === $user->getUID()) { + if ($this->session->exists(self::SESSION_UID_DONE) + && $this->session->get(self::SESSION_UID_DONE) === $user->getUID()) { return false; } diff --git a/lib/private/Avatar/UserAvatar.php b/lib/private/Avatar/UserAvatar.php index 51c44b23a55..bef0a20e7b8 100644 --- a/lib/private/Avatar/UserAvatar.php +++ b/lib/private/Avatar/UserAvatar.php @@ -82,8 +82,8 @@ class UserAvatar extends Avatar { $img = new \OCP\Image(); if ( - (is_resource($data) && get_resource_type($data) === 'gd') || - (is_object($data) && get_class($data) === \GdImage::class) + (is_resource($data) && get_resource_type($data) === 'gd') + || (is_object($data) && get_class($data) === \GdImage::class) ) { $img->setResource($data); } elseif (is_resource($data)) { diff --git a/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php b/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php index 982693bcfe8..8faf4627251 100644 --- a/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php +++ b/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php @@ -68,6 +68,11 @@ class GenerateBlurhashMetadata implements IEventListener { return; } + // Preview are disabled, so we skip generating the blurhash. + if (!$this->preview->isAvailable($file)) { + return; + } + $preview = $this->preview->getPreview($file, 64, 64, cacheResult: false); $image = @imagecreatefromstring($preview->getContent()); diff --git a/lib/private/Calendar/Manager.php b/lib/private/Calendar/Manager.php index 21370e74d54..0e2a3f5f679 100644 --- a/lib/private/Calendar/Manager.php +++ b/lib/private/Calendar/Manager.php @@ -236,7 +236,7 @@ class Manager implements IManager { $this->logger->warning('iMip message could not be processed because user has no calendars'); return false; } - + try { /** @var VCalendar $vObject|null */ $calendarObject = Reader::read($calendarData); diff --git a/lib/private/Collaboration/AutoComplete/Manager.php b/lib/private/Collaboration/AutoComplete/Manager.php index c4dd4093e69..cc5df78beea 100644 --- a/lib/private/Collaboration/AutoComplete/Manager.php +++ b/lib/private/Collaboration/AutoComplete/Manager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Collaboration/Collaborators/GroupPlugin.php b/lib/private/Collaboration/Collaborators/GroupPlugin.php index a7b84b72199..a59d5981825 100644 --- a/lib/private/Collaboration/Collaborators/GroupPlugin.php +++ b/lib/private/Collaboration/Collaborators/GroupPlugin.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Collaboration/Collaborators/LookupPlugin.php b/lib/private/Collaboration/Collaborators/LookupPlugin.php index 2c8dc845458..fb6b9f2e0e8 100644 --- a/lib/private/Collaboration/Collaborators/LookupPlugin.php +++ b/lib/private/Collaboration/Collaborators/LookupPlugin.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index 278ba19aa5a..55e3945ace2 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -228,8 +229,8 @@ class MailPlugin implements ISearchPlugin { $reachedEnd = true; if ($this->shareeEnumeration) { - $reachedEnd = (count($result['wide']) < $offset + $limit) && - (count($userResults['wide']) < $offset + $limit); + $reachedEnd = (count($result['wide']) < $offset + $limit) + && (count($userResults['wide']) < $offset + $limit); $result['wide'] = array_slice($result['wide'], $offset, $limit); $userResults['wide'] = array_slice($userResults['wide'], $offset, $limit); diff --git a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php index 89d5c4e4f79..f4c1793ea0a 100644 --- a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php +++ b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Collaboration/Collaborators/RemotePlugin.php b/lib/private/Collaboration/Collaborators/RemotePlugin.php index 788ece70cb9..037c6f6cbea 100644 --- a/lib/private/Collaboration/Collaborators/RemotePlugin.php +++ b/lib/private/Collaboration/Collaborators/RemotePlugin.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Collaboration/Collaborators/Search.php b/lib/private/Collaboration/Collaborators/Search.php index 78b57b52400..32c70549a7b 100644 --- a/lib/private/Collaboration/Collaborators/Search.php +++ b/lib/private/Collaboration/Collaborators/Search.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Collaboration/Collaborators/SearchResult.php b/lib/private/Collaboration/Collaborators/SearchResult.php index 73c0fed41e0..c9c2f032f36 100644 --- a/lib/private/Collaboration/Collaborators/SearchResult.php +++ b/lib/private/Collaboration/Collaborators/SearchResult.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Collaboration/Collaborators/UserPlugin.php b/lib/private/Collaboration/Collaborators/UserPlugin.php index d196abae042..671181aea35 100644 --- a/lib/private/Collaboration/Collaborators/UserPlugin.php +++ b/lib/private/Collaboration/Collaborators/UserPlugin.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -147,11 +148,11 @@ class UserPlugin implements ISearchPlugin { if ( - $this->shareeEnumerationFullMatch && - $lowerSearch !== '' && (strtolower($uid) === $lowerSearch || - strtolower($userDisplayName) === $lowerSearch || - ($this->shareeEnumerationFullMatchIgnoreSecondDisplayName && trim(strtolower(preg_replace('/ \(.*\)$/', '', $userDisplayName))) === $lowerSearch) || - ($this->shareeEnumerationFullMatchEmail && strtolower($userEmail ?? '') === $lowerSearch)) + $this->shareeEnumerationFullMatch + && $lowerSearch !== '' && (strtolower($uid) === $lowerSearch + || strtolower($userDisplayName) === $lowerSearch + || ($this->shareeEnumerationFullMatchIgnoreSecondDisplayName && trim(strtolower(preg_replace('/ \(.*\)$/', '', $userDisplayName))) === $lowerSearch) + || ($this->shareeEnumerationFullMatchEmail && strtolower($userEmail ?? '') === $lowerSearch)) ) { if (strtolower($uid) === $lowerSearch) { $foundUserById = true; @@ -169,8 +170,8 @@ class UserPlugin implements ISearchPlugin { ]; } else { $addToWideResults = false; - if ($this->shareeEnumeration && - !($this->shareeEnumerationInGroupOnly || $this->shareeEnumerationPhone)) { + if ($this->shareeEnumeration + && !($this->shareeEnumerationInGroupOnly || $this->shareeEnumerationPhone)) { $addToWideResults = true; } diff --git a/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php b/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php index e468ad4eb4c..9c18531c8e7 100644 --- a/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php +++ b/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php @@ -15,6 +15,7 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\IEventListener; use OCP\Files\Events\Node\NodeDeletedEvent; +use OCP\Files\Events\Node\NodeRenamedEvent; use OCP\Share\Events\ShareCreatedEvent; use OCP\Share\Events\ShareDeletedEvent; @@ -27,6 +28,7 @@ class FileReferenceEventListener implements IEventListener { public static function register(IEventDispatcher $eventDispatcher): void { $eventDispatcher->addServiceListener(NodeDeletedEvent::class, FileReferenceEventListener::class); + $eventDispatcher->addServiceListener(NodeRenamedEvent::class, FileReferenceEventListener::class); $eventDispatcher->addServiceListener(ShareDeletedEvent::class, FileReferenceEventListener::class); $eventDispatcher->addServiceListener(ShareCreatedEvent::class, FileReferenceEventListener::class); } @@ -42,6 +44,9 @@ class FileReferenceEventListener implements IEventListener { $this->manager->invalidateCache((string)$event->getNode()->getId()); } + if ($event instanceof NodeRenamedEvent) { + $this->manager->invalidateCache((string)$event->getTarget()->getId()); + } if ($event instanceof ShareDeletedEvent) { $this->manager->invalidateCache((string)$event->getShare()->getNodeId()); } diff --git a/lib/private/Collaboration/Resources/Collection.php b/lib/private/Collaboration/Resources/Collection.php index cf5f7740ced..2481a3e9a09 100644 --- a/lib/private/Collaboration/Resources/Collection.php +++ b/lib/private/Collaboration/Resources/Collection.php @@ -164,8 +164,8 @@ class Collection implements ICollection { } protected function isSameResource(IResource $resource1, IResource $resource2): bool { - return $resource1->getType() === $resource2->getType() && - $resource1->getId() === $resource2->getId(); + return $resource1->getType() === $resource2->getType() + && $resource1->getId() === $resource2->getId(); } protected function removeCollection(): void { diff --git a/lib/private/Color.php b/lib/private/Color.php index e96d6fd23bd..d97c519e552 100644 --- a/lib/private/Color.php +++ b/lib/private/Color.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Command/CronBus.php b/lib/private/Command/CronBus.php index 1ff9bb7099a..a12520469a9 100644 --- a/lib/private/Command/CronBus.php +++ b/lib/private/Command/CronBus.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Config/ConfigManager.php b/lib/private/Config/ConfigManager.php new file mode 100644 index 00000000000..1980269e2ca --- /dev/null +++ b/lib/private/Config/ConfigManager.php @@ -0,0 +1,250 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OC\Config; + +use JsonException; +use NCU\Config\Exceptions\TypeConflictException; +use NCU\Config\IUserConfig; +use NCU\Config\Lexicon\ConfigLexiconEntry; +use NCU\Config\ValueType; +use OC\AppConfig; +use OCP\App\IAppManager; +use OCP\IAppConfig; +use OCP\Server; +use Psr\Log\LoggerInterface; + +/** + * tools to maintains configurations + * + * @since 32.0.0 + */ +class ConfigManager { + /** @var AppConfig|null $appConfig */ + private ?IAppConfig $appConfig = null; + /** @var UserConfig|null $userConfig */ + private ?IUserConfig $userConfig = null; + + public function __construct( + private readonly LoggerInterface $logger, + ) { + } + + /** + * Use the rename values from the list of ConfigLexiconEntry defined in each app ConfigLexicon + * to migrate config value to a new config key. + * Migration will only occur if new config key has no value in database. + * The previous value from the key set in rename will be deleted from the database when migration + * is over. + * + * This method should be mainly called during a new upgrade or when a new app is enabled. + * + * @see ConfigLexiconEntry + * @internal + * @since 32.0.0 + * @param string|null $appId when set to NULL the method will be executed for all enabled apps of the instance + */ + public function migrateConfigLexiconKeys(?string $appId = null): void { + if ($appId === null) { + $this->migrateConfigLexiconKeys('core'); + $appManager = Server::get(IAppManager::class); + foreach ($appManager->getEnabledApps() as $app) { + $this->migrateConfigLexiconKeys($app); + } + + return; + } + + $this->loadConfigServices(); + + // it is required to ignore aliases when moving config values + $this->appConfig->ignoreLexiconAliases(true); + $this->userConfig->ignoreLexiconAliases(true); + + $this->migrateAppConfigKeys($appId); + $this->migrateUserConfigKeys($appId); + + // switch back to normal behavior + $this->appConfig->ignoreLexiconAliases(false); + $this->userConfig->ignoreLexiconAliases(false); + } + + /** + * config services cannot be load at __construct() or install will fail + */ + private function loadConfigServices(): void { + if ($this->appConfig === null) { + $this->appConfig = Server::get(IAppConfig::class); + } + if ($this->userConfig === null) { + $this->userConfig = Server::get(IUserConfig::class); + } + } + + /** + * Get details from lexicon related to AppConfig and search for entries with rename to initiate + * a migration to new config key + */ + private function migrateAppConfigKeys(string $appId): void { + $lexicon = $this->appConfig->getConfigDetailsFromLexicon($appId); + foreach ($lexicon['entries'] as $entry) { + // only interested in entries with rename set + if ($entry->getRename() === null) { + continue; + } + + // only migrate if rename config key has a value and the new config key hasn't + if ($this->appConfig->hasKey($appId, $entry->getRename()) + && !$this->appConfig->hasKey($appId, $entry->getKey())) { + try { + $this->migrateAppConfigValue($appId, $entry); + } catch (TypeConflictException $e) { + $this->logger->error('could not migrate AppConfig value', ['appId' => $appId, 'entry' => $entry, 'exception' => $e]); + continue; + } + } + + // we only delete previous config value if migration went fine. + $this->appConfig->deleteKey($appId, $entry->getRename()); + } + } + + /** + * Get details from lexicon related to UserConfig and search for entries with rename to initiate + * a migration to new config key + */ + private function migrateUserConfigKeys(string $appId): void { + $lexicon = $this->userConfig->getConfigDetailsFromLexicon($appId); + foreach ($lexicon['entries'] as $entry) { + // only interested in keys with rename set + if ($entry->getRename() === null) { + continue; + } + + foreach ($this->userConfig->getValuesByUsers($appId, $entry->getRename()) as $userId => $value) { + if ($this->userConfig->hasKey($userId, $appId, $entry->getKey())) { + continue; + } + + try { + $this->migrateUserConfigValue($userId, $appId, $entry); + } catch (TypeConflictException $e) { + $this->logger->error('could not migrate UserConfig value', ['userId' => $userId, 'appId' => $appId, 'entry' => $entry, 'exception' => $e]); + continue; + } + + $this->userConfig->deleteUserConfig($userId, $appId, $entry->getRename()); + } + } + } + + + /** + * converting value from rename to the new key + * + * @throws TypeConflictException if previous value does not fit the expected type + */ + private function migrateAppConfigValue(string $appId, ConfigLexiconEntry $entry): void { + $value = $this->appConfig->getValueMixed($appId, $entry->getRename(), lazy: null); + switch ($entry->getValueType()) { + case ValueType::STRING: + $this->appConfig->setValueString($appId, $entry->getKey(), $value); + return; + + case ValueType::INT: + $this->appConfig->setValueInt($appId, $entry->getKey(), $this->convertToInt($value)); + return; + + case ValueType::FLOAT: + $this->appConfig->setValueFloat($appId, $entry->getKey(), $this->convertToFloat($value)); + return; + + case ValueType::BOOL: + $this->appConfig->setValueBool($appId, $entry->getKey(), $this->convertToBool($value, $entry)); + return; + + case ValueType::ARRAY: + $this->appConfig->setValueArray($appId, $entry->getKey(), $this->convertToArray($value)); + return; + } + } + + /** + * converting value from rename to the new key + * + * @throws TypeConflictException if previous value does not fit the expected type + */ + private function migrateUserConfigValue(string $userId, string $appId, ConfigLexiconEntry $entry): void { + $value = $this->userConfig->getValueMixed($userId, $appId, $entry->getRename(), lazy: null); + switch ($entry->getValueType()) { + case ValueType::STRING: + $this->userConfig->setValueString($userId, $appId, $entry->getKey(), $value); + return; + + case ValueType::INT: + $this->userConfig->setValueInt($userId, $appId, $entry->getKey(), $this->convertToInt($value)); + return; + + case ValueType::FLOAT: + $this->userConfig->setValueFloat($userId, $appId, $entry->getKey(), $this->convertToFloat($value)); + return; + + case ValueType::BOOL: + $this->userConfig->setValueBool($userId, $appId, $entry->getKey(), $this->convertToBool($value, $entry)); + return; + + case ValueType::ARRAY: + $this->userConfig->setValueArray($userId, $appId, $entry->getKey(), $this->convertToArray($value)); + return; + } + } + + public function convertToInt(string $value): int { + if (!is_numeric($value) || (float)$value <> (int)$value) { + throw new TypeConflictException('Value is not an integer'); + } + + return (int)$value; + } + + public function convertToFloat(string $value): float { + if (!is_numeric($value)) { + throw new TypeConflictException('Value is not a float'); + } + + return (float)$value; + } + + public function convertToBool(string $value, ?ConfigLexiconEntry $entry = null): bool { + if (in_array(strtolower($value), ['true', '1', 'on', 'yes'])) { + $valueBool = true; + } elseif (in_array(strtolower($value), ['false', '0', 'off', 'no'])) { + $valueBool = false; + } else { + throw new TypeConflictException('Value cannot be converted to boolean'); + } + if ($entry?->hasOption(ConfigLexiconEntry::RENAME_INVERT_BOOLEAN) === true) { + $valueBool = !$valueBool; + } + + return $valueBool; + } + + public function convertToArray(string $value): array { + try { + $valueArray = json_decode($value, true, flags: JSON_THROW_ON_ERROR); + } catch (JsonException) { + throw new TypeConflictException('Value is not a valid json'); + } + if (!is_array($valueArray)) { + throw new TypeConflictException('Value is not an array'); + } + + return $valueArray; + } +} diff --git a/lib/private/Config/UserConfig.php b/lib/private/Config/UserConfig.php index 77a86a5e1c7..7848f1728e3 100644 --- a/lib/private/Config/UserConfig.php +++ b/lib/private/Config/UserConfig.php @@ -25,6 +25,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IConfig; use OCP\IDBConnection; use OCP\Security\ICrypto; +use OCP\Server; use Psr\Log\LoggerInterface; /** @@ -62,8 +63,9 @@ class UserConfig implements IUserConfig { private array $fastLoaded = []; /** @var array<string, boolean> ['user_id' => bool] */ private array $lazyLoaded = []; - /** @var array<array-key, array{entries: array<array-key, ConfigLexiconEntry>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */ + /** @var array<string, array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */ private array $configLexiconDetails = []; + private bool $ignoreLexiconAliases = false; public function __construct( protected IDBConnection $connection, @@ -150,6 +152,7 @@ class UserConfig implements IUserConfig { public function hasKey(string $userId, string $app, string $key, ?bool $lazy = false): bool { $this->assertParams($userId, $app, $key); $this->loadConfig($userId, $lazy); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); if ($lazy === null) { $appCache = $this->getValues($userId, $app); @@ -178,6 +181,7 @@ class UserConfig implements IUserConfig { public function isSensitive(string $userId, string $app, string $key, ?bool $lazy = false): bool { $this->assertParams($userId, $app, $key); $this->loadConfig($userId, $lazy); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); if (!isset($this->valueDetails[$userId][$app][$key])) { throw new UnknownKeyException('unknown config key'); @@ -201,6 +205,7 @@ class UserConfig implements IUserConfig { public function isIndexed(string $userId, string $app, string $key, ?bool $lazy = false): bool { $this->assertParams($userId, $app, $key); $this->loadConfig($userId, $lazy); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); if (!isset($this->valueDetails[$userId][$app][$key])) { throw new UnknownKeyException('unknown config key'); @@ -222,6 +227,8 @@ class UserConfig implements IUserConfig { * @since 31.0.0 */ public function isLazy(string $userId, string $app, string $key): bool { + $this->matchAndApplyLexiconDefinition($userId, $app, $key); + // there is a huge probability the non-lazy config are already loaded // meaning that we can start by only checking if a current non-lazy key exists if ($this->hasKey($userId, $app, $key, false)) { @@ -349,6 +356,7 @@ class UserConfig implements IUserConfig { ?array $userIds = null, ): array { $this->assertParams('', $app, $key, allowEmptyUser: true); + $this->matchAndApplyLexiconDefinition('', $app, $key); $qb = $this->connection->getQueryBuilder(); $qb->select('userid', 'configvalue', 'type') @@ -464,6 +472,7 @@ class UserConfig implements IUserConfig { */ private function searchUsersByTypedValue(string $app, string $key, string|array $value, bool $caseInsensitive = false): Generator { $this->assertParams('', $app, $key, allowEmptyUser: true); + $this->matchAndApplyLexiconDefinition('', $app, $key); $qb = $this->connection->getQueryBuilder(); $qb->from('preferences'); @@ -541,6 +550,7 @@ class UserConfig implements IUserConfig { string $default = '', ?bool $lazy = false, ): string { + $this->matchAndApplyLexiconDefinition($userId, $app, $key); try { $lazy ??= $this->isLazy($userId, $app, $key); } catch (UnknownKeyException) { @@ -710,6 +720,7 @@ class UserConfig implements IUserConfig { ValueType $type, ): string { $this->assertParams($userId, $app, $key); + $origKey = $key; if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, default: $default)) { // returns default if strictness of lexicon is set to WARNING (block and report) return $default; @@ -746,6 +757,15 @@ class UserConfig implements IUserConfig { } $this->decryptSensitiveValue($userId, $app, $key, $value); + + // in case the key was modified while running matchAndApplyLexiconDefinition() we are + // interested to check options in case a modification of the value is needed + // ie inverting value from previous key when using lexicon option RENAME_INVERT_BOOLEAN + if ($origKey !== $key && $type === ValueType::BOOL) { + $configManager = Server::get(ConfigManager::class); + $value = ($configManager->convertToBool($value, $this->getLexiconEntry($app, $key))) ? '1' : '0'; + } + return $value; } @@ -764,6 +784,7 @@ class UserConfig implements IUserConfig { public function getValueType(string $userId, string $app, string $key, ?bool $lazy = null): ValueType { $this->assertParams($userId, $app, $key); $this->loadConfig($userId, $lazy); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); if (!isset($this->valueDetails[$userId][$app][$key]['type'])) { throw new UnknownKeyException('unknown config key'); @@ -788,6 +809,7 @@ class UserConfig implements IUserConfig { public function getValueFlags(string $userId, string $app, string $key, bool $lazy = false): int { $this->assertParams($userId, $app, $key); $this->loadConfig($userId, $lazy); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); if (!isset($this->valueDetails[$userId][$app][$key])) { throw new UnknownKeyException('unknown config key'); @@ -1045,6 +1067,11 @@ class UserConfig implements IUserConfig { int $flags, ValueType $type, ): bool { + // Primary email addresses are always(!) expected to be lowercase + if ($app === 'settings' && $key === 'email') { + $value = strtolower($value); + } + $this->assertParams($userId, $app, $key); if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, $flags)) { // returns false as database is not updated @@ -1129,8 +1156,8 @@ class UserConfig implements IUserConfig { * we only accept a different type from the one stored in database * if the one stored in database is not-defined (VALUE_MIXED) */ - if ($currType !== ValueType::MIXED && - $currType !== $type) { + if ($currType !== ValueType::MIXED + && $currType !== $type) { try { $currTypeDef = $currType->getDefinition(); $typeDef = $type->getDefinition(); @@ -1197,8 +1224,8 @@ class UserConfig implements IUserConfig { public function updateType(string $userId, string $app, string $key, ValueType $type = ValueType::MIXED): bool { $this->assertParams($userId, $app, $key); $this->loadConfigAll($userId); - // confirm key exists - $this->isLazy($userId, $app, $key); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); + $this->isLazy($userId, $app, $key); // confirm key exists $update = $this->connection->getQueryBuilder(); $update->update('preferences') @@ -1227,6 +1254,7 @@ class UserConfig implements IUserConfig { public function updateSensitive(string $userId, string $app, string $key, bool $sensitive): bool { $this->assertParams($userId, $app, $key); $this->loadConfigAll($userId); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); try { if ($sensitive === $this->isSensitive($userId, $app, $key, null)) { @@ -1282,6 +1310,8 @@ class UserConfig implements IUserConfig { */ public function updateGlobalSensitive(string $app, string $key, bool $sensitive): void { $this->assertParams('', $app, $key, allowEmptyUser: true); + $this->matchAndApplyLexiconDefinition('', $app, $key); + foreach (array_keys($this->getValuesByUsers($app, $key)) as $userId) { try { $this->updateSensitive($userId, $app, $key, $sensitive); @@ -1311,6 +1341,7 @@ class UserConfig implements IUserConfig { public function updateIndexed(string $userId, string $app, string $key, bool $indexed): bool { $this->assertParams($userId, $app, $key); $this->loadConfigAll($userId); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); try { if ($indexed === $this->isIndexed($userId, $app, $key, null)) { @@ -1366,6 +1397,8 @@ class UserConfig implements IUserConfig { */ public function updateGlobalIndexed(string $app, string $key, bool $indexed): void { $this->assertParams('', $app, $key, allowEmptyUser: true); + $this->matchAndApplyLexiconDefinition('', $app, $key); + foreach (array_keys($this->getValuesByUsers($app, $key)) as $userId) { try { $this->updateIndexed($userId, $app, $key, $indexed); @@ -1392,6 +1425,7 @@ class UserConfig implements IUserConfig { public function updateLazy(string $userId, string $app, string $key, bool $lazy): bool { $this->assertParams($userId, $app, $key); $this->loadConfigAll($userId); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); try { if ($lazy === $this->isLazy($userId, $app, $key)) { @@ -1426,6 +1460,7 @@ class UserConfig implements IUserConfig { */ public function updateGlobalLazy(string $app, string $key, bool $lazy): void { $this->assertParams('', $app, $key, allowEmptyUser: true); + $this->matchAndApplyLexiconDefinition('', $app, $key); $update = $this->connection->getQueryBuilder(); $update->update('preferences') @@ -1451,6 +1486,8 @@ class UserConfig implements IUserConfig { public function getDetails(string $userId, string $app, string $key): array { $this->assertParams($userId, $app, $key); $this->loadConfigAll($userId); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); + $lazy = $this->isLazy($userId, $app, $key); if ($lazy) { @@ -1498,6 +1535,8 @@ class UserConfig implements IUserConfig { */ public function deleteUserConfig(string $userId, string $app, string $key): void { $this->assertParams($userId, $app, $key); + $this->matchAndApplyLexiconDefinition($userId, $app, $key); + $qb = $this->connection->getQueryBuilder(); $qb->delete('preferences') ->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId))) @@ -1520,6 +1559,8 @@ class UserConfig implements IUserConfig { */ public function deleteKey(string $app, string $key): void { $this->assertParams('', $app, $key, allowEmptyUser: true); + $this->matchAndApplyLexiconDefinition('', $app, $key); + $qb = $this->connection->getQueryBuilder(); $qb->delete('preferences') ->where($qb->expr()->eq('appid', $qb->createNamedParameter($app))) @@ -1538,6 +1579,7 @@ class UserConfig implements IUserConfig { */ public function deleteApp(string $app): void { $this->assertParams('', $app, allowEmptyUser: true); + $qb = $this->connection->getQueryBuilder(); $qb->delete('preferences') ->where($qb->expr()->eq('appid', $qb->createNamedParameter($app))); @@ -1830,7 +1872,8 @@ class UserConfig implements IUserConfig { } /** - * match and apply current use of config values with defined lexicon + * Match and apply current use of config values with defined lexicon. + * Set $lazy to NULL only if only interested into checking that $key is alias. * * @throws UnknownKeyException * @throws TypeConflictException @@ -1839,17 +1882,27 @@ class UserConfig implements IUserConfig { private function matchAndApplyLexiconDefinition( string $userId, string $app, - string $key, - bool &$lazy, - ValueType &$type, + string &$key, + ?bool &$lazy = null, + ValueType &$type = ValueType::MIXED, int &$flags = 0, string &$default = '', ): bool { $configDetails = $this->getConfigDetailsFromLexicon($app); + if (array_key_exists($key, $configDetails['aliases']) && !$this->ignoreLexiconAliases) { + // in case '$rename' is set in ConfigLexiconEntry, we use the new config key + $key = $configDetails['aliases'][$key]; + } + if (!array_key_exists($key, $configDetails['entries'])) { return $this->applyLexiconStrictness($configDetails['strictness'], 'The user config key ' . $app . '/' . $key . ' is not defined in the config lexicon'); } + // if lazy is NULL, we ignore all check on the type/lazyness/default from Lexicon + if ($lazy === null) { + return true; + } + /** @var ConfigLexiconEntry $configValue */ $configValue = $configDetails['entries'][$key]; if ($type === ValueType::MIXED) { @@ -1934,24 +1987,42 @@ class UserConfig implements IUserConfig { * extract details from registered $appId's config lexicon * * @param string $appId + * @internal * - * @return array{entries: array<array-key, ConfigLexiconEntry>, strictness: ConfigLexiconStrictness} + * @return array{entries: array<string, ConfigLexiconEntry>, aliases: array<string, string>, strictness: ConfigLexiconStrictness} */ - private function getConfigDetailsFromLexicon(string $appId): array { + public function getConfigDetailsFromLexicon(string $appId): array { if (!array_key_exists($appId, $this->configLexiconDetails)) { - $entries = []; + $entries = $aliases = []; $bootstrapCoordinator = \OCP\Server::get(Coordinator::class); $configLexicon = $bootstrapCoordinator->getRegistrationContext()?->getConfigLexicon($appId); foreach ($configLexicon?->getUserConfigs() ?? [] as $configEntry) { $entries[$configEntry->getKey()] = $configEntry; + if ($configEntry->getRename() !== null) { + $aliases[$configEntry->getRename()] = $configEntry->getKey(); + } } $this->configLexiconDetails[$appId] = [ 'entries' => $entries, + 'aliases' => $aliases, 'strictness' => $configLexicon?->getStrictness() ?? ConfigLexiconStrictness::IGNORE ]; } return $this->configLexiconDetails[$appId]; } + + private function getLexiconEntry(string $appId, string $key): ?ConfigLexiconEntry { + return $this->getConfigDetailsFromLexicon($appId)['entries'][$key] ?? null; + } + + /** + * if set to TRUE, ignore aliases defined in Config Lexicon during the use of the methods of this class + * + * @internal + */ + public function ignoreLexiconAliases(bool $ignore): void { + $this->ignoreLexiconAliases = $ignore; + } } diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php index f896c0abebe..4cf1e0da8ca 100644 --- a/lib/private/Console/Application.php +++ b/lib/private/Console/Application.php @@ -74,8 +74,8 @@ class Application { if ($this->memoryInfo->isMemoryLimitSufficient() === false) { $output->getErrorOutput()->writeln( - '<comment>The current PHP memory limit ' . - 'is below the recommended value of 512MB.</comment>' + '<comment>The current PHP memory limit ' + . 'is below the recommended value of 512MB.</comment>' ); } diff --git a/lib/private/Contacts/ContactsMenu/ActionFactory.php b/lib/private/Contacts/ContactsMenu/ActionFactory.php index 71ebe575fdd..40037598d49 100644 --- a/lib/private/Contacts/ContactsMenu/ActionFactory.php +++ b/lib/private/Contacts/ContactsMenu/ActionFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php b/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php index 0d4cc9b9b01..cdaf9308bfc 100644 --- a/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php +++ b/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Contacts/ContactsMenu/Manager.php b/lib/private/Contacts/ContactsMenu/Manager.php index 65a2c4469ea..f8def45421b 100644 --- a/lib/private/Contacts/ContactsMenu/Manager.php +++ b/lib/private/Contacts/ContactsMenu/Manager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php b/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php index c852fc90b9e..266125f5ed5 100644 --- a/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php +++ b/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php index 96dd578b2ef..88bdc377e2b 100644 --- a/lib/private/DB/Connection.php +++ b/lib/private/DB/Connection.php @@ -894,9 +894,9 @@ class Connection extends PrimaryReadReplicaConnection { private function reconnectIfNeeded(): void { if ( - !isset($this->lastConnectionCheck[$this->getConnectionName()]) || - time() <= $this->lastConnectionCheck[$this->getConnectionName()] + 30 || - $this->isTransactionActive() + !isset($this->lastConnectionCheck[$this->getConnectionName()]) + || time() <= $this->lastConnectionCheck[$this->getConnectionName()] + 30 + || $this->isTransactionActive() ) { return; } diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php index 2f4c8131d9f..40579c7a898 100644 --- a/lib/private/DB/MigrationService.php +++ b/lib/private/DB/MigrationService.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2017 ownCloud GmbH diff --git a/lib/private/DB/MySqlTools.php b/lib/private/DB/MySqlTools.php index cd6b812be61..3413be43417 100644 --- a/lib/private/DB/MySqlTools.php +++ b/lib/private/DB/MySqlTools.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 ownCloud GmbH * SPDX-License-Identifier: AGPL-3.0-only @@ -45,7 +46,7 @@ class MySqlTools { return false; } - return str_contains($row, 'maria') && version_compare($row, '10.3', '>=') || - !str_contains($row, 'maria') && version_compare($row, '8.0', '>='); + return str_contains($row, 'maria') && version_compare($row, '10.3', '>=') + || !str_contains($row, 'maria') && version_compare($row, '8.0', '>='); } } diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php index 559c29df208..52f82db2232 100644 --- a/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php +++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php index 2466493c1fa..48dc1da6330 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php index 6791430b1b0..8fae6275916 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php index ee430a6bd71..354a2b126d7 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php index 956b2123f2c..53aa530054b 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php b/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php index 2942eeccdf7..d748c791321 100644 --- a/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php +++ b/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php @@ -126,8 +126,8 @@ class PartitionedQueryBuilder extends ShardedQueryBuilder { $selectPartition = null; } if ( - ($select === $checkColumn || $select === '*') && - $selectPartition === $partition + ($select === $checkColumn || $select === '*') + && $selectPartition === $partition ) { return; } @@ -151,8 +151,8 @@ class PartitionedQueryBuilder extends ShardedQueryBuilder { foreach ($this->selects as $select) { foreach ($this->partitions as $partition) { if (is_string($select['select']) && ( - $select['select'] === '*' || - $partition->isColumnInPartition($select['select'])) + $select['select'] === '*' + || $partition->isColumnInPartition($select['select'])) ) { if (isset($this->splitQueries[$partition->name])) { if ($select['alias']) { @@ -444,4 +444,19 @@ class PartitionedQueryBuilder extends ShardedQueryBuilder { public function getPartitionCount(): int { return count($this->splitQueries) + 1; } + + public function hintShardKey(string $column, mixed $value, bool $overwrite = false): self { + if (str_contains($column, '.')) { + [$alias, $column] = explode('.', $column); + $partition = $this->getPartition($alias); + if ($partition) { + $this->splitQueries[$partition->name]->query->hintShardKey($column, $value, $overwrite); + } else { + parent::hintShardKey($column, $value, $overwrite); + } + } else { + parent::hintShardKey($column, $value, $overwrite); + } + return $this; + } } diff --git a/lib/private/DB/SchemaWrapper.php b/lib/private/DB/SchemaWrapper.php index 473c0009237..0d5b2040513 100644 --- a/lib/private/DB/SchemaWrapper.php +++ b/lib/private/DB/SchemaWrapper.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Diagnostics/Event.php b/lib/private/Diagnostics/Event.php index cf36bf9f82a..11d6505a888 100644 --- a/lib/private/Diagnostics/Event.php +++ b/lib/private/Diagnostics/Event.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Diagnostics/EventLogger.php b/lib/private/Diagnostics/EventLogger.php index 40cbd3e9e5d..3ec35a5e9ce 100644 --- a/lib/private/Diagnostics/EventLogger.php +++ b/lib/private/Diagnostics/EventLogger.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Diagnostics/Query.php b/lib/private/Diagnostics/Query.php index 81610074709..020fc4bb512 100644 --- a/lib/private/Diagnostics/Query.php +++ b/lib/private/Diagnostics/Query.php @@ -56,7 +56,7 @@ class Query implements IQuery { public function getStart() { return $this->start; } - + /** * @return float */ diff --git a/lib/private/DirectEditing/Manager.php b/lib/private/DirectEditing/Manager.php index 4823b6b4456..154002ef340 100644 --- a/lib/private/DirectEditing/Manager.php +++ b/lib/private/DirectEditing/Manager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/DirectEditing/Token.php b/lib/private/DirectEditing/Token.php index 12ad9411216..ca01265f9df 100644 --- a/lib/private/DirectEditing/Token.php +++ b/lib/private/DirectEditing/Token.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/EmojiHelper.php b/lib/private/EmojiHelper.php index 514973b2959..52ab441e73a 100644 --- a/lib/private/EmojiHelper.php +++ b/lib/private/EmojiHelper.php @@ -19,8 +19,8 @@ class EmojiHelper implements IEmojiHelper { } public function doesPlatformSupportEmoji(): bool { - return $this->db->supports4ByteText() && - \class_exists(\IntlBreakIterator::class); + return $this->db->supports4ByteText() + && \class_exists(\IntlBreakIterator::class); } public function isValidSingleEmoji(string $emoji): bool { @@ -48,17 +48,17 @@ class EmojiHelper implements IEmojiHelper { if (strlen($emoji) >= 2) { // If the current code-point is an emoji or a modifier (like a skin-tone) // just continue and check the next character - if ($codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_SYMBOL || - $codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_LETTER || - $codePointType === \IntlChar::CHAR_CATEGORY_OTHER_SYMBOL || - $codePointType === \IntlChar::CHAR_CATEGORY_FORMAT_CHAR || // i.e. 🏴 🏴 - $codePointType === \IntlChar::CHAR_CATEGORY_OTHER_PUNCTUATION || // i.e. ‼️ ⁉️ #⃣ - $codePointType === \IntlChar::CHAR_CATEGORY_LOWERCASE_LETTER || // i.e. ℹ️ - $codePointType === \IntlChar::CHAR_CATEGORY_MATH_SYMBOL || // i.e. ↔️ ◻️ ⤴️ ⤵️ - $codePointType === \IntlChar::CHAR_CATEGORY_ENCLOSING_MARK || // i.e. 0⃣..9⃣ - $codePointType === \IntlChar::CHAR_CATEGORY_DECIMAL_DIGIT_NUMBER || // i.e. 0⃣..9⃣ - $codePointType === \IntlChar::CHAR_CATEGORY_DASH_PUNCTUATION || // i.e. 〰️ - $codePointType === \IntlChar::CHAR_CATEGORY_GENERAL_OTHER_TYPES + if ($codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_SYMBOL + || $codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_LETTER + || $codePointType === \IntlChar::CHAR_CATEGORY_OTHER_SYMBOL + || $codePointType === \IntlChar::CHAR_CATEGORY_FORMAT_CHAR // i.e. 🏴 🏴 + || $codePointType === \IntlChar::CHAR_CATEGORY_OTHER_PUNCTUATION // i.e. ‼️ ⁉️ #⃣ + || $codePointType === \IntlChar::CHAR_CATEGORY_LOWERCASE_LETTER // i.e. ℹ️ + || $codePointType === \IntlChar::CHAR_CATEGORY_MATH_SYMBOL // i.e. ↔️ ◻️ ⤴️ ⤵️ + || $codePointType === \IntlChar::CHAR_CATEGORY_ENCLOSING_MARK // i.e. 0⃣..9⃣ + || $codePointType === \IntlChar::CHAR_CATEGORY_DECIMAL_DIGIT_NUMBER // i.e. 0⃣..9⃣ + || $codePointType === \IntlChar::CHAR_CATEGORY_DASH_PUNCTUATION // i.e. 〰️ + || $codePointType === \IntlChar::CHAR_CATEGORY_GENERAL_OTHER_TYPES ) { continue; } diff --git a/lib/private/Encryption/EncryptionEventListener.php b/lib/private/Encryption/EncryptionEventListener.php index 59ac0dea932..d51b4b0d531 100644 --- a/lib/private/Encryption/EncryptionEventListener.php +++ b/lib/private/Encryption/EncryptionEventListener.php @@ -17,7 +17,9 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\IEventListener; use OCP\Files\Events\Node\NodeRenamedEvent; +use OCP\Files\NotFoundException; use OCP\IUser; +use OCP\IUserManager; use OCP\IUserSession; use OCP\Share\Events\ShareCreatedEvent; use OCP\Share\Events\ShareDeletedEvent; @@ -31,6 +33,7 @@ class EncryptionEventListener implements IEventListener { private IUserSession $userSession, private SetupManager $setupManager, private Manager $encryptionManager, + private IUserManager $userManager, ) { } @@ -50,10 +53,14 @@ class EncryptionEventListener implements IEventListener { } elseif ($event instanceof ShareCreatedEvent) { $this->getUpdate()->postShared($event->getShare()->getNode()); } elseif ($event instanceof ShareDeletedEvent) { - // In case the unsharing happens in a background job, we don't have - // a session and we load instead the user from the UserManager - $owner = $event->getShare()->getNode()->getOwner(); - $this->getUpdate($owner)->postUnshared($event->getShare()->getNode()); + try { + // In case the unsharing happens in a background job, we don't have + // a session and we load instead the user from the UserManager + $owner = $this->userManager->get($event->getShare()->getShareOwner()); + $this->getUpdate($owner)->postUnshared($event->getShare()->getNode()); + } catch (NotFoundException $e) { + /* The node was deleted already, nothing to update */ + } } elseif ($event instanceof NodeRestoredEvent) { $this->getUpdate()->postRestore($event->getTarget()); } @@ -78,7 +85,7 @@ class EncryptionEventListener implements IEventListener { $this->updater = new Update( new Util( new View(), - \OC::$server->getUserManager(), + $this->userManager, \OC::$server->getGroupManager(), \OC::$server->getConfig()), \OC::$server->getEncryptionManager(), diff --git a/lib/private/Encryption/Keys/Storage.php b/lib/private/Encryption/Keys/Storage.php index 2c0ce9e5ef3..cce22b9138a 100644 --- a/lib/private/Encryption/Keys/Storage.php +++ b/lib/private/Encryption/Keys/Storage.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Encryption/Util.php b/lib/private/Encryption/Util.php index 0566ab9a760..2d7bc28129b 100644 --- a/lib/private/Encryption/Util.php +++ b/lib/private/Encryption/Util.php @@ -290,8 +290,8 @@ class Util { if (count($root) > 1) { // detect alternative key storage root $rootDir = $this->getKeyStorageRoot(); - if ($rootDir !== '' && - str_starts_with(Filesystem::normalizePath($path), Filesystem::normalizePath($rootDir)) + if ($rootDir !== '' + && str_starts_with(Filesystem::normalizePath($path), Filesystem::normalizePath($rootDir)) ) { return true; } diff --git a/lib/private/Federation/CloudFederationFactory.php b/lib/private/Federation/CloudFederationFactory.php index f5f25d14ea1..d06de0f2f58 100644 --- a/lib/private/Federation/CloudFederationFactory.php +++ b/lib/private/Federation/CloudFederationFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Federation/CloudFederationNotification.php b/lib/private/Federation/CloudFederationNotification.php index 855580843ba..6ae805df1d9 100644 --- a/lib/private/Federation/CloudFederationNotification.php +++ b/lib/private/Federation/CloudFederationNotification.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Federation/CloudFederationProviderManager.php b/lib/private/Federation/CloudFederationProviderManager.php index e9354294351..81b5d717a56 100644 --- a/lib/private/Federation/CloudFederationProviderManager.php +++ b/lib/private/Federation/CloudFederationProviderManager.php @@ -227,8 +227,8 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager private function prepareOcmPayload(string $uri, string $payload): array { $payload = array_merge($this->getDefaultRequestOptions(), ['body' => $payload]); - if ($this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_ENFORCED, lazy: true) && - $this->signatoryManager->getRemoteSignatory($this->signatureManager->extractIdentityFromUri($uri)) === null) { + if ($this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_ENFORCED, lazy: true) + && $this->signatoryManager->getRemoteSignatory($this->signatureManager->extractIdentityFromUri($uri)) === null) { return $payload; } diff --git a/lib/private/Federation/CloudFederationShare.php b/lib/private/Federation/CloudFederationShare.php index 3ec53d89ed3..2eb06b3acea 100644 --- a/lib/private/Federation/CloudFederationShare.php +++ b/lib/private/Federation/CloudFederationShare.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index cb160115851..329466e682d 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -668,8 +668,8 @@ class Cache implements ICache { $shardDefinition = $this->connection->getShardDefinition('filecache'); if ( - $shardDefinition && - $shardDefinition->getShardForKey($sourceCache->getNumericStorageId()) !== $shardDefinition->getShardForKey($this->getNumericStorageId()) + $shardDefinition + && $shardDefinition->getShardForKey($sourceCache->getNumericStorageId()) !== $shardDefinition->getShardForKey($this->getNumericStorageId()) ) { $this->moveFromStorageSharded($shardDefinition, $sourceCache, $sourceData, $targetPath); return; diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php index ff2d6766893..3ddcf1ca4e6 100644 --- a/lib/private/Files/Cache/QuerySearchHelper.php +++ b/lib/private/Files/Cache/QuerySearchHelper.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Cache/SearchBuilder.php b/lib/private/Files/Cache/SearchBuilder.php index 6a0cba7f1f2..e1d3c42a8a2 100644 --- a/lib/private/Files/Cache/SearchBuilder.php +++ b/lib/private/Files/Cache/SearchBuilder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Cache/Storage.php b/lib/private/Files/Cache/Storage.php index 2b49e65f0b4..1a3bda58e6a 100644 --- a/lib/private/Files/Cache/Storage.php +++ b/lib/private/Files/Cache/Storage.php @@ -213,6 +213,7 @@ class Storage { $query = $db->getQueryBuilder(); $query->delete('filecache') ->where($query->expr()->in('storage', $query->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY))); + $query->runAcrossAllShards(); $query->executeStatement(); $query = $db->getQueryBuilder(); diff --git a/lib/private/Files/Cache/Wrapper/JailPropagator.php b/lib/private/Files/Cache/Wrapper/JailPropagator.php index 19ca4a13ece..d6409b7875e 100644 --- a/lib/private/Files/Cache/Wrapper/JailPropagator.php +++ b/lib/private/Files/Cache/Wrapper/JailPropagator.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Config/CachedMountFileInfo.php b/lib/private/Files/Config/CachedMountFileInfo.php index 90a6b47f9d8..69bd4e9301e 100644 --- a/lib/private/Files/Config/CachedMountFileInfo.php +++ b/lib/private/Files/Config/CachedMountFileInfo.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index 09ac6d1416a..3e53a67a044 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -151,9 +151,9 @@ class UserMountCache implements IUserMountCache { if (isset($newMounts[$key])) { $newMount = $newMounts[$key]; if ( - $newMount->getStorageId() !== $cachedMount->getStorageId() || - $newMount->getMountId() !== $cachedMount->getMountId() || - $newMount->getMountProvider() !== $cachedMount->getMountProvider() + $newMount->getStorageId() !== $cachedMount->getStorageId() + || $newMount->getMountId() !== $cachedMount->getMountId() + || $newMount->getMountProvider() !== $cachedMount->getMountProvider() ) { $changed[] = [$cachedMount, $newMount]; } diff --git a/lib/private/Files/Conversion/ConversionManager.php b/lib/private/Files/Conversion/ConversionManager.php index cf1085f66f0..2c98a4c6404 100644 --- a/lib/private/Files/Conversion/ConversionManager.php +++ b/lib/private/Files/Conversion/ConversionManager.php @@ -129,7 +129,7 @@ class ConversionManager implements IConversionManager { $this->preferredProviders[$class] = $this->serverContainer->get($class); continue; } - + $this->providers[$class] = $this->serverContainer->get($class); } catch (NotFoundExceptionInterface|ContainerExceptionInterface|Throwable $e) { $this->logger->error('Failed to load file conversion provider ' . $class, [ @@ -175,7 +175,7 @@ class ConversionManager implements IConversionManager { } } } - + return null; } } diff --git a/lib/private/Files/FilenameValidator.php b/lib/private/Files/FilenameValidator.php index 57a62b0b219..a78c6d3cc3c 100644 --- a/lib/private/Files/FilenameValidator.php +++ b/lib/private/Files/FilenameValidator.php @@ -232,7 +232,7 @@ class FilenameValidator implements IFilenameValidator { $forbiddenCharacters = $this->getForbiddenCharacters(); if ($charReplacement === null) { - $charReplacement = array_diff([' ', '_', '-'], $forbiddenCharacters); + $charReplacement = array_diff(['_', '-', ' '], $forbiddenCharacters); $charReplacement = reset($charReplacement) ?: ''; } if (mb_strlen($charReplacement) !== 1) { diff --git a/lib/private/Files/Mount/ObjectHomeMountProvider.php b/lib/private/Files/Mount/ObjectHomeMountProvider.php index 99c52108fa8..4b088f2c808 100644 --- a/lib/private/Files/Mount/ObjectHomeMountProvider.php +++ b/lib/private/Files/Mount/ObjectHomeMountProvider.php @@ -7,117 +7,39 @@ */ namespace OC\Files\Mount; +use OC\Files\ObjectStore\HomeObjectStoreStorage; +use OC\Files\ObjectStore\PrimaryObjectStoreConfig; use OCP\Files\Config\IHomeMountProvider; +use OCP\Files\Mount\IMountPoint; use OCP\Files\Storage\IStorageFactory; -use OCP\IConfig; use OCP\IUser; -use Psr\Log\LoggerInterface; /** * Mount provider for object store home storages */ class ObjectHomeMountProvider implements IHomeMountProvider { - /** - * @var IConfig - */ - private $config; - - /** - * ObjectStoreHomeMountProvider constructor. - * - * @param IConfig $config - */ - public function __construct(IConfig $config) { - $this->config = $config; + public function __construct( + private PrimaryObjectStoreConfig $objectStoreConfig, + ) { } /** - * Get the cache mount for a user + * Get the home mount for a user * * @param IUser $user * @param IStorageFactory $loader - * @return \OCP\Files\Mount\IMountPoint + * @return ?IMountPoint */ - public function getHomeMountForUser(IUser $user, IStorageFactory $loader) { - $config = $this->getMultiBucketObjectStoreConfig($user); - if ($config === null) { - $config = $this->getSingleBucketObjectStoreConfig($user); - } - - if ($config === null) { + public function getHomeMountForUser(IUser $user, IStorageFactory $loader): ?IMountPoint { + $objectStoreConfig = $this->objectStoreConfig->getObjectStoreConfigForUser($user); + if ($objectStoreConfig === null) { return null; } + $arguments = array_merge($objectStoreConfig['arguments'], [ + 'objectstore' => $this->objectStoreConfig->buildObjectStore($objectStoreConfig), + 'user' => $user, + ]); - return new HomeMountPoint($user, '\OC\Files\ObjectStore\HomeObjectStoreStorage', '/' . $user->getUID(), $config['arguments'], $loader, null, null, self::class); - } - - /** - * @param IUser $user - * @return array|null - */ - private function getSingleBucketObjectStoreConfig(IUser $user) { - $config = $this->config->getSystemValue('objectstore'); - if (!is_array($config)) { - return null; - } - - // sanity checks - if (empty($config['class'])) { - \OC::$server->get(LoggerInterface::class)->error('No class given for objectstore', ['app' => 'files']); - } - if (!isset($config['arguments'])) { - $config['arguments'] = []; - } - // instantiate object store implementation - $config['arguments']['objectstore'] = new $config['class']($config['arguments']); - - $config['arguments']['user'] = $user; - - return $config; - } - - /** - * @param IUser $user - * @return array|null - */ - private function getMultiBucketObjectStoreConfig(IUser $user) { - $config = $this->config->getSystemValue('objectstore_multibucket'); - if (!is_array($config)) { - return null; - } - - // sanity checks - if (empty($config['class'])) { - \OC::$server->get(LoggerInterface::class)->error('No class given for objectstore', ['app' => 'files']); - } - if (!isset($config['arguments'])) { - $config['arguments'] = []; - } - - $bucket = $this->config->getUserValue($user->getUID(), 'homeobjectstore', 'bucket', null); - - if ($bucket === null) { - /* - * Use any provided bucket argument as prefix - * and add the mapping from username => bucket - */ - if (!isset($config['arguments']['bucket'])) { - $config['arguments']['bucket'] = ''; - } - $mapper = new \OC\Files\ObjectStore\Mapper($user, $this->config); - $numBuckets = $config['arguments']['num_buckets'] ?? 64; - $config['arguments']['bucket'] .= $mapper->getBucket($numBuckets); - - $this->config->setUserValue($user->getUID(), 'homeobjectstore', 'bucket', $config['arguments']['bucket']); - } else { - $config['arguments']['bucket'] = $bucket; - } - - // instantiate object store implementation - $config['arguments']['objectstore'] = new $config['class']($config['arguments']); - - $config['arguments']['user'] = $user; - - return $config; + return new HomeMountPoint($user, HomeObjectStoreStorage::class, '/' . $user->getUID(), $arguments, $loader, null, null, self::class); } } diff --git a/lib/private/Files/Mount/RootMountProvider.php b/lib/private/Files/Mount/RootMountProvider.php index 86f8188978f..5e0c924ad38 100644 --- a/lib/private/Files/Mount/RootMountProvider.php +++ b/lib/private/Files/Mount/RootMountProvider.php @@ -10,79 +10,41 @@ namespace OC\Files\Mount; use OC; use OC\Files\ObjectStore\ObjectStoreStorage; +use OC\Files\ObjectStore\PrimaryObjectStoreConfig; use OC\Files\Storage\LocalRootStorage; -use OC_App; use OCP\Files\Config\IRootMountProvider; use OCP\Files\Storage\IStorageFactory; use OCP\IConfig; -use Psr\Log\LoggerInterface; class RootMountProvider implements IRootMountProvider { + private PrimaryObjectStoreConfig $objectStoreConfig; private IConfig $config; - private LoggerInterface $logger; - public function __construct(IConfig $config, LoggerInterface $logger) { + public function __construct(PrimaryObjectStoreConfig $objectStoreConfig, IConfig $config) { + $this->objectStoreConfig = $objectStoreConfig; $this->config = $config; - $this->logger = $logger; } public function getRootMounts(IStorageFactory $loader): array { - $objectStore = $this->config->getSystemValue('objectstore', null); - $objectStoreMultiBucket = $this->config->getSystemValue('objectstore_multibucket', null); + $objectStoreConfig = $this->objectStoreConfig->getObjectStoreConfigForRoot(); - if ($objectStoreMultiBucket) { - return [$this->getMultiBucketStoreRootMount($loader, $objectStoreMultiBucket)]; - } elseif ($objectStore) { - return [$this->getObjectStoreRootMount($loader, $objectStore)]; + if ($objectStoreConfig) { + return [$this->getObjectStoreRootMount($loader, $objectStoreConfig)]; } else { return [$this->getLocalRootMount($loader)]; } } - private function validateObjectStoreConfig(array &$config) { - if (empty($config['class'])) { - $this->logger->error('No class given for objectstore', ['app' => 'files']); - } - if (!isset($config['arguments'])) { - $config['arguments'] = []; - } - - // instantiate object store implementation - $name = $config['class']; - if (str_starts_with($name, 'OCA\\') && substr_count($name, '\\') >= 2) { - $segments = explode('\\', $name); - OC_App::loadApp(strtolower($segments[1])); - } - } - private function getLocalRootMount(IStorageFactory $loader): MountPoint { $configDataDirectory = $this->config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data'); return new MountPoint(LocalRootStorage::class, '/', ['datadir' => $configDataDirectory], $loader, null, null, self::class); } - private function getObjectStoreRootMount(IStorageFactory $loader, array $config): MountPoint { - $this->validateObjectStoreConfig($config); - - $config['arguments']['objectstore'] = new $config['class']($config['arguments']); - // mount with plain / root object store implementation - $config['class'] = ObjectStoreStorage::class; - - return new MountPoint($config['class'], '/', $config['arguments'], $loader, null, null, self::class); - } - - private function getMultiBucketStoreRootMount(IStorageFactory $loader, array $config): MountPoint { - $this->validateObjectStoreConfig($config); - - if (!isset($config['arguments']['bucket'])) { - $config['arguments']['bucket'] = ''; - } - // put the root FS always in first bucket for multibucket configuration - $config['arguments']['bucket'] .= '0'; - - $config['arguments']['objectstore'] = new $config['class']($config['arguments']); - // mount with plain / root object store implementation - $config['class'] = ObjectStoreStorage::class; + private function getObjectStoreRootMount(IStorageFactory $loader, array $objectStoreConfig): MountPoint { + $arguments = array_merge($objectStoreConfig['arguments'], [ + 'objectstore' => $this->objectStoreConfig->buildObjectStore($objectStoreConfig), + ]); - return new MountPoint($config['class'], '/', $config['arguments'], $loader, null, null, self::class); + return new MountPoint(ObjectStoreStorage::class, '/', $arguments, $loader, null, null, self::class); } } diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index 16365948031..7453b553119 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -460,4 +461,12 @@ class Folder extends Node implements \OCP\Files\Folder { return $this->search($query); } + + public function verifyPath($fileName, $readonly = false): void { + $this->view->verifyPath( + $this->getPath(), + $fileName, + $readonly, + ); + } } diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php index 5879748d951..37b1efa0fad 100644 --- a/lib/private/Files/Node/LazyFolder.php +++ b/lib/private/Files/Node/LazyFolder.php @@ -561,4 +561,8 @@ class LazyFolder implements Folder { public function getMetadata(): array { return $this->data['metadata'] ?? $this->__call(__FUNCTION__, func_get_args()); } + + public function verifyPath($fileName, $readonly = false): void { + $this->__call(__FUNCTION__, func_get_args()); + } } diff --git a/lib/private/Files/Notify/Change.php b/lib/private/Files/Notify/Change.php index d2448e5deec..c8eccd11ae2 100644 --- a/lib/private/Files/Notify/Change.php +++ b/lib/private/Files/Notify/Change.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Notify/RenameChange.php b/lib/private/Files/Notify/RenameChange.php index 98fd7099a58..28554ceaa26 100644 --- a/lib/private/Files/Notify/RenameChange.php +++ b/lib/private/Files/Notify/RenameChange.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/ObjectStore/Azure.php b/lib/private/Files/ObjectStore/Azure.php index 575cc336ba8..2729bb3c037 100644 --- a/lib/private/Files/ObjectStore/Azure.php +++ b/lib/private/Files/ObjectStore/Azure.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index ebe87399ab4..10ee6aec167 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -67,7 +67,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil $this->logger = \OCP\Server::get(LoggerInterface::class); } - public function mkdir(string $path, bool $force = false): bool { + public function mkdir(string $path, bool $force = false, array $metadata = []): bool { $path = $this->normalizePath($path); if (!$force && $this->file_exists($path)) { $this->logger->warning("Tried to create an object store folder that already exists: $path"); @@ -77,7 +77,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil $mTime = time(); $data = [ 'mimetype' => 'httpd/unix-directory', - 'size' => 0, + 'size' => $metadata['size'] ?? 0, 'mtime' => $mTime, 'storage_mtime' => $mTime, 'permissions' => \OCP\Constants::PERMISSION_ALL, @@ -413,16 +413,6 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil //create a empty file, need to have at least on char to make it // work with all object storage implementations $this->file_put_contents($path, ' '); - $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path); - $stat = [ - 'etag' => $this->getETag($path), - 'mimetype' => $mimeType, - 'size' => 0, - 'mtime' => $mtime, - 'storage_mtime' => $mtime, - 'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE, - ]; - $this->getCache()->put($path, $stat); } catch (\Exception $ex) { $this->logger->error( 'Could not create object for ' . $path, @@ -607,8 +597,8 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath, ?ICacheEntry $sourceCacheEntry = null): bool { $sourceCache = $sourceStorage->getCache(); if ( - $sourceStorage->instanceOfStorage(ObjectStoreStorage::class) && - $sourceStorage->getObjectStore()->getStorageId() === $this->getObjectStore()->getStorageId() + $sourceStorage->instanceOfStorage(ObjectStoreStorage::class) + && $sourceStorage->getObjectStore()->getStorageId() === $this->getObjectStore()->getStorageId() ) { if ($this->getCache()->get($targetInternalPath)) { $this->unlink($targetInternalPath); @@ -709,7 +699,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil if ($cache->inCache($to)) { $cache->remove($to); } - $this->mkdir($to); + $this->mkdir($to, false, ['size' => $sourceEntry->getSize()]); foreach ($sourceCache->getFolderContentsById($sourceEntry->getId()) as $child) { $this->copyInner($sourceCache, $child, $to . '/' . $child->getName()); diff --git a/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php b/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php new file mode 100644 index 00000000000..fdfe989addc --- /dev/null +++ b/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php @@ -0,0 +1,140 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace OC\Files\ObjectStore; + +use OCP\App\IAppManager; +use OCP\Files\ObjectStore\IObjectStore; +use OCP\IConfig; +use OCP\IUser; + +/** + * @psalm-type ObjectStoreConfig array{class: class-string<IObjectStore>, arguments: array{multibucket: bool, ...}} + */ +class PrimaryObjectStoreConfig { + public function __construct( + private readonly IConfig $config, + private readonly IAppManager $appManager, + ) { + } + + /** + * @param ObjectStoreConfig $config + */ + public function buildObjectStore(array $config): IObjectStore { + return new $config['class']($config['arguments']); + } + + /** + * @return ?ObjectStoreConfig + */ + public function getObjectStoreConfigForRoot(): ?array { + $config = $this->getObjectStoreConfig(); + + if ($config && $config['arguments']['multibucket']) { + if (!isset($config['arguments']['bucket'])) { + $config['arguments']['bucket'] = ''; + } + + // put the root FS always in first bucket for multibucket configuration + $config['arguments']['bucket'] .= '0'; + } + return $config; + } + + /** + * @return ?ObjectStoreConfig + */ + public function getObjectStoreConfigForUser(IUser $user): ?array { + $config = $this->getObjectStoreConfig(); + + if ($config && $config['arguments']['multibucket']) { + $config['arguments']['bucket'] = $this->getBucketForUser($user, $config); + } + return $config; + } + + /** + * @return ?ObjectStoreConfig + */ + private function getObjectStoreConfig(): ?array { + $objectStore = $this->config->getSystemValue('objectstore', null); + $objectStoreMultiBucket = $this->config->getSystemValue('objectstore_multibucket', null); + + // new-style multibucket config uses the same 'objectstore' key but sets `'multibucket' => true`, transparently upgrade older style config + if ($objectStoreMultiBucket) { + $objectStoreMultiBucket['arguments']['multibucket'] = true; + return $this->validateObjectStoreConfig($objectStoreMultiBucket); + } elseif ($objectStore) { + return $this->validateObjectStoreConfig($objectStore); + } else { + return null; + } + } + + /** + * @return ObjectStoreConfig + */ + private function validateObjectStoreConfig(array $config) { + if (!isset($config['class'])) { + throw new \Exception('No class configured for object store'); + } + if (!isset($config['arguments'])) { + $config['arguments'] = []; + } + $class = $config['class']; + $arguments = $config['arguments']; + if (!is_array($arguments)) { + throw new \Exception('Configured object store arguments are not an array'); + } + if (!isset($arguments['multibucket'])) { + $arguments['multibucket'] = false; + } + if (!is_bool($arguments['multibucket'])) { + throw new \Exception('arguments.multibucket must be a boolean in object store configuration'); + } + + if (!is_string($class)) { + throw new \Exception('Configured class for object store is not a string'); + } + + if (str_starts_with($class, 'OCA\\') && substr_count($class, '\\') >= 2) { + [$appId] = explode('\\', $class); + $this->appManager->loadApp(strtolower($appId)); + } + + if (!is_a($class, IObjectStore::class, true)) { + throw new \Exception('Configured class for object store is not an object store'); + } + return [ + 'class' => $class, + 'arguments' => $arguments, + ]; + } + + private function getBucketForUser(IUser $user, array $config): string { + $bucket = $this->config->getUserValue($user->getUID(), 'homeobjectstore', 'bucket', null); + + if ($bucket === null) { + /* + * Use any provided bucket argument as prefix + * and add the mapping from username => bucket + */ + if (!isset($config['arguments']['bucket'])) { + $config['arguments']['bucket'] = ''; + } + $mapper = new Mapper($user, $this->config); + $numBuckets = isset($config['arguments']['num_buckets']) ? $config['arguments']['num_buckets'] : 64; + $bucket = $config['arguments']['bucket'] . $mapper->getBucket($numBuckets); + + $this->config->setUserValue($user->getUID(), 'homeobjectstore', 'bucket', $bucket); + } + + return $bucket; + } +} diff --git a/lib/private/Files/ObjectStore/S3.php b/lib/private/Files/ObjectStore/S3.php index 23c061db174..72e1751e23d 100644 --- a/lib/private/Files/ObjectStore/S3.php +++ b/lib/private/Files/ObjectStore/S3.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/ObjectStore/S3ConfigTrait.php b/lib/private/Files/ObjectStore/S3ConfigTrait.php index 63f14ac2d00..5b086db8f77 100644 --- a/lib/private/Files/ObjectStore/S3ConfigTrait.php +++ b/lib/private/Files/ObjectStore/S3ConfigTrait.php @@ -18,6 +18,10 @@ trait S3ConfigTrait { /** Maximum number of concurrent multipart uploads */ protected int $concurrency; + /** Timeout, in seconds, for the connection to S3 server, not for the + * request. */ + protected float $connectTimeout; + protected int $timeout; protected string|false $proxy; diff --git a/lib/private/Files/ObjectStore/S3ConnectionTrait.php b/lib/private/Files/ObjectStore/S3ConnectionTrait.php index b7017583dc2..67b82a44ab7 100644 --- a/lib/private/Files/ObjectStore/S3ConnectionTrait.php +++ b/lib/private/Files/ObjectStore/S3ConnectionTrait.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -39,6 +40,7 @@ trait S3ConnectionTrait { // Default to 5 like the S3 SDK does $this->concurrency = $params['concurrency'] ?? 5; $this->proxy = $params['proxy'] ?? false; + $this->connectTimeout = $params['connect_timeout'] ?? 5; $this->timeout = $params['timeout'] ?? 15; $this->storageClass = !empty($params['storageClass']) ? $params['storageClass'] : 'STANDARD'; $this->uploadPartSize = $params['uploadPartSize'] ?? 524288000; @@ -102,8 +104,7 @@ trait S3ConnectionTrait { 'use_arn_region' => false, 'http' => [ 'verify' => $this->getCertificateBundlePath(), - // Timeout for the connection to S3 server, not for the request. - 'connect_timeout' => 5 + 'connect_timeout' => $this->connectTimeout, ], 'use_aws_shared_config_files' => false, 'retries' => [ diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php index 61e8158b863..5e6dcf88a42 100644 --- a/lib/private/Files/ObjectStore/S3ObjectTrait.php +++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php @@ -119,28 +119,54 @@ trait S3ObjectTrait { protected function writeMultiPart(string $urn, StreamInterface $stream, array $metaData): void { $mimetype = $metaData['mimetype'] ?? null; unset($metaData['mimetype']); - $uploader = new MultipartUploader($this->getConnection(), $stream, [ - 'bucket' => $this->bucket, - 'concurrency' => $this->concurrency, - 'key' => $urn, - 'part_size' => $this->uploadPartSize, - 'params' => [ - 'ContentType' => $mimetype, - 'Metadata' => $this->buildS3Metadata($metaData), - 'StorageClass' => $this->storageClass, - ] + $this->getSSECParameters(), - ]); - try { - $uploader->upload(); - } catch (S3MultipartUploadException $e) { + $attempts = 0; + $uploaded = false; + $concurrency = $this->concurrency; + $exception = null; + $state = null; + + // retry multipart upload once with concurrency at half on failure + while (!$uploaded && $attempts <= 1) { + $uploader = new MultipartUploader($this->getConnection(), $stream, [ + 'bucket' => $this->bucket, + 'concurrency' => $concurrency, + 'key' => $urn, + 'part_size' => $this->uploadPartSize, + 'state' => $state, + 'params' => [ + 'ContentType' => $mimetype, + 'Metadata' => $this->buildS3Metadata($metaData), + 'StorageClass' => $this->storageClass, + ] + $this->getSSECParameters(), + ]); + + try { + $uploader->upload(); + $uploaded = true; + } catch (S3MultipartUploadException $e) { + $exception = $e; + $attempts++; + + if ($concurrency > 1) { + $concurrency = round($concurrency / 2); + } + + if ($stream->isSeekable()) { + $stream->rewind(); + } + } + } + + if (!$uploaded) { // if anything goes wrong with multipart, make sure that you don´t poison and // slow down s3 bucket with orphaned fragments - $uploadInfo = $e->getState()->getId(); - if ($e->getState()->isInitiated() && (array_key_exists('UploadId', $uploadInfo))) { + $uploadInfo = $exception->getState()->getId(); + if ($exception->getState()->isInitiated() && (array_key_exists('UploadId', $uploadInfo))) { $this->getConnection()->abortMultipartUpload($uploadInfo); } - throw new \OCA\DAV\Connector\Sabre\Exception\BadGateway('Error while uploading to S3 bucket', 0, $e); + + throw new \OCA\DAV\Connector\Sabre\Exception\BadGateway('Error while uploading to S3 bucket', 0, $exception); } } diff --git a/lib/private/Files/ObjectStore/S3Signature.php b/lib/private/Files/ObjectStore/S3Signature.php index 994d65cc219..b80382ff67d 100644 --- a/lib/private/Files/ObjectStore/S3Signature.php +++ b/lib/private/Files/ObjectStore/S3Signature.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/ObjectStore/StorageObjectStore.php b/lib/private/Files/ObjectStore/StorageObjectStore.php index 4361795ec45..888602a62e4 100644 --- a/lib/private/Files/ObjectStore/StorageObjectStore.php +++ b/lib/private/Files/ObjectStore/StorageObjectStore.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Search/QueryOptimizer/FlattenNestedBool.php b/lib/private/Files/Search/QueryOptimizer/FlattenNestedBool.php index 2bde6f0bbdb..bb7bef2ed63 100644 --- a/lib/private/Files/Search/QueryOptimizer/FlattenNestedBool.php +++ b/lib/private/Files/Search/QueryOptimizer/FlattenNestedBool.php @@ -14,8 +14,8 @@ class FlattenNestedBool extends QueryOptimizerStep { public function processOperator(ISearchOperator &$operator) { if ( $operator instanceof SearchBinaryOperator && ( - $operator->getType() === ISearchBinaryOperator::OPERATOR_OR || - $operator->getType() === ISearchBinaryOperator::OPERATOR_AND + $operator->getType() === ISearchBinaryOperator::OPERATOR_OR + || $operator->getType() === ISearchBinaryOperator::OPERATOR_AND ) ) { $newArguments = []; diff --git a/lib/private/Files/Search/QueryOptimizer/FlattenSingleArgumentBinaryOperation.php b/lib/private/Files/Search/QueryOptimizer/FlattenSingleArgumentBinaryOperation.php index cb04351534a..7e99c04f197 100644 --- a/lib/private/Files/Search/QueryOptimizer/FlattenSingleArgumentBinaryOperation.php +++ b/lib/private/Files/Search/QueryOptimizer/FlattenSingleArgumentBinaryOperation.php @@ -16,11 +16,11 @@ class FlattenSingleArgumentBinaryOperation extends ReplacingOptimizerStep { public function processOperator(ISearchOperator &$operator): bool { parent::processOperator($operator); if ( - $operator instanceof ISearchBinaryOperator && - count($operator->getArguments()) === 1 && - ( - $operator->getType() === ISearchBinaryOperator::OPERATOR_OR || - $operator->getType() === ISearchBinaryOperator::OPERATOR_AND + $operator instanceof ISearchBinaryOperator + && count($operator->getArguments()) === 1 + && ( + $operator->getType() === ISearchBinaryOperator::OPERATOR_OR + || $operator->getType() === ISearchBinaryOperator::OPERATOR_AND ) ) { $operator = $operator->getArguments()[0]; diff --git a/lib/private/Files/Search/QueryOptimizer/OrEqualsToIn.php b/lib/private/Files/Search/QueryOptimizer/OrEqualsToIn.php index 42d960cc22a..6df35c9c9a2 100644 --- a/lib/private/Files/Search/QueryOptimizer/OrEqualsToIn.php +++ b/lib/private/Files/Search/QueryOptimizer/OrEqualsToIn.php @@ -18,8 +18,8 @@ use OCP\Files\Search\ISearchOperator; class OrEqualsToIn extends ReplacingOptimizerStep { public function processOperator(ISearchOperator &$operator): bool { if ( - $operator instanceof ISearchBinaryOperator && - $operator->getType() === ISearchBinaryOperator::OPERATOR_OR + $operator instanceof ISearchBinaryOperator + && $operator->getType() === ISearchBinaryOperator::OPERATOR_OR ) { $groups = $this->groupEqualsComparisonsByField($operator->getArguments()); $newParts = array_map(function (array $group) { diff --git a/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php b/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php index 9d50746d5d1..2994a9365a7 100644 --- a/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php +++ b/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php @@ -52,9 +52,9 @@ class PathPrefixOptimizer extends QueryOptimizerStep { private function operatorPairIsPathPrefix(ISearchOperator $like, ISearchOperator $equal): bool { return ( - $like instanceof ISearchComparison && $equal instanceof ISearchComparison && - !$like->getExtra() && !$equal->getExtra() && $like->getField() === 'path' && $equal->getField() === 'path' && - $like->getType() === ISearchComparison::COMPARE_LIKE_CASE_SENSITIVE && $equal->getType() === ISearchComparison::COMPARE_EQUAL + $like instanceof ISearchComparison && $equal instanceof ISearchComparison + && !$like->getExtra() && !$equal->getExtra() && $like->getField() === 'path' && $equal->getField() === 'path' + && $like->getType() === ISearchComparison::COMPARE_LIKE_CASE_SENSITIVE && $equal->getType() === ISearchComparison::COMPARE_EQUAL && $like->getValue() === SearchComparison::escapeLikeParameter($equal->getValue()) . '/%' ); } diff --git a/lib/private/Files/Search/QueryOptimizer/SplitLargeIn.php b/lib/private/Files/Search/QueryOptimizer/SplitLargeIn.php index 3e5258a715f..8aee1975708 100644 --- a/lib/private/Files/Search/QueryOptimizer/SplitLargeIn.php +++ b/lib/private/Files/Search/QueryOptimizer/SplitLargeIn.php @@ -18,9 +18,9 @@ use OCP\Files\Search\ISearchOperator; class SplitLargeIn extends ReplacingOptimizerStep { public function processOperator(ISearchOperator &$operator): bool { if ( - $operator instanceof ISearchComparison && - $operator->getType() === ISearchComparison::COMPARE_IN && - count($operator->getValue()) > 1000 + $operator instanceof ISearchComparison + && $operator->getType() === ISearchComparison::COMPARE_IN + && count($operator->getValue()) > 1000 ) { $chunks = array_chunk($operator->getValue(), 1000); $chunkComparisons = array_map(function (array $values) use ($operator) { diff --git a/lib/private/Files/Search/SearchBinaryOperator.php b/lib/private/Files/Search/SearchBinaryOperator.php index 59a1ba2dfaf..49f599933f4 100644 --- a/lib/private/Files/Search/SearchBinaryOperator.php +++ b/lib/private/Files/Search/SearchBinaryOperator.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Search/SearchOrder.php b/lib/private/Files/Search/SearchOrder.php index 3dcbc02bc1a..5a036653f4e 100644 --- a/lib/private/Files/Search/SearchOrder.php +++ b/lib/private/Files/Search/SearchOrder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Search/SearchQuery.php b/lib/private/Files/Search/SearchQuery.php index 1793e42d349..592749cf4a0 100644 --- a/lib/private/Files/Search/SearchQuery.php +++ b/lib/private/Files/Search/SearchQuery.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index 7f97187179e..d6260c38fb0 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -23,7 +23,6 @@ use OC\Share\Share; use OC\Share20\ShareDisableChecker; use OC_App; use OC_Hook; -use OC_Util; use OCA\Files_External\Config\ExternalMountPoint; use OCA\Files_Sharing\External\Mount; use OCA\Files_Sharing\ISharedMountPoint; @@ -157,7 +156,7 @@ class SetupManager { if ($mount instanceof HomeMountPoint) { $user = $mount->getUser(); return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) { - return OC_Util::getUserQuota($user); + return $user->getQuotaBytes(); }, 'root' => 'files', 'include_external_storage' => $quotaIncludeExternal]); } @@ -172,9 +171,9 @@ class SetupManager { return new PermissionsMask([ 'storage' => $storage, 'mask' => Constants::PERMISSION_ALL & ~( - Constants::PERMISSION_UPDATE | - Constants::PERMISSION_CREATE | - Constants::PERMISSION_DELETE + Constants::PERMISSION_UPDATE + | Constants::PERMISSION_CREATE + | Constants::PERMISSION_DELETE ), ]); } diff --git a/lib/private/Files/SimpleFS/SimpleFile.php b/lib/private/Files/SimpleFS/SimpleFile.php index 0bfaea21788..d9c1b47d2f1 100644 --- a/lib/private/Files/SimpleFS/SimpleFile.php +++ b/lib/private/Files/SimpleFS/SimpleFile.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/SimpleFS/SimpleFolder.php b/lib/private/Files/SimpleFS/SimpleFolder.php index 0da552e402b..62f3db25e9b 100644 --- a/lib/private/Files/SimpleFS/SimpleFolder.php +++ b/lib/private/Files/SimpleFS/SimpleFolder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php index b1e02cf2e6c..2dc359169d7 100644 --- a/lib/private/Files/Storage/Common.php +++ b/lib/private/Files/Storage/Common.php @@ -550,8 +550,8 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage, public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool { if ( - !$sourceStorage->instanceOfStorage(Encryption::class) && - $this->isSameStorage($sourceStorage) + !$sourceStorage->instanceOfStorage(Encryption::class) + && $this->isSameStorage($sourceStorage) ) { // resolve any jailed paths while ($sourceStorage->instanceOfStorage(Jail::class)) { diff --git a/lib/private/Files/Storage/DAV.php b/lib/private/Files/Storage/DAV.php index 10670d6331a..afd8f87e2de 100644 --- a/lib/private/Files/Storage/DAV.php +++ b/lib/private/Files/Storage/DAV.php @@ -350,7 +350,13 @@ class DAV extends Common { } } - return $response->getBody(); + $content = $response->getBody(); + + if ($content === null || is_string($content)) { + return false; + } + + return $content; case 'w': case 'wb': case 'a': @@ -390,6 +396,8 @@ class DAV extends Common { $this->writeBack($tmpFile, $path); }); } + + return false; } public function writeBack(string $tmpFile, string $path): void { diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index 4d38d2d37aa..51a5f99908d 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -185,11 +185,11 @@ class Encryption extends Wrapper { public function rename(string $source, string $target): bool { $result = $this->storage->rename($source, $target); - if ($result && + if ($result // versions always use the keys from the original file, so we can skip // this step for versions - $this->isVersion($target) === false && - $this->encryptionManager->isEnabled()) { + && $this->isVersion($target) === false + && $this->encryptionManager->isEnabled()) { $sourcePath = $this->getFullPath($source); if (!$this->util->isExcluded($sourcePath)) { $targetPath = $this->getFullPath($target); @@ -210,9 +210,9 @@ class Encryption extends Wrapper { public function rmdir(string $path): bool { $result = $this->storage->rmdir($path); $fullPath = $this->getFullPath($path); - if ($result && - $this->util->isExcluded($fullPath) === false && - $this->encryptionManager->isEnabled() + if ($result + && $this->util->isExcluded($fullPath) === false + && $this->encryptionManager->isEnabled() ) { $this->keyStorage->deleteAllFileKeys($fullPath); } @@ -225,9 +225,9 @@ class Encryption extends Wrapper { $metaData = $this->getMetaData($path); if ( - !$this->is_dir($path) && - isset($metaData['encrypted']) && - $metaData['encrypted'] === true + !$this->is_dir($path) + && isset($metaData['encrypted']) + && $metaData['encrypted'] === true ) { $fullPath = $this->getFullPath($path); $module = $this->getEncryptionModule($path); @@ -384,9 +384,9 @@ class Encryption extends Wrapper { $size = $this->storage->filesize($path); $result = $unencryptedSize; - if ($unencryptedSize < 0 || - ($size > 0 && $unencryptedSize === $size) || - $unencryptedSize > $size + if ($unencryptedSize < 0 + || ($size > 0 && $unencryptedSize === $size) + || $unencryptedSize > $size ) { // check if we already calculate the unencrypted size for the // given path to avoid recursions @@ -634,8 +634,8 @@ class Encryption extends Wrapper { ): bool { // for versions we have nothing to do, because versions should always use the // key from the original file. Just create a 1:1 copy and done - if ($this->isVersion($targetInternalPath) || - $this->isVersion($sourceInternalPath)) { + if ($this->isVersion($targetInternalPath) + || $this->isVersion($sourceInternalPath)) { // remember that we try to create a version so that we can detect it during // fopen($sourceInternalPath) and by-pass the encryption in order to // create a 1:1 copy of the file diff --git a/lib/private/Files/Stream/Encryption.php b/lib/private/Files/Stream/Encryption.php index 0d55385820c..ef147ec421f 100644 --- a/lib/private/Files/Stream/Encryption.php +++ b/lib/private/Files/Stream/Encryption.php @@ -312,8 +312,8 @@ class Encryption extends Wrapper { // for seekable streams the pointer is moved back to the beginning of the encrypted block // flush will start writing there when the position moves to another block - $positionInFile = (int)floor($this->position / $this->unencryptedBlockSize) * - $this->util->getBlockSize() + $this->headerSize; + $positionInFile = (int)floor($this->position / $this->unencryptedBlockSize) + * $this->util->getBlockSize() + $this->headerSize; $resultFseek = $this->parentStreamSeek($positionInFile); // only allow writes on seekable streams, or at the end of the encrypted stream @@ -336,8 +336,8 @@ class Encryption extends Wrapper { // if $data doesn't fit the current block, the fill the current block and reiterate // after the block is filled, it is flushed and $data is updatedxxx } else { - $this->cache = substr($this->cache, 0, $blockPosition) . - substr($data, 0, $this->unencryptedBlockSize - $blockPosition); + $this->cache = substr($this->cache, 0, $blockPosition) + . substr($data, 0, $this->unencryptedBlockSize - $blockPosition); $this->flush(); $this->position += ($this->unencryptedBlockSize - $blockPosition); $length += ($this->unencryptedBlockSize - $blockPosition); diff --git a/lib/private/Files/Stream/SeekableHttpStream.php b/lib/private/Files/Stream/SeekableHttpStream.php index 5ed04ed9066..6ce0a880e8d 100644 --- a/lib/private/Files/Stream/SeekableHttpStream.php +++ b/lib/private/Files/Stream/SeekableHttpStream.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index 6832b4e1551..63eecf5e1d6 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -938,7 +938,7 @@ class View { try { $exists = $this->file_exists($target); - if ($this->shouldEmitHooks()) { + if ($this->shouldEmitHooks($target)) { \OC_Hook::emit( Filesystem::CLASSNAME, Filesystem::signal_copy, @@ -978,7 +978,7 @@ class View { $this->changeLock($target, ILockingProvider::LOCK_SHARED); $lockTypePath2 = ILockingProvider::LOCK_SHARED; - if ($this->shouldEmitHooks() && $result !== false) { + if ($this->shouldEmitHooks($target) && $result !== false) { \OC_Hook::emit( Filesystem::CLASSNAME, Filesystem::signal_post_copy, diff --git a/lib/private/FullTextSearch/FullTextSearchManager.php b/lib/private/FullTextSearch/FullTextSearchManager.php index 3ef8547ad3f..989da8d6bae 100644 --- a/lib/private/FullTextSearch/FullTextSearchManager.php +++ b/lib/private/FullTextSearch/FullTextSearchManager.php @@ -53,9 +53,9 @@ class FullTextSearchManager implements IFullTextSearchManager { * @since 16.0.0 */ public function isAvailable(): bool { - if ($this->indexService === null || - $this->providerService === null || - $this->searchService === null) { + if ($this->indexService === null + || $this->providerService === null + || $this->searchService === null) { return false; } diff --git a/lib/private/FullTextSearch/Model/IndexDocument.php b/lib/private/FullTextSearch/Model/IndexDocument.php index 8bd20bad1e0..a51447393ed 100644 --- a/lib/private/FullTextSearch/Model/IndexDocument.php +++ b/lib/private/FullTextSearch/Model/IndexDocument.php @@ -512,8 +512,8 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * @since 16.0.0 */ final public function addExcerpt(string $source, string $excerpt): IIndexDocument { - $this->excerpts[] = - [ + $this->excerpts[] + = [ 'source' => $source, 'excerpt' => $this->cleanExcerpt($excerpt) ]; diff --git a/lib/private/GlobalScale/Config.php b/lib/private/GlobalScale/Config.php index 02acc1ab50a..2f729c2702e 100644 --- a/lib/private/GlobalScale/Config.php +++ b/lib/private/GlobalScale/Config.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Group/Group.php b/lib/private/Group/Group.php index 147c5baf543..6e42fad8b9f 100644 --- a/lib/private/Group/Group.php +++ b/lib/private/Group/Group.php @@ -377,7 +377,7 @@ class Group implements IGroup { */ public function hideFromCollaboration(): bool { return array_reduce($this->backends, function (bool $hide, GroupInterface $backend) { - return $hide | ($backend instanceof IHideFromCollaborationBackend && $backend->hideGroup($this->gid)); + return $hide || ($backend instanceof IHideFromCollaborationBackend && $backend->hideGroup($this->gid)); }, false); } } diff --git a/lib/private/Hooks/BasicEmitter.php b/lib/private/Hooks/BasicEmitter.php index c9444b40473..091334b71c8 100644 --- a/lib/private/Hooks/BasicEmitter.php +++ b/lib/private/Hooks/BasicEmitter.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Hooks/Emitter.php b/lib/private/Hooks/Emitter.php index 8a63ac9ed3a..86eb410860c 100644 --- a/lib/private/Hooks/Emitter.php +++ b/lib/private/Hooks/Emitter.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Hooks/EmitterTrait.php b/lib/private/Hooks/EmitterTrait.php index 8bffb6f7c3b..7b2ec4ad7fe 100644 --- a/lib/private/Hooks/EmitterTrait.php +++ b/lib/private/Hooks/EmitterTrait.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Hooks/PublicEmitter.php b/lib/private/Hooks/PublicEmitter.php index 042b616e264..77cb2bf30dd 100644 --- a/lib/private/Hooks/PublicEmitter.php +++ b/lib/private/Hooks/PublicEmitter.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Http/Client/Client.php b/lib/private/Http/Client/Client.php index c3f8f589827..553a8921a80 100644 --- a/lib/private/Http/Client/Client.php +++ b/lib/private/Http/Client/Client.php @@ -149,8 +149,8 @@ class Client implements IClient { } private function isLocalAddressAllowed(array $options) : bool { - if (($options['nextcloud']['allow_local_address'] ?? false) || - $this->config->getSystemValueBool('allow_local_remote_servers', false)) { + if (($options['nextcloud']['allow_local_address'] ?? false) + || $this->config->getSystemValueBool('allow_local_remote_servers', false)) { return true; } diff --git a/lib/private/Http/Client/Response.php b/lib/private/Http/Client/Response.php index adf83306d07..1e4cb3b8fa2 100644 --- a/lib/private/Http/Client/Response.php +++ b/lib/private/Http/Client/Response.php @@ -11,49 +11,25 @@ namespace OC\Http\Client; use OCP\Http\Client\IResponse; use Psr\Http\Message\ResponseInterface; -/** - * Class Response - * - * @package OC\Http - */ class Response implements IResponse { - /** @var ResponseInterface */ - private $response; - - /** - * @var bool - */ - private $stream; + private ResponseInterface $response; + private bool $stream; - /** - * @param ResponseInterface $response - * @param bool $stream - */ - public function __construct(ResponseInterface $response, $stream = false) { + public function __construct(ResponseInterface $response, bool $stream = false) { $this->response = $response; $this->stream = $stream; } - /** - * @return string|resource - */ public function getBody() { - return $this->stream ? - $this->response->getBody()->detach(): - $this->response->getBody()->getContents(); + return $this->stream + ? $this->response->getBody()->detach() + :$this->response->getBody()->getContents(); } - /** - * @return int - */ public function getStatusCode(): int { return $this->response->getStatusCode(); } - /** - * @param string $key - * @return string - */ public function getHeader(string $key): string { $headers = $this->response->getHeader($key); @@ -64,9 +40,6 @@ class Response implements IResponse { return $headers[0]; } - /** - * @return array - */ public function getHeaders(): array { return $this->response->getHeaders(); } diff --git a/lib/private/Image.php b/lib/private/Image.php index 96699a0046b..3b8cb79c853 100644 --- a/lib/private/Image.php +++ b/lib/private/Image.php @@ -699,11 +699,11 @@ class Image implements IImage { fclose($fp); unset($fp); - $headerFormat = 'A4Riff/' . // get n string - 'I1Filesize/' . // get integer (file size but not actual size) - 'A4Webp/' . // get n string - 'A4Vp/' . // get n string - 'A74Chunk'; + $headerFormat = 'A4Riff/' // get n string + . 'I1Filesize/' // get integer (file size but not actual size) + . 'A4Webp/' // get n string + . 'A4Vp/' // get n string + . 'A74Chunk'; $header = unpack($headerFormat, $data); unset($data, $headerFormat); diff --git a/lib/private/Installer.php b/lib/private/Installer.php index f32b0e5919a..3bbef3252f4 100644 --- a/lib/private/Installer.php +++ b/lib/private/Installer.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace OC; use Doctrine\DBAL\Exception\TableExistsException; +use OC\App\AppStore\AppNotFoundException; use OC\App\AppStore\Bundles\Bundle; use OC\App\AppStore\Fetcher\AppFetcher; use OC\AppFramework\Bootstrap\Coordinator; @@ -174,6 +175,7 @@ class Installer { * @param string $appId * @param bool [$allowUnstable] * + * @throws AppNotFoundException If the app is not found on the appstore * @throws \Exception If the installation was not successful */ public function downloadApp(string $appId, bool $allowUnstable = false): void { @@ -341,6 +343,9 @@ class Installer { // otherwise we just copy the outer directory $this->copyRecursive($extractDir, $baseDir); Files::rmdirr($extractDir); + if (function_exists('opcache_reset')) { + opcache_reset(); + } return; } // Signature does not match @@ -353,9 +358,9 @@ class Installer { } } - throw new \Exception( + throw new AppNotFoundException( sprintf( - 'Could not download app %s', + 'Could not download app %s, it was not found on the appstore', $appId ) ); diff --git a/lib/private/L10N/Factory.php b/lib/private/L10N/Factory.php index 5645693f8d9..6a747744829 100644 --- a/lib/private/L10N/Factory.php +++ b/lib/private/L10N/Factory.php @@ -437,8 +437,8 @@ class Factory implements IFactory { } // Use language from request - if ($this->userSession->getUser() instanceof IUser && - $user->getUID() === $this->userSession->getUser()->getUID()) { + if ($this->userSession->getUser() instanceof IUser + && $user->getUID() === $this->userSession->getUser()->getUID()) { try { return $this->getLanguageFromRequest(); } catch (LanguageNotFoundException $e) { @@ -517,10 +517,10 @@ class Factory implements IFactory { // use formal version of german ("Sie" instead of "Du") if the default // language is set to 'de_DE' if possible if ( - is_string($defaultLanguage) && - strtolower($lang) === 'de' && - strtolower($defaultLanguage) === 'de_de' && - $this->languageExists($app, 'de_DE') + is_string($defaultLanguage) + && strtolower($lang) === 'de' + && strtolower($defaultLanguage) === 'de_de' + && $this->languageExists($app, 'de_DE') ) { $result = 'de_DE'; } diff --git a/lib/private/L10N/LanguageNotFoundException.php b/lib/private/L10N/LanguageNotFoundException.php index 31b08b2ec14..087a384e00e 100644 --- a/lib/private/L10N/LanguageNotFoundException.php +++ b/lib/private/L10N/LanguageNotFoundException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/LargeFileHelper.php b/lib/private/LargeFileHelper.php index 238fb0790b8..fa4c72da756 100755 --- a/lib/private/LargeFileHelper.php +++ b/lib/private/LargeFileHelper.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Lockdown/Filesystem/NullCache.php b/lib/private/Lockdown/Filesystem/NullCache.php index e84ff40e00c..5a27c5d5c6e 100644 --- a/lib/private/Lockdown/Filesystem/NullCache.php +++ b/lib/private/Lockdown/Filesystem/NullCache.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -21,20 +22,23 @@ class NullCache implements ICache { } public function get($file) { - return $file !== '' ? null : - new CacheEntry([ - 'fileid' => -1, - 'parent' => -1, - 'name' => '', - 'path' => '', - 'size' => '0', - 'mtime' => time(), - 'storage_mtime' => time(), - 'etag' => '', - 'mimetype' => FileInfo::MIMETYPE_FOLDER, - 'mimepart' => 'httpd', - 'permissions' => Constants::PERMISSION_READ - ]); + if ($file !== '') { + return false; + } + + return new CacheEntry([ + 'fileid' => -1, + 'parent' => -1, + 'name' => '', + 'path' => '', + 'size' => '0', + 'mtime' => time(), + 'storage_mtime' => time(), + 'etag' => '', + 'mimetype' => FileInfo::MIMETYPE_FOLDER, + 'mimepart' => 'httpd', + 'permissions' => Constants::PERMISSION_READ + ]); } public function getFolderContents($folder) { diff --git a/lib/private/Lockdown/Filesystem/NullStorage.php b/lib/private/Lockdown/Filesystem/NullStorage.php index 967f8b5108e..71a40d8da1e 100644 --- a/lib/private/Lockdown/Filesystem/NullStorage.php +++ b/lib/private/Lockdown/Filesystem/NullStorage.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Lockdown/LockdownManager.php b/lib/private/Lockdown/LockdownManager.php index 3b45709d5c9..4f351812bad 100644 --- a/lib/private/Lockdown/LockdownManager.php +++ b/lib/private/Lockdown/LockdownManager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Log.php b/lib/private/Log.php index 746e4d75b91..301a25d12c1 100644 --- a/lib/private/Log.php +++ b/lib/private/Log.php @@ -306,9 +306,9 @@ class Log implements ILogger, IDataLogger { protected function checkLogSecret(string $conditionSecret): bool { $request = \OCP\Server::get(IRequest::class); - if ($request->getMethod() === 'PUT' && - !str_contains($request->getHeader('Content-Type'), 'application/x-www-form-urlencoded') && - !str_contains($request->getHeader('Content-Type'), 'application/json')) { + if ($request->getMethod() === 'PUT' + && !str_contains($request->getHeader('Content-Type'), 'application/x-www-form-urlencoded') + && !str_contains($request->getHeader('Content-Type'), 'application/json')) { return hash_equals($conditionSecret, ''); } diff --git a/lib/private/Log/ErrorHandler.php b/lib/private/Log/ErrorHandler.php index e1faf336118..6597274a868 100644 --- a/lib/private/Log/ErrorHandler.php +++ b/lib/private/Log/ErrorHandler.php @@ -72,9 +72,9 @@ class ErrorHandler { private static function errnoToLogLevel(int $errno): int { return match ($errno) { - E_USER_WARNING => ILogger::WARN, + E_WARNING, E_USER_WARNING => ILogger::WARN, E_DEPRECATED, E_USER_DEPRECATED => ILogger::DEBUG, - E_USER_NOTICE => ILogger::INFO, + E_NOTICE, E_USER_NOTICE => ILogger::INFO, default => ILogger::ERROR, }; } diff --git a/lib/private/Log/ExceptionSerializer.php b/lib/private/Log/ExceptionSerializer.php index 6d94bf51f45..af7c9e48435 100644 --- a/lib/private/Log/ExceptionSerializer.php +++ b/lib/private/Log/ExceptionSerializer.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Log/LogDetails.php b/lib/private/Log/LogDetails.php index 8c1efaea20d..6063b25cef9 100644 --- a/lib/private/Log/LogDetails.php +++ b/lib/private/Log/LogDetails.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Log/LogFactory.php b/lib/private/Log/LogFactory.php index bbe77de198c..ee6054b81f8 100644 --- a/lib/private/Log/LogFactory.php +++ b/lib/private/Log/LogFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Log/Rotate.php b/lib/private/Log/Rotate.php index 839c40726b7..ee1593b87ac 100644 --- a/lib/private/Log/Rotate.php +++ b/lib/private/Log/Rotate.php @@ -7,6 +7,8 @@ */ namespace OC\Log; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\TimedJob; use OCP\IConfig; use OCP\Log\RotationTrait; use Psr\Log\LoggerInterface; @@ -17,9 +19,15 @@ use Psr\Log\LoggerInterface; * For more professional log management set the 'logfile' config to a different * location and manage that with your own tools. */ -class Rotate extends \OCP\BackgroundJob\Job { +class Rotate extends TimedJob { use RotationTrait; + public function __construct(ITimeFactory $time) { + parent::__construct($time); + + $this->setInterval(3600); + } + public function run($argument): void { $config = \OCP\Server::get(IConfig::class); $this->filePath = $config->getSystemValueString('logfile', $config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/nextcloud.log'); diff --git a/lib/private/Log/Syslog.php b/lib/private/Log/Syslog.php index bd2c39509b1..46214599eb8 100644 --- a/lib/private/Log/Syslog.php +++ b/lib/private/Log/Syslog.php @@ -20,15 +20,18 @@ class Syslog extends LogDetails implements IWriter { ILogger::FATAL => LOG_CRIT, ]; + private string $tag; + public function __construct( SystemConfig $config, ?string $tag = null, ) { parent::__construct($config); if ($tag === null) { - $tag = $config->getValue('syslog_tag', 'Nextcloud'); + $this->tag = $config->getValue('syslog_tag', 'Nextcloud'); + } else { + $this->tag = $tag; } - openlog($tag, LOG_PID | LOG_CONS, LOG_USER); } public function __destruct() { @@ -41,6 +44,7 @@ class Syslog extends LogDetails implements IWriter { */ public function write(string $app, $message, int $level): void { $syslog_level = $this->levels[$level]; + openlog($this->tag, LOG_PID | LOG_CONS, LOG_USER); syslog($syslog_level, $this->logDetailsAsJSON($app, $message, $level)); } } diff --git a/lib/private/Log/Systemdlog.php b/lib/private/Log/Systemdlog.php index 46de0f7db97..ffea0511732 100644 --- a/lib/private/Log/Systemdlog.php +++ b/lib/private/Log/Systemdlog.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Mail/Message.php b/lib/private/Mail/Message.php index faeba469e20..523a4836760 100644 --- a/lib/private/Mail/Message.php +++ b/lib/private/Mail/Message.php @@ -316,7 +316,7 @@ class Message implements IMessage { public function getAutoSubmitted(): string { $headers = $this->symfonyEmail->getHeaders(); - return $headers->has(AutoSubmitted::HEADER) ? - $headers->get(AutoSubmitted::HEADER)->getBodyAsString() : AutoSubmitted::VALUE_NO; + return $headers->has(AutoSubmitted::HEADER) + ? $headers->get(AutoSubmitted::HEADER)->getBodyAsString() : AutoSubmitted::VALUE_NO; } } diff --git a/lib/private/Mail/Provider/Manager.php b/lib/private/Mail/Provider/Manager.php index 61791620198..f162d30b834 100644 --- a/lib/private/Mail/Provider/Manager.php +++ b/lib/private/Mail/Provider/Manager.php @@ -17,7 +17,7 @@ use Psr\Log\LoggerInterface; use Throwable; class Manager implements IManager { - + protected ?array $providersCollection = null; public function __construct( @@ -63,7 +63,7 @@ class Manager implements IManager { * @return array<string,string> collection of provider id and label ['jmap' => 'JMap Connector'] */ public function types(): array { - + // construct types collection $types = []; // extract id and name from providers collection @@ -72,7 +72,7 @@ class Manager implements IManager { } // return types collection return $types; - + } /** @@ -131,7 +131,7 @@ class Manager implements IManager { if (!is_array($this->providersCollection)) { $this->providers(); } - + if (isset($this->providersCollection[$providerId])) { return $this->providersCollection[$providerId]; } @@ -150,7 +150,7 @@ class Manager implements IManager { * @return array<string,array<string,IService>> collection of provider id, service id and object ['jmap' => ['Service1' => IServiceObject]] */ public function services(string $userId): array { - + // initilize collection $services = []; // retrieve and iterate through mail providers @@ -164,7 +164,7 @@ class Manager implements IManager { } // return collection return $services; - + } /** @@ -179,7 +179,7 @@ class Manager implements IManager { * @return IService|null returns service object or null if none found */ public function findServiceById(string $userId, string $serviceId, ?string $providerId = null): ?IService { - + // evaluate if provider id was specified if ($providerId !== null) { // find provider @@ -204,7 +204,7 @@ class Manager implements IManager { } } } - + // return null if no match was found return null; @@ -223,7 +223,7 @@ class Manager implements IManager { * @return IService|null returns service object or null if none found */ public function findServiceByAddress(string $userId, string $address, ?string $providerId = null): ?IService { - + // evaluate if provider id was specified if ($providerId !== null) { // find provider diff --git a/lib/private/Memcache/APCu.php b/lib/private/Memcache/APCu.php index 024462d227b..937f8a863ab 100644 --- a/lib/private/Memcache/APCu.php +++ b/lib/private/Memcache/APCu.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Memcache/ArrayCache.php b/lib/private/Memcache/ArrayCache.php index 4cac60c272c..9b3540b771f 100644 --- a/lib/private/Memcache/ArrayCache.php +++ b/lib/private/Memcache/ArrayCache.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Memcache/CADTrait.php b/lib/private/Memcache/CADTrait.php index 3bf94246338..d0f6611c4f3 100644 --- a/lib/private/Memcache/CADTrait.php +++ b/lib/private/Memcache/CADTrait.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Memcache/CASTrait.php b/lib/private/Memcache/CASTrait.php index 945f1539f99..8c2d2a46b19 100644 --- a/lib/private/Memcache/CASTrait.php +++ b/lib/private/Memcache/CASTrait.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Memcache/Cache.php b/lib/private/Memcache/Cache.php index 2a2a6e2a23f..774769b25fe 100644 --- a/lib/private/Memcache/Cache.php +++ b/lib/private/Memcache/Cache.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Memcache/Factory.php b/lib/private/Memcache/Factory.php index a44f0127651..b54189937fc 100644 --- a/lib/private/Memcache/Factory.php +++ b/lib/private/Memcache/Factory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -134,8 +135,8 @@ class Factory implements ICacheFactory { $this->profiler->add($cache); } - if ($this->lockingCacheClass === Redis::class && - $this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) { + if ($this->lockingCacheClass === Redis::class + && $this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) { $cache = new LoggerWrapperCache($cache, $this->logFile); } return $cache; diff --git a/lib/private/Memcache/Memcached.php b/lib/private/Memcache/Memcached.php index 620013feda6..d8b624a978a 100644 --- a/lib/private/Memcache/Memcached.php +++ b/lib/private/Memcache/Memcached.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -48,8 +49,8 @@ class Memcached extends Cache implements IMemcache { * @psalm-suppress TypeDoesNotContainType */ if (\Memcached::HAVE_IGBINARY) { - $defaultOptions[\Memcached::OPT_SERIALIZER] = - \Memcached::SERIALIZER_IGBINARY; + $defaultOptions[\Memcached::OPT_SERIALIZER] + = \Memcached::SERIALIZER_IGBINARY; } $options = \OC::$server->getConfig()->getSystemValue('memcached_options', []); if (is_array($options)) { diff --git a/lib/private/Memcache/NullCache.php b/lib/private/Memcache/NullCache.php index b667869bf0d..eac1e6ddadc 100644 --- a/lib/private/Memcache/NullCache.php +++ b/lib/private/Memcache/NullCache.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Memcache/Redis.php b/lib/private/Memcache/Redis.php index 711531e0ac2..f8c51570c4f 100644 --- a/lib/private/Memcache/Redis.php +++ b/lib/private/Memcache/Redis.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Migration/ConsoleOutput.php b/lib/private/Migration/ConsoleOutput.php index 7ccc4e7825a..31412bf4ff0 100644 --- a/lib/private/Migration/ConsoleOutput.php +++ b/lib/private/Migration/ConsoleOutput.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2015 ownCloud GmbH diff --git a/lib/private/Migration/NullOutput.php b/lib/private/Migration/NullOutput.php index 3f4cc38dba8..8db7b950af8 100644 --- a/lib/private/Migration/NullOutput.php +++ b/lib/private/Migration/NullOutput.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-only diff --git a/lib/private/Migration/SimpleOutput.php b/lib/private/Migration/SimpleOutput.php index 31420d49932..b7a07cc6ff2 100644 --- a/lib/private/Migration/SimpleOutput.php +++ b/lib/private/Migration/SimpleOutput.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2015 ownCloud GmbH diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php index b75e52deacb..8c457db8beb 100644 --- a/lib/private/Notification/Manager.php +++ b/lib/private/Notification/Manager.php @@ -217,7 +217,9 @@ class Manager implements IManager { * @since 8.2.0 */ public function hasNotifiers(): bool { - return !empty($this->notifiers) || !empty($this->notifierClasses); + return !empty($this->notifiers) + || !empty($this->notifierClasses) + || (!$this->parsedRegistrationContext && !empty($this->coordinator->getRegistrationContext()->getNotifierServices())); } /** diff --git a/lib/private/Notification/Notification.php b/lib/private/Notification/Notification.php index f8f1e247854..fcce7fd0020 100644 --- a/lib/private/Notification/Notification.php +++ b/lib/private/Notification/Notification.php @@ -429,8 +429,7 @@ class Notification implements INotification { public function isValid(): bool { return $this->isValidCommon() - && - $this->getSubject() !== '' + && $this->getSubject() !== '' ; } @@ -456,8 +455,7 @@ class Notification implements INotification { return $this->isValidCommon() - && - $this->getParsedSubject() !== '' + && $this->getParsedSubject() !== '' ; } @@ -468,14 +466,10 @@ class Notification implements INotification { return $this->getApp() !== '' - && - $this->getUser() !== '' - && - $this->getDateTime()->getTimestamp() !== 0 - && - $this->getObjectType() !== '' - && - $this->getObjectId() !== '' + && $this->getUser() !== '' + && $this->getDateTime()->getTimestamp() !== 0 + && $this->getObjectType() !== '' + && $this->getObjectId() !== '' ; } } diff --git a/lib/private/OCM/Model/OCMProvider.php b/lib/private/OCM/Model/OCMProvider.php index f4b0ac584de..be13d65a40f 100644 --- a/lib/private/OCM/Model/OCMProvider.php +++ b/lib/private/OCM/Model/OCMProvider.php @@ -11,18 +11,22 @@ namespace OC\OCM\Model; use NCU\Security\Signature\Model\Signatory; use OCP\EventDispatcher\IEventDispatcher; +use OCP\IConfig; use OCP\OCM\Events\ResourceTypeRegisterEvent; use OCP\OCM\Exceptions\OCMArgumentException; use OCP\OCM\Exceptions\OCMProviderException; -use OCP\OCM\IOCMProvider; +use OCP\OCM\ICapabilityAwareOCMProvider; use OCP\OCM\IOCMResource; /** * @since 28.0.0 */ -class OCMProvider implements IOCMProvider { +class OCMProvider implements ICapabilityAwareOCMProvider { + private string $provider; private bool $enabled = false; private string $apiVersion = ''; + private string $inviteAcceptDialog = ''; + private array $capabilities = []; private string $endPoint = ''; /** @var IOCMResource[] */ private array $resourceTypes = []; @@ -31,7 +35,9 @@ class OCMProvider implements IOCMProvider { public function __construct( protected IEventDispatcher $dispatcher, + protected IConfig $config, ) { + $this->provider = 'Nextcloud ' . $config->getSystemValue('version'); } /** @@ -71,6 +77,30 @@ class OCMProvider implements IOCMProvider { } /** + * returns the invite accept dialog + * + * @return string + * @since 32.0.0 + */ + public function getInviteAcceptDialog(): string { + return $this->inviteAcceptDialog; + } + + /** + * set the invite accept dialog + * + * @param string $inviteAcceptDialog + * + * @return $this + * @since 32.0.0 + */ + public function setInviteAcceptDialog(string $inviteAcceptDialog): static { + $this->inviteAcceptDialog = $inviteAcceptDialog; + + return $this; + } + + /** * @param string $endPoint * * @return $this @@ -89,6 +119,34 @@ class OCMProvider implements IOCMProvider { } /** + * @return string + */ + public function getProvider(): string { + return $this->provider; + } + + /** + * @param array $capabilities + * + * @return $this + */ + public function setCapabilities(array $capabilities): static { + foreach ($capabilities as $value) { + if (!in_array($value, $this->capabilities)) { + array_push($this->capabilities, $value); + } + } + + return $this; + } + + /** + * @return array + */ + public function getCapabilities(): array { + return $this->capabilities; + } + /** * create a new resource to later add it with {@see IOCMProvider::addResourceType()} * @return IOCMResource */ @@ -166,9 +224,8 @@ class OCMProvider implements IOCMProvider { * * @param array $data * - * @return $this + * @return OCMProvider&static * @throws OCMProviderException in case a descent provider cannot be generated from data - * @see self::jsonSerialize() */ public function import(array $data): static { $this->setEnabled(is_bool($data['enabled'] ?? '') ? $data['enabled'] : false) @@ -209,21 +266,7 @@ class OCMProvider implements IOCMProvider { } /** - * @return array{ - * enabled: bool, - * apiVersion: '1.0-proposal1', - * endPoint: string, - * publicKey?: array{ - * keyId: string, - * publicKeyPem: string - * }, - * resourceTypes: list<array{ - * name: string, - * shareTypes: list<string>, - * protocols: array<string, string> - * }>, - * version: string - * } + * @since 28.0.0 */ public function jsonSerialize(): array { $resourceTypes = []; @@ -231,7 +274,7 @@ class OCMProvider implements IOCMProvider { $resourceTypes[] = $res->jsonSerialize(); } - return [ + $response = [ 'enabled' => $this->isEnabled(), 'apiVersion' => '1.0-proposal1', // deprecated, but keep it to stay compatible with old version 'version' => $this->getApiVersion(), // informative but real version @@ -239,5 +282,16 @@ class OCMProvider implements IOCMProvider { 'publicKey' => $this->getSignatory()?->jsonSerialize(), 'resourceTypes' => $resourceTypes ]; + + $capabilities = $this->getCapabilities(); + $inviteAcceptDialog = $this->getInviteAcceptDialog(); + if ($capabilities) { + $response['capabilities'] = $capabilities; + } + if ($inviteAcceptDialog) { + $response['inviteAcceptDialog'] = $inviteAcceptDialog; + } + return $response; + } } diff --git a/lib/private/OCM/OCMDiscoveryService.php b/lib/private/OCM/OCMDiscoveryService.php index af612416372..a151bbc753c 100644 --- a/lib/private/OCM/OCMDiscoveryService.php +++ b/lib/private/OCM/OCMDiscoveryService.php @@ -17,8 +17,8 @@ use OCP\ICache; use OCP\ICacheFactory; use OCP\IConfig; use OCP\OCM\Exceptions\OCMProviderException; +use OCP\OCM\ICapabilityAwareOCMProvider; use OCP\OCM\IOCMDiscoveryService; -use OCP\OCM\IOCMProvider; use Psr\Log\LoggerInterface; /** @@ -31,7 +31,7 @@ class OCMDiscoveryService implements IOCMDiscoveryService { ICacheFactory $cacheFactory, private IClientService $clientService, private IConfig $config, - private IOCMProvider $provider, + private ICapabilityAwareOCMProvider $provider, private LoggerInterface $logger, ) { $this->cache = $cacheFactory->createDistributed('ocm-discovery'); @@ -42,10 +42,10 @@ class OCMDiscoveryService implements IOCMDiscoveryService { * @param string $remote * @param bool $skipCache * - * @return IOCMProvider + * @return ICapabilityAwareOCMProvider * @throws OCMProviderException */ - public function discover(string $remote, bool $skipCache = false): IOCMProvider { + public function discover(string $remote, bool $skipCache = false): ICapabilityAwareOCMProvider { $remote = rtrim($remote, '/'); if (!str_starts_with($remote, 'http://') && !str_starts_with($remote, 'https://')) { // if scheme not specified, we test both; diff --git a/lib/private/Preview/Bundled.php b/lib/private/Preview/Bundled.php index 836dc4bd357..6100e8262a4 100644 --- a/lib/private/Preview/Bundled.php +++ b/lib/private/Preview/Bundled.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Preview/GeneratorHelper.php b/lib/private/Preview/GeneratorHelper.php index 5f43c94b624..e914dcc2002 100644 --- a/lib/private/Preview/GeneratorHelper.php +++ b/lib/private/Preview/GeneratorHelper.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Preview/Imaginary.php b/lib/private/Preview/Imaginary.php index baa883f4bd9..d421da74ac8 100644 --- a/lib/private/Preview/Imaginary.php +++ b/lib/private/Preview/Imaginary.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Preview/Krita.php b/lib/private/Preview/Krita.php index 2e77c7befd2..e96fac993aa 100644 --- a/lib/private/Preview/Krita.php +++ b/lib/private/Preview/Krita.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Preview/MimeIconProvider.php b/lib/private/Preview/MimeIconProvider.php index 80545bd4063..d1963fe882b 100644 --- a/lib/private/Preview/MimeIconProvider.php +++ b/lib/private/Preview/MimeIconProvider.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -54,7 +55,7 @@ class MimeIconProvider implements IMimeIconProvider { return null; } - + private function searchfileName(string $fileName): ?string { // If the file exists in the current enabled legacy // custom theme, let's return it @@ -65,7 +66,7 @@ class MimeIconProvider implements IMimeIconProvider { return $this->urlGenerator->getAbsoluteURL($path); } } - + // Previously, we used to pass this through Theming // But it was only used to colour icons containing // 0082c9. Since with vue we moved to inline svg icons, diff --git a/lib/private/Preview/Movie.php b/lib/private/Preview/Movie.php index 7de543198f4..47895f999d8 100644 --- a/lib/private/Preview/Movie.php +++ b/lib/private/Preview/Movie.php @@ -166,8 +166,8 @@ class Movie extends ProviderV2 { $returnCode = -1; $output = ''; if (is_resource($proc)) { - $stdout = trim(stream_get_contents($pipes[1])); $stderr = trim(stream_get_contents($pipes[2])); + $stdout = trim(stream_get_contents($pipes[1])); $returnCode = proc_close($proc); $output = $stdout . $stderr; } diff --git a/lib/private/Preview/SGI.php b/lib/private/Preview/SGI.php index 06ea9c0c69a..78b1ea5828a 100644 --- a/lib/private/Preview/SGI.php +++ b/lib/private/Preview/SGI.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Preview/TGA.php b/lib/private/Preview/TGA.php index 62e5aadc2af..675907b4e49 100644 --- a/lib/private/Preview/TGA.php +++ b/lib/private/Preview/TGA.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php index fa62a7b0257..0bb0280406c 100644 --- a/lib/private/PreviewManager.php +++ b/lib/private/PreviewManager.php @@ -154,7 +154,7 @@ class PreviewManager implements IPreview { $mimeType = null, bool $cacheResult = true, ): ISimpleFile { - $this->throwIfPreviewsDisabled($file); + $this->throwIfPreviewsDisabled($file, $mimeType); $previewConcurrency = $this->getGenerator()->getNumConcurrentPreviews('preview_concurrency_all'); $sem = Generator::guardWithSemaphore(Generator::SEMAPHORE_ID_ALL, $previewConcurrency); try { @@ -178,7 +178,7 @@ class PreviewManager implements IPreview { * @since 19.0.0 */ public function generatePreviews(File $file, array $specifications, $mimeType = null) { - $this->throwIfPreviewsDisabled($file); + $this->throwIfPreviewsDisabled($file, $mimeType); return $this->getGenerator()->generatePreviews($file, $specifications, $mimeType); } @@ -213,13 +213,15 @@ class PreviewManager implements IPreview { /** * Check if a preview can be generated for a file */ - public function isAvailable(\OCP\Files\FileInfo $file): bool { + public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null): bool { if (!$this->enablePreviews) { return false; } + $fileMimeType = $mimeType ?? $file->getMimeType(); + $this->registerCoreProviders(); - if (!$this->isMimeSupported($file->getMimetype())) { + if (!$this->isMimeSupported($fileMimeType)) { return false; } @@ -229,7 +231,7 @@ class PreviewManager implements IPreview { } foreach ($this->providers as $supportedMimeType => $providers) { - if (preg_match($supportedMimeType, $file->getMimetype())) { + if (preg_match($supportedMimeType, $fileMimeType)) { foreach ($providers as $providerClosure) { $provider = $this->helper->getProvider($providerClosure); if (!($provider instanceof IProviderV2)) { @@ -455,8 +457,8 @@ class PreviewManager implements IPreview { /** * @throws NotFoundException if preview generation is disabled */ - private function throwIfPreviewsDisabled(File $file): void { - if (!$this->isAvailable($file)) { + private function throwIfPreviewsDisabled(File $file, ?string $mimeType = null): void { + if (!$this->isAvailable($file, $mimeType)) { throw new NotFoundException('Previews disabled'); } } diff --git a/lib/private/PreviewNotAvailableException.php b/lib/private/PreviewNotAvailableException.php index b1fec912769..582f337acd1 100644 --- a/lib/private/PreviewNotAvailableException.php +++ b/lib/private/PreviewNotAvailableException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Profile/ProfileManager.php b/lib/private/Profile/ProfileManager.php index 13860286356..84c7ea48373 100644 --- a/lib/private/Profile/ProfileManager.php +++ b/lib/private/Profile/ProfileManager.php @@ -247,8 +247,8 @@ class ProfileManager implements IProfileManager { case IAccountManager::PROPERTY_ORGANISATION: case IAccountManager::PROPERTY_ROLE: case IAccountManager::PROPERTY_PRONOUNS: - $profileParameters[$property] = - $this->isProfileFieldVisible($property, $targetUser, $visitingUser) + $profileParameters[$property] + = $this->isProfileFieldVisible($property, $targetUser, $visitingUser) // Explicitly set to null when value is empty string ? ($account->getProperty($property)->getValue() ?: null) : null; diff --git a/lib/private/RedisFactory.php b/lib/private/RedisFactory.php index dcb56cee9ef..f13f9299c1c 100644 --- a/lib/private/RedisFactory.php +++ b/lib/private/RedisFactory.php @@ -152,8 +152,8 @@ class RedisFactory { } public function isAvailable(): bool { - return \extension_loaded('redis') && - \version_compare(\phpversion('redis'), self::REDIS_MINIMAL_VERSION, '>='); + return \extension_loaded('redis') + && \version_compare(\phpversion('redis'), self::REDIS_MINIMAL_VERSION, '>='); } /** @@ -163,7 +163,7 @@ class RedisFactory { * @return boolean */ private function isConnectionParametersSupported(): bool { - return \extension_loaded('redis') && - \version_compare(\phpversion('redis'), self::REDIS_EXTRA_PARAMETERS_MINIMAL_VERSION, '>='); + return \extension_loaded('redis') + && \version_compare(\phpversion('redis'), self::REDIS_EXTRA_PARAMETERS_MINIMAL_VERSION, '>='); } } diff --git a/lib/private/Remote/Api/ApiBase.php b/lib/private/Remote/Api/ApiBase.php index dff3edb51b9..b2f96fb3c24 100644 --- a/lib/private/Remote/Api/ApiBase.php +++ b/lib/private/Remote/Api/ApiBase.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Remote/Api/ApiCollection.php b/lib/private/Remote/Api/ApiCollection.php index 65039f4b5aa..f154cd21926 100644 --- a/lib/private/Remote/Api/ApiCollection.php +++ b/lib/private/Remote/Api/ApiCollection.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Remote/Api/ApiFactory.php b/lib/private/Remote/Api/ApiFactory.php index 7daddd16011..795584e566a 100644 --- a/lib/private/Remote/Api/ApiFactory.php +++ b/lib/private/Remote/Api/ApiFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Remote/Api/NotFoundException.php b/lib/private/Remote/Api/NotFoundException.php index 5251313f5f0..361d03d24ed 100644 --- a/lib/private/Remote/Api/NotFoundException.php +++ b/lib/private/Remote/Api/NotFoundException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Remote/Api/OCS.php b/lib/private/Remote/Api/OCS.php index de07eb8bc56..36bc22751a5 100644 --- a/lib/private/Remote/Api/OCS.php +++ b/lib/private/Remote/Api/OCS.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Remote/Credentials.php b/lib/private/Remote/Credentials.php index fb0f03ae148..7f1ffaa727c 100644 --- a/lib/private/Remote/Credentials.php +++ b/lib/private/Remote/Credentials.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Remote/Instance.php b/lib/private/Remote/Instance.php index ac3233b93c9..10403af4ec7 100644 --- a/lib/private/Remote/Instance.php +++ b/lib/private/Remote/Instance.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -123,7 +124,13 @@ class Instance implements IInstance { private function downloadStatus($url) { try { $request = $this->clientService->newClient()->get($url); - return $request->getBody(); + $content = $request->getBody(); + + // IResponse.getBody responds with null|resource if returning a stream response was requested. + // As that's not the case here, we can just ignore the psalm warning by adding an assertion. + assert(is_string($content)); + + return $content; } catch (\Exception $e) { return false; } diff --git a/lib/private/Remote/InstanceFactory.php b/lib/private/Remote/InstanceFactory.php index f3047b851b2..f1b7a1de4ba 100644 --- a/lib/private/Remote/InstanceFactory.php +++ b/lib/private/Remote/InstanceFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Remote/User.php b/lib/private/Remote/User.php index 5c8e9d3ca4e..ae1032cdc1c 100644 --- a/lib/private/Remote/User.php +++ b/lib/private/Remote/User.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/AddCleanupUpdaterBackupsJob.php b/lib/private/Repair/AddCleanupUpdaterBackupsJob.php index 8bd938b7e3a..e631a3303f1 100644 --- a/lib/private/Repair/AddCleanupUpdaterBackupsJob.php +++ b/lib/private/Repair/AddCleanupUpdaterBackupsJob.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/AddMetadataGenerationJob.php b/lib/private/Repair/AddMetadataGenerationJob.php index 4535fb0c9e0..76c60f303a7 100644 --- a/lib/private/Repair/AddMetadataGenerationJob.php +++ b/lib/private/Repair/AddMetadataGenerationJob.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/ClearFrontendCaches.php b/lib/private/Repair/ClearFrontendCaches.php index 77a3df5598a..5c57a63379d 100644 --- a/lib/private/Repair/ClearFrontendCaches.php +++ b/lib/private/Repair/ClearFrontendCaches.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/ClearGeneratedAvatarCache.php b/lib/private/Repair/ClearGeneratedAvatarCache.php index 2dea4bd2d61..0f743afbb4c 100644 --- a/lib/private/Repair/ClearGeneratedAvatarCache.php +++ b/lib/private/Repair/ClearGeneratedAvatarCache.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/ClearGeneratedAvatarCacheJob.php b/lib/private/Repair/ClearGeneratedAvatarCacheJob.php index 38cf03b731a..524a470e62a 100644 --- a/lib/private/Repair/ClearGeneratedAvatarCacheJob.php +++ b/lib/private/Repair/ClearGeneratedAvatarCacheJob.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/Collation.php b/lib/private/Repair/Collation.php index 5a309892bf0..43229792217 100644 --- a/lib/private/Repair/Collation.php +++ b/lib/private/Repair/Collation.php @@ -97,11 +97,11 @@ class Collation implements IRepairStep { // fetch tables by columns $statement = $connection->executeQuery( - 'SELECT DISTINCT(TABLE_NAME) AS `table`' . - ' FROM INFORMATION_SCHEMA . COLUMNS' . - ' WHERE TABLE_SCHEMA = ?' . - " AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')" . - " AND TABLE_NAME LIKE '*PREFIX*%'", + 'SELECT DISTINCT(TABLE_NAME) AS `table`' + . ' FROM INFORMATION_SCHEMA . COLUMNS' + . ' WHERE TABLE_SCHEMA = ?' + . " AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')" + . " AND TABLE_NAME LIKE '*PREFIX*%'", [$dbName] ); $rows = $statement->fetchAll(); @@ -112,11 +112,11 @@ class Collation implements IRepairStep { // fetch tables by collation $statement = $connection->executeQuery( - 'SELECT DISTINCT(TABLE_NAME) AS `table`' . - ' FROM INFORMATION_SCHEMA . TABLES' . - ' WHERE TABLE_SCHEMA = ?' . - " AND TABLE_COLLATION <> '" . $characterSet . "_bin'" . - " AND TABLE_NAME LIKE '*PREFIX*%'", + 'SELECT DISTINCT(TABLE_NAME) AS `table`' + . ' FROM INFORMATION_SCHEMA . TABLES' + . ' WHERE TABLE_SCHEMA = ?' + . " AND TABLE_COLLATION <> '" . $characterSet . "_bin'" + . " AND TABLE_NAME LIKE '*PREFIX*%'", [$dbName] ); $rows = $statement->fetchAll(); diff --git a/lib/private/Repair/ConfigKeyMigration.php b/lib/private/Repair/ConfigKeyMigration.php new file mode 100644 index 00000000000..da4aa153dc5 --- /dev/null +++ b/lib/private/Repair/ConfigKeyMigration.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OC\Repair; + +use OC\Config\ConfigManager; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class ConfigKeyMigration implements IRepairStep { + public function __construct( + private ConfigManager $configManager, + ) { + } + + public function getName(): string { + return 'Migrate config keys'; + } + + public function run(IOutput $output) { + $this->configManager->migrateConfigLexiconKeys(); + } +} diff --git a/lib/private/Repair/MoveUpdaterStepFile.php b/lib/private/Repair/MoveUpdaterStepFile.php index eb9f78b0a39..bb8f9d3acfc 100644 --- a/lib/private/Repair/MoveUpdaterStepFile.php +++ b/lib/private/Repair/MoveUpdaterStepFile.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/NC13/AddLogRotateJob.php b/lib/private/Repair/NC13/AddLogRotateJob.php index 8fe68a42819..bd6c510785f 100644 --- a/lib/private/Repair/NC13/AddLogRotateJob.php +++ b/lib/private/Repair/NC13/AddLogRotateJob.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php b/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php index 4f80b3809e8..5cee33b381c 100644 --- a/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php +++ b/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/Owncloud/CleanPreviews.php b/lib/private/Repair/Owncloud/CleanPreviews.php index 86e173cf402..50ee965e087 100644 --- a/lib/private/Repair/Owncloud/CleanPreviews.php +++ b/lib/private/Repair/Owncloud/CleanPreviews.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/Owncloud/DropAccountTermsTable.php b/lib/private/Repair/Owncloud/DropAccountTermsTable.php index 18f169c9b49..534825c146a 100644 --- a/lib/private/Repair/Owncloud/DropAccountTermsTable.php +++ b/lib/private/Repair/Owncloud/DropAccountTermsTable.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/Owncloud/MoveAvatars.php b/lib/private/Repair/Owncloud/MoveAvatars.php index 7fdabae7a66..9e3f4b89b13 100644 --- a/lib/private/Repair/Owncloud/MoveAvatars.php +++ b/lib/private/Repair/Owncloud/MoveAvatars.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/Owncloud/SaveAccountsTableData.php b/lib/private/Repair/Owncloud/SaveAccountsTableData.php index 08665687b29..ab1560ddb8d 100644 --- a/lib/private/Repair/Owncloud/SaveAccountsTableData.php +++ b/lib/private/Repair/Owncloud/SaveAccountsTableData.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/Owncloud/UpdateLanguageCodes.php b/lib/private/Repair/Owncloud/UpdateLanguageCodes.php index e27ab06b2f3..8d9046ad49f 100644 --- a/lib/private/Repair/Owncloud/UpdateLanguageCodes.php +++ b/lib/private/Repair/Owncloud/UpdateLanguageCodes.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Repair/RepairMimeTypes.php b/lib/private/Repair/RepairMimeTypes.php index 28b22ec3f20..3c9720b9e91 100644 --- a/lib/private/Repair/RepairMimeTypes.php +++ b/lib/private/Repair/RepairMimeTypes.php @@ -350,7 +350,7 @@ class RepairMimeTypes implements IRepairStep { return $this->updateMimetypes($updatedMimetypes); } - + /** * Check if there are any migrations available diff --git a/lib/private/Route/CachingRouter.php b/lib/private/Route/CachingRouter.php index 7dd26827d3c..becdb807f73 100644 --- a/lib/private/Route/CachingRouter.php +++ b/lib/private/Route/CachingRouter.php @@ -15,10 +15,16 @@ use OCP\IConfig; use OCP\IRequest; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Routing\Matcher\CompiledUrlMatcher; +use Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherDumper; +use Symfony\Component\Routing\RouteCollection; class CachingRouter extends Router { protected ICache $cache; + protected array $legacyCreatedRoutes = []; + public function __construct( ICacheFactory $cacheFactory, LoggerInterface $logger, @@ -54,4 +60,98 @@ class CachingRouter extends Router { return $url; } } + + private function serializeRouteCollection(RouteCollection $collection): array { + $dumper = new CompiledUrlMatcherDumper($collection); + return $dumper->getCompiledRoutes(); + } + + /** + * Find the route matching $url + * + * @param string $url The url to find + * @throws \Exception + * @return array + */ + public function findMatchingRoute(string $url): array { + $this->eventLogger->start('cacheroute:match', 'Match route'); + $key = $this->context->getHost() . '#' . $this->context->getBaseUrl() . '#rootCollection'; + $cachedRoutes = $this->cache->get($key); + if (!$cachedRoutes) { + parent::loadRoutes(); + $cachedRoutes = $this->serializeRouteCollection($this->root); + $this->cache->set($key, $cachedRoutes, ($this->config->getSystemValueBool('debug') ? 3 : 3600)); + } + $matcher = new CompiledUrlMatcher($cachedRoutes, $this->context); + $this->eventLogger->start('cacheroute:url:match', 'Symfony URL match call'); + try { + $parameters = $matcher->match($url); + } catch (ResourceNotFoundException $e) { + if (!str_ends_with($url, '/')) { + // We allow links to apps/files? for backwards compatibility reasons + // However, since Symfony does not allow empty route names, the route + // we need to match is '/', so we need to append the '/' here. + try { + $parameters = $matcher->match($url . '/'); + } catch (ResourceNotFoundException $newException) { + // If we still didn't match a route, we throw the original exception + throw $e; + } + } else { + throw $e; + } + } + $this->eventLogger->end('cacheroute:url:match'); + + $this->eventLogger->end('cacheroute:match'); + return $parameters; + } + + /** + * @param array{action:mixed, ...} $parameters + */ + protected function callLegacyActionRoute(array $parameters): void { + /* + * Closures cannot be serialized to cache, so for legacy routes calling an action we have to include the routes.php file again + */ + $app = $parameters['app']; + $this->useCollection($app); + parent::requireRouteFile($parameters['route-file'], $app); + $collection = $this->getCollection($app); + $parameters['action'] = $collection->get($parameters['_route'])?->getDefault('action'); + parent::callLegacyActionRoute($parameters); + } + + /** + * Create a \OC\Route\Route. + * Deprecated + * + * @param string $name Name of the route to create. + * @param string $pattern The pattern to match + * @param array $defaults An array of default parameter values + * @param array $requirements An array of requirements for parameters (regexes) + */ + public function create($name, $pattern, array $defaults = [], array $requirements = []): Route { + $this->legacyCreatedRoutes[] = $name; + return parent::create($name, $pattern, $defaults, $requirements); + } + + /** + * Require a routes.php file + */ + protected function requireRouteFile(string $file, string $appName): void { + $this->legacyCreatedRoutes = []; + parent::requireRouteFile($file, $appName); + foreach ($this->legacyCreatedRoutes as $routeName) { + $route = $this->collection?->get($routeName); + if ($route === null) { + /* Should never happen */ + throw new \Exception("Could not find route $routeName"); + } + if ($route->hasDefault('action')) { + $route->setDefault('route-file', $file); + $route->setDefault('app', $appName); + } + } + } } diff --git a/lib/private/Route/Route.php b/lib/private/Route/Route.php index ab5a1f6b59a..08231649e76 100644 --- a/lib/private/Route/Route.php +++ b/lib/private/Route/Route.php @@ -124,15 +124,9 @@ class Route extends SymfonyRoute implements IRoute { * The action to execute when this route matches, includes a file like * it is called directly * @param string $file - * @return void */ public function actionInclude($file) { - $function = function ($param) use ($file) { - unset($param['_route']); - $_GET = array_merge($_GET, $param); - unset($param); - require_once "$file"; - } ; - $this->action($function); + $this->setDefault('file', $file); + return $this; } } diff --git a/lib/private/Route/Router.php b/lib/private/Route/Router.php index 376852a1b6e..90225212e9a 100644 --- a/lib/private/Route/Router.php +++ b/lib/private/Route/Router.php @@ -53,7 +53,7 @@ class Router implements IRouter { public function __construct( protected LoggerInterface $logger, IRequest $request, - private IConfig $config, + protected IConfig $config, protected IEventLogger $eventLogger, private ContainerInterface $container, protected IAppManager $appManager, @@ -74,6 +74,14 @@ class Router implements IRouter { $this->root = $this->getCollection('root'); } + public function setContext(RequestContext $context): void { + $this->context = $context; + } + + public function getRouteCollection() { + return $this->root; + } + /** * Get the files to load the routes from * @@ -82,7 +90,7 @@ class Router implements IRouter { public function getRoutingFiles() { if ($this->routingFiles === null) { $this->routingFiles = []; - foreach (\OC_APP::getEnabledApps() as $app) { + foreach ($this->appManager->getEnabledApps() as $app) { try { $appPath = $this->appManager->getAppPath($app); $file = $appPath . '/appinfo/routes.php'; @@ -102,7 +110,7 @@ class Router implements IRouter { * * @param null|string $app */ - public function loadRoutes($app = null) { + public function loadRoutes(?string $app = null, bool $skipLoadingCore = false): void { if (is_string($app)) { $app = $this->appManager->cleanAppId($app); } @@ -117,7 +125,7 @@ class Router implements IRouter { $routingFiles = $this->getRoutingFiles(); $this->eventLogger->start('route:load:attributes', 'Loading Routes from attributes'); - foreach (\OC_App::getEnabledApps() as $enabledApp) { + foreach ($this->appManager->getEnabledApps() as $enabledApp) { $this->loadAttributeRoutes($enabledApp); } $this->eventLogger->end('route:load:attributes'); @@ -165,7 +173,7 @@ class Router implements IRouter { } $this->eventLogger->end('route:load:files'); - if (!isset($this->loadedApps['core'])) { + if (!$skipLoadingCore && !isset($this->loadedApps['core'])) { $this->loadedApps['core'] = true; $this->useCollection('root'); $this->setupRoutes($this->getAttributeRoutes('core'), 'core'); @@ -312,17 +320,11 @@ class Router implements IRouter { $application = $this->getApplicationClass($caller[0]); \OC\AppFramework\App::main($caller[1], $caller[2], $application->getContainer(), $parameters); } elseif (isset($parameters['action'])) { - $action = $parameters['action']; - if (!is_callable($action)) { - throw new \Exception('not a callable action'); - } - unset($parameters['action']); - unset($parameters['caller']); - $this->eventLogger->start('route:run:call', 'Run callable route'); - call_user_func($action, $parameters); - $this->eventLogger->end('route:run:call'); + $this->logger->warning('Deprecated action route used', ['parameters' => $parameters]); + $this->callLegacyActionRoute($parameters); } elseif (isset($parameters['file'])) { - include $parameters['file']; + $this->logger->debug('Deprecated file route used', ['parameters' => $parameters]); + $this->includeLegacyFileRoute($parameters); } else { throw new \Exception('no action available'); } @@ -330,6 +332,32 @@ class Router implements IRouter { } /** + * @param array{file:mixed, ...} $parameters + */ + protected function includeLegacyFileRoute(array $parameters): void { + $param = $parameters; + unset($param['_route']); + $_GET = array_merge($_GET, $param); + unset($param); + require_once $parameters['file']; + } + + /** + * @param array{action:mixed, ...} $parameters + */ + protected function callLegacyActionRoute(array $parameters): void { + $action = $parameters['action']; + if (!is_callable($action)) { + throw new \Exception('not a callable action'); + } + unset($parameters['action']); + unset($parameters['caller']); + $this->eventLogger->start('route:run:call', 'Run callable route'); + call_user_func($action, $parameters); + $this->eventLogger->end('route:run:call'); + } + + /** * Get the url generator * * @return \Symfony\Component\Routing\Generator\UrlGenerator @@ -492,7 +520,7 @@ class Router implements IRouter { * @param string $file the route file location to include * @param string $appName */ - private function requireRouteFile($file, $appName) { + protected function requireRouteFile(string $file, string $appName): void { $this->setupRoutes(include $file, $appName); } diff --git a/lib/private/Security/Hasher.php b/lib/private/Security/Hasher.php index ba661f5a356..722fdab902f 100644 --- a/lib/private/Security/Hasher.php +++ b/lib/private/Security/Hasher.php @@ -106,8 +106,8 @@ class Hasher implements IHasher { // Verify whether it matches a legacy PHPass or SHA1 string $hashLength = \strlen($hash); - if (($hashLength === 60 && password_verify($message . $this->legacySalt, $hash)) || - ($hashLength === 40 && hash_equals($hash, sha1($message)))) { + if (($hashLength === 60 && password_verify($message . $this->legacySalt, $hash)) + || ($hashLength === 40 && hash_equals($hash, sha1($message)))) { $newHash = $this->hash($message); return true; } @@ -115,8 +115,8 @@ class Hasher implements IHasher { // Verify whether it matches a legacy PHPass or SHA1 string // Retry with empty passwordsalt for cases where it was not set $hashLength = \strlen($hash); - if (($hashLength === 60 && password_verify($message, $hash)) || - ($hashLength === 40 && hash_equals($hash, sha1($message)))) { + if (($hashLength === 60 && password_verify($message, $hash)) + || ($hashLength === 40 && hash_equals($hash, sha1($message)))) { $newHash = $this->hash($message); return true; } diff --git a/lib/private/Security/Signature/Model/SignedRequest.php b/lib/private/Security/Signature/Model/SignedRequest.php index f30935e83b1..12a43f32bcc 100644 --- a/lib/private/Security/Signature/Model/SignedRequest.php +++ b/lib/private/Security/Signature/Model/SignedRequest.php @@ -74,8 +74,8 @@ class SignedRequest implements ISignedRequest, JsonSerializable { */ public function getDigest(): string { if ($this->digest === '') { - $this->digest = $this->digestAlgorithm->value . '=' . - base64_encode(hash($this->digestAlgorithm->getHashingAlgorithm(), $this->body, true)); + $this->digest = $this->digestAlgorithm->value . '=' + . base64_encode(hash($this->digestAlgorithm->getHashingAlgorithm(), $this->body, true)); } return $this->digest; } diff --git a/lib/private/Security/VerificationToken/VerificationToken.php b/lib/private/Security/VerificationToken/VerificationToken.php index 1995b482597..89f45180359 100644 --- a/lib/private/Security/VerificationToken/VerificationToken.php +++ b/lib/private/Security/VerificationToken/VerificationToken.php @@ -85,9 +85,9 @@ class VerificationToken implements IVerificationToken { ): string { $token = $this->secureRandom->generate( 21, - ISecureRandom::CHAR_DIGITS . - ISecureRandom::CHAR_LOWER . - ISecureRandom::CHAR_UPPER + ISecureRandom::CHAR_DIGITS + . ISecureRandom::CHAR_LOWER + . ISecureRandom::CHAR_UPPER ); $tokenValue = $this->timeFactory->getTime() . ':' . $token; $encryptedValue = $this->crypto->encrypt($tokenValue, $passwordPrefix . $this->config->getSystemValueString('secret')); diff --git a/lib/private/Server.php b/lib/private/Server.php index ea8c1ce3797..c78decd90cb 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -55,6 +56,7 @@ use OC\Files\Mount\RootMountProvider; use OC\Files\Node\HookConnector; use OC\Files\Node\LazyRoot; use OC\Files\Node\Root; +use OC\Files\ObjectStore\PrimaryObjectStoreConfig; use OC\Files\SetupManager; use OC\Files\Storage\StorageFactory; use OC\Files\Template\TemplateManager; @@ -195,6 +197,7 @@ use OCP\Lock\ILockingProvider; use OCP\Lockdown\ILockdownManager; use OCP\Log\ILogFactory; use OCP\Mail\IMailer; +use OCP\OCM\ICapabilityAwareOCMProvider; use OCP\OCM\IOCMDiscoveryService; use OCP\OCM\IOCMProvider; use OCP\Preview\IMimeIconProvider; @@ -319,7 +322,7 @@ class Server extends ServerContainer implements IServerContainer { return new Profiler($c->get(SystemConfig::class)); }); - $this->registerService(\OCP\Encryption\IManager::class, function (Server $c): Encryption\Manager { + $this->registerService(Encryption\Manager::class, function (Server $c): Encryption\Manager { $view = new View(); $util = new Encryption\Util( $view, @@ -336,6 +339,7 @@ class Server extends ServerContainer implements IServerContainer { new ArrayCache() ); }); + $this->registerAlias(\OCP\Encryption\IManager::class, Encryption\Manager::class); $this->registerService(IFile::class, function (ContainerInterface $c) { $util = new Encryption\Util( @@ -568,6 +572,7 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(IAppConfig::class, \OC\AppConfig::class); $this->registerAlias(IUserConfig::class, \OC\Config\UserConfig::class); + $this->registerAlias(IAppManager::class, AppManager::class); $this->registerService(IFactory::class, function (Server $c) { return new \OC\L10N\Factory( @@ -604,7 +609,7 @@ class Server extends ServerContainer implements IServerContainer { $prefixClosure = function () use ($logQuery, $serverVersion): ?string { if (!$logQuery) { try { - $v = \OCP\Server::get(IAppConfig::class)->getAppInstalledVersions(); + $v = \OCP\Server::get(IAppConfig::class)->getAppInstalledVersions(true); } catch (\Doctrine\DBAL\Exception $e) { // Database service probably unavailable // Probably related to https://github.com/nextcloud/server/issues/37424 @@ -619,7 +624,7 @@ class Server extends ServerContainer implements IServerContainer { ]; } $v['core'] = implode(',', $serverVersion->getVersion()); - $version = implode(',', $v); + $version = implode(',', array_keys($v)) . implode(',', $v); $instanceId = \OC_Util::getInstanceId(); $path = \OC::$SERVERROOT; return md5($instanceId . '-' . $version . '-' . $path); @@ -776,21 +781,6 @@ class Server extends ServerContainer implements IServerContainer { }); $this->registerAlias(ITempManager::class, TempManager::class); - - $this->registerService(AppManager::class, function (ContainerInterface $c) { - // TODO: use auto-wiring - return new \OC\App\AppManager( - $c->get(IUserSession::class), - $c->get(\OCP\IConfig::class), - $c->get(IGroupManager::class), - $c->get(ICacheFactory::class), - $c->get(IEventDispatcher::class), - $c->get(LoggerInterface::class), - $c->get(ServerVersion::class), - ); - }); - $this->registerAlias(IAppManager::class, AppManager::class); - $this->registerAlias(IDateTimeZone::class, DateTimeZone::class); $this->registerService(IDateTimeFormatter::class, function (Server $c) { @@ -819,10 +809,11 @@ class Server extends ServerContainer implements IServerContainer { $config = $c->get(\OCP\IConfig::class); $logger = $c->get(LoggerInterface::class); + $objectStoreConfig = $c->get(PrimaryObjectStoreConfig::class); $manager->registerProvider(new CacheMountProvider($config)); $manager->registerHomeProvider(new LocalHomeMountProvider()); - $manager->registerHomeProvider(new ObjectHomeMountProvider($config)); - $manager->registerRootProvider(new RootMountProvider($config, $c->get(LoggerInterface::class))); + $manager->registerHomeProvider(new ObjectHomeMountProvider($objectStoreConfig)); + $manager->registerRootProvider(new RootMountProvider($objectStoreConfig, $config)); $manager->registerRootProvider(new ObjectStorePreviewCacheMountProvider($logger, $config)); return $manager; @@ -1269,7 +1260,8 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(IPhoneNumberUtil::class, PhoneNumberUtil::class); - $this->registerAlias(IOCMProvider::class, OCMProvider::class); + $this->registerAlias(ICapabilityAwareOCMProvider::class, OCMProvider::class); + $this->registerDeprecatedAlias(IOCMProvider::class, OCMProvider::class); $this->registerAlias(ISetupCheckManager::class, SetupCheckManager::class); diff --git a/lib/private/Session/CryptoWrapper.php b/lib/private/Session/CryptoWrapper.php index 380c699d32d..40c2ba6adf3 100644 --- a/lib/private/Session/CryptoWrapper.php +++ b/lib/private/Session/CryptoWrapper.php @@ -59,7 +59,7 @@ class CryptoWrapper { [ 'expires' => 0, 'path' => $webRoot, - 'domain' => '', + 'domain' => \OCP\Server::get(\OCP\IConfig::class)->getSystemValueString('cookie_domain'), 'secure' => $secureCookie, 'httponly' => true, 'samesite' => 'Lax', diff --git a/lib/private/Settings/DeclarativeManager.php b/lib/private/Settings/DeclarativeManager.php index dea0c678f20..534b4b19984 100644 --- a/lib/private/Settings/DeclarativeManager.php +++ b/lib/private/Settings/DeclarativeManager.php @@ -15,6 +15,7 @@ use OCP\IAppConfig; use OCP\IConfig; use OCP\IGroupManager; use OCP\IUser; +use OCP\Security\ICrypto; use OCP\Server; use OCP\Settings\DeclarativeSettingsTypes; use OCP\Settings\Events\DeclarativeSettingsGetValueEvent; @@ -49,6 +50,7 @@ class DeclarativeManager implements IDeclarativeManager { private IConfig $config, private IAppConfig $appConfig, private LoggerInterface $logger, + private ICrypto $crypto, ) { } @@ -266,7 +268,7 @@ class DeclarativeManager implements IDeclarativeManager { $this->eventDispatcher->dispatchTyped(new DeclarativeSettingsSetValueEvent($user, $app, $formId, $fieldId, $value)); break; case DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL: - $this->saveInternalValue($user, $app, $fieldId, $value); + $this->saveInternalValue($user, $app, $formId, $fieldId, $value); break; default: throw new Exception('Unknown storage type "' . $storageType . '"'); @@ -290,18 +292,52 @@ class DeclarativeManager implements IDeclarativeManager { private function getInternalValue(IUser $user, string $app, string $formId, string $fieldId): mixed { $sectionType = $this->getSectionType($app, $fieldId); $defaultValue = $this->getDefaultValue($app, $formId, $fieldId); + + $field = $this->getSchemaField($app, $formId, $fieldId); + $isSensitive = $field !== null && isset($field['sensitive']) && $field['sensitive'] === true; + switch ($sectionType) { case DeclarativeSettingsTypes::SECTION_TYPE_ADMIN: - return $this->config->getAppValue($app, $fieldId, $defaultValue); + $value = $this->config->getAppValue($app, $fieldId, $defaultValue); + break; case DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL: - return $this->config->getUserValue($user->getUID(), $app, $fieldId, $defaultValue); + $value = $this->config->getUserValue($user->getUID(), $app, $fieldId, $defaultValue); + break; default: throw new Exception('Unknown section type "' . $sectionType . '"'); } + if ($isSensitive && $value !== '') { + try { + $value = $this->crypto->decrypt($value); + } catch (Exception $e) { + $this->logger->warning('Failed to decrypt sensitive value for field {field} in app {app}: {message}', [ + 'field' => $fieldId, + 'app' => $app, + 'message' => $e->getMessage(), + ]); + $value = $defaultValue; + } + } + return $value; } - private function saveInternalValue(IUser $user, string $app, string $fieldId, mixed $value): void { + private function saveInternalValue(IUser $user, string $app, string $formId, string $fieldId, mixed $value): void { $sectionType = $this->getSectionType($app, $fieldId); + + $field = $this->getSchemaField($app, $formId, $fieldId); + if ($field !== null && isset($field['sensitive']) && $field['sensitive'] === true && $value !== '' && $value !== 'dummySecret') { + try { + $value = $this->crypto->encrypt($value); + } catch (Exception $e) { + $this->logger->warning('Failed to decrypt sensitive value for field {field} in app {app}: {message}', [ + 'field' => $fieldId, + 'app' => $app, + 'message' => $e->getMessage()] + ); + throw new Exception('Failed to encrypt sensitive value'); + } + } + switch ($sectionType) { case DeclarativeSettingsTypes::SECTION_TYPE_ADMIN: $this->appConfig->setValueString($app, $fieldId, $value); @@ -314,6 +350,27 @@ class DeclarativeManager implements IDeclarativeManager { } } + private function getSchemaField(string $app, string $formId, string $fieldId): ?array { + $form = $this->getForm($app, $formId); + if ($form !== null) { + foreach ($form->getSchema()['fields'] as $field) { + if ($field['id'] === $fieldId) { + return $field; + } + } + } + foreach ($this->appSchemas[$app] ?? [] as $schema) { + if ($schema['id'] === $formId) { + foreach ($schema['fields'] as $field) { + if ($field['id'] === $fieldId) { + return $field; + } + } + } + } + return null; + } + private function getDefaultValue(string $app, string $formId, string $fieldId): mixed { foreach ($this->appSchemas[$app] as $schema) { if ($schema['id'] === $formId) { @@ -391,6 +448,12 @@ class DeclarativeManager implements IDeclarativeManager { ]); return false; } + if (isset($field['sensitive']) && $field['sensitive'] === true && !in_array($field['type'], [DeclarativeSettingsTypes::TEXT, DeclarativeSettingsTypes::PASSWORD])) { + $this->logger->warning('Declarative settings: sensitive field type is supported only for TEXT and PASSWORD types ({app}, {form_id}, {field_id})', [ + 'app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId, + ]); + return false; + } if (!$this->validateField($appId, $formId, $field)) { return false; } diff --git a/lib/private/Settings/Manager.php b/lib/private/Settings/Manager.php index c96c04f34ff..78dc64c3c3f 100644 --- a/lib/private/Settings/Manager.php +++ b/lib/private/Settings/Manager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Settings/Section.php b/lib/private/Settings/Section.php index 9cc6523b9ae..6cd8885d2df 100644 --- a/lib/private/Settings/Section.php +++ b/lib/private/Settings/Section.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Setup.php b/lib/private/Setup.php index 959797fb962..4082cd5df50 100644 --- a/lib/private/Setup.php +++ b/lib/private/Setup.php @@ -187,8 +187,8 @@ class Setup { if (\OC_Util::runningOnMac()) { $errors[] = [ 'error' => $this->l10n->t( - 'Mac OS X is not supported and %s will not work properly on this platform. ' . - 'Use it at your own risk!', + 'Mac OS X is not supported and %s will not work properly on this platform. ' + . 'Use it at your own risk!', [$this->defaults->getProductName()] ), 'hint' => $this->l10n->t('For the best results, please consider using a GNU/Linux server instead.'), @@ -198,8 +198,8 @@ class Setup { if ($this->iniWrapper->getString('open_basedir') !== '' && PHP_INT_SIZE === 4) { $errors[] = [ 'error' => $this->l10n->t( - 'It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. ' . - 'This will lead to problems with files over 4 GB and is highly discouraged.', + 'It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. ' + . 'This will lead to problems with files over 4 GB and is highly discouraged.', [$this->defaults->getProductName()] ), 'hint' => $this->l10n->t('Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP.'), @@ -304,11 +304,15 @@ class Setup { $error = []; $dbType = $options['dbtype']; - if (empty($options['adminlogin'])) { - $error[] = $l->t('Set an admin Login.'); - } - if (empty($options['adminpass'])) { - $error[] = $l->t('Set an admin password.'); + $disableAdminUser = (bool)($options['admindisable'] ?? false); + + if (!$disableAdminUser) { + if (empty($options['adminlogin'])) { + $error[] = $l->t('Set an admin Login.'); + } + if (empty($options['adminpass'])) { + $error[] = $l->t('Set an admin password.'); + } } if (empty($options['directory'])) { $options['directory'] = \OC::$SERVERROOT . '/data'; @@ -318,8 +322,6 @@ class Setup { $dbType = 'sqlite'; } - $username = htmlspecialchars_decode($options['adminlogin']); - $password = htmlspecialchars_decode($options['adminpass']); $dataDir = htmlspecialchars_decode($options['directory']); $class = self::$dbSetupClasses[$dbType]; @@ -375,7 +377,7 @@ class Setup { $this->outputDebug($output, 'Configuring database'); $dbSetup->initialize($options); try { - $dbSetup->setupDatabase($username); + $dbSetup->setupDatabase(); } catch (\OC\DatabaseSetupException $e) { $error[] = [ 'error' => $e->getMessage(), @@ -405,19 +407,22 @@ class Setup { return $error; } - $this->outputDebug($output, 'Create admin account'); - - // create the admin account and group $user = null; - try { - $user = Server::get(IUserManager::class)->createUser($username, $password); - if (!$user) { - $error[] = "Account <$username> could not be created."; + if (!$disableAdminUser) { + $username = htmlspecialchars_decode($options['adminlogin']); + $password = htmlspecialchars_decode($options['adminpass']); + $this->outputDebug($output, 'Create admin account'); + + try { + $user = Server::get(IUserManager::class)->createUser($username, $password); + if (!$user) { + $error[] = "Account <$username> could not be created."; + return $error; + } + } catch (Exception $exception) { + $error[] = $exception->getMessage(); return $error; } - } catch (Exception $exception) { - $error[] = $exception->getMessage(); - return $error; } $config = Server::get(IConfig::class); @@ -432,7 +437,7 @@ class Setup { } $group = Server::get(IGroupManager::class)->createGroup('admin'); - if ($group instanceof IGroup) { + if ($user !== null && $group instanceof IGroup) { $group->addUser($user); } @@ -464,26 +469,28 @@ class Setup { $bootstrapCoordinator = Server::get(\OC\AppFramework\Bootstrap\Coordinator::class); $bootstrapCoordinator->runInitialRegistration(); - // Create a session token for the newly created user - // The token provider requires a working db, so it's not injected on setup - /** @var \OC\User\Session $userSession */ - $userSession = Server::get(IUserSession::class); - $provider = Server::get(PublicKeyTokenProvider::class); - $userSession->setTokenProvider($provider); - $userSession->login($username, $password); - $user = $userSession->getUser(); - if (!$user) { - $error[] = 'No account found in session.'; - return $error; - } - $userSession->createSessionToken($request, $user->getUID(), $username, $password); + if (!$disableAdminUser) { + // Create a session token for the newly created user + // The token provider requires a working db, so it's not injected on setup + /** @var \OC\User\Session $userSession */ + $userSession = Server::get(IUserSession::class); + $provider = Server::get(PublicKeyTokenProvider::class); + $userSession->setTokenProvider($provider); + $userSession->login($username, $password); + $user = $userSession->getUser(); + if (!$user) { + $error[] = 'No account found in session.'; + return $error; + } + $userSession->createSessionToken($request, $user->getUID(), $username, $password); - $session = $userSession->getSession(); - $session->set('last-password-confirm', Server::get(ITimeFactory::class)->getTime()); + $session = $userSession->getSession(); + $session->set('last-password-confirm', Server::get(ITimeFactory::class)->getTime()); - // Set email for admin - if (!empty($options['adminemail'])) { - $user->setSystemEMailAddress($options['adminemail']); + // Set email for admin + if (!empty($options['adminemail'])) { + $user->setSystemEMailAddress($options['adminemail']); + } } return $error; diff --git a/lib/private/Setup/AbstractDatabase.php b/lib/private/Setup/AbstractDatabase.php index dbbb587206b..ec4ce040090 100644 --- a/lib/private/Setup/AbstractDatabase.php +++ b/lib/private/Setup/AbstractDatabase.php @@ -127,10 +127,7 @@ abstract class AbstractDatabase { return $connection; } - /** - * @param string $username - */ - abstract public function setupDatabase($username); + abstract public function setupDatabase(); public function runMigrations(?IOutput $output = null) { if (!is_dir(\OC::$SERVERROOT . '/core/Migrations')) { diff --git a/lib/private/Setup/MySQL.php b/lib/private/Setup/MySQL.php index 6dd9855d851..1e2dda4c609 100644 --- a/lib/private/Setup/MySQL.php +++ b/lib/private/Setup/MySQL.php @@ -16,7 +16,7 @@ use OCP\Security\ISecureRandom; class MySQL extends AbstractDatabase { public $dbprettyname = 'MySQL/MariaDB'; - public function setupDatabase($username) { + public function setupDatabase() { //check if the database user has admin right $connection = $this->connect(['dbname' => null]); @@ -28,7 +28,7 @@ class MySQL extends AbstractDatabase { } if ($this->tryCreateDbUser) { - $this->createSpecificUser($username, new ConnectionAdapter($connection)); + $this->createSpecificUser('oc_admin', new ConnectionAdapter($connection)); } $this->config->setValues([ diff --git a/lib/private/Setup/OCI.php b/lib/private/Setup/OCI.php index 47e5e5436a5..61c7f968787 100644 --- a/lib/private/Setup/OCI.php +++ b/lib/private/Setup/OCI.php @@ -40,7 +40,7 @@ class OCI extends AbstractDatabase { return $errors; } - public function setupDatabase($username) { + public function setupDatabase() { try { $this->connect(); } catch (\Exception $e) { diff --git a/lib/private/Setup/PostgreSQL.php b/lib/private/Setup/PostgreSQL.php index b1cf031e876..9a686db2e54 100644 --- a/lib/private/Setup/PostgreSQL.php +++ b/lib/private/Setup/PostgreSQL.php @@ -16,10 +16,9 @@ class PostgreSQL extends AbstractDatabase { public $dbprettyname = 'PostgreSQL'; /** - * @param string $username * @throws \OC\DatabaseSetupException */ - public function setupDatabase($username) { + public function setupDatabase() { try { $connection = $this->connect([ 'dbname' => 'postgres' @@ -46,7 +45,7 @@ class PostgreSQL extends AbstractDatabase { //use the admin login data for the new database user //add prefix to the postgresql user name to prevent collisions - $this->dbUser = 'oc_' . strtolower($username); + $this->dbUser = 'oc_admin'; //create a new password so we don't need to store the admin config in the config file $this->dbPassword = \OC::$server->get(ISecureRandom::class)->generate(30, ISecureRandom::CHAR_ALPHANUMERIC); diff --git a/lib/private/Setup/Sqlite.php b/lib/private/Setup/Sqlite.php index 1b90ebd5a5e..b34b1e32ede 100644 --- a/lib/private/Setup/Sqlite.php +++ b/lib/private/Setup/Sqlite.php @@ -45,7 +45,7 @@ class Sqlite extends AbstractDatabase { } } - public function setupDatabase($username) { + public function setupDatabase() { $datadir = $this->config->getValue( 'datadirectory', \OC::$SERVERROOT . '/data' diff --git a/lib/private/Share/Share.php b/lib/private/Share/Share.php index 56a4c6410c5..1121d71e45f 100644 --- a/lib/private/Share/Share.php +++ b/lib/private/Share/Share.php @@ -133,8 +133,8 @@ class Share extends Constants { // for file/folder shares we need to compare file_source, otherwise we compare item_source // only group shares if they already point to the same target, otherwise the file where shared // before grouping of shares was added. In this case we don't group them to avoid confusions - if (($fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) || - (!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) { + if (($fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) + || (!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) { // add the first item to the list of grouped shares if (!isset($result[$key]['grouped'])) { $result[$key]['grouped'][] = $result[$key]; diff --git a/lib/private/Share20/Exception/BackendError.php b/lib/private/Share20/Exception/BackendError.php index 60f7dcc1a17..b2585367727 100644 --- a/lib/private/Share20/Exception/BackendError.php +++ b/lib/private/Share20/Exception/BackendError.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Share20/Exception/InvalidShare.php b/lib/private/Share20/Exception/InvalidShare.php index 755efdfd2cc..8756455f9d2 100644 --- a/lib/private/Share20/Exception/InvalidShare.php +++ b/lib/private/Share20/Exception/InvalidShare.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/private/Share20/LegacyHooks.php b/lib/private/Share20/LegacyHooks.php index 99c2b0a9a87..3bce0b9560a 100644 --- a/lib/private/Share20/LegacyHooks.php +++ b/lib/private/Share20/LegacyHooks.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -69,9 +70,9 @@ class LegacyHooks { // Prepare hook $shareType = $share->getShareType(); $sharedWith = ''; - if ($shareType === IShare::TYPE_USER || - $shareType === IShare::TYPE_GROUP || - $shareType === IShare::TYPE_REMOTE) { + if ($shareType === IShare::TYPE_USER + || $shareType === IShare::TYPE_GROUP + || $shareType === IShare::TYPE_REMOTE) { $sharedWith = $share->getSharedWith(); } diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 2104c07593a..01664c6a0a3 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -182,8 +182,8 @@ class Manager implements IManager { } // Cannot share with yourself - if ($share->getShareType() === IShare::TYPE_USER && - $share->getSharedWith() === $share->getSharedBy()) { + if ($share->getShareType() === IShare::TYPE_USER + && $share->getSharedWith() === $share->getSharedBy()) { throw new \InvalidArgumentException($this->l->t('Cannot share with yourself')); } @@ -193,8 +193,8 @@ class Manager implements IManager { } // And it should be a file or a folder - if (!($share->getNode() instanceof \OCP\Files\File) && - !($share->getNode() instanceof \OCP\Files\Folder)) { + if (!($share->getNode() instanceof \OCP\Files\File) + && !($share->getNode() instanceof \OCP\Files\Folder)) { throw new \InvalidArgumentException($this->l->t('Shared path must be either a file or a folder')); } @@ -251,8 +251,8 @@ class Manager implements IManager { // Link shares are allowed to have no read permissions to allow upload to hidden folders $noReadPermissionRequired = $share->getShareType() === IShare::TYPE_LINK || $share->getShareType() === IShare::TYPE_EMAIL; - if (!$noReadPermissionRequired && - ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) { + if (!$noReadPermissionRequired + && ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) { throw new \InvalidArgumentException($this->l->t('Shares need at least read permissions')); } @@ -561,8 +561,8 @@ class Manager implements IManager { } // Check if public upload is allowed - if ($share->getNodeType() === 'folder' && !$this->shareApiLinkAllowPublicUpload() && - ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) { + if ($share->getNodeType() === 'folder' && !$this->shareApiLinkAllowPublicUpload() + && ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) { throw new \InvalidArgumentException($this->l->t('Public upload is not allowed')); } } @@ -698,8 +698,8 @@ class Manager implements IManager { } // Cannot share with the owner - if ($share->getShareType() === IShare::TYPE_USER && - $share->getSharedWith() === $share->getShareOwner()) { + if ($share->getShareType() === IShare::TYPE_USER + && $share->getSharedWith() === $share->getShareOwner()) { throw new \InvalidArgumentException($this->l->t('Cannot share with the share owner')); } @@ -791,14 +791,14 @@ class Manager implements IManager { } // We can only change the recipient on user shares - if ($share->getSharedWith() !== $originalShare->getSharedWith() && - $share->getShareType() !== IShare::TYPE_USER) { + if ($share->getSharedWith() !== $originalShare->getSharedWith() + && $share->getShareType() !== IShare::TYPE_USER) { throw new \InvalidArgumentException($this->l->t('Can only update recipient on user shares')); } // Cannot share with the owner - if ($share->getShareType() === IShare::TYPE_USER && - $share->getSharedWith() === $share->getShareOwner()) { + if ($share->getShareType() === IShare::TYPE_USER + && $share->getSharedWith() === $share->getShareOwner()) { throw new \InvalidArgumentException($this->l->t('Cannot share with the share owner')); } @@ -949,11 +949,11 @@ class Manager implements IManager { * @return boolean whether the password was updated or not. */ private function updateSharePasswordIfNeeded(IShare $share, IShare $originalShare) { - $passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) && - (($share->getPassword() !== null && $originalShare->getPassword() === null) || - ($share->getPassword() === null && $originalShare->getPassword() !== null) || - ($share->getPassword() !== null && $originalShare->getPassword() !== null && - !$this->hasher->verify($share->getPassword(), $originalShare->getPassword()))); + $passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) + && (($share->getPassword() !== null && $originalShare->getPassword() === null) + || ($share->getPassword() === null && $originalShare->getPassword() !== null) + || ($share->getPassword() !== null && $originalShare->getPassword() !== null + && !$this->hasher->verify($share->getPassword(), $originalShare->getPassword()))); // Password updated. if ($passwordsAreDifferent) { @@ -1237,9 +1237,9 @@ class Manager implements IManager { * @inheritdoc */ public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0, bool $onlyValid = true) { - if ($path !== null && - !($path instanceof \OCP\Files\File) && - !($path instanceof \OCP\Files\Folder)) { + if ($path !== null + && !($path instanceof \OCP\Files\File) + && !($path instanceof \OCP\Files\Folder)) { throw new \InvalidArgumentException($this->l->t('Invalid path')); } @@ -1798,8 +1798,8 @@ class Manager implements IManager { * @return bool */ public function shareApiLinkDefaultExpireDateEnforced() { - return $this->shareApiLinkDefaultExpireDate() && - $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes'; + return $this->shareApiLinkDefaultExpireDate() + && $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes'; } @@ -1836,8 +1836,8 @@ class Manager implements IManager { * @return bool */ public function shareApiInternalDefaultExpireDateEnforced(): bool { - return $this->shareApiInternalDefaultExpireDate() && - $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes'; + return $this->shareApiInternalDefaultExpireDate() + && $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes'; } /** @@ -1846,8 +1846,8 @@ class Manager implements IManager { * @return bool */ public function shareApiRemoteDefaultExpireDateEnforced(): bool { - return $this->shareApiRemoteDefaultExpireDate() && - $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes'; + return $this->shareApiRemoteDefaultExpireDate() + && $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes'; } /** @@ -1915,13 +1915,13 @@ class Manager implements IManager { } public function limitEnumerationToGroups(): bool { - return $this->allowEnumeration() && - $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes'; + return $this->allowEnumeration() + && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes'; } public function limitEnumerationToPhone(): bool { - return $this->allowEnumeration() && - $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes'; + return $this->allowEnumeration() + && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes'; } public function allowEnumerationFullMatch(): bool { @@ -1940,6 +1940,10 @@ class Manager implements IManager { return $this->appConfig->getValueBool('core', 'shareapi_allow_custom_tokens', false); } + public function allowViewWithoutDownload(): bool { + return $this->appConfig->getValueBool('core', 'shareapi_allow_view_without_download', true); + } + public function currentUserCanEnumerateTargetUser(?IUser $currentUser, IUser $targetUser): bool { if ($this->allowEnumerationFullMatch()) { return true; diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php index eba3f4f26f1..d920edfd90e 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -174,9 +174,9 @@ class ProviderFactory implements IProviderFactory { public function getProviderForType($shareType) { $provider = null; - if ($shareType === IShare::TYPE_USER || - $shareType === IShare::TYPE_GROUP || - $shareType === IShare::TYPE_LINK + if ($shareType === IShare::TYPE_USER + || $shareType === IShare::TYPE_GROUP + || $shareType === IShare::TYPE_LINK ) { $provider = $this->defaultShareProvider(); } elseif ($shareType === IShare::TYPE_REMOTE || $shareType === IShare::TYPE_REMOTE_GROUP) { diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php index 466817efc9a..8caabb0898a 100644 --- a/lib/private/Share20/Share.php +++ b/lib/private/Share20/Share.php @@ -14,8 +14,10 @@ use OCP\Files\IRootFolder; use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\IUserManager; +use OCP\Server; use OCP\Share\Exceptions\IllegalIDChangeException; use OCP\Share\IAttributes; +use OCP\Share\IManager; use OCP\Share\IShare; class Share implements IShare { @@ -418,8 +420,8 @@ class Share implements IShare { * @inheritdoc */ public function isExpired() { - return $this->getExpirationDate() !== null && - $this->getExpirationDate() <= new \DateTime(); + return $this->getExpirationDate() !== null + && $this->getExpirationDate() <= new \DateTime(); } /** @@ -622,4 +624,23 @@ class Share implements IShare { public function getReminderSent(): bool { return $this->reminderSent; } + + public function canSeeContent(): bool { + $shareManager = Server::get(IManager::class); + + $allowViewWithoutDownload = $shareManager->allowViewWithoutDownload(); + // If the share manager allows viewing without download, we can always see the content. + if ($allowViewWithoutDownload) { + return true; + } + + // No "allow preview" header set, so we must check if + // the share has not explicitly disabled download permissions + $attributes = $this->getAttributes(); + if ($attributes?->getAttribute('permissions', 'download') === false) { + return false; + } + + return true; + } } diff --git a/lib/private/Share20/ShareAttributes.php b/lib/private/Share20/ShareAttributes.php index 96da1e336e3..f90fbd9c6cd 100644 --- a/lib/private/Share20/ShareAttributes.php +++ b/lib/private/Share20/ShareAttributes.php @@ -32,8 +32,8 @@ class ShareAttributes implements IAttributes { * @inheritdoc */ public function getAttribute(string $scope, string $key): mixed { - if (\array_key_exists($scope, $this->attributes) && - \array_key_exists($key, $this->attributes[$scope])) { + if (\array_key_exists($scope, $this->attributes) + && \array_key_exists($key, $this->attributes[$scope])) { return $this->attributes[$scope][$key]; } return null; diff --git a/lib/private/Share20/ShareHelper.php b/lib/private/Share20/ShareHelper.php index d4a54f1d687..3f6bab98a7f 100644 --- a/lib/private/Share20/ShareHelper.php +++ b/lib/private/Share20/ShareHelper.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Support/Subscription/Registry.php b/lib/private/Support/Subscription/Registry.php index 5eed6885f78..34f24d1d026 100644 --- a/lib/private/Support/Subscription/Registry.php +++ b/lib/private/Support/Subscription/Registry.php @@ -138,8 +138,8 @@ class Registry implements IRegistry { */ public function delegateIsHardUserLimitReached(?IManager $notificationManager = null): bool { $subscription = $this->getSubscription(); - if ($subscription instanceof ISubscription && - $subscription->hasValidSubscription()) { + if ($subscription instanceof ISubscription + && $subscription->hasValidSubscription()) { $userLimitReached = $subscription->isHardUserLimitReached(); if ($userLimitReached && $notificationManager instanceof IManager) { $this->notifyAboutReachedUserLimit($notificationManager); diff --git a/lib/private/TaskProcessing/SynchronousBackgroundJob.php b/lib/private/TaskProcessing/SynchronousBackgroundJob.php index de3b424176c..19c53d59932 100644 --- a/lib/private/TaskProcessing/SynchronousBackgroundJob.php +++ b/lib/private/TaskProcessing/SynchronousBackgroundJob.php @@ -59,8 +59,8 @@ class SynchronousBackgroundJob extends QueuedJob { // check if this job needs to be scheduled again: // if there is at least one preferred synchronous provider that has a scheduled task - $synchronousProviders = array_filter($providers, fn ($provider) => - $provider instanceof ISynchronousProvider); + $synchronousProviders = array_filter($providers, fn ($provider) + => $provider instanceof ISynchronousProvider); $synchronousPreferredProviders = array_filter($synchronousProviders, function ($provider) { $taskTypeId = $provider->getTaskTypeId(); $preferredProvider = $this->taskProcessingManager->getPreferredProvider($taskTypeId); diff --git a/lib/private/Teams/TeamManager.php b/lib/private/Teams/TeamManager.php index d75b0209c71..13d6cc459a9 100644 --- a/lib/private/Teams/TeamManager.php +++ b/lib/private/Teams/TeamManager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/Template/JSCombiner.php b/lib/private/Template/JSCombiner.php index 5fce3effb3f..a94f822a448 100644 --- a/lib/private/Template/JSCombiner.php +++ b/lib/private/Template/JSCombiner.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php index caffbfceefa..cfc387d2164 100644 --- a/lib/private/TemplateLayout.php +++ b/lib/private/TemplateLayout.php @@ -201,7 +201,7 @@ class TemplateLayout { if ($this->config->getSystemValueBool('installed', false)) { if (empty(self::$versionHash)) { - $v = $this->appManager->getAppInstalledVersions(); + $v = $this->appManager->getAppInstalledVersions(true); $v['core'] = implode('.', $this->serverVersion->getVersion()); self::$versionHash = substr(md5(implode(',', $v)), 0, 8); } diff --git a/lib/private/URLGenerator.php b/lib/private/URLGenerator.php index c78ecac0903..1a2978b84d7 100644 --- a/lib/private/URLGenerator.php +++ b/lib/private/URLGenerator.php @@ -189,14 +189,14 @@ class URLGenerator implements IURLGenerator { $basename = substr(basename($file), 0, -4); try { - $appPath = $this->getAppManager()->getAppPath($appName); - } catch (AppPathNotFoundException $e) { if ($appName === 'core' || $appName === '') { $appName = 'core'; $appPath = false; } else { - throw new RuntimeException('image not found: image: ' . $file . ' webroot: ' . \OC::$WEBROOT . ' serverroot: ' . \OC::$SERVERROOT); + $appPath = $this->getAppManager()->getAppPath($appName); } + } catch (AppPathNotFoundException $e) { + throw new RuntimeException('image not found: image: ' . $file . ' webroot: ' . \OC::$WEBROOT . ' serverroot: ' . \OC::$SERVERROOT); } // Check if the app is in the app folder diff --git a/lib/private/Updater.php b/lib/private/Updater.php index 7707a310d99..6495bad2da2 100644 --- a/lib/private/Updater.php +++ b/lib/private/Updater.php @@ -167,8 +167,8 @@ class Updater extends BasicEmitter { // Vendor was not set correctly on install, so we have to white-list known versions if ($currentVendor === '' && ( - isset($allowedPreviousVersions['owncloud'][$oldVersion]) || - isset($allowedPreviousVersions['owncloud'][$majorMinor]) + isset($allowedPreviousVersions['owncloud'][$oldVersion]) + || isset($allowedPreviousVersions['owncloud'][$majorMinor]) )) { $currentVendor = 'owncloud'; $this->config->setAppValue('core', 'vendor', $currentVendor); @@ -176,13 +176,13 @@ class Updater extends BasicEmitter { if ($currentVendor === 'nextcloud') { return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) - && (version_compare($oldVersion, $newVersion, '<=') || - $this->config->getSystemValueBool('debug', false)); + && (version_compare($oldVersion, $newVersion, '<=') + || $this->config->getSystemValueBool('debug', false)); } // Check if the instance can be migrated - return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) || - isset($allowedPreviousVersions[$currentVendor][$oldVersion]); + return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) + || isset($allowedPreviousVersions[$currentVendor][$oldVersion]); } /** diff --git a/lib/private/Updater/VersionCheck.php b/lib/private/Updater/VersionCheck.php index 53bfc0d5d5f..be410b06c3e 100644 --- a/lib/private/Updater/VersionCheck.php +++ b/lib/private/Updater/VersionCheck.php @@ -105,17 +105,20 @@ class VersionCheck { } /** - * @codeCoverageIgnore - * @param string $url - * @return resource|string * @throws \Exception */ - protected function getUrlContent($url) { - $client = $this->clientService->newClient(); - $response = $client->get($url, [ + protected function getUrlContent(string $url): string { + $response = $this->clientService->newClient()->get($url, [ 'timeout' => 5, ]); - return $response->getBody(); + + $content = $response->getBody(); + + // IResponse.getBody responds with null|resource if returning a stream response was requested. + // As that's not the case here, we can just ignore the psalm warning by adding an assertion. + assert(is_string($content)); + + return $content; } private function computeCategory(): int { diff --git a/lib/private/User/LazyUser.php b/lib/private/User/LazyUser.php index 715265f6a39..501169019d4 100644 --- a/lib/private/User/LazyUser.php +++ b/lib/private/User/LazyUser.php @@ -160,6 +160,10 @@ class LazyUser implements IUser { return $this->getUser()->getQuota(); } + public function getQuotaBytes(): int|float { + return $this->getUser()->getQuotaBytes(); + } + public function setQuota($quota) { $this->getUser()->setQuota($quota); } diff --git a/lib/private/User/Listeners/UserChangedListener.php b/lib/private/User/Listeners/UserChangedListener.php index 983a4e81233..8f618950255 100644 --- a/lib/private/User/Listeners/UserChangedListener.php +++ b/lib/private/User/Listeners/UserChangedListener.php @@ -28,7 +28,7 @@ class UserChangedListener implements IEventListener { if (!($event instanceof UserChangedEvent)) { return; } - + $user = $event->getUser(); $feature = $event->getFeature(); $oldValue = $event->getOldValue(); diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index ca5d90f8c00..097fd9a0dc8 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -320,9 +320,9 @@ class Manager extends PublicEmitter implements IUserManager { $users, function (IUser $user) use ($search): bool { try { - return mb_stripos($user->getUID(), $search) !== false || - mb_stripos($user->getDisplayName(), $search) !== false || - mb_stripos($user->getEMailAddress() ?? '', $search) !== false; + return mb_stripos($user->getUID(), $search) !== false + || mb_stripos($user->getDisplayName(), $search) !== false + || mb_stripos($user->getEMailAddress() ?? '', $search) !== false; } catch (NoUserException $ex) { $this->logger->error('Error while filtering disabled users', ['exception' => $ex, 'userUID' => $user->getUID()]); return false; @@ -724,7 +724,8 @@ class Manager extends PublicEmitter implements IUserManager { // User ID is too long if (strlen($uid) > IUser::MAX_USERID_LENGTH) { - throw new \InvalidArgumentException($l->t('Login is too long')); + // TRANSLATORS User ID is too long + throw new \InvalidArgumentException($l->t('Username is too long')); } if (!$this->verifyUid($uid, $checkDataDirectory)) { diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index 27570822ef2..95e4b6e4a87 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -967,6 +968,7 @@ class Session implements IUserSession, Emitter { if ($webRoot === '') { $webRoot = '/'; } + $domain = $this->config->getSystemValueString('cookie_domain'); $maxAge = $this->config->getSystemValueInt('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); \OC\Http\CookieHelper::setCookie( @@ -974,7 +976,7 @@ class Session implements IUserSession, Emitter { $username, $maxAge, $webRoot, - '', + $domain, $secureCookie, true, \OC\Http\CookieHelper::SAMESITE_LAX @@ -984,7 +986,7 @@ class Session implements IUserSession, Emitter { $token, $maxAge, $webRoot, - '', + $domain, $secureCookie, true, \OC\Http\CookieHelper::SAMESITE_LAX @@ -995,7 +997,7 @@ class Session implements IUserSession, Emitter { $this->session->getId(), $maxAge, $webRoot, - '', + $domain, $secureCookie, true, \OC\Http\CookieHelper::SAMESITE_LAX @@ -1011,18 +1013,19 @@ class Session implements IUserSession, Emitter { public function unsetMagicInCookie() { //TODO: DI for cookies and IRequest $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https'; + $domain = $this->config->getSystemValueString('cookie_domain'); unset($_COOKIE['nc_username']); //TODO: DI unset($_COOKIE['nc_token']); unset($_COOKIE['nc_session_id']); - setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true); - setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true); - setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true); + setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, $domain, $secureCookie, true); + setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, $domain, $secureCookie, true); + setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, $domain, $secureCookie, true); // old cookies might be stored under /webroot/ instead of /webroot // and Firefox doesn't like it! - setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true); - setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true); - setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true); + setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', $domain, $secureCookie, true); + setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', $domain, $secureCookie, true); + setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', $domain, $secureCookie, true); } /** diff --git a/lib/private/User/User.php b/lib/private/User/User.php index 8e01a15695c..88ed0d44387 100644 --- a/lib/private/User/User.php +++ b/lib/private/User/User.php @@ -558,6 +558,19 @@ class User implements IUser { return $quota; } + public function getQuotaBytes(): int|float { + $quota = $this->getQuota(); + if ($quota === 'none') { + return \OCP\Files\FileInfo::SPACE_UNLIMITED; + } + + $bytes = \OCP\Util::computerFileSize($quota); + if ($bytes === false) { + return \OCP\Files\FileInfo::SPACE_UNKNOWN; + } + return $bytes; + } + /** * set the users' quota * diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index abac0d2635e..24982ab9e80 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -9,6 +9,7 @@ declare(strict_types=1); use OC\App\DependencyAnalyzer; use OC\App\Platform; use OC\AppFramework\Bootstrap\Coordinator; +use OC\Config\ConfigManager; use OC\DB\MigrationService; use OC\Installer; use OC\Repair; @@ -211,7 +212,7 @@ class OC_App { array $groups = []) { // Check if app is already downloaded /** @var Installer $installer */ - $installer = \OCP\Server::get(Installer::class); + $installer = Server::get(Installer::class); $isDownloaded = $installer->isDownloaded($appId); if (!$isDownloaded) { @@ -246,7 +247,7 @@ class OC_App { } } - \OCP\Server::get(LoggerInterface::class)->error('No application directories are marked as writable.', ['app' => 'core']); + Server::get(LoggerInterface::class)->error('No application directories are marked as writable.', ['app' => 'core']); return null; } @@ -310,12 +311,14 @@ class OC_App { * @param string $appId * @param bool $refreshAppPath should be set to true only during install/upgrade * @return string|false - * @deprecated 11.0.0 use \OCP\Server::get(IAppManager)->getAppPath() + * @deprecated 11.0.0 use Server::get(IAppManager)->getAppPath() */ public static function getAppPath(string $appId, bool $refreshAppPath = false) { $appId = self::cleanAppId($appId); if ($appId === '') { return false; + } elseif ($appId === 'core') { + return __DIR__ . '/../../../core'; } if (($dir = self::findAppInDirectories($appId, $refreshAppPath)) != false) { @@ -347,7 +350,7 @@ class OC_App { */ public static function getAppVersionByPath(string $path): string { $infoFile = $path . '/appinfo/info.xml'; - $appData = \OCP\Server::get(IAppManager::class)->getAppInfoByPath($infoFile); + $appData = Server::get(IAppManager::class)->getAppInfoByPath($infoFile); return $appData['version'] ?? ''; } @@ -389,7 +392,7 @@ class OC_App { * @deprecated 20.0.0 Please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface */ public static function registerLogIn(array $entry) { - \OCP\Server::get(LoggerInterface::class)->debug('OC_App::registerLogIn() is deprecated, please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface'); + Server::get(LoggerInterface::class)->debug('OC_App::registerLogIn() is deprecated, please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface'); self::$altLogin[] = $entry; } @@ -398,11 +401,11 @@ class OC_App { */ public static function getAlternativeLogIns(): array { /** @var Coordinator $bootstrapCoordinator */ - $bootstrapCoordinator = \OCP\Server::get(Coordinator::class); + $bootstrapCoordinator = Server::get(Coordinator::class); foreach ($bootstrapCoordinator->getRegistrationContext()->getAlternativeLogins() as $registration) { if (!in_array(IAlternativeLogin::class, class_implements($registration->getService()), true)) { - \OCP\Server::get(LoggerInterface::class)->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [ + Server::get(LoggerInterface::class)->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [ 'option' => $registration->getService(), 'interface' => IAlternativeLogin::class, 'app' => $registration->getAppId(), @@ -412,9 +415,9 @@ class OC_App { try { /** @var IAlternativeLogin $provider */ - $provider = \OCP\Server::get($registration->getService()); + $provider = Server::get($registration->getService()); } catch (ContainerExceptionInterface $e) { - \OCP\Server::get(LoggerInterface::class)->error('Alternative login option {option} can not be initialized.', + Server::get(LoggerInterface::class)->error('Alternative login option {option} can not be initialized.', [ 'exception' => $e, 'option' => $registration->getService(), @@ -431,7 +434,7 @@ class OC_App { 'class' => $provider->getClass(), ]; } catch (Throwable $e) { - \OCP\Server::get(LoggerInterface::class)->error('Alternative login option {option} had an error while loading.', + Server::get(LoggerInterface::class)->error('Alternative login option {option} had an error while loading.', [ 'exception' => $e, 'option' => $registration->getService(), @@ -450,7 +453,7 @@ class OC_App { * @deprecated 31.0.0 Use IAppManager::getAllAppsInAppsFolders instead */ public static function getAllApps(): array { - return \OCP\Server::get(IAppManager::class)->getAllAppsInAppsFolders(); + return Server::get(IAppManager::class)->getAllAppsInAppsFolders(); } /** @@ -459,7 +462,7 @@ class OC_App { * @deprecated 32.0.0 Use \OCP\Support\Subscription\IRegistry::delegateGetSupportedApps instead */ public function getSupportedApps(): array { - $subscriptionRegistry = \OCP\Server::get(\OCP\Support\Subscription\IRegistry::class); + $subscriptionRegistry = Server::get(\OCP\Support\Subscription\IRegistry::class); $supportedApps = $subscriptionRegistry->delegateGetSupportedApps(); return $supportedApps; } @@ -484,12 +487,12 @@ class OC_App { if (!in_array($app, $blacklist)) { $info = $appManager->getAppInfo($app, false, $langCode); if (!is_array($info)) { - \OCP\Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']); + Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']); continue; } if (!isset($info['name'])) { - \OCP\Server::get(LoggerInterface::class)->error('App id "' . $app . '" has no name in appinfo', ['app' => 'core']); + Server::get(LoggerInterface::class)->error('App id "' . $app . '" has no name in appinfo', ['app' => 'core']); continue; } @@ -556,7 +559,7 @@ class OC_App { public static function shouldUpgrade(string $app): bool { $versions = self::getAppVersions(); - $currentVersion = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppVersion($app); + $currentVersion = Server::get(\OCP\App\IAppManager::class)->getAppVersion($app); if ($currentVersion && isset($versions[$app])) { $installedVersion = $versions[$app]; if (!version_compare($currentVersion, $installedVersion, '=')) { @@ -645,7 +648,7 @@ class OC_App { * @deprecated 32.0.0 Use IAppManager::getAppInstalledVersions or IAppConfig::getAppInstalledVersions instead */ public static function getAppVersions(): array { - return \OCP\Server::get(IAppConfig::class)->getAppInstalledVersions(); + return Server::get(IAppConfig::class)->getAppInstalledVersions(); } /** @@ -663,13 +666,13 @@ class OC_App { } if (is_file($appPath . '/appinfo/database.xml')) { - \OCP\Server::get(LoggerInterface::class)->error('The appinfo/database.xml file is not longer supported. Used in ' . $appId); + Server::get(LoggerInterface::class)->error('The appinfo/database.xml file is not longer supported. Used in ' . $appId); return false; } \OC::$server->getAppManager()->clearAppsCache(); $l = \OC::$server->getL10N('core'); - $appData = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppInfo($appId, false, $l->getLanguageCode()); + $appData = Server::get(\OCP\App\IAppManager::class)->getAppInfo($appId, false, $l->getLanguageCode()); $ignoreMaxApps = \OC::$server->getConfig()->getSystemValue('app_install_overwrite', []); $ignoreMax = in_array($appId, $ignoreMaxApps, true); @@ -709,9 +712,13 @@ class OC_App { self::setAppTypes($appId); - $version = \OCP\Server::get(\OCP\App\IAppManager::class)->getAppVersion($appId); + $version = Server::get(\OCP\App\IAppManager::class)->getAppVersion($appId); \OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version); + // migrate eventual new config keys in the process + /** @psalm-suppress InternalMethod */ + Server::get(ConfigManager::class)->migrateConfigLexiconKeys($appId); + \OC::$server->get(IEventDispatcher::class)->dispatchTyped(new AppUpdateEvent($appId)); \OC::$server->get(IEventDispatcher::class)->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent( ManagerEvent::EVENT_APP_UPDATE, $appId diff --git a/lib/private/legacy/OC_Defaults.php b/lib/private/legacy/OC_Defaults.php index f7015a1863a..0d460ff966d 100644 --- a/lib/private/legacy/OC_Defaults.php +++ b/lib/private/legacy/OC_Defaults.php @@ -228,9 +228,9 @@ class OC_Defaults { if ($this->themeExist('getShortFooter')) { $footer = $this->theme->getShortFooter(); } else { - $footer = '<a href="' . $this->getBaseUrl() . '" target="_blank"' . - ' rel="noreferrer noopener">' . $this->getEntity() . '</a>' . - ' – ' . $this->getSlogan(); + $footer = '<a href="' . $this->getBaseUrl() . '" target="_blank"' + . ' rel="noreferrer noopener">' . $this->getEntity() . '</a>' + . ' – ' . $this->getSlogan(); } return $footer; diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php index 87c820dcd53..4388f775623 100644 --- a/lib/private/legacy/OC_Helper.php +++ b/lib/private/legacy/OC_Helper.php @@ -272,7 +272,7 @@ class OC_Helper { } else { $user = \OC::$server->getUserSession()->getUser(); } - $quota = OC_Util::getUserQuota($user); + $quota = $user?->getQuotaBytes() ?? \OCP\Files\FileInfo::SPACE_UNKNOWN; if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { // always get free space / total space from root + mount points return self::getGlobalStorageInfo($quota, $user, $mount); diff --git a/lib/private/legacy/OC_Response.php b/lib/private/legacy/OC_Response.php index 86274f5fcb7..c45852b4b1d 100644 --- a/lib/private/legacy/OC_Response.php +++ b/lib/private/legacy/OC_Response.php @@ -78,7 +78,6 @@ class OC_Response { header('X-Frame-Options: SAMEORIGIN'); // Disallow iFraming from other domains header('X-Permitted-Cross-Domain-Policies: none'); // https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html header('X-Robots-Tag: noindex, nofollow'); // https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag - header('X-XSS-Protection: 1; mode=block'); // Enforce browser based XSS filters } } } diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 9444da4f36d..948dfcf7926 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -98,7 +98,7 @@ class OC_Util { * * @param IUser|null $user * @return int|\OCP\Files\FileInfo::SPACE_UNLIMITED|false|float Quota bytes - * @deprecated 9.0.0 - Use \OCP\IUser::getQuota + * @deprecated 9.0.0 - Use \OCP\IUser::getQuota or \OCP\IUser::getQuotaBytes */ public static function getUserQuota(?IUser $user) { if (is_null($user)) { @@ -187,14 +187,13 @@ class OC_Util { $child = $target->newFolder($file); self::copyr($source . '/' . $file, $child); } else { - $child = $target->newFile($file); $sourceStream = fopen($source . '/' . $file, 'r'); if ($sourceStream === false) { $logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']); closedir($dir); return; } - $child->putContent($sourceStream); + $target->newFile($file, $sourceStream); } } } @@ -480,8 +479,8 @@ class OC_Util { * TODO: Should probably be implemented in the above generic dependency * check somehow in the long-term. */ - if ($iniWrapper->getBool('mbstring.func_overload') !== null && - $iniWrapper->getBool('mbstring.func_overload') === true) { + if ($iniWrapper->getBool('mbstring.func_overload') !== null + && $iniWrapper->getBool('mbstring.func_overload') === true) { $errors[] = [ 'error' => $l->t('<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>.', [$iniWrapper->getString('mbstring.func_overload')]), 'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.') diff --git a/lib/public/Accounts/PropertyDoesNotExistException.php b/lib/public/Accounts/PropertyDoesNotExistException.php index d0f10cdf12f..1d27ef1df30 100644 --- a/lib/public/Accounts/PropertyDoesNotExistException.php +++ b/lib/public/Accounts/PropertyDoesNotExistException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Activity/IEventMerger.php b/lib/public/Activity/IEventMerger.php index e9355c88004..5d0f691f2d4 100644 --- a/lib/public/Activity/IEventMerger.php +++ b/lib/public/Activity/IEventMerger.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Activity/IFilter.php b/lib/public/Activity/IFilter.php index 75d53650127..008de6f5bca 100644 --- a/lib/public/Activity/IFilter.php +++ b/lib/public/Activity/IFilter.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Activity/IProvider.php b/lib/public/Activity/IProvider.php index 17fffbb26e2..dec4e7ade64 100644 --- a/lib/public/Activity/IProvider.php +++ b/lib/public/Activity/IProvider.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Activity/ISetting.php b/lib/public/Activity/ISetting.php index c5c5c523477..1304ab8c658 100644 --- a/lib/public/Activity/ISetting.php +++ b/lib/public/Activity/ISetting.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/App/AppPathNotFoundException.php b/lib/public/App/AppPathNotFoundException.php index 5e3ea7a9919..56d6571ea68 100644 --- a/lib/public/App/AppPathNotFoundException.php +++ b/lib/public/App/AppPathNotFoundException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/App/Events/AppUpdateEvent.php b/lib/public/App/Events/AppUpdateEvent.php index 344e7def080..2cf59ff7949 100644 --- a/lib/public/App/Events/AppUpdateEvent.php +++ b/lib/public/App/Events/AppUpdateEvent.php @@ -16,15 +16,13 @@ use OCP\EventDispatcher\Event; * @since 27.0.0 */ class AppUpdateEvent extends Event { - private string $appId; - /** * @since 27.0.0 */ - public function __construct(string $appId) { + public function __construct( + private readonly string $appId, + ) { parent::__construct(); - - $this->appId = $appId; } /** diff --git a/lib/public/App/IAppManager.php b/lib/public/App/IAppManager.php index 67ef2d796be..20019ce1ffd 100644 --- a/lib/public/App/IAppManager.php +++ b/lib/public/App/IAppManager.php @@ -57,7 +57,7 @@ interface IAppManager { * @return array<string, string> * @since 32.0.0 */ - public function getAppInstalledVersions(): array; + public function getAppInstalledVersions(bool $onlyEnabled = false): array; /** * Returns the app icon or null if none is found @@ -184,7 +184,7 @@ interface IAppManager { * List all apps enabled for a user * * @param \OCP\IUser $user - * @return string[] + * @return list<string> * @since 8.1.0 */ public function getEnabledAppsForUser(IUser $user); diff --git a/lib/public/AppFramework/App.php b/lib/public/AppFramework/App.php index 6860de7c324..c00fde47418 100644 --- a/lib/public/AppFramework/App.php +++ b/lib/public/AppFramework/App.php @@ -9,6 +9,7 @@ declare(strict_types=1); */ namespace OCP\AppFramework; +use OC\AppFramework\Utility\SimpleContainer; use OC\ServerContainer; use OCP\IConfig; use OCP\Server; @@ -57,16 +58,23 @@ class App { $classNameParts = explode('\\', trim($applicationClassName, '\\')); foreach ($e->getTrace() as $step) { - if (isset($step['class'], $step['function'], $step['args'][0]) && - $step['class'] === ServerContainer::class && - $step['function'] === 'query' && - $step['args'][0] === $applicationClassName) { + if (isset($step['class'], $step['function'], $step['args'][0]) + && $step['class'] === ServerContainer::class + && $step['function'] === 'query' + && $step['args'][0] === $applicationClassName) { $setUpViaQuery = true; break; - } elseif (isset($step['class'], $step['function'], $step['args'][0]) && - $step['class'] === ServerContainer::class && - $step['function'] === 'getAppContainer' && - $step['args'][1] === $classNameParts[1]) { + } elseif (isset($step['class'], $step['function'], $step['args'][0]) + && $step['class'] === ServerContainer::class + && $step['function'] === 'getAppContainer' + && $step['args'][1] === $classNameParts[1]) { + $setUpViaQuery = true; + break; + } elseif (isset($step['class'], $step['function'], $step['args'][0]) + && $step['class'] === SimpleContainer::class + && preg_match('/{closure:OC\\\\AppFramework\\\\Utility\\\\SimpleContainer::buildClass\\(\\):\\d+}/', $step['function']) + && $step['args'][0] === $this) { + /* We are setup through a lazy ghost, fine */ $setUpViaQuery = true; break; } diff --git a/lib/public/AppFramework/Controller.php b/lib/public/AppFramework/Controller.php index 7c25b3382e7..cdeaac99366 100644 --- a/lib/public/AppFramework/Controller.php +++ b/lib/public/AppFramework/Controller.php @@ -135,7 +135,7 @@ abstract class Controller { return $responder($response); } - throw new \DomainException('No responder registered for format ' . - $format . '!'); + throw new \DomainException('No responder registered for format ' + . $format . '!'); } } diff --git a/lib/public/AppFramework/Db/Entity.php b/lib/public/AppFramework/Db/Entity.php index a44a9a8bced..3094070af5f 100644 --- a/lib/public/AppFramework/Db/Entity.php +++ b/lib/public/AppFramework/Db/Entity.php @@ -159,8 +159,8 @@ abstract class Entity { if (property_exists($this, $name)) { return $this->$name; } else { - throw new \BadFunctionCallException($name . - ' is not a valid attribute'); + throw new \BadFunctionCallException($name + . ' is not a valid attribute'); } } @@ -180,8 +180,8 @@ abstract class Entity { } elseif ($this->isGetterForBoolProperty($methodName)) { return $this->getter(lcfirst(substr($methodName, 2))); } else { - throw new \BadFunctionCallException($methodName . - ' does not exist'); + throw new \BadFunctionCallException($methodName + . ' does not exist'); } } diff --git a/lib/public/AppFramework/Db/QBMapper.php b/lib/public/AppFramework/Db/QBMapper.php index 4071a4a47a4..7fb5b2a9afd 100644 --- a/lib/public/AppFramework/Db/QBMapper.php +++ b/lib/public/AppFramework/Db/QBMapper.php @@ -296,8 +296,8 @@ abstract class QBMapper { * @since 14.0.0 */ private function buildDebugMessage(string $msg, IQueryBuilder $sql): string { - return $msg . - ': query "' . $sql->getSQL() . '"; '; + return $msg + . ': query "' . $sql->getSQL() . '"; '; } diff --git a/lib/public/AppFramework/Http/Attribute/RequestHeader.php b/lib/public/AppFramework/Http/Attribute/RequestHeader.php index c9327eec4c0..1d0fbbfa0c3 100644 --- a/lib/public/AppFramework/Http/Attribute/RequestHeader.php +++ b/lib/public/AppFramework/Http/Attribute/RequestHeader.php @@ -21,30 +21,14 @@ use Attribute; #[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class RequestHeader { /** - * @param string $name The name of the request header - * @param string $description The description of the request header + * @param lowercase-string $name The name of the request header + * @param non-empty-string $description The description of the request header + * @param bool $indirect Allow indirect usage of the header for example in a middleware. Enabling this turns off the check which ensures that the header must be referenced in the controller method. */ public function __construct( protected string $name, protected string $description, + protected bool $indirect = false, ) { } - - /** - * @return string The name of the request header. - * - * @since 32.0.0 - */ - public function getName(): string { - return $this->name; - } - - /** - * @return string The description of the request header. - * - * @since 32.0.0 - */ - public function getDescription(): string { - return $this->description; - } } diff --git a/lib/public/AppFramework/Http/FileDisplayResponse.php b/lib/public/AppFramework/Http/FileDisplayResponse.php index fda160eafc5..c18404b7d91 100644 --- a/lib/public/AppFramework/Http/FileDisplayResponse.php +++ b/lib/public/AppFramework/Http/FileDisplayResponse.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/Http/Response.php b/lib/public/AppFramework/Http/Response.php index 8037243d7a4..bdebb12c00d 100644 --- a/lib/public/AppFramework/Http/Response.php +++ b/lib/public/AppFramework/Http/Response.php @@ -96,7 +96,7 @@ class Response { $time = \OCP\Server::get(ITimeFactory::class); $expires->setTimestamp($time->getTime()); $expires->add(new \DateInterval('PT' . $cacheSeconds . 'S')); - $this->addHeader('Expires', $expires->format(\DateTimeInterface::RFC2822)); + $this->addHeader('Expires', $expires->format(\DateTimeInterface::RFC7231)); } else { $this->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); unset($this->headers['Expires']); @@ -238,7 +238,7 @@ class Response { ]; if ($this->lastModified) { - $mergeWith['Last-Modified'] = $this->lastModified->format(\DateTimeInterface::RFC2822); + $mergeWith['Last-Modified'] = $this->lastModified->format(\DateTimeInterface::RFC7231); } if ($this->ETag) { diff --git a/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php b/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php index 4f958a2620c..281bb559a10 100644 --- a/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php +++ b/lib/public/AppFramework/Http/Template/ExternalShareMenuAction.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/Http/Template/IMenuAction.php b/lib/public/AppFramework/Http/Template/IMenuAction.php index 50b346add86..124e95fe019 100644 --- a/lib/public/AppFramework/Http/Template/IMenuAction.php +++ b/lib/public/AppFramework/Http/Template/IMenuAction.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/Http/Template/LinkMenuAction.php b/lib/public/AppFramework/Http/Template/LinkMenuAction.php index 6ae1fcdf13b..391802a1dce 100644 --- a/lib/public/AppFramework/Http/Template/LinkMenuAction.php +++ b/lib/public/AppFramework/Http/Template/LinkMenuAction.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php b/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php index ef5d2f67f7e..4c156cdecea 100644 --- a/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php +++ b/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -44,6 +45,7 @@ class PublicTemplateResponse extends TemplateResponse { ) { parent::__construct($appName, $templateName, $params, 'public', $status, $headers); \OCP\Util::addScript('core', 'public-page-menu'); + \OCP\Util::addScript('core', 'public-page-user-menu'); $state = \OCP\Server::get(IInitialStateService::class); $state->provideLazyInitialState('core', 'public-page-menu', function () { diff --git a/lib/public/AppFramework/Http/Template/SimpleMenuAction.php b/lib/public/AppFramework/Http/Template/SimpleMenuAction.php index 4cbbd5302d7..03cb9b4c7ea 100644 --- a/lib/public/AppFramework/Http/Template/SimpleMenuAction.php +++ b/lib/public/AppFramework/Http/Template/SimpleMenuAction.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/OCS/OCSBadRequestException.php b/lib/public/AppFramework/OCS/OCSBadRequestException.php index c229468fb0d..77b8ec6c86d 100644 --- a/lib/public/AppFramework/OCS/OCSBadRequestException.php +++ b/lib/public/AppFramework/OCS/OCSBadRequestException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/OCS/OCSException.php b/lib/public/AppFramework/OCS/OCSException.php index 962bad830e7..02901992f8d 100644 --- a/lib/public/AppFramework/OCS/OCSException.php +++ b/lib/public/AppFramework/OCS/OCSException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/OCS/OCSForbiddenException.php b/lib/public/AppFramework/OCS/OCSForbiddenException.php index 03b1db6104f..0d001377043 100644 --- a/lib/public/AppFramework/OCS/OCSForbiddenException.php +++ b/lib/public/AppFramework/OCS/OCSForbiddenException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/OCS/OCSNotFoundException.php b/lib/public/AppFramework/OCS/OCSNotFoundException.php index 997b0c390f9..67cea9ed759 100644 --- a/lib/public/AppFramework/OCS/OCSNotFoundException.php +++ b/lib/public/AppFramework/OCS/OCSNotFoundException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php b/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php index 2e67263bcb9..4fc2820eaec 100644 --- a/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php +++ b/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/AppFramework/PublicShareController.php b/lib/public/AppFramework/PublicShareController.php index 458606455d1..999b3827565 100644 --- a/lib/public/AppFramework/PublicShareController.php +++ b/lib/public/AppFramework/PublicShareController.php @@ -98,8 +98,8 @@ abstract class PublicShareController extends Controller { } // If we are authenticated properly - if ($this->session->get('public_link_authenticated_token') === $this->getToken() && - $this->session->get('public_link_authenticated_password_hash') === $this->getPasswordHash()) { + if ($this->session->get('public_link_authenticated_token') === $this->getToken() + && $this->session->get('public_link_authenticated_password_hash') === $this->getPasswordHash()) { return true; } diff --git a/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php b/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php index 835fd1eac9d..6ca8e68ed95 100644 --- a/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php +++ b/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Authentication/Exceptions/PasswordUnavailableException.php b/lib/public/Authentication/Exceptions/PasswordUnavailableException.php index 6a425f4ddd9..89e254e8ba1 100644 --- a/lib/public/Authentication/Exceptions/PasswordUnavailableException.php +++ b/lib/public/Authentication/Exceptions/PasswordUnavailableException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Authentication/IProvideUserSecretBackend.php b/lib/public/Authentication/IProvideUserSecretBackend.php index c005f6c9d59..dfab35c5f48 100644 --- a/lib/public/Authentication/IProvideUserSecretBackend.php +++ b/lib/public/Authentication/IProvideUserSecretBackend.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-only diff --git a/lib/public/Authentication/LoginCredentials/ICredentials.php b/lib/public/Authentication/LoginCredentials/ICredentials.php index a1c802f73b0..9848bbbe821 100644 --- a/lib/public/Authentication/LoginCredentials/ICredentials.php +++ b/lib/public/Authentication/LoginCredentials/ICredentials.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/BackgroundJob/TimedJob.php b/lib/public/BackgroundJob/TimedJob.php index 296bd9e4e32..486c03c5fda 100644 --- a/lib/public/BackgroundJob/TimedJob.php +++ b/lib/public/BackgroundJob/TimedJob.php @@ -63,8 +63,8 @@ abstract class TimedJob extends Job { * @since 24.0.0 */ public function setTimeSensitivity(int $sensitivity): void { - if ($sensitivity !== self::TIME_SENSITIVE && - $sensitivity !== self::TIME_INSENSITIVE) { + if ($sensitivity !== self::TIME_SENSITIVE + && $sensitivity !== self::TIME_INSENSITIVE) { throw new \InvalidArgumentException('Invalid sensitivity'); } diff --git a/lib/public/BeforeSabrePubliclyLoadedEvent.php b/lib/public/BeforeSabrePubliclyLoadedEvent.php index c69cf867a43..33f9f8bc378 100644 --- a/lib/public/BeforeSabrePubliclyLoadedEvent.php +++ b/lib/public/BeforeSabrePubliclyLoadedEvent.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Calendar/BackendTemporarilyUnavailableException.php b/lib/public/Calendar/BackendTemporarilyUnavailableException.php index e02ef1a84fd..c2bbb1417ee 100644 --- a/lib/public/Calendar/BackendTemporarilyUnavailableException.php +++ b/lib/public/Calendar/BackendTemporarilyUnavailableException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Calendar/ICalendar.php b/lib/public/Calendar/ICalendar.php index 2dfc1ca632f..50152d1240b 100644 --- a/lib/public/Calendar/ICalendar.php +++ b/lib/public/Calendar/ICalendar.php @@ -8,10 +8,18 @@ declare(strict_types=1); */ namespace OCP\Calendar; +use DateTimeInterface; + /** * Interface ICalendar * * @since 13.0.0 + * + * @psalm-type CalendarSearchOptions = array{ + * timerange?: array{start?: DateTimeInterface, end?: DateTimeInterface}, + * uid?: string, + * types?: string[], + * } */ interface ICalendar { /** @@ -41,13 +49,63 @@ interface ICalendar { public function getDisplayColor(): ?string; /** - * @param string $pattern which should match within the $searchProperties - * @param array $searchProperties defines the properties within the query pattern should match - * @param array $options - optional parameters: - * ['timerange' => ['start' => new DateTime(...), 'end' => new DateTime(...)]] - * @param int|null $limit - limit number of search results - * @param int|null $offset - offset for paging of search results - * @return array an array of events/journals/todos which are arrays of key-value-pairs. the events are sorted by start date (closest first, furthest last) + * Search the current calendar for matching events. + * + * This method searches for events in the calendar that match a given pattern within specified properties. + * The search is case-insensitive. It supports optional parameters such as a time range, limit, and offset. + * The results are sorted by start date, with the closest events appearing first. + * + * @param string $pattern A string to search for within the events. The search is done case-insensitive. + * @param array $searchProperties Defines the properties within which the pattern should match. + * @param array $options Optional parameters for the search: + * - 'timerange' element that can have 'start' (DateTimeInterface), 'end' (DateTimeInterface), or both. + * - 'uid' element to look for events with a given uid. + * - 'types' element to only return events for a given type (e.g. VEVENT or VTODO) + * @psalm-param CalendarSearchOptions $options + * @param int|null $limit Limit the number of search results. + * @param int|null $offset For paging of search results. + * @return array An array of events/journals/todos which are arrays of key-value-pairs. The events are sorted by start date (closest first, furthest last). + * + * Implementation Details: + * + * An event can consist of many sub-events, typically the case for events with recurrence rules. On a database level, + * there's only one event stored (with a matching first occurrence and last occurrence timestamp). Expanding an event + * into sub-events is done on the backend level. Using limit, offset, and timerange comes with some drawbacks. + * When asking the database for events, the result is ordered by the primary key to guarantee a stable order. + * After expanding the events into sub-events, they are sorted by the date (closest to furthest). + * + * Usage Examples: + * + * 1) Find 7 events within the next two weeks: + * + * $dateTime = (new DateTimeImmutable())->setTimestamp($this->timeFactory->getTime()); + * $inTwoWeeks = $dateTime->add(new DateInterval('P14D')); + * + * $calendar->search( + * '', + * [], + * ['timerange' => ['start' => $dateTime, 'end' => $inTwoWeeks]], + * 7 + * ); + * + * Note: When combining timerange and limit, it's possible that the expected outcome is not in the order you would expect. + * + * Example: Create 7 events for tomorrow, starting from 11:00, 30 minutes each. Then create an 8th event for tomorrow at 10:00. + * The above code will list the event at 11:00 first, missing the event at 10:00. The reason is the ordering by the primary key + * and expanding on the backend level. This is a technical limitation. The easiest workaround is to fetch more events + * than you actually need, with the downside of needing more resources. + * + * Related: + * - https://github.com/nextcloud/server/pull/45222 + * - https://github.com/nextcloud/server/issues/53002 + * + * 2) Find all events where the location property contains the string 'Berlin': + * + * $calendar->search( + * 'Berlin', + * ['LOCATION'] + * ); + * * @since 13.0.0 */ public function search(string $pattern, array $searchProperties = [], array $options = [], ?int $limit = null, ?int $offset = null): array; diff --git a/lib/public/Calendar/ICalendarExport.php b/lib/public/Calendar/ICalendarExport.php index 61b286e1668..d884c104a4a 100644 --- a/lib/public/Calendar/ICalendarExport.php +++ b/lib/public/Calendar/ICalendarExport.php @@ -16,7 +16,7 @@ use Generator; * @since 32.0.0 */ interface ICalendarExport { - + /** * Export objects * diff --git a/lib/public/Calendar/ICalendarIsEnabled.php b/lib/public/Calendar/ICalendarIsEnabled.php index 868159d208f..6bcb487e3dc 100644 --- a/lib/public/Calendar/ICalendarIsEnabled.php +++ b/lib/public/Calendar/ICalendarIsEnabled.php @@ -13,7 +13,7 @@ namespace OCP\Calendar; * @since 32.0.0 */ interface ICalendarIsEnabled { - + /** * Indicates whether the calendar is enabled * diff --git a/lib/public/Calendar/ICalendarIsShared.php b/lib/public/Calendar/ICalendarIsShared.php index 8121c826f4e..6f63c6eefd0 100644 --- a/lib/public/Calendar/ICalendarIsShared.php +++ b/lib/public/Calendar/ICalendarIsShared.php @@ -14,7 +14,7 @@ namespace OCP\Calendar; * @since 31.0.0 */ interface ICalendarIsShared { - + /** * Indicates whether the calendar is shared with the current user * diff --git a/lib/public/Calendar/ICalendarIsWritable.php b/lib/public/Calendar/ICalendarIsWritable.php index f80769e9033..5bf08a25cdc 100644 --- a/lib/public/Calendar/ICalendarIsWritable.php +++ b/lib/public/Calendar/ICalendarIsWritable.php @@ -14,7 +14,7 @@ namespace OCP\Calendar; * @since 31.0.0 */ interface ICalendarIsWritable { - + /** * Indicates whether the calendar can be modified * diff --git a/lib/public/Calendar/IMetadataProvider.php b/lib/public/Calendar/IMetadataProvider.php index bee840c955f..acacf7efdaf 100644 --- a/lib/public/Calendar/IMetadataProvider.php +++ b/lib/public/Calendar/IMetadataProvider.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Calendar/Resource/IBackend.php b/lib/public/Calendar/Resource/IBackend.php index b43d79e3618..23d37c102f2 100644 --- a/lib/public/Calendar/Resource/IBackend.php +++ b/lib/public/Calendar/Resource/IBackend.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Calendar/Resource/IResource.php b/lib/public/Calendar/Resource/IResource.php index f284eee955f..15abe4e2d0f 100644 --- a/lib/public/Calendar/Resource/IResource.php +++ b/lib/public/Calendar/Resource/IResource.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Calendar/Resource/IResourceMetadata.php b/lib/public/Calendar/Resource/IResourceMetadata.php index acf02bc3609..29f628d6f7f 100644 --- a/lib/public/Calendar/Resource/IResourceMetadata.php +++ b/lib/public/Calendar/Resource/IResourceMetadata.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Calendar/Room/IBackend.php b/lib/public/Calendar/Room/IBackend.php index 52ec2fa5948..c99f5fbdb72 100644 --- a/lib/public/Calendar/Room/IBackend.php +++ b/lib/public/Calendar/Room/IBackend.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Calendar/Room/IRoom.php b/lib/public/Calendar/Room/IRoom.php index 580c676331f..526e65b8f5f 100644 --- a/lib/public/Calendar/Room/IRoom.php +++ b/lib/public/Calendar/Room/IRoom.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Calendar/Room/IRoomMetadata.php b/lib/public/Calendar/Room/IRoomMetadata.php index 3fb4089b6a7..15d4b501e12 100644 --- a/lib/public/Calendar/Room/IRoomMetadata.php +++ b/lib/public/Calendar/Room/IRoomMetadata.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Capabilities/IPublicCapability.php b/lib/public/Capabilities/IPublicCapability.php index 3936d6032af..1a9dd965b16 100644 --- a/lib/public/Capabilities/IPublicCapability.php +++ b/lib/public/Capabilities/IPublicCapability.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Collaboration/AutoComplete/IManager.php b/lib/public/Collaboration/AutoComplete/IManager.php index 976bbfb7f18..2d5443b921d 100644 --- a/lib/public/Collaboration/AutoComplete/IManager.php +++ b/lib/public/Collaboration/AutoComplete/IManager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Collaboration/AutoComplete/ISorter.php b/lib/public/Collaboration/AutoComplete/ISorter.php index 4b9f2b72e7c..1009092af6a 100644 --- a/lib/public/Collaboration/AutoComplete/ISorter.php +++ b/lib/public/Collaboration/AutoComplete/ISorter.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Collaboration/Collaborators/ISearch.php b/lib/public/Collaboration/Collaborators/ISearch.php index 95151d49a86..d2c5c85c07f 100644 --- a/lib/public/Collaboration/Collaborators/ISearch.php +++ b/lib/public/Collaboration/Collaborators/ISearch.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Collaboration/Collaborators/ISearchPlugin.php b/lib/public/Collaboration/Collaborators/ISearchPlugin.php index ec875d7d017..e55a095e2b6 100644 --- a/lib/public/Collaboration/Collaborators/ISearchPlugin.php +++ b/lib/public/Collaboration/Collaborators/ISearchPlugin.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Collaboration/Collaborators/ISearchResult.php b/lib/public/Collaboration/Collaborators/ISearchResult.php index 8e693caa677..bcc5a91ce99 100644 --- a/lib/public/Collaboration/Collaborators/ISearchResult.php +++ b/lib/public/Collaboration/Collaborators/ISearchResult.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Collaboration/Collaborators/SearchResultType.php b/lib/public/Collaboration/Collaborators/SearchResultType.php index c5a8b4e303a..3fdbefdcf1f 100644 --- a/lib/public/Collaboration/Collaborators/SearchResultType.php +++ b/lib/public/Collaboration/Collaborators/SearchResultType.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Color.php b/lib/public/Color.php index 5523dbd94cb..ed955b8f056 100644 --- a/lib/public/Color.php +++ b/lib/public/Color.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Comments/ICommentsEventHandler.php b/lib/public/Comments/ICommentsEventHandler.php index dc0a554ff11..148ead2c367 100644 --- a/lib/public/Comments/ICommentsEventHandler.php +++ b/lib/public/Comments/ICommentsEventHandler.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Contacts/ContactsMenu/IAction.php b/lib/public/Contacts/ContactsMenu/IAction.php index 4a7133a999b..00fe8ba35c4 100644 --- a/lib/public/Contacts/ContactsMenu/IAction.php +++ b/lib/public/Contacts/ContactsMenu/IAction.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Contacts/ContactsMenu/IActionFactory.php b/lib/public/Contacts/ContactsMenu/IActionFactory.php index a4785d1c70c..69e6030e95b 100644 --- a/lib/public/Contacts/ContactsMenu/IActionFactory.php +++ b/lib/public/Contacts/ContactsMenu/IActionFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Contacts/ContactsMenu/IContactsStore.php b/lib/public/Contacts/ContactsMenu/IContactsStore.php index ceb68d99849..67913a2d919 100644 --- a/lib/public/Contacts/ContactsMenu/IContactsStore.php +++ b/lib/public/Contacts/ContactsMenu/IContactsStore.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Contacts/ContactsMenu/IEntry.php b/lib/public/Contacts/ContactsMenu/IEntry.php index c361b71bb7c..9ae8a207297 100644 --- a/lib/public/Contacts/ContactsMenu/IEntry.php +++ b/lib/public/Contacts/ContactsMenu/IEntry.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Contacts/ContactsMenu/ILinkAction.php b/lib/public/Contacts/ContactsMenu/ILinkAction.php index 92bccfd8dda..559e04885c5 100644 --- a/lib/public/Contacts/ContactsMenu/ILinkAction.php +++ b/lib/public/Contacts/ContactsMenu/ILinkAction.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/DB/ISchemaWrapper.php b/lib/public/DB/ISchemaWrapper.php index 16b776c05b9..dcf22b52d3d 100644 --- a/lib/public/DB/ISchemaWrapper.php +++ b/lib/public/DB/ISchemaWrapper.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/DB/QueryBuilder/IFunctionBuilder.php b/lib/public/DB/QueryBuilder/IFunctionBuilder.php index 84c3780dbce..480ec1cb1ac 100644 --- a/lib/public/DB/QueryBuilder/IFunctionBuilder.php +++ b/lib/public/DB/QueryBuilder/IFunctionBuilder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/DirectEditing/ACreateEmpty.php b/lib/public/DirectEditing/ACreateEmpty.php index f30cc2465f9..6ad499ec760 100644 --- a/lib/public/DirectEditing/ACreateEmpty.php +++ b/lib/public/DirectEditing/ACreateEmpty.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/DirectEditing/ACreateFromTemplate.php b/lib/public/DirectEditing/ACreateFromTemplate.php index 6348b5d3545..e56e9c09cbb 100644 --- a/lib/public/DirectEditing/ACreateFromTemplate.php +++ b/lib/public/DirectEditing/ACreateFromTemplate.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/DirectEditing/ATemplate.php b/lib/public/DirectEditing/ATemplate.php index cc0ed24336b..a70488d8e89 100644 --- a/lib/public/DirectEditing/ATemplate.php +++ b/lib/public/DirectEditing/ATemplate.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/DirectEditing/IToken.php b/lib/public/DirectEditing/IToken.php index 53a67883f54..64abbf939f4 100644 --- a/lib/public/DirectEditing/IToken.php +++ b/lib/public/DirectEditing/IToken.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/DirectEditing/RegisterDirectEditorEvent.php b/lib/public/DirectEditing/RegisterDirectEditorEvent.php index 72d5ea39fe8..cbf9b07185d 100644 --- a/lib/public/DirectEditing/RegisterDirectEditorEvent.php +++ b/lib/public/DirectEditing/RegisterDirectEditorEvent.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/EventDispatcher/JsonSerializer.php b/lib/public/EventDispatcher/JsonSerializer.php index 1eb75ed7527..d05367b746d 100644 --- a/lib/public/EventDispatcher/JsonSerializer.php +++ b/lib/public/EventDispatcher/JsonSerializer.php @@ -9,6 +9,8 @@ declare(strict_types=1); namespace OCP\EventDispatcher; +use OC\Files\Node\NonExistingFile; +use OC\Files\Node\NonExistingFolder; use OCP\Files\FileInfo; use OCP\IUser; @@ -24,10 +26,16 @@ final class JsonSerializer { * @since 30.0.0 */ public static function serializeFileInfo(FileInfo $node): array { - return [ - 'id' => $node->getId(), - 'path' => $node->getPath(), - ]; + if ($node instanceof NonExistingFile || $node instanceof NonExistingFolder) { + return [ + 'path' => $node->getPath(), + ]; + } else { + return [ + 'id' => $node->getId(), + 'path' => $node->getPath(), + ]; + } } /** diff --git a/lib/public/Federation/Exceptions/ActionNotSupportedException.php b/lib/public/Federation/Exceptions/ActionNotSupportedException.php index 690e7a554c7..7f0e0f46907 100644 --- a/lib/public/Federation/Exceptions/ActionNotSupportedException.php +++ b/lib/public/Federation/Exceptions/ActionNotSupportedException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/Exceptions/AuthenticationFailedException.php b/lib/public/Federation/Exceptions/AuthenticationFailedException.php index f9482c3a19c..6ce5314844e 100644 --- a/lib/public/Federation/Exceptions/AuthenticationFailedException.php +++ b/lib/public/Federation/Exceptions/AuthenticationFailedException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/Exceptions/BadRequestException.php b/lib/public/Federation/Exceptions/BadRequestException.php index 52e3b0e0db4..0210437a8d5 100644 --- a/lib/public/Federation/Exceptions/BadRequestException.php +++ b/lib/public/Federation/Exceptions/BadRequestException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php b/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php index 606fb08d0fc..f753f5f3326 100644 --- a/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php +++ b/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/Exceptions/ProviderCouldNotAddShareException.php b/lib/public/Federation/Exceptions/ProviderCouldNotAddShareException.php index 7f1218c349e..168eb2b8aeb 100644 --- a/lib/public/Federation/Exceptions/ProviderCouldNotAddShareException.php +++ b/lib/public/Federation/Exceptions/ProviderCouldNotAddShareException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php b/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php index 4b3d0341fe9..64dfcf0f856 100644 --- a/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php +++ b/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/ICloudFederationFactory.php b/lib/public/Federation/ICloudFederationFactory.php index a25e4ee30f7..5238188b4fa 100644 --- a/lib/public/Federation/ICloudFederationFactory.php +++ b/lib/public/Federation/ICloudFederationFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/ICloudFederationNotification.php b/lib/public/Federation/ICloudFederationNotification.php index 8545c9d51f2..c550a936927 100644 --- a/lib/public/Federation/ICloudFederationNotification.php +++ b/lib/public/Federation/ICloudFederationNotification.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/ICloudFederationProvider.php b/lib/public/Federation/ICloudFederationProvider.php index 067ceba160e..b30041f81d6 100644 --- a/lib/public/Federation/ICloudFederationProvider.php +++ b/lib/public/Federation/ICloudFederationProvider.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/ICloudFederationProviderManager.php b/lib/public/Federation/ICloudFederationProviderManager.php index 9f5258721ab..68adb4b4da7 100644 --- a/lib/public/Federation/ICloudFederationProviderManager.php +++ b/lib/public/Federation/ICloudFederationProviderManager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Federation/ICloudFederationShare.php b/lib/public/Federation/ICloudFederationShare.php index 197ebf1af9a..0b67bbfadee 100644 --- a/lib/public/Federation/ICloudFederationShare.php +++ b/lib/public/Federation/ICloudFederationShare.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files.php b/lib/public/Files.php index 3df3152b0ef..b169032e16c 100644 --- a/lib/public/Files.php +++ b/lib/public/Files.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/public/Files/Config/Event/UserMountAddedEvent.php b/lib/public/Files/Config/Event/UserMountAddedEvent.php index f2846f2ff2b..8abd7512188 100644 --- a/lib/public/Files/Config/Event/UserMountAddedEvent.php +++ b/lib/public/Files/Config/Event/UserMountAddedEvent.php @@ -11,7 +11,6 @@ namespace OCP\Files\Config\Event; use OCP\EventDispatcher\Event; use OCP\Files\Config\ICachedMountInfo; -use OCP\Files\Mount\IMountPoint; /** * Event emitted when a user mount was added. @@ -20,7 +19,7 @@ use OCP\Files\Mount\IMountPoint; */ class UserMountAddedEvent extends Event { public function __construct( - public readonly IMountPoint|ICachedMountInfo $mountPoint, + public readonly ICachedMountInfo $mountPoint, ) { parent::__construct(); } diff --git a/lib/public/Files/Config/Event/UserMountRemovedEvent.php b/lib/public/Files/Config/Event/UserMountRemovedEvent.php index bdf264c9c4b..0de7cfc4a99 100644 --- a/lib/public/Files/Config/Event/UserMountRemovedEvent.php +++ b/lib/public/Files/Config/Event/UserMountRemovedEvent.php @@ -11,7 +11,6 @@ namespace OCP\Files\Config\Event; use OCP\EventDispatcher\Event; use OCP\Files\Config\ICachedMountInfo; -use OCP\Files\Mount\IMountPoint; /** * Event emitted when a user mount was removed. @@ -20,7 +19,7 @@ use OCP\Files\Mount\IMountPoint; */ class UserMountRemovedEvent extends Event { public function __construct( - public readonly IMountPoint|ICachedMountInfo $mountPoint, + public readonly ICachedMountInfo $mountPoint, ) { parent::__construct(); } diff --git a/lib/public/Files/Config/Event/UserMountUpdatedEvent.php b/lib/public/Files/Config/Event/UserMountUpdatedEvent.php index 36d9cd55562..f797bef134e 100644 --- a/lib/public/Files/Config/Event/UserMountUpdatedEvent.php +++ b/lib/public/Files/Config/Event/UserMountUpdatedEvent.php @@ -11,7 +11,6 @@ namespace OCP\Files\Config\Event; use OCP\EventDispatcher\Event; use OCP\Files\Config\ICachedMountInfo; -use OCP\Files\Mount\IMountPoint; /** * Event emitted when a user mount was moved. @@ -20,8 +19,8 @@ use OCP\Files\Mount\IMountPoint; */ class UserMountUpdatedEvent extends Event { public function __construct( - public readonly IMountPoint|ICachedMountInfo $oldMountPoint, - public readonly IMountPoint|ICachedMountInfo $newMountPoint, + public readonly ICachedMountInfo $oldMountPoint, + public readonly ICachedMountInfo $newMountPoint, ) { parent::__construct(); } diff --git a/lib/public/Files/Config/ICachedMountFileInfo.php b/lib/public/Files/Config/ICachedMountFileInfo.php index 7b331059645..a9b30d8ba6d 100644 --- a/lib/public/Files/Config/ICachedMountFileInfo.php +++ b/lib/public/Files/Config/ICachedMountFileInfo.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/DavUtil.php b/lib/public/Files/DavUtil.php index 40d17c77c88..6dde3179bb8 100644 --- a/lib/public/Files/DavUtil.php +++ b/lib/public/Files/DavUtil.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-only diff --git a/lib/public/Files/EmptyFileNameException.php b/lib/public/Files/EmptyFileNameException.php index ec13a9fc2be..1630ce63ea2 100644 --- a/lib/public/Files/EmptyFileNameException.php +++ b/lib/public/Files/EmptyFileNameException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Folder.php b/lib/public/Files/Folder.php index 3128a17c10c..a35d2d78bc9 100644 --- a/lib/public/Files/Folder.php +++ b/lib/public/Files/Folder.php @@ -199,4 +199,15 @@ interface Folder extends Node { * @since 9.1.0 */ public function getRecent($limit, $offset = 0); + + /** + * Verify if the given path is valid and allowed from this folder. + * + * @param string $path the path from this folder + * @param string $fileName + * @param bool $readonly Check only if the path is allowed for read-only access + * @throws InvalidPathException + * @since 32.0.0 + */ + public function verifyPath($fileName, $readonly = false): void; } diff --git a/lib/public/Files/GenericFileException.php b/lib/public/Files/GenericFileException.php index 288d668e3e7..66a3b5e5ac4 100644 --- a/lib/public/Files/GenericFileException.php +++ b/lib/public/Files/GenericFileException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/IAppData.php b/lib/public/Files/IAppData.php index e5a5c2b7143..4d0c4da6a8a 100644 --- a/lib/public/Files/IAppData.php +++ b/lib/public/Files/IAppData.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/IFilenameValidator.php b/lib/public/Files/IFilenameValidator.php index d8bd06d179d..9b7fa1e2e2e 100644 --- a/lib/public/Files/IFilenameValidator.php +++ b/lib/public/Files/IFilenameValidator.php @@ -43,7 +43,7 @@ interface IFilenameValidator { * If no sanitizing is needed the same name is returned. * * @param string $name The filename to sanitize - * @param null|string $charReplacement Character to use for replacing forbidden ones - by default space, dash or underscore is used if allowed. + * @param null|string $charReplacement Character to use for replacing forbidden ones - by default underscore, dash or space is used if allowed. * @throws \InvalidArgumentException if no character replacement was given (and the default could not be applied) or the replacement is not valid. * @since 32.0.0 */ diff --git a/lib/public/Files/InvalidDirectoryException.php b/lib/public/Files/InvalidDirectoryException.php index 7f87eed1a17..b9640209cbf 100644 --- a/lib/public/Files/InvalidDirectoryException.php +++ b/lib/public/Files/InvalidDirectoryException.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Notify/IChange.php b/lib/public/Files/Notify/IChange.php index 8f252411a5a..c7c758eec11 100644 --- a/lib/public/Files/Notify/IChange.php +++ b/lib/public/Files/Notify/IChange.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Notify/INotifyHandler.php b/lib/public/Files/Notify/INotifyHandler.php index 8777779ca4a..09b3dbca919 100644 --- a/lib/public/Files/Notify/INotifyHandler.php +++ b/lib/public/Files/Notify/INotifyHandler.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Notify/IRenameChange.php b/lib/public/Files/Notify/IRenameChange.php index 3e1ae7ed447..b1bfae5fc00 100644 --- a/lib/public/Files/Notify/IRenameChange.php +++ b/lib/public/Files/Notify/IRenameChange.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Search/ISearchBinaryOperator.php b/lib/public/Files/Search/ISearchBinaryOperator.php index 661be44596d..fa7ef4d1bb3 100644 --- a/lib/public/Files/Search/ISearchBinaryOperator.php +++ b/lib/public/Files/Search/ISearchBinaryOperator.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Search/ISearchComparison.php b/lib/public/Files/Search/ISearchComparison.php index 01b69f5d24c..ab298fa0a57 100644 --- a/lib/public/Files/Search/ISearchComparison.php +++ b/lib/public/Files/Search/ISearchComparison.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -51,7 +52,7 @@ interface ISearchComparison extends ISearchOperator { * @since 28.0.0 */ public const COMPARE_DEFINED = 'is-defined'; - + /** * @since 29.0.0 */ diff --git a/lib/public/Files/Search/ISearchOperator.php b/lib/public/Files/Search/ISearchOperator.php index a604bd96b9d..f6ae8edcbb1 100644 --- a/lib/public/Files/Search/ISearchOperator.php +++ b/lib/public/Files/Search/ISearchOperator.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Search/ISearchOrder.php b/lib/public/Files/Search/ISearchOrder.php index 23f71e2133e..e6e68849443 100644 --- a/lib/public/Files/Search/ISearchOrder.php +++ b/lib/public/Files/Search/ISearchOrder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Search/ISearchQuery.php b/lib/public/Files/Search/ISearchQuery.php index 109998aee65..1b400c56e5b 100644 --- a/lib/public/Files/Search/ISearchQuery.php +++ b/lib/public/Files/Search/ISearchQuery.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/SimpleFS/ISimpleFile.php b/lib/public/Files/SimpleFS/ISimpleFile.php index 10cdc0a919d..4e77299ab00 100644 --- a/lib/public/Files/SimpleFS/ISimpleFile.php +++ b/lib/public/Files/SimpleFS/ISimpleFile.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/SimpleFS/ISimpleFolder.php b/lib/public/Files/SimpleFS/ISimpleFolder.php index 79b9fca1dac..95efc676688 100644 --- a/lib/public/Files/SimpleFS/ISimpleFolder.php +++ b/lib/public/Files/SimpleFS/ISimpleFolder.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/SimpleFS/ISimpleRoot.php b/lib/public/Files/SimpleFS/ISimpleRoot.php index 5c01c6a2a2e..6be8a1d47c9 100644 --- a/lib/public/Files/SimpleFS/ISimpleRoot.php +++ b/lib/public/Files/SimpleFS/ISimpleRoot.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Storage/IChunkedFileWrite.php b/lib/public/Files/Storage/IChunkedFileWrite.php index e166a7f3b1f..0cf27814f0e 100644 --- a/lib/public/Files/Storage/IChunkedFileWrite.php +++ b/lib/public/Files/Storage/IChunkedFileWrite.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Storage/IDisableEncryptionStorage.php b/lib/public/Files/Storage/IDisableEncryptionStorage.php index 98a4b4897da..19951da2015 100644 --- a/lib/public/Files/Storage/IDisableEncryptionStorage.php +++ b/lib/public/Files/Storage/IDisableEncryptionStorage.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Storage/INotifyStorage.php b/lib/public/Files/Storage/INotifyStorage.php index 0e5cf53af21..063ff815581 100644 --- a/lib/public/Files/Storage/INotifyStorage.php +++ b/lib/public/Files/Storage/INotifyStorage.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Files/Template/RegisterTemplateCreatorEvent.php b/lib/public/Files/Template/RegisterTemplateCreatorEvent.php index c931f3e2a78..a9e7fa01252 100644 --- a/lib/public/Files/Template/RegisterTemplateCreatorEvent.php +++ b/lib/public/Files/Template/RegisterTemplateCreatorEvent.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/GlobalScale/IConfig.php b/lib/public/GlobalScale/IConfig.php index 31df152f644..bae5dd7aa66 100644 --- a/lib/public/GlobalScale/IConfig.php +++ b/lib/public/GlobalScale/IConfig.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Group/Backend/INamedBackend.php b/lib/public/Group/Backend/INamedBackend.php index 8b9ef9ffbba..d98cc8cdb83 100644 --- a/lib/public/Group/Backend/INamedBackend.php +++ b/lib/public/Group/Backend/INamedBackend.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Http/Client/IResponse.php b/lib/public/Http/Client/IResponse.php index deec2cf97b1..53032ef2a37 100644 --- a/lib/public/Http/Client/IResponse.php +++ b/lib/public/Http/Client/IResponse.php @@ -15,8 +15,9 @@ namespace OCP\Http\Client; */ interface IResponse { /** - * @return string|resource + * @return null|resource|string * @since 8.1.0 + * @sicne 8.2.0 with stream enabled, the function returns null or a resource */ public function getBody(); diff --git a/lib/public/IAddressBook.php b/lib/public/IAddressBook.php index 780b005fe8d..5a5cc487cee 100644 --- a/lib/public/IAddressBook.php +++ b/lib/public/IAddressBook.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. diff --git a/lib/public/IAppConfig.php b/lib/public/IAppConfig.php index f4210793476..fcc528fe11f 100644 --- a/lib/public/IAppConfig.php +++ b/lib/public/IAppConfig.php @@ -514,5 +514,5 @@ interface IAppConfig { * @return array<string, string> * @since 32.0.0 */ - public function getAppInstalledVersions(): array; + public function getAppInstalledVersions(bool $onlyEnabled = false): array; } diff --git a/lib/public/IPreview.php b/lib/public/IPreview.php index 5a2bcde69f1..3c9eadd4577 100644 --- a/lib/public/IPreview.php +++ b/lib/public/IPreview.php @@ -92,10 +92,12 @@ interface IPreview { * Check if a preview can be generated for a file * * @param \OCP\Files\FileInfo $file + * @param string|null $mimeType To force a given mimetype for the file * @return bool * @since 8.0.0 + * @since 32.0.0 - isAvailable($mimeType) added the $mimeType argument to the signature */ - public function isAvailable(\OCP\Files\FileInfo $file); + public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null); /** * Generates previews of a file diff --git a/lib/public/IUser.php b/lib/public/IUser.php index 52f79083dc1..945e7e1602a 100644 --- a/lib/public/IUser.php +++ b/lib/public/IUser.php @@ -281,6 +281,15 @@ interface IUser { public function getQuota(); /** + * Get the users' quota in machine readable form. If a specific quota is set + * for the user, then the quota is returned in bytes. Otherwise the default value is returned. + * If a default setting was not set, it is return as `\OCP\Files\FileInfo::SPACE_UNLIMITED`, i.e. quota is not limited. + * + * @since 32.0.0 + */ + public function getQuotaBytes(): int|float; + + /** * set the users' quota * * @param string $quota diff --git a/lib/public/LDAP/IDeletionFlagSupport.php b/lib/public/LDAP/IDeletionFlagSupport.php index 89615c67307..1ae38e1a5d1 100644 --- a/lib/public/LDAP/IDeletionFlagSupport.php +++ b/lib/public/LDAP/IDeletionFlagSupport.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -17,7 +18,7 @@ interface IDeletionFlagSupport { * @since 11.0.0 */ public function flagRecord($uid); - + /** * Unflag record for deletion. * @param string $uid user id diff --git a/lib/public/LDAP/ILDAPProvider.php b/lib/public/LDAP/ILDAPProvider.php index 22f4b872adc..7e1f27eb368 100644 --- a/lib/public/LDAP/ILDAPProvider.php +++ b/lib/public/LDAP/ILDAPProvider.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/LDAP/ILDAPProviderFactory.php b/lib/public/LDAP/ILDAPProviderFactory.php index f175a3abfd0..720027ce012 100644 --- a/lib/public/LDAP/ILDAPProviderFactory.php +++ b/lib/public/LDAP/ILDAPProviderFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Lockdown/ILockdownManager.php b/lib/public/Lockdown/ILockdownManager.php index 4ae846ae8da..fe8adaecf91 100644 --- a/lib/public/Lockdown/ILockdownManager.php +++ b/lib/public/Lockdown/ILockdownManager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Log/IFileBased.php b/lib/public/Log/IFileBased.php index e3ea25fad09..ace10ee1b68 100644 --- a/lib/public/Log/IFileBased.php +++ b/lib/public/Log/IFileBased.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Log/ILogFactory.php b/lib/public/Log/ILogFactory.php index 49b56ff102c..db7adca2192 100644 --- a/lib/public/Log/ILogFactory.php +++ b/lib/public/Log/ILogFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Log/IWriter.php b/lib/public/Log/IWriter.php index 8d2b438a0fe..2fcbc094881 100644 --- a/lib/public/Log/IWriter.php +++ b/lib/public/Log/IWriter.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Log/RotationTrait.php b/lib/public/Log/RotationTrait.php index 03100613c4c..73b3b16b665 100644 --- a/lib/public/Log/RotationTrait.php +++ b/lib/public/Log/RotationTrait.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Mail/Provider/IAddress.php b/lib/public/Mail/Provider/IAddress.php index 121467390dc..47bb9148968 100644 --- a/lib/public/Mail/Provider/IAddress.php +++ b/lib/public/Mail/Provider/IAddress.php @@ -17,7 +17,7 @@ namespace OCP\Mail\Provider; * */ interface IAddress { - + /** * sets the mail address * diff --git a/lib/public/Mail/Provider/IManager.php b/lib/public/Mail/Provider/IManager.php index 3c639ef21ef..b55fed3f26f 100644 --- a/lib/public/Mail/Provider/IManager.php +++ b/lib/public/Mail/Provider/IManager.php @@ -17,7 +17,7 @@ namespace OCP\Mail\Provider; * */ interface IManager { - + /** * determine if any mail providers are registered * diff --git a/lib/public/Mail/Provider/IMessage.php b/lib/public/Mail/Provider/IMessage.php index e3dfbe6981d..599d9b0566d 100644 --- a/lib/public/Mail/Provider/IMessage.php +++ b/lib/public/Mail/Provider/IMessage.php @@ -17,7 +17,7 @@ namespace OCP\Mail\Provider; * */ interface IMessage { - + /** * arbitrary unique text string identifying this message * @@ -117,7 +117,7 @@ interface IMessage { * @return self return this object for command chaining */ public function setBcc(IAddress ...$value): self; - + /** * gets the blind copy to recipient(s) of this message * diff --git a/lib/public/Migration/Attributes/AddColumn.php b/lib/public/Migration/Attributes/AddColumn.php index 8d16b9b6e8d..d84a0c1f60c 100644 --- a/lib/public/Migration/Attributes/AddColumn.php +++ b/lib/public/Migration/Attributes/AddColumn.php @@ -23,8 +23,8 @@ class AddColumn extends ColumnMigrationAttribute { */ public function definition(): string { $type = is_null($this->getType()) ? '' : ' (' . $this->getType()->value . ')'; - return empty($this->getName()) ? - 'Addition of a new column' . $type . ' to table \'' . $this->getTable() . '\'' + return empty($this->getName()) + ? 'Addition of a new column' . $type . ' to table \'' . $this->getTable() . '\'' : 'Addition of column \'' . $this->getName() . '\'' . $type . ' to table \'' . $this->getTable() . '\''; } } diff --git a/lib/public/Migration/Attributes/DropColumn.php b/lib/public/Migration/Attributes/DropColumn.php index 1de0ba58489..a1cd5790cc7 100644 --- a/lib/public/Migration/Attributes/DropColumn.php +++ b/lib/public/Migration/Attributes/DropColumn.php @@ -22,8 +22,8 @@ class DropColumn extends ColumnMigrationAttribute { * @since 30.0.0 */ public function definition(): string { - return empty($this->getName()) ? - 'Deletion of a column from table \'' . $this->getTable() . '\'' + return empty($this->getName()) + ? 'Deletion of a column from table \'' . $this->getTable() . '\'' : 'Deletion of column \'' . $this->getName() . '\' from table \'' . $this->getTable() . '\''; } } diff --git a/lib/public/Migration/Attributes/ModifyColumn.php b/lib/public/Migration/Attributes/ModifyColumn.php index ef7250ffb34..6fc44ebb824 100644 --- a/lib/public/Migration/Attributes/ModifyColumn.php +++ b/lib/public/Migration/Attributes/ModifyColumn.php @@ -23,8 +23,8 @@ class ModifyColumn extends ColumnMigrationAttribute { */ public function definition(): string { $type = is_null($this->getType()) ? '' : ' to ' . $this->getType()->value; - return empty($this->getName()) ? - 'Modification of a column from table \'' . $this->getTable() . '\'' . $type + return empty($this->getName()) + ? 'Modification of a column from table \'' . $this->getTable() . '\'' . $type : 'Modification of column \'' . $this->getName() . '\' from table \'' . $this->getTable() . '\'' . $type; } } diff --git a/lib/public/OCM/ICapabilityAwareOCMProvider.php b/lib/public/OCM/ICapabilityAwareOCMProvider.php new file mode 100644 index 00000000000..ae290abd2f8 --- /dev/null +++ b/lib/public/OCM/ICapabilityAwareOCMProvider.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCP\OCM; + +/** + * Version 1.1 and 1.2 extensions to the Open Cloud Mesh Discovery API + * @link https://github.com/cs3org/OCM-API/ + * @since 32.0.0 + */ +interface ICapabilityAwareOCMProvider extends IOCMProvider { + /** + * get the capabilities + * + * @return array + * @since 32.0.0 + */ + public function getCapabilities(): array; + + /** + * get the provider name + * + * @return string + * @since 32.0.0 + */ + public function getProvider(): string; + + /** + * returns the invite accept dialog + * + * @return string + * @since 32.0.0 + */ + public function getInviteAcceptDialog(): string; + + /** + * set the capabilities + * + * @param array $capabilities + * + * @return $this + * @since 32.0.0 + */ + public function setCapabilities(array $capabilities): static; + + /** + * set the invite accept dialog + * + * @param string $inviteAcceptDialog + * + * @return $this + * @since 32.0.0 + */ + public function setInviteAcceptDialog(string $inviteAcceptDialog): static; +} diff --git a/lib/public/OCM/IOCMProvider.php b/lib/public/OCM/IOCMProvider.php index a267abc52d2..7141b0a9ab9 100644 --- a/lib/public/OCM/IOCMProvider.php +++ b/lib/public/OCM/IOCMProvider.php @@ -16,6 +16,7 @@ use OCP\OCM\Exceptions\OCMProviderException; * Model based on the Open Cloud Mesh Discovery API * @link https://github.com/cs3org/OCM-API/ * @since 28.0.0 + * @deprecated 32.0.0 Please use {@see \OCP\OCM\ICapabilityAwareOCMProvider} */ interface IOCMProvider extends JsonSerializable { /** diff --git a/lib/public/Remote/Api/IApiCollection.php b/lib/public/Remote/Api/IApiCollection.php index da1964997bd..e7181ab20f2 100644 --- a/lib/public/Remote/Api/IApiCollection.php +++ b/lib/public/Remote/Api/IApiCollection.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Remote/Api/IApiFactory.php b/lib/public/Remote/Api/IApiFactory.php index 0e95dc98e70..2089c61be82 100644 --- a/lib/public/Remote/Api/IApiFactory.php +++ b/lib/public/Remote/Api/IApiFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Remote/Api/ICapabilitiesApi.php b/lib/public/Remote/Api/ICapabilitiesApi.php index d9ab037bcc6..d0e3fd7ad80 100644 --- a/lib/public/Remote/Api/ICapabilitiesApi.php +++ b/lib/public/Remote/Api/ICapabilitiesApi.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Remote/Api/IUserApi.php b/lib/public/Remote/Api/IUserApi.php index c8b5e64d003..268594c0340 100644 --- a/lib/public/Remote/Api/IUserApi.php +++ b/lib/public/Remote/Api/IUserApi.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Remote/ICredentials.php b/lib/public/Remote/ICredentials.php index efe87a350c8..c261d57093d 100644 --- a/lib/public/Remote/ICredentials.php +++ b/lib/public/Remote/ICredentials.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Remote/IInstance.php b/lib/public/Remote/IInstance.php index 47c10cb4ac1..6186c2e1819 100644 --- a/lib/public/Remote/IInstance.php +++ b/lib/public/Remote/IInstance.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Remote/IInstanceFactory.php b/lib/public/Remote/IInstanceFactory.php index 15435901a74..1cd2b3330ce 100644 --- a/lib/public/Remote/IInstanceFactory.php +++ b/lib/public/Remote/IInstanceFactory.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Remote/IUser.php b/lib/public/Remote/IUser.php index 3c22695c20b..329e8876c0d 100644 --- a/lib/public/Remote/IUser.php +++ b/lib/public/Remote/IUser.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/RichObjectStrings/Definitions.php b/lib/public/RichObjectStrings/Definitions.php index 5974659e16b..d6717e54aea 100644 --- a/lib/public/RichObjectStrings/Definitions.php +++ b/lib/public/RichObjectStrings/Definitions.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -374,6 +375,12 @@ class Definitions { 'description' => 'The blurhash of the image', 'example' => 'LEHV9uae2yk8pyo0adR*.7kCMdnj', ], + 'hide-download' => [ + 'since' => '31.0.5', + 'required' => false, + 'description' => 'Whether the download option should be hidden. If not set to `yes` the option can be shown', + 'example' => 'yes', + ], ], ], 'forms-form' => [ diff --git a/lib/public/RichObjectStrings/IValidator.php b/lib/public/RichObjectStrings/IValidator.php index 3bf83582adc..fc486663c73 100644 --- a/lib/public/RichObjectStrings/IValidator.php +++ b/lib/public/RichObjectStrings/IValidator.php @@ -26,6 +26,7 @@ namespace OCP\RichObjectStrings; * path?: string, * mimetype?: string, * 'preview-available'?: 'yes'|'no', + * 'hide-download'?: 'yes'|'no', * mtime?: string, * latitude?: string, * longitude?: string, diff --git a/lib/public/RichObjectStrings/InvalidObjectExeption.php b/lib/public/RichObjectStrings/InvalidObjectExeption.php index 0316310c5f9..603f4432ba6 100644 --- a/lib/public/RichObjectStrings/InvalidObjectExeption.php +++ b/lib/public/RichObjectStrings/InvalidObjectExeption.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Route/IRoute.php b/lib/public/Route/IRoute.php index fffd4b9c1a1..7dba6225aff 100644 --- a/lib/public/Route/IRoute.php +++ b/lib/public/Route/IRoute.php @@ -34,8 +34,9 @@ interface IRoute { * it is called directly * * @param string $file - * @return void + * @return $this * @since 7.0.0 + * @deprecated 32.0.0 Use a proper controller instead */ public function actionInclude($file); @@ -70,6 +71,7 @@ interface IRoute { * This function is called with $class set to a callable or * to the class with $function * @since 7.0.0 + * @deprecated 32.0.0 Use a proper controller instead */ public function action($class, $function = null); diff --git a/lib/public/Settings/IDeclarativeSettingsForm.php b/lib/public/Settings/IDeclarativeSettingsForm.php index d471cdf4a93..419905b7b23 100644 --- a/lib/public/Settings/IDeclarativeSettingsForm.php +++ b/lib/public/Settings/IDeclarativeSettingsForm.php @@ -27,6 +27,7 @@ namespace OCP\Settings; * label?: string, * default: mixed, * options?: list<string|array{name: string, value: mixed}>, + * sensitive?: boolean, * } * * @psalm-type DeclarativeSettingsFormFieldWithValue = DeclarativeSettingsFormField&array{ diff --git a/lib/public/Settings/IIconSection.php b/lib/public/Settings/IIconSection.php index e514a0176b7..4d0fe40aa29 100644 --- a/lib/public/Settings/IIconSection.php +++ b/lib/public/Settings/IIconSection.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Settings/IManager.php b/lib/public/Settings/IManager.php index 0bb1a396671..954fd3fdb56 100644 --- a/lib/public/Settings/IManager.php +++ b/lib/public/Settings/IManager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Settings/ISettings.php b/lib/public/Settings/ISettings.php index a733eb7956d..e33556f0b4a 100644 --- a/lib/public/Settings/ISettings.php +++ b/lib/public/Settings/ISettings.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Share/IAttributes.php b/lib/public/Share/IAttributes.php index fad19c60aad..9ddd8275dd6 100644 --- a/lib/public/Share/IAttributes.php +++ b/lib/public/Share/IAttributes.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2019 ownCloud GmbH * SPDX-License-Identifier: AGPL-3.0-only diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php index 89d6f5e4a87..35915ad9d90 100644 --- a/lib/public/Share/IManager.php +++ b/lib/public/Share/IManager.php @@ -473,6 +473,14 @@ interface IManager { public function allowCustomTokens(): bool; /** + * Check if the current user can view the share + * even if the download is disabled. + * + * @since 32.0.0 + */ + public function allowViewWithoutDownload(): bool; + + /** * Check if the current user can enumerate the target user * * @param IUser|null $currentUser diff --git a/lib/public/Share/IShare.php b/lib/public/Share/IShare.php index 337210e3b91..5d8c64e1314 100644 --- a/lib/public/Share/IShare.php +++ b/lib/public/Share/IShare.php @@ -633,4 +633,11 @@ interface IShare { * @since 31.0.0 */ public function getReminderSent(): bool; + + /** + * Check if the current user can see this share files contents. + * This will check the download permissions as well as the global + * admin setting to allow viewing files without downloading. + */ + public function canSeeContent(): bool; } diff --git a/lib/public/Share/IShareHelper.php b/lib/public/Share/IShareHelper.php index c4a33e717f9..152fc99a446 100644 --- a/lib/public/Share/IShareHelper.php +++ b/lib/public/Share/IShareHelper.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Teams/ITeamManager.php b/lib/public/Teams/ITeamManager.php index 144a141f93e..3f737b4229c 100644 --- a/lib/public/Teams/ITeamManager.php +++ b/lib/public/Teams/ITeamManager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Teams/ITeamResourceProvider.php b/lib/public/Teams/ITeamResourceProvider.php index 54c4879a47c..ff724ab8ae2 100644 --- a/lib/public/Teams/ITeamResourceProvider.php +++ b/lib/public/Teams/ITeamResourceProvider.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Teams/Team.php b/lib/public/Teams/Team.php index 8ece28bf648..474ebaed84f 100644 --- a/lib/public/Teams/Team.php +++ b/lib/public/Teams/Team.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/Teams/TeamResource.php b/lib/public/Teams/TeamResource.php index e9c6470b2c9..acb98380562 100644 --- a/lib/public/Teams/TeamResource.php +++ b/lib/public/Teams/TeamResource.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/WorkflowEngine/ICheck.php b/lib/public/WorkflowEngine/ICheck.php index 79c1a864ae0..4671eb84c3e 100644 --- a/lib/public/WorkflowEngine/ICheck.php +++ b/lib/public/WorkflowEngine/ICheck.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/WorkflowEngine/IManager.php b/lib/public/WorkflowEngine/IManager.php index b9235abafef..f66a9460f06 100644 --- a/lib/public/WorkflowEngine/IManager.php +++ b/lib/public/WorkflowEngine/IManager.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/public/WorkflowEngine/IOperation.php b/lib/public/WorkflowEngine/IOperation.php index 9f867eb811a..cda20acb7e5 100644 --- a/lib/public/WorkflowEngine/IOperation.php +++ b/lib/public/WorkflowEngine/IOperation.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib/unstable/Config/Lexicon/ConfigLexiconEntry.php b/lib/unstable/Config/Lexicon/ConfigLexiconEntry.php index d7d781d8e26..d0d9b4cbd23 100644 --- a/lib/unstable/Config/Lexicon/ConfigLexiconEntry.php +++ b/lib/unstable/Config/Lexicon/ConfigLexiconEntry.php @@ -17,6 +17,9 @@ use NCU\Config\ValueType; * @experimental 31.0.0 */ class ConfigLexiconEntry { + /** @experimental 32.0.0 */ + public const RENAME_INVERT_BOOLEAN = 1; + private string $definition = ''; private ?string $default = null; @@ -26,6 +29,7 @@ class ConfigLexiconEntry { * @param string $definition optional description of config key available when using occ command * @param bool $lazy set config value as lazy * @param int $flags set flags + * @param string|null $rename previous config key to migrate config value from * @param bool $deprecated set config key as deprecated * * @experimental 31.0.0 @@ -40,6 +44,8 @@ class ConfigLexiconEntry { private readonly bool $lazy = false, private readonly int $flags = 0, private readonly bool $deprecated = false, + private readonly ?string $rename = null, + private readonly int $options = 0, ) { /** @psalm-suppress UndefinedClass */ if (\OC::$CLI) { // only store definition if ran from CLI @@ -199,6 +205,25 @@ class ConfigLexiconEntry { } /** + * should be called/used only during migration/upgrade. + * link to an old config key. + * + * @return string|null not NULL if value can be imported from a previous key + * @experimental 32.0.0 + */ + public function getRename(): ?string { + return $this->rename; + } + + /** + * @experimental 32.0.0 + * @return bool TRUE if $option was set during the creation of the entry. + */ + public function hasOption(int $option): bool { + return (($option & $this->options) !== 0); + } + + /** * returns if config key is set as deprecated * * @return bool TRUE if config si deprecated |