diff options
author | John Molakvoæ <skjnldsv@users.noreply.github.com> | 2024-03-15 13:03:34 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-15 13:03:34 +0100 |
commit | 9338ef36ded767f2c35b7ec575b351859420ed09 (patch) | |
tree | 65c53c6a36f300859dc22b2d423275bcf2911367 /lib | |
parent | 6b09a79227a5dc98aa4620c6e5e15b610a06c806 (diff) | |
parent | df1cd1ba7e6e1f6e66a2b3229b5c082f1b81162e (diff) | |
download | nextcloud-server-9338ef36ded767f2c35b7ec575b351859420ed09.tar.gz nextcloud-server-9338ef36ded767f2c35b7ec575b351859420ed09.zip |
Merge branch 'master' into refactor/OC-Server-getShareManager
Signed-off-by: John Molakvoæ <skjnldsv@users.noreply.github.com>
Diffstat (limited to 'lib')
845 files changed, 28019 insertions, 11265 deletions
diff --git a/lib/autoloader.php b/lib/autoloader.php index a29b9aece79..26540b754a5 100644 --- a/lib/autoloader.php +++ b/lib/autoloader.php @@ -37,8 +37,8 @@ declare(strict_types=1); namespace OC; use \OCP\AutoloadNotAllowedException; -use OCP\ILogger; use OCP\ICache; +use Psr\Log\LoggerInterface; class Autoloader { /** @var bool */ @@ -105,7 +105,7 @@ class Autoloader { * Remove "apps/" from inclusion path for smooth migration to multi app dir */ if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) { - \OCP\Util::writeLog('core', 'include path for class "' . $class . '" starts with "apps/"', ILogger::DEBUG); + \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) { diff --git a/lib/base.php b/lib/base.php index 7153e481eda..891161ff0c6 100644 --- a/lib/base.php +++ b/lib/base.php @@ -35,6 +35,7 @@ declare(strict_types=1); * @author Lukas Reschke <lukas@statuscode.ch> * @author MartB <mart.b@outlook.de> * @author Michael Gapczynski <GapczynskiM@gmail.com> + * @author MichaIng <micha@dietpi.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Owen Winkler <a_github@midnightcircus.com> * @author Phil Davis <phil.davis@inf.org> @@ -114,8 +115,6 @@ class OC { public static string $configDir; - public static int $VERSION_MTIME = 0; - /** * requested app */ @@ -390,11 +389,16 @@ class OC { $ocVersion = \OCP\Util::getVersion(); $ocVersion = implode('.', $ocVersion); $incompatibleApps = $appManager->getIncompatibleApps($ocVersion); + $incompatibleOverwrites = $systemConfig->getValue('app_install_overwrite', []); $incompatibleShippedApps = []; + $incompatibleDisabledApps = []; foreach ($incompatibleApps as $appInfo) { if ($appManager->isShipped($appInfo['id'])) { $incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')'; } + if (!in_array($appInfo['id'], $incompatibleOverwrites)) { + $incompatibleDisabledApps[] = $appInfo; + } } if (!empty($incompatibleShippedApps)) { @@ -404,7 +408,7 @@ class OC { } $tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion)); - $tmpl->assign('incompatibleAppsList', $incompatibleApps); + $tmpl->assign('incompatibleAppsList', $incompatibleDisabledApps); try { $defaults = new \OC_Defaults(); $tmpl->assign('productName', $defaults->getName()); @@ -610,10 +614,9 @@ class OC { self::$CLI = (php_sapi_name() == 'cli'); - // Add default composer PSR-4 autoloader + // Add default composer PSR-4 autoloader, ensure apcu to be disabled self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php'; - OC::$VERSION_MTIME = filemtime(OC::$SERVERROOT . '/version.php'); - self::$composerAutoloader->setApcuPrefix('composer_autoload_' . md5(OC::$SERVERROOT . '_' . OC::$VERSION_MTIME)); + self::$composerAutoloader->setApcuPrefix(null); try { self::initPaths(); @@ -991,16 +994,7 @@ class OC { // Check if Nextcloud is installed or in maintenance (update) mode if (!$systemConfig->getValue('installed', false)) { \OC::$server->getSession()->clear(); - $setupHelper = new OC\Setup( - $systemConfig, - Server::get(\bantu\IniGetWrapper\IniGetWrapper::class), - Server::get(\OCP\L10N\IFactory::class)->get('lib'), - Server::get(\OCP\Defaults::class), - Server::get(\Psr\Log\LoggerInterface::class), - Server::get(\OCP\Security\ISecureRandom::class), - Server::get(\OC\Installer::class) - ); - $controller = new OC\Core\Controller\SetupController($setupHelper); + $controller = Server::get(\OC\Core\Controller\SetupController::class); $controller->run($_POST); exit(); } @@ -1024,21 +1018,6 @@ class OC { } } - // emergency app disabling - if ($requestPath === '/disableapp' - && $request->getMethod() === 'POST' - ) { - \OC_JSON::callCheck(); - \OC_JSON::checkAdminUser(); - $appIds = (array)$request->getParam('appid'); - foreach ($appIds as $appId) { - $appId = \OC_App::cleanAppId($appId); - Server::get(\OCP\App\IAppManager::class)->disableApp($appId); - } - \OC_JSON::success(); - exit(); - } - // Always load authentication apps OC_App::loadApps(['authentication']); OC_App::loadApps(['extended_authentication']); @@ -1123,7 +1102,7 @@ class OC { } $l = Server::get(\OCP\L10N\IFactory::class)->get('lib'); OC_Template::printErrorPage( - $l->t('404'), + '404', $l->t('The page could not be found on the server.'), 404 ); @@ -1134,11 +1113,14 @@ class OC { * Check login: apache auth, auth token, basic auth */ public static function handleLogin(OCP\IRequest $request): bool { + if ($request->getHeader('X-Nextcloud-Federation')) { + return false; + } $userSession = Server::get(\OC\User\Session::class); if (OC_User::handleApacheAuth()) { return true; } - if (self::tryAppEcosystemV2Login($request)) { + if (self::tryAppAPILogin($request)) { return true; } if ($userSession->tryTokenLogin($request)) { @@ -1179,17 +1161,17 @@ class OC { } } - protected static function tryAppEcosystemV2Login(OCP\IRequest $request): bool { + protected static function tryAppAPILogin(OCP\IRequest $request): bool { $appManager = Server::get(OCP\App\IAppManager::class); - if (!$request->getHeader('AE-SIGNATURE')) { + if (!$request->getHeader('AUTHORIZATION-APP-API')) { return false; } - if (!$appManager->isInstalled('app_ecosystem_v2')) { + if (!$appManager->isInstalled('app_api')) { return false; } try { - $appEcosystemV2Service = Server::get(OCA\AppEcosystemV2\Service\AppEcosystemV2Service::class); - return $appEcosystemV2Service->validateExAppRequestToNC($request); + $appAPIService = Server::get(OCA\AppAPI\Service\AppAPIService::class); + return $appAPIService->validateExAppRequestToNC($request); } catch (\Psr\Container\NotFoundExceptionInterface|\Psr\Container\ContainerExceptionInterface $e) { return false; } diff --git a/lib/composer/composer/InstalledVersions.php b/lib/composer/composer/InstalledVersions.php index c6b54af7ba2..51e734a774b 100644 --- a/lib/composer/composer/InstalledVersions.php +++ b/lib/composer/composer/InstalledVersions.php @@ -98,7 +98,7 @@ class InstalledVersions { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; } } @@ -119,7 +119,7 @@ class InstalledVersions */ public static function satisfies(VersionParser $parser, $packageName, $constraint) { - $constraint = $parser->parseConstraints($constraint); + $constraint = $parser->parseConstraints((string) $constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint); @@ -328,7 +328,9 @@ class InstalledVersions if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } @@ -340,12 +342,17 @@ class InstalledVersions // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = require __DIR__ . '/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; } else { self::$installed = array(); } } - $installed[] = self::$installed; + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } return $installed; } diff --git a/lib/composer/composer/LICENSE b/lib/composer/composer/LICENSE index f27399a042d..62ecfd8d004 100644 --- a/lib/composer/composer/LICENSE +++ b/lib/composer/composer/LICENSE @@ -1,4 +1,3 @@ - Copyright (c) Nils Adermann, Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy @@ -18,4 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 704d59d000b..3aa5c6a2b8c 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -38,14 +38,18 @@ return array( 'OCP\\AppFramework\\Http' => $baseDir . '/lib/public/AppFramework/Http.php', 'OCP\\AppFramework\\Http\\Attribute\\ARateLimit' => $baseDir . '/lib/public/AppFramework/Http/Attribute/ARateLimit.php', 'OCP\\AppFramework\\Http\\Attribute\\AnonRateLimit' => $baseDir . '/lib/public/AppFramework/Http/Attribute/AnonRateLimit.php', + 'OCP\\AppFramework\\Http\\Attribute\\ApiRoute' => $baseDir . '/lib/public/AppFramework/Http/Attribute/ApiRoute.php', 'OCP\\AppFramework\\Http\\Attribute\\AuthorizedAdminSetting' => $baseDir . '/lib/public/AppFramework/Http/Attribute/AuthorizedAdminSetting.php', 'OCP\\AppFramework\\Http\\Attribute\\BruteForceProtection' => $baseDir . '/lib/public/AppFramework/Http/Attribute/BruteForceProtection.php', 'OCP\\AppFramework\\Http\\Attribute\\CORS' => $baseDir . '/lib/public/AppFramework/Http/Attribute/CORS.php', + 'OCP\\AppFramework\\Http\\Attribute\\FrontpageRoute' => $baseDir . '/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php', 'OCP\\AppFramework\\Http\\Attribute\\IgnoreOpenAPI' => $baseDir . '/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php', 'OCP\\AppFramework\\Http\\Attribute\\NoAdminRequired' => $baseDir . '/lib/public/AppFramework/Http/Attribute/NoAdminRequired.php', 'OCP\\AppFramework\\Http\\Attribute\\NoCSRFRequired' => $baseDir . '/lib/public/AppFramework/Http/Attribute/NoCSRFRequired.php', + 'OCP\\AppFramework\\Http\\Attribute\\OpenAPI' => $baseDir . '/lib/public/AppFramework/Http/Attribute/OpenAPI.php', 'OCP\\AppFramework\\Http\\Attribute\\PasswordConfirmationRequired' => $baseDir . '/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php', 'OCP\\AppFramework\\Http\\Attribute\\PublicPage' => $baseDir . '/lib/public/AppFramework/Http/Attribute/PublicPage.php', + 'OCP\\AppFramework\\Http\\Attribute\\Route' => $baseDir . '/lib/public/AppFramework/Http/Attribute/Route.php', 'OCP\\AppFramework\\Http\\Attribute\\StrictCookiesRequired' => $baseDir . '/lib/public/AppFramework/Http/Attribute/StrictCookiesRequired.php', 'OCP\\AppFramework\\Http\\Attribute\\SubAdminRequired' => $baseDir . '/lib/public/AppFramework/Http/Attribute/SubAdminRequired.php', 'OCP\\AppFramework\\Http\\Attribute\\UseSession' => $baseDir . '/lib/public/AppFramework/Http/Attribute/UseSession.php', @@ -65,6 +69,7 @@ return array( 'OCP\\AppFramework\\Http\\IOutput' => $baseDir . '/lib/public/AppFramework/Http/IOutput.php', 'OCP\\AppFramework\\Http\\JSONResponse' => $baseDir . '/lib/public/AppFramework/Http/JSONResponse.php', 'OCP\\AppFramework\\Http\\NotFoundResponse' => $baseDir . '/lib/public/AppFramework/Http/NotFoundResponse.php', + 'OCP\\AppFramework\\Http\\ParameterOutOfRangeException' => $baseDir . '/lib/public/AppFramework/Http/ParameterOutOfRangeException.php', 'OCP\\AppFramework\\Http\\RedirectResponse' => $baseDir . '/lib/public/AppFramework/Http/RedirectResponse.php', 'OCP\\AppFramework\\Http\\RedirectToDefaultAppResponse' => $baseDir . '/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php', 'OCP\\AppFramework\\Http\\Response' => $baseDir . '/lib/public/AppFramework/Http/Response.php', @@ -106,13 +111,17 @@ return array( 'OCP\\Authentication\\Events\\AnyLoginFailedEvent' => $baseDir . '/lib/public/Authentication/Events/AnyLoginFailedEvent.php', 'OCP\\Authentication\\Events\\LoginFailedEvent' => $baseDir . '/lib/public/Authentication/Events/LoginFailedEvent.php', 'OCP\\Authentication\\Exceptions\\CredentialsUnavailableException' => $baseDir . '/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php', + 'OCP\\Authentication\\Exceptions\\ExpiredTokenException' => $baseDir . '/lib/public/Authentication/Exceptions/ExpiredTokenException.php', + 'OCP\\Authentication\\Exceptions\\InvalidTokenException' => $baseDir . '/lib/public/Authentication/Exceptions/InvalidTokenException.php', 'OCP\\Authentication\\Exceptions\\PasswordUnavailableException' => $baseDir . '/lib/public/Authentication/Exceptions/PasswordUnavailableException.php', + 'OCP\\Authentication\\Exceptions\\WipeTokenException' => $baseDir . '/lib/public/Authentication/Exceptions/WipeTokenException.php', 'OCP\\Authentication\\IAlternativeLogin' => $baseDir . '/lib/public/Authentication/IAlternativeLogin.php', 'OCP\\Authentication\\IApacheBackend' => $baseDir . '/lib/public/Authentication/IApacheBackend.php', 'OCP\\Authentication\\IProvideUserSecretBackend' => $baseDir . '/lib/public/Authentication/IProvideUserSecretBackend.php', 'OCP\\Authentication\\LoginCredentials\\ICredentials' => $baseDir . '/lib/public/Authentication/LoginCredentials/ICredentials.php', 'OCP\\Authentication\\LoginCredentials\\IStore' => $baseDir . '/lib/public/Authentication/LoginCredentials/IStore.php', 'OCP\\Authentication\\Token\\IProvider' => $baseDir . '/lib/public/Authentication/Token/IProvider.php', + 'OCP\\Authentication\\Token\\IToken' => $baseDir . '/lib/public/Authentication/Token/IToken.php', 'OCP\\Authentication\\TwoFactorAuth\\ALoginSetupController' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/ALoginSetupController.php', 'OCP\\Authentication\\TwoFactorAuth\\IActivatableAtLogin' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IActivatableAtLogin.php', 'OCP\\Authentication\\TwoFactorAuth\\IActivatableByAdmin' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IActivatableByAdmin.php', @@ -165,6 +174,7 @@ return array( 'OCP\\Capabilities\\IInitialStateExcludedCapability' => $baseDir . '/lib/public/Capabilities/IInitialStateExcludedCapability.php', 'OCP\\Capabilities\\IPublicCapability' => $baseDir . '/lib/public/Capabilities/IPublicCapability.php', 'OCP\\Collaboration\\AutoComplete\\AutoCompleteEvent' => $baseDir . '/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php', + 'OCP\\Collaboration\\AutoComplete\\AutoCompleteFilterEvent' => $baseDir . '/lib/public/Collaboration/AutoComplete/AutoCompleteFilterEvent.php', 'OCP\\Collaboration\\AutoComplete\\IManager' => $baseDir . '/lib/public/Collaboration/AutoComplete/IManager.php', 'OCP\\Collaboration\\AutoComplete\\ISorter' => $baseDir . '/lib/public/Collaboration/AutoComplete/ISorter.php', 'OCP\\Collaboration\\Collaborators\\ISearch' => $baseDir . '/lib/public/Collaboration/Collaborators/ISearch.php', @@ -177,6 +187,7 @@ return array( 'OCP\\Collaboration\\Reference\\IReferenceManager' => $baseDir . '/lib/public/Collaboration/Reference/IReferenceManager.php', 'OCP\\Collaboration\\Reference\\IReferenceProvider' => $baseDir . '/lib/public/Collaboration/Reference/IReferenceProvider.php', 'OCP\\Collaboration\\Reference\\ISearchableReferenceProvider' => $baseDir . '/lib/public/Collaboration/Reference/ISearchableReferenceProvider.php', + 'OCP\\Collaboration\\Reference\\LinkReferenceProvider' => $baseDir . '/lib/public/Collaboration/Reference/LinkReferenceProvider.php', 'OCP\\Collaboration\\Reference\\Reference' => $baseDir . '/lib/public/Collaboration/Reference/Reference.php', 'OCP\\Collaboration\\Reference\\RenderReferenceEvent' => $baseDir . '/lib/public/Collaboration/Reference/RenderReferenceEvent.php', 'OCP\\Collaboration\\Resources\\CollectionException' => $baseDir . '/lib/public/Collaboration/Resources/CollectionException.php', @@ -206,6 +217,7 @@ return array( 'OCP\\Constants' => $baseDir . '/lib/public/Constants.php', 'OCP\\Contacts\\ContactsMenu\\IAction' => $baseDir . '/lib/public/Contacts/ContactsMenu/IAction.php', 'OCP\\Contacts\\ContactsMenu\\IActionFactory' => $baseDir . '/lib/public/Contacts/ContactsMenu/IActionFactory.php', + 'OCP\\Contacts\\ContactsMenu\\IBulkProvider' => $baseDir . '/lib/public/Contacts/ContactsMenu/IBulkProvider.php', 'OCP\\Contacts\\ContactsMenu\\IContactsStore' => $baseDir . '/lib/public/Contacts/ContactsMenu/IContactsStore.php', 'OCP\\Contacts\\ContactsMenu\\IEntry' => $baseDir . '/lib/public/Contacts/ContactsMenu/IEntry.php', 'OCP\\Contacts\\ContactsMenu\\ILinkAction' => $baseDir . '/lib/public/Contacts/ContactsMenu/ILinkAction.php', @@ -240,7 +252,6 @@ return array( 'OCP\\Dashboard\\Model\\WidgetItem' => $baseDir . '/lib/public/Dashboard/Model/WidgetItem.php', 'OCP\\Dashboard\\Model\\WidgetItems' => $baseDir . '/lib/public/Dashboard/Model/WidgetItems.php', 'OCP\\Dashboard\\Model\\WidgetOptions' => $baseDir . '/lib/public/Dashboard/Model/WidgetOptions.php', - 'OCP\\Dashboard\\RegisterWidgetEvent' => $baseDir . '/lib/public/Dashboard/RegisterWidgetEvent.php', 'OCP\\DataCollector\\AbstractDataCollector' => $baseDir . '/lib/public/DataCollector/AbstractDataCollector.php', 'OCP\\DataCollector\\IDataCollector' => $baseDir . '/lib/public/DataCollector/IDataCollector.php', 'OCP\\Defaults' => $baseDir . '/lib/public/Defaults.php', @@ -265,6 +276,11 @@ return array( 'OCP\\EventDispatcher\\GenericEvent' => $baseDir . '/lib/public/EventDispatcher/GenericEvent.php', 'OCP\\EventDispatcher\\IEventDispatcher' => $baseDir . '/lib/public/EventDispatcher/IEventDispatcher.php', 'OCP\\EventDispatcher\\IEventListener' => $baseDir . '/lib/public/EventDispatcher/IEventListener.php', + 'OCP\\Exceptions\\AbortedEventException' => $baseDir . '/lib/public/Exceptions/AbortedEventException.php', + 'OCP\\Exceptions\\AppConfigException' => $baseDir . '/lib/public/Exceptions/AppConfigException.php', + 'OCP\\Exceptions\\AppConfigIncorrectTypeException' => $baseDir . '/lib/public/Exceptions/AppConfigIncorrectTypeException.php', + 'OCP\\Exceptions\\AppConfigTypeConflictException' => $baseDir . '/lib/public/Exceptions/AppConfigTypeConflictException.php', + 'OCP\\Exceptions\\AppConfigUnknownKeyException' => $baseDir . '/lib/public/Exceptions/AppConfigUnknownKeyException.php', 'OCP\\Federation\\Events\\TrustedServerRemovedEvent' => $baseDir . '/lib/public/Federation/Events/TrustedServerRemovedEvent.php', 'OCP\\Federation\\Exceptions\\ActionNotSupportedException' => $baseDir . '/lib/public/Federation/Exceptions/ActionNotSupportedException.php', 'OCP\\Federation\\Exceptions\\AuthenticationFailedException' => $baseDir . '/lib/public/Federation/Exceptions/AuthenticationFailedException.php', @@ -280,6 +296,18 @@ return array( 'OCP\\Federation\\ICloudId' => $baseDir . '/lib/public/Federation/ICloudId.php', 'OCP\\Federation\\ICloudIdManager' => $baseDir . '/lib/public/Federation/ICloudIdManager.php', 'OCP\\Files' => $baseDir . '/lib/public/Files.php', + 'OCP\\FilesMetadata\\AMetadataEvent' => $baseDir . '/lib/public/FilesMetadata/AMetadataEvent.php', + 'OCP\\FilesMetadata\\Event\\MetadataBackgroundEvent' => $baseDir . '/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php', + 'OCP\\FilesMetadata\\Event\\MetadataLiveEvent' => $baseDir . '/lib/public/FilesMetadata/Event/MetadataLiveEvent.php', + 'OCP\\FilesMetadata\\Event\\MetadataNamedEvent' => $baseDir . '/lib/public/FilesMetadata/Event/MetadataNamedEvent.php', + 'OCP\\FilesMetadata\\Exceptions\\FilesMetadataException' => $baseDir . '/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php', + 'OCP\\FilesMetadata\\Exceptions\\FilesMetadataKeyFormatException' => $baseDir . '/lib/public/FilesMetadata/Exceptions/FilesMetadataKeyFormatException.php', + 'OCP\\FilesMetadata\\Exceptions\\FilesMetadataNotFoundException' => $baseDir . '/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php', + 'OCP\\FilesMetadata\\Exceptions\\FilesMetadataTypeException' => $baseDir . '/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php', + 'OCP\\FilesMetadata\\IFilesMetadataManager' => $baseDir . '/lib/public/FilesMetadata/IFilesMetadataManager.php', + 'OCP\\FilesMetadata\\IMetadataQuery' => $baseDir . '/lib/public/FilesMetadata/IMetadataQuery.php', + 'OCP\\FilesMetadata\\Model\\IFilesMetadata' => $baseDir . '/lib/public/FilesMetadata/Model/IFilesMetadata.php', + 'OCP\\FilesMetadata\\Model\\IMetadataValueWrapper' => $baseDir . '/lib/public/FilesMetadata/Model/IMetadataValueWrapper.php', 'OCP\\Files\\AlreadyExistsException' => $baseDir . '/lib/public/Files/AlreadyExistsException.php', 'OCP\\Files\\AppData\\IAppDataFactory' => $baseDir . '/lib/public/Files/AppData/IAppDataFactory.php', 'OCP\\Files\\Cache\\AbstractCacheEvent' => $baseDir . '/lib/public/Files/Cache/AbstractCacheEvent.php', @@ -302,6 +330,7 @@ return array( 'OCP\\Files\\Config\\IMountProviderCollection' => $baseDir . '/lib/public/Files/Config/IMountProviderCollection.php', 'OCP\\Files\\Config\\IRootMountProvider' => $baseDir . '/lib/public/Files/Config/IRootMountProvider.php', 'OCP\\Files\\Config\\IUserMountCache' => $baseDir . '/lib/public/Files/Config/IUserMountCache.php', + 'OCP\\Files\\ConnectionLostException' => $baseDir . '/lib/public/Files/ConnectionLostException.php', 'OCP\\Files\\DavUtil' => $baseDir . '/lib/public/Files/DavUtil.php', 'OCP\\Files\\EmptyFileNameException' => $baseDir . '/lib/public/Files/EmptyFileNameException.php', 'OCP\\Files\\EntityTooLargeException' => $baseDir . '/lib/public/Files/EntityTooLargeException.php', @@ -401,6 +430,7 @@ return array( 'OCP\\Files\\UnseekableException' => $baseDir . '/lib/public/Files/UnseekableException.php', 'OCP\\Files_FullTextSearch\\Model\\AFilesDocument' => $baseDir . '/lib/public/Files_FullTextSearch/Model/AFilesDocument.php', 'OCP\\FullTextSearch\\Exceptions\\FullTextSearchAppNotAvailableException' => $baseDir . '/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php', + 'OCP\\FullTextSearch\\Exceptions\\FullTextSearchIndexNotAvailableException' => $baseDir . '/lib/public/FullTextSearch/Exceptions/FullTextSearchIndexNotAvailableException.php', 'OCP\\FullTextSearch\\IFullTextSearchManager' => $baseDir . '/lib/public/FullTextSearch/IFullTextSearchManager.php', 'OCP\\FullTextSearch\\IFullTextSearchPlatform' => $baseDir . '/lib/public/FullTextSearch/IFullTextSearchPlatform.php', 'OCP\\FullTextSearch\\IFullTextSearchProvider' => $baseDir . '/lib/public/FullTextSearch/IFullTextSearchProvider.php', @@ -421,6 +451,7 @@ return array( 'OCP\\GroupInterface' => $baseDir . '/lib/public/GroupInterface.php', 'OCP\\Group\\Backend\\ABackend' => $baseDir . '/lib/public/Group/Backend/ABackend.php', 'OCP\\Group\\Backend\\IAddToGroupBackend' => $baseDir . '/lib/public/Group/Backend/IAddToGroupBackend.php', + 'OCP\\Group\\Backend\\IBatchMethodsBackend' => $baseDir . '/lib/public/Group/Backend/IBatchMethodsBackend.php', 'OCP\\Group\\Backend\\ICountDisabledInGroup' => $baseDir . '/lib/public/Group/Backend/ICountDisabledInGroup.php', 'OCP\\Group\\Backend\\ICountUsersBackend' => $baseDir . '/lib/public/Group/Backend/ICountUsersBackend.php', 'OCP\\Group\\Backend\\ICreateGroupBackend' => $baseDir . '/lib/public/Group/Backend/ICreateGroupBackend.php', @@ -483,6 +514,7 @@ return array( 'OCP\\IMemcache' => $baseDir . '/lib/public/IMemcache.php', 'OCP\\IMemcacheTTL' => $baseDir . '/lib/public/IMemcacheTTL.php', 'OCP\\INavigationManager' => $baseDir . '/lib/public/INavigationManager.php', + 'OCP\\IPhoneNumberUtil' => $baseDir . '/lib/public/IPhoneNumberUtil.php', 'OCP\\IPreview' => $baseDir . '/lib/public/IPreview.php', 'OCP\\IRequest' => $baseDir . '/lib/public/IRequest.php', 'OCP\\IRequestId' => $baseDir . '/lib/public/IRequestId.php', @@ -534,6 +566,12 @@ return array( 'OCP\\Notification\\IManager' => $baseDir . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\INotification' => $baseDir . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => $baseDir . '/lib/public/Notification/INotifier.php', + '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\\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', 'OCP\\OCS\\IDiscoveryService' => $baseDir . '/lib/public/OCS/IDiscoveryService.php', 'OCP\\PreConditionNotMetException' => $baseDir . '/lib/public/PreConditionNotMetException.php', 'OCP\\Preview\\BeforePreviewFetchedEvent' => $baseDir . '/lib/public/Preview/BeforePreviewFetchedEvent.php', @@ -543,6 +581,7 @@ return array( 'OCP\\Preview\\IVersionedPreviewFile' => $baseDir . '/lib/public/Preview/IVersionedPreviewFile.php', 'OCP\\Profile\\BeforeTemplateRenderedEvent' => $baseDir . '/lib/public/Profile/BeforeTemplateRenderedEvent.php', 'OCP\\Profile\\ILinkAction' => $baseDir . '/lib/public/Profile/ILinkAction.php', + 'OCP\\Profile\\IProfileManager' => $baseDir . '/lib/public/Profile/IProfileManager.php', 'OCP\\Profile\\ParameterDoesNotExistException' => $baseDir . '/lib/public/Profile/ParameterDoesNotExistException.php', 'OCP\\Profiler\\IProfile' => $baseDir . '/lib/public/Profiler/IProfile.php', 'OCP\\Profiler\\IProfiler' => $baseDir . '/lib/public/Profiler/IProfiler.php', @@ -561,6 +600,11 @@ return array( 'OCP\\Route\\IRouter' => $baseDir . '/lib/public/Route/IRouter.php', 'OCP\\SabrePluginEvent' => $baseDir . '/lib/public/SabrePluginEvent.php', 'OCP\\SabrePluginException' => $baseDir . '/lib/public/SabrePluginException.php', + 'OCP\\Search\\FilterDefinition' => $baseDir . '/lib/public/Search/FilterDefinition.php', + 'OCP\\Search\\IFilter' => $baseDir . '/lib/public/Search/IFilter.php', + 'OCP\\Search\\IFilterCollection' => $baseDir . '/lib/public/Search/IFilterCollection.php', + 'OCP\\Search\\IFilteringProvider' => $baseDir . '/lib/public/Search/IFilteringProvider.php', + 'OCP\\Search\\IInAppSearch' => $baseDir . '/lib/public/Search/IInAppSearch.php', 'OCP\\Search\\IProvider' => $baseDir . '/lib/public/Search/IProvider.php', 'OCP\\Search\\ISearchQuery' => $baseDir . '/lib/public/Search/ISearchQuery.php', 'OCP\\Search\\PagedProvider' => $baseDir . '/lib/public/Search/PagedProvider.php', @@ -581,15 +625,26 @@ return array( 'OCP\\Security\\IRemoteHostValidator' => $baseDir . '/lib/public/Security/IRemoteHostValidator.php', 'OCP\\Security\\ISecureRandom' => $baseDir . '/lib/public/Security/ISecureRandom.php', 'OCP\\Security\\ITrustedDomainHelper' => $baseDir . '/lib/public/Security/ITrustedDomainHelper.php', + 'OCP\\Security\\RateLimiting\\ILimiter' => $baseDir . '/lib/public/Security/RateLimiting/ILimiter.php', + 'OCP\\Security\\RateLimiting\\IRateLimitExceededException' => $baseDir . '/lib/public/Security/RateLimiting/IRateLimitExceededException.php', 'OCP\\Security\\VerificationToken\\IVerificationToken' => $baseDir . '/lib/public/Security/VerificationToken/IVerificationToken.php', 'OCP\\Security\\VerificationToken\\InvalidTokenException' => $baseDir . '/lib/public/Security/VerificationToken/InvalidTokenException.php', 'OCP\\Server' => $baseDir . '/lib/public/Server.php', 'OCP\\Session\\Exceptions\\SessionNotAvailableException' => $baseDir . '/lib/public/Session/Exceptions/SessionNotAvailableException.php', + 'OCP\\Settings\\DeclarativeSettingsTypes' => $baseDir . '/lib/public/Settings/DeclarativeSettingsTypes.php', + 'OCP\\Settings\\Events\\DeclarativeSettingsGetValueEvent' => $baseDir . '/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php', + 'OCP\\Settings\\Events\\DeclarativeSettingsRegisterFormEvent' => $baseDir . '/lib/public/Settings/Events/DeclarativeSettingsRegisterFormEvent.php', + 'OCP\\Settings\\Events\\DeclarativeSettingsSetValueEvent' => $baseDir . '/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php', + 'OCP\\Settings\\IDeclarativeManager' => $baseDir . '/lib/public/Settings/IDeclarativeManager.php', + 'OCP\\Settings\\IDeclarativeSettingsForm' => $baseDir . '/lib/public/Settings/IDeclarativeSettingsForm.php', 'OCP\\Settings\\IDelegatedSettings' => $baseDir . '/lib/public/Settings/IDelegatedSettings.php', 'OCP\\Settings\\IIconSection' => $baseDir . '/lib/public/Settings/IIconSection.php', 'OCP\\Settings\\IManager' => $baseDir . '/lib/public/Settings/IManager.php', 'OCP\\Settings\\ISettings' => $baseDir . '/lib/public/Settings/ISettings.php', 'OCP\\Settings\\ISubAdminSettings' => $baseDir . '/lib/public/Settings/ISubAdminSettings.php', + 'OCP\\SetupCheck\\ISetupCheck' => $baseDir . '/lib/public/SetupCheck/ISetupCheck.php', + 'OCP\\SetupCheck\\ISetupCheckManager' => $baseDir . '/lib/public/SetupCheck/ISetupCheckManager.php', + 'OCP\\SetupCheck\\SetupResult' => $baseDir . '/lib/public/SetupCheck/SetupResult.php', 'OCP\\Share' => $baseDir . '/lib/public/Share.php', 'OCP\\Share\\Events\\BeforeShareCreatedEvent' => $baseDir . '/lib/public/Share/Events/BeforeShareCreatedEvent.php', 'OCP\\Share\\Events\\BeforeShareDeletedEvent' => $baseDir . '/lib/public/Share/Events/BeforeShareDeletedEvent.php', @@ -618,6 +673,8 @@ return array( 'OCP\\SpeechToText\\Events\\TranscriptionSuccessfulEvent' => $baseDir . '/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php', 'OCP\\SpeechToText\\ISpeechToTextManager' => $baseDir . '/lib/public/SpeechToText/ISpeechToTextManager.php', 'OCP\\SpeechToText\\ISpeechToTextProvider' => $baseDir . '/lib/public/SpeechToText/ISpeechToTextProvider.php', + 'OCP\\SpeechToText\\ISpeechToTextProviderWithId' => $baseDir . '/lib/public/SpeechToText/ISpeechToTextProviderWithId.php', + 'OCP\\SpeechToText\\ISpeechToTextProviderWithUserId' => $baseDir . '/lib/public/SpeechToText/ISpeechToTextProviderWithUserId.php', 'OCP\\Support\\CrashReport\\ICollectBreadcrumbs' => $baseDir . '/lib/public/Support/CrashReport/ICollectBreadcrumbs.php', 'OCP\\Support\\CrashReport\\IMessageReporter' => $baseDir . '/lib/public/Support/CrashReport/IMessageReporter.php', 'OCP\\Support\\CrashReport\\IRegistry' => $baseDir . '/lib/public/Support/CrashReport/IRegistry.php', @@ -641,22 +698,42 @@ return array( 'OCP\\Talk\\IConversation' => $baseDir . '/lib/public/Talk/IConversation.php', 'OCP\\Talk\\IConversationOptions' => $baseDir . '/lib/public/Talk/IConversationOptions.php', 'OCP\\Talk\\ITalkBackend' => $baseDir . '/lib/public/Talk/ITalkBackend.php', + 'OCP\\Teams\\ITeamManager' => $baseDir . '/lib/public/Teams/ITeamManager.php', + 'OCP\\Teams\\ITeamResourceProvider' => $baseDir . '/lib/public/Teams/ITeamResourceProvider.php', + 'OCP\\Teams\\Team' => $baseDir . '/lib/public/Teams/Team.php', + 'OCP\\Teams\\TeamResource' => $baseDir . '/lib/public/Teams/TeamResource.php', 'OCP\\Template' => $baseDir . '/lib/public/Template.php', 'OCP\\TextProcessing\\Events\\AbstractTextProcessingEvent' => $baseDir . '/lib/public/TextProcessing/Events/AbstractTextProcessingEvent.php', 'OCP\\TextProcessing\\Events\\TaskFailedEvent' => $baseDir . '/lib/public/TextProcessing/Events/TaskFailedEvent.php', 'OCP\\TextProcessing\\Events\\TaskSuccessfulEvent' => $baseDir . '/lib/public/TextProcessing/Events/TaskSuccessfulEvent.php', + 'OCP\\TextProcessing\\Exception\\TaskFailureException' => $baseDir . '/lib/public/TextProcessing/Exception/TaskFailureException.php', 'OCP\\TextProcessing\\FreePromptTaskType' => $baseDir . '/lib/public/TextProcessing/FreePromptTaskType.php', 'OCP\\TextProcessing\\HeadlineTaskType' => $baseDir . '/lib/public/TextProcessing/HeadlineTaskType.php', 'OCP\\TextProcessing\\IManager' => $baseDir . '/lib/public/TextProcessing/IManager.php', 'OCP\\TextProcessing\\IProvider' => $baseDir . '/lib/public/TextProcessing/IProvider.php', + 'OCP\\TextProcessing\\IProviderWithExpectedRuntime' => $baseDir . '/lib/public/TextProcessing/IProviderWithExpectedRuntime.php', + 'OCP\\TextProcessing\\IProviderWithId' => $baseDir . '/lib/public/TextProcessing/IProviderWithId.php', + 'OCP\\TextProcessing\\IProviderWithUserId' => $baseDir . '/lib/public/TextProcessing/IProviderWithUserId.php', 'OCP\\TextProcessing\\ITaskType' => $baseDir . '/lib/public/TextProcessing/ITaskType.php', 'OCP\\TextProcessing\\SummaryTaskType' => $baseDir . '/lib/public/TextProcessing/SummaryTaskType.php', 'OCP\\TextProcessing\\Task' => $baseDir . '/lib/public/TextProcessing/Task.php', 'OCP\\TextProcessing\\TopicsTaskType' => $baseDir . '/lib/public/TextProcessing/TopicsTaskType.php', + 'OCP\\TextToImage\\Events\\AbstractTextToImageEvent' => $baseDir . '/lib/public/TextToImage/Events/AbstractTextToImageEvent.php', + 'OCP\\TextToImage\\Events\\TaskFailedEvent' => $baseDir . '/lib/public/TextToImage/Events/TaskFailedEvent.php', + 'OCP\\TextToImage\\Events\\TaskSuccessfulEvent' => $baseDir . '/lib/public/TextToImage/Events/TaskSuccessfulEvent.php', + 'OCP\\TextToImage\\Exception\\TaskFailureException' => $baseDir . '/lib/public/TextToImage/Exception/TaskFailureException.php', + 'OCP\\TextToImage\\Exception\\TaskNotFoundException' => $baseDir . '/lib/public/TextToImage/Exception/TaskNotFoundException.php', + 'OCP\\TextToImage\\Exception\\TextToImageException' => $baseDir . '/lib/public/TextToImage/Exception/TextToImageException.php', + 'OCP\\TextToImage\\IManager' => $baseDir . '/lib/public/TextToImage/IManager.php', + 'OCP\\TextToImage\\IProvider' => $baseDir . '/lib/public/TextToImage/IProvider.php', + 'OCP\\TextToImage\\IProviderWithUserId' => $baseDir . '/lib/public/TextToImage/IProviderWithUserId.php', + 'OCP\\TextToImage\\Task' => $baseDir . '/lib/public/TextToImage/Task.php', 'OCP\\Translation\\CouldNotTranslateException' => $baseDir . '/lib/public/Translation/CouldNotTranslateException.php', 'OCP\\Translation\\IDetectLanguageProvider' => $baseDir . '/lib/public/Translation/IDetectLanguageProvider.php', 'OCP\\Translation\\ITranslationManager' => $baseDir . '/lib/public/Translation/ITranslationManager.php', 'OCP\\Translation\\ITranslationProvider' => $baseDir . '/lib/public/Translation/ITranslationProvider.php', + 'OCP\\Translation\\ITranslationProviderWithId' => $baseDir . '/lib/public/Translation/ITranslationProviderWithId.php', + 'OCP\\Translation\\ITranslationProviderWithUserId' => $baseDir . '/lib/public/Translation/ITranslationProviderWithUserId.php', 'OCP\\Translation\\LanguageTuple' => $baseDir . '/lib/public/Translation/LanguageTuple.php', 'OCP\\UserInterface' => $baseDir . '/lib/public/UserInterface.php', 'OCP\\UserMigration\\IExportDestination' => $baseDir . '/lib/public/UserMigration/IExportDestination.php', @@ -689,6 +766,11 @@ return array( 'OCP\\User\\Events\\BeforeUserLoggedInEvent' => $baseDir . '/lib/public/User/Events/BeforeUserLoggedInEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInWithCookieEvent' => $baseDir . '/lib/public/User/Events/BeforeUserLoggedInWithCookieEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedOutEvent' => $baseDir . '/lib/public/User/Events/BeforeUserLoggedOutEvent.php', + 'OCP\\User\\Events\\OutOfOfficeChangedEvent' => $baseDir . '/lib/public/User/Events/OutOfOfficeChangedEvent.php', + 'OCP\\User\\Events\\OutOfOfficeClearedEvent' => $baseDir . '/lib/public/User/Events/OutOfOfficeClearedEvent.php', + 'OCP\\User\\Events\\OutOfOfficeEndedEvent' => $baseDir . '/lib/public/User/Events/OutOfOfficeEndedEvent.php', + 'OCP\\User\\Events\\OutOfOfficeScheduledEvent' => $baseDir . '/lib/public/User/Events/OutOfOfficeScheduledEvent.php', + 'OCP\\User\\Events\\OutOfOfficeStartedEvent' => $baseDir . '/lib/public/User/Events/OutOfOfficeStartedEvent.php', 'OCP\\User\\Events\\PasswordUpdatedEvent' => $baseDir . '/lib/public/User/Events/PasswordUpdatedEvent.php', 'OCP\\User\\Events\\PostLoginEvent' => $baseDir . '/lib/public/User/Events/PostLoginEvent.php', 'OCP\\User\\Events\\UserChangedEvent' => $baseDir . '/lib/public/User/Events/UserChangedEvent.php', @@ -700,6 +782,8 @@ return array( 'OCP\\User\\Events\\UserLoggedInWithCookieEvent' => $baseDir . '/lib/public/User/Events/UserLoggedInWithCookieEvent.php', 'OCP\\User\\Events\\UserLoggedOutEvent' => $baseDir . '/lib/public/User/Events/UserLoggedOutEvent.php', 'OCP\\User\\GetQuotaEvent' => $baseDir . '/lib/public/User/GetQuotaEvent.php', + 'OCP\\User\\IAvailabilityCoordinator' => $baseDir . '/lib/public/User/IAvailabilityCoordinator.php', + 'OCP\\User\\IOutOfOfficeData' => $baseDir . '/lib/public/User/IOutOfOfficeData.php', 'OCP\\Util' => $baseDir . '/lib/public/Util.php', 'OCP\\WorkflowEngine\\EntityContext\\IContextPortation' => $baseDir . '/lib/public/WorkflowEngine/EntityContext/IContextPortation.php', 'OCP\\WorkflowEngine\\EntityContext\\IDisplayName' => $baseDir . '/lib/public/WorkflowEngine/EntityContext/IDisplayName.php', @@ -801,7 +885,9 @@ return array( 'OC\\App\\AppStore\\Bundles\\EnterpriseBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/EnterpriseBundle.php', 'OC\\App\\AppStore\\Bundles\\GroupwareBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/GroupwareBundle.php', 'OC\\App\\AppStore\\Bundles\\HubBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/HubBundle.php', + 'OC\\App\\AppStore\\Bundles\\PublicSectorBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/PublicSectorBundle.php', 'OC\\App\\AppStore\\Bundles\\SocialSharingBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/SocialSharingBundle.php', + 'OC\\App\\AppStore\\Fetcher\\AppDiscoverFetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php', 'OC\\App\\AppStore\\Fetcher\\AppFetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/AppFetcher.php', 'OC\\App\\AppStore\\Fetcher\\CategoryFetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/CategoryFetcher.php', 'OC\\App\\AppStore\\Fetcher\\Fetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/Fetcher.php', @@ -887,11 +973,9 @@ return array( 'OC\\Avatar\\GuestAvatar' => $baseDir . '/lib/private/Avatar/GuestAvatar.php', 'OC\\Avatar\\PlaceholderAvatar' => $baseDir . '/lib/private/Avatar/PlaceholderAvatar.php', 'OC\\Avatar\\UserAvatar' => $baseDir . '/lib/private/Avatar/UserAvatar.php', - 'OC\\BackgroundJob\\Job' => $baseDir . '/lib/private/BackgroundJob/Job.php', 'OC\\BackgroundJob\\JobList' => $baseDir . '/lib/private/BackgroundJob/JobList.php', - 'OC\\BackgroundJob\\QueuedJob' => $baseDir . '/lib/private/BackgroundJob/QueuedJob.php', - 'OC\\BackgroundJob\\TimedJob' => $baseDir . '/lib/private/BackgroundJob/TimedJob.php', 'OC\\BinaryFinder' => $baseDir . '/lib/private/BinaryFinder.php', + 'OC\\Blurhash\\Listener\\GenerateBlurhashMetadata' => $baseDir . '/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php', 'OC\\Broadcast\\Events\\BroadcastEvent' => $baseDir . '/lib/private/Broadcast/Events/BroadcastEvent.php', 'OC\\Cache\\CappedMemoryCache' => $baseDir . '/lib/private/Cache/CappedMemoryCache.php', 'OC\\Cache\\File' => $baseDir . '/lib/private/Cache/File.php', @@ -947,6 +1031,7 @@ return array( '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', + 'OC\\Core\\BackgroundJobs\\GenerateMetadataJob' => $baseDir . '/core/BackgroundJobs/GenerateMetadataJob.php', 'OC\\Core\\BackgroundJobs\\LookupServerSendCheckBackgroundJob' => $baseDir . '/core/BackgroundJobs/LookupServerSendCheckBackgroundJob.php', 'OC\\Core\\Command\\App\\Disable' => $baseDir . '/core/Command/App/Disable.php', 'OC\\Core\\Command\\App\\Enable' => $baseDir . '/core/Command/App/Enable.php', @@ -958,6 +1043,7 @@ return array( 'OC\\Core\\Command\\Background\\Ajax' => $baseDir . '/core/Command/Background/Ajax.php', 'OC\\Core\\Command\\Background\\Base' => $baseDir . '/core/Command/Background/Base.php', 'OC\\Core\\Command\\Background\\Cron' => $baseDir . '/core/Command/Background/Cron.php', + 'OC\\Core\\Command\\Background\\Delete' => $baseDir . '/core/Command/Background/Delete.php', 'OC\\Core\\Command\\Background\\Job' => $baseDir . '/core/Command/Background/Job.php', 'OC\\Core\\Command\\Background\\ListCommand' => $baseDir . '/core/Command/Background/ListCommand.php', 'OC\\Core\\Command\\Background\\WebCron' => $baseDir . '/core/Command/Background/WebCron.php', @@ -994,6 +1080,7 @@ return array( 'OC\\Core\\Command\\Encryption\\SetDefaultModule' => $baseDir . '/core/Command/Encryption/SetDefaultModule.php', 'OC\\Core\\Command\\Encryption\\ShowKeyStorageRoot' => $baseDir . '/core/Command/Encryption/ShowKeyStorageRoot.php', 'OC\\Core\\Command\\Encryption\\Status' => $baseDir . '/core/Command/Encryption/Status.php', + 'OC\\Core\\Command\\FilesMetadata\\Get' => $baseDir . '/core/Command/FilesMetadata/Get.php', 'OC\\Core\\Command\\Group\\Add' => $baseDir . '/core/Command/Group/Add.php', 'OC\\Core\\Command\\Group\\AddUser' => $baseDir . '/core/Command/Group/AddUser.php', 'OC\\Core\\Command\\Group\\Delete' => $baseDir . '/core/Command/Group/Delete.php', @@ -1029,6 +1116,7 @@ return array( 'OC\\Core\\Command\\Security\\ImportCertificate' => $baseDir . '/core/Command/Security/ImportCertificate.php', 'OC\\Core\\Command\\Security\\ListCertificates' => $baseDir . '/core/Command/Security/ListCertificates.php', 'OC\\Core\\Command\\Security\\RemoveCertificate' => $baseDir . '/core/Command/Security/RemoveCertificate.php', + 'OC\\Core\\Command\\SetupChecks' => $baseDir . '/core/Command/SetupChecks.php', 'OC\\Core\\Command\\Status' => $baseDir . '/core/Command/Status.php', 'OC\\Core\\Command\\SystemTag\\Add' => $baseDir . '/core/Command/SystemTag/Add.php', 'OC\\Core\\Command\\SystemTag\\Delete' => $baseDir . '/core/Command/SystemTag/Delete.php', @@ -1049,6 +1137,7 @@ return array( 'OC\\Core\\Command\\User\\Disable' => $baseDir . '/core/Command/User/Disable.php', 'OC\\Core\\Command\\User\\Enable' => $baseDir . '/core/Command/User/Enable.php', 'OC\\Core\\Command\\User\\Info' => $baseDir . '/core/Command/User/Info.php', + '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\\Report' => $baseDir . '/core/Command/User/Report.php', @@ -1072,6 +1161,7 @@ return array( 'OC\\Core\\Controller\\LostController' => $baseDir . '/core/Controller/LostController.php', 'OC\\Core\\Controller\\NavigationController' => $baseDir . '/core/Controller/NavigationController.php', 'OC\\Core\\Controller\\OCJSController' => $baseDir . '/core/Controller/OCJSController.php', + 'OC\\Core\\Controller\\OCMController' => $baseDir . '/core/Controller/OCMController.php', 'OC\\Core\\Controller\\OCSController' => $baseDir . '/core/Controller/OCSController.php', 'OC\\Core\\Controller\\PreviewController' => $baseDir . '/core/Controller/PreviewController.php', 'OC\\Core\\Controller\\ProfileApiController' => $baseDir . '/core/Controller/ProfileApiController.php', @@ -1081,7 +1171,9 @@ return array( 'OC\\Core\\Controller\\ReferenceController' => $baseDir . '/core/Controller/ReferenceController.php', 'OC\\Core\\Controller\\SearchController' => $baseDir . '/core/Controller/SearchController.php', 'OC\\Core\\Controller\\SetupController' => $baseDir . '/core/Controller/SetupController.php', + 'OC\\Core\\Controller\\TeamsApiController' => $baseDir . '/core/Controller/TeamsApiController.php', 'OC\\Core\\Controller\\TextProcessingApiController' => $baseDir . '/core/Controller/TextProcessingApiController.php', + 'OC\\Core\\Controller\\TextToImageApiController' => $baseDir . '/core/Controller/TextToImageApiController.php', 'OC\\Core\\Controller\\TranslationApiController' => $baseDir . '/core/Controller/TranslationApiController.php', 'OC\\Core\\Controller\\TwoFactorChallengeController' => $baseDir . '/core/Controller/TwoFactorChallengeController.php', 'OC\\Core\\Controller\\UnifiedSearchController' => $baseDir . '/core/Controller/UnifiedSearchController.php', @@ -1163,6 +1255,15 @@ return array( 'OC\\Core\\Migrations\\Version28000Date20230616104802' => $baseDir . '/core/Migrations/Version28000Date20230616104802.php', 'OC\\Core\\Migrations\\Version28000Date20230728104802' => $baseDir . '/core/Migrations/Version28000Date20230728104802.php', 'OC\\Core\\Migrations\\Version28000Date20230803221055' => $baseDir . '/core/Migrations/Version28000Date20230803221055.php', + 'OC\\Core\\Migrations\\Version28000Date20230906104802' => $baseDir . '/core/Migrations/Version28000Date20230906104802.php', + 'OC\\Core\\Migrations\\Version28000Date20231004103301' => $baseDir . '/core/Migrations/Version28000Date20231004103301.php', + 'OC\\Core\\Migrations\\Version28000Date20231103104802' => $baseDir . '/core/Migrations/Version28000Date20231103104802.php', + 'OC\\Core\\Migrations\\Version28000Date20231126110901' => $baseDir . '/core/Migrations/Version28000Date20231126110901.php', + 'OC\\Core\\Migrations\\Version29000Date20231126110901' => $baseDir . '/core/Migrations/Version29000Date20231126110901.php', + 'OC\\Core\\Migrations\\Version29000Date20231213104850' => $baseDir . '/core/Migrations/Version29000Date20231213104850.php', + 'OC\\Core\\Migrations\\Version29000Date20240124132201' => $baseDir . '/core/Migrations/Version29000Date20240124132201.php', + 'OC\\Core\\Migrations\\Version29000Date20240124132202' => $baseDir . '/core/Migrations/Version29000Date20240124132202.php', + 'OC\\Core\\Migrations\\Version29000Date20240131122720' => $baseDir . '/core/Migrations/Version29000Date20240131122720.php', 'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php', 'OC\\Core\\Service\\LoginFlowV2Service' => $baseDir . '/core/Service/LoginFlowV2Service.php', 'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php', @@ -1183,14 +1284,12 @@ return array( 'OC\\DB\\MissingColumnInformation' => $baseDir . '/lib/private/DB/MissingColumnInformation.php', 'OC\\DB\\MissingIndexInformation' => $baseDir . '/lib/private/DB/MissingIndexInformation.php', 'OC\\DB\\MissingPrimaryKeyInformation' => $baseDir . '/lib/private/DB/MissingPrimaryKeyInformation.php', - 'OC\\DB\\MySQLMigrator' => $baseDir . '/lib/private/DB/MySQLMigrator.php', 'OC\\DB\\MySqlTools' => $baseDir . '/lib/private/DB/MySqlTools.php', 'OC\\DB\\OCSqlitePlatform' => $baseDir . '/lib/private/DB/OCSqlitePlatform.php', 'OC\\DB\\ObjectParameter' => $baseDir . '/lib/private/DB/ObjectParameter.php', 'OC\\DB\\OracleConnection' => $baseDir . '/lib/private/DB/OracleConnection.php', 'OC\\DB\\OracleMigrator' => $baseDir . '/lib/private/DB/OracleMigrator.php', 'OC\\DB\\PgSqlTools' => $baseDir . '/lib/private/DB/PgSqlTools.php', - 'OC\\DB\\PostgreSqlMigrator' => $baseDir . '/lib/private/DB/PostgreSqlMigrator.php', 'OC\\DB\\PreparedStatement' => $baseDir . '/lib/private/DB/PreparedStatement.php', 'OC\\DB\\QueryBuilder\\CompositeExpression' => $baseDir . '/lib/private/DB/QueryBuilder/CompositeExpression.php', 'OC\\DB\\QueryBuilder\\ExpressionBuilder\\ExpressionBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php', @@ -1249,9 +1348,19 @@ return array( 'OC\\Federation\\CloudFederationShare' => $baseDir . '/lib/private/Federation/CloudFederationShare.php', 'OC\\Federation\\CloudId' => $baseDir . '/lib/private/Federation/CloudId.php', 'OC\\Federation\\CloudIdManager' => $baseDir . '/lib/private/Federation/CloudIdManager.php', + 'OC\\FilesMetadata\\FilesMetadataManager' => $baseDir . '/lib/private/FilesMetadata/FilesMetadataManager.php', + 'OC\\FilesMetadata\\Job\\UpdateSingleMetadata' => $baseDir . '/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php', + 'OC\\FilesMetadata\\Listener\\MetadataDelete' => $baseDir . '/lib/private/FilesMetadata/Listener/MetadataDelete.php', + 'OC\\FilesMetadata\\Listener\\MetadataUpdate' => $baseDir . '/lib/private/FilesMetadata/Listener/MetadataUpdate.php', + 'OC\\FilesMetadata\\MetadataQuery' => $baseDir . '/lib/private/FilesMetadata/MetadataQuery.php', + 'OC\\FilesMetadata\\Model\\FilesMetadata' => $baseDir . '/lib/private/FilesMetadata/Model/FilesMetadata.php', + 'OC\\FilesMetadata\\Model\\MetadataValueWrapper' => $baseDir . '/lib/private/FilesMetadata/Model/MetadataValueWrapper.php', + 'OC\\FilesMetadata\\Service\\IndexRequestService' => $baseDir . '/lib/private/FilesMetadata/Service/IndexRequestService.php', + 'OC\\FilesMetadata\\Service\\MetadataRequestService' => $baseDir . '/lib/private/FilesMetadata/Service/MetadataRequestService.php', 'OC\\Files\\AppData\\AppData' => $baseDir . '/lib/private/Files/AppData/AppData.php', 'OC\\Files\\AppData\\Factory' => $baseDir . '/lib/private/Files/AppData/Factory.php', 'OC\\Files\\Cache\\Cache' => $baseDir . '/lib/private/Files/Cache/Cache.php', + 'OC\\Files\\Cache\\CacheDependencies' => $baseDir . '/lib/private/Files/Cache/CacheDependencies.php', 'OC\\Files\\Cache\\CacheEntry' => $baseDir . '/lib/private/Files/Cache/CacheEntry.php', 'OC\\Files\\Cache\\CacheQueryBuilder' => $baseDir . '/lib/private/Files/Cache/CacheQueryBuilder.php', 'OC\\Files\\Cache\\FailedCache' => $baseDir . '/lib/private/Files/Cache/FailedCache.php', @@ -1274,6 +1383,7 @@ return array( 'OC\\Files\\Cache\\Wrapper\\JailPropagator' => $baseDir . '/lib/private/Files/Cache/Wrapper/JailPropagator.php', 'OC\\Files\\Config\\CachedMountFileInfo' => $baseDir . '/lib/private/Files/Config/CachedMountFileInfo.php', 'OC\\Files\\Config\\CachedMountInfo' => $baseDir . '/lib/private/Files/Config/CachedMountInfo.php', + 'OC\\Files\\Config\\LazyPathCachedMountInfo' => $baseDir . '/lib/private/Files/Config/LazyPathCachedMountInfo.php', 'OC\\Files\\Config\\LazyStorageMountInfo' => $baseDir . '/lib/private/Files/Config/LazyStorageMountInfo.php', 'OC\\Files\\Config\\MountProviderCollection' => $baseDir . '/lib/private/Files/Config/MountProviderCollection.php', 'OC\\Files\\Config\\UserMountCache' => $baseDir . '/lib/private/Files/Config/UserMountCache.php', @@ -1282,6 +1392,7 @@ return array( 'OC\\Files\\Filesystem' => $baseDir . '/lib/private/Files/Filesystem.php', 'OC\\Files\\Lock\\LockManager' => $baseDir . '/lib/private/Files/Lock/LockManager.php', 'OC\\Files\\Mount\\CacheMountProvider' => $baseDir . '/lib/private/Files/Mount/CacheMountProvider.php', + 'OC\\Files\\Mount\\HomeMountPoint' => $baseDir . '/lib/private/Files/Mount/HomeMountPoint.php', 'OC\\Files\\Mount\\LocalHomeMountProvider' => $baseDir . '/lib/private/Files/Mount/LocalHomeMountProvider.php', 'OC\\Files\\Mount\\Manager' => $baseDir . '/lib/private/Files/Mount/Manager.php', 'OC\\Files\\Mount\\MountPoint' => $baseDir . '/lib/private/Files/Mount/MountPoint.php', @@ -1315,9 +1426,15 @@ return array( 'OC\\Files\\ObjectStore\\Swift' => $baseDir . '/lib/private/Files/ObjectStore/Swift.php', 'OC\\Files\\ObjectStore\\SwiftFactory' => $baseDir . '/lib/private/Files/ObjectStore/SwiftFactory.php', 'OC\\Files\\ObjectStore\\SwiftV2CachingAuthService' => $baseDir . '/lib/private/Files/ObjectStore/SwiftV2CachingAuthService.php', + 'OC\\Files\\Search\\QueryOptimizer\\FlattenNestedBool' => $baseDir . '/lib/private/Files/Search/QueryOptimizer/FlattenNestedBool.php', + 'OC\\Files\\Search\\QueryOptimizer\\FlattenSingleArgumentBinaryOperation' => $baseDir . '/lib/private/Files/Search/QueryOptimizer/FlattenSingleArgumentBinaryOperation.php', + 'OC\\Files\\Search\\QueryOptimizer\\MergeDistributiveOperations' => $baseDir . '/lib/private/Files/Search/QueryOptimizer/MergeDistributiveOperations.php', + 'OC\\Files\\Search\\QueryOptimizer\\OrEqualsToIn' => $baseDir . '/lib/private/Files/Search/QueryOptimizer/OrEqualsToIn.php', 'OC\\Files\\Search\\QueryOptimizer\\PathPrefixOptimizer' => $baseDir . '/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php', 'OC\\Files\\Search\\QueryOptimizer\\QueryOptimizer' => $baseDir . '/lib/private/Files/Search/QueryOptimizer/QueryOptimizer.php', 'OC\\Files\\Search\\QueryOptimizer\\QueryOptimizerStep' => $baseDir . '/lib/private/Files/Search/QueryOptimizer/QueryOptimizerStep.php', + 'OC\\Files\\Search\\QueryOptimizer\\ReplacingOptimizerStep' => $baseDir . '/lib/private/Files/Search/QueryOptimizer/ReplacingOptimizerStep.php', + 'OC\\Files\\Search\\QueryOptimizer\\SplitLargeIn' => $baseDir . '/lib/private/Files/Search/QueryOptimizer/SplitLargeIn.php', 'OC\\Files\\Search\\SearchBinaryOperator' => $baseDir . '/lib/private/Files/Search/SearchBinaryOperator.php', 'OC\\Files\\Search\\SearchComparison' => $baseDir . '/lib/private/Files/Search/SearchComparison.php', 'OC\\Files\\Search\\SearchOrder' => $baseDir . '/lib/private/Files/Search/SearchOrder.php', @@ -1344,6 +1461,7 @@ return array( 'OC\\Files\\Storage\\Wrapper\\EncodingDirectoryWrapper' => $baseDir . '/lib/private/Files/Storage/Wrapper/EncodingDirectoryWrapper.php', 'OC\\Files\\Storage\\Wrapper\\Encryption' => $baseDir . '/lib/private/Files/Storage/Wrapper/Encryption.php', 'OC\\Files\\Storage\\Wrapper\\Jail' => $baseDir . '/lib/private/Files/Storage/Wrapper/Jail.php', + 'OC\\Files\\Storage\\Wrapper\\KnownMtime' => $baseDir . '/lib/private/Files/Storage/Wrapper/KnownMtime.php', 'OC\\Files\\Storage\\Wrapper\\PermissionsMask' => $baseDir . '/lib/private/Files/Storage/Wrapper/PermissionsMask.php', 'OC\\Files\\Storage\\Wrapper\\Quota' => $baseDir . '/lib/private/Files/Storage/Wrapper/Quota.php', 'OC\\Files\\Storage\\Wrapper\\Wrapper' => $baseDir . '/lib/private/Files/Storage/Wrapper/Wrapper.php', @@ -1440,14 +1558,6 @@ return array( 'OC\\Memcache\\Redis' => $baseDir . '/lib/private/Memcache/Redis.php', 'OC\\Memcache\\WithLocalCache' => $baseDir . '/lib/private/Memcache/WithLocalCache.php', 'OC\\MemoryInfo' => $baseDir . '/lib/private/MemoryInfo.php', - 'OC\\Metadata\\Capabilities' => $baseDir . '/lib/private/Metadata/Capabilities.php', - 'OC\\Metadata\\FileEventListener' => $baseDir . '/lib/private/Metadata/FileEventListener.php', - 'OC\\Metadata\\FileMetadata' => $baseDir . '/lib/private/Metadata/FileMetadata.php', - 'OC\\Metadata\\FileMetadataMapper' => $baseDir . '/lib/private/Metadata/FileMetadataMapper.php', - 'OC\\Metadata\\IMetadataManager' => $baseDir . '/lib/private/Metadata/IMetadataManager.php', - 'OC\\Metadata\\IMetadataProvider' => $baseDir . '/lib/private/Metadata/IMetadataProvider.php', - 'OC\\Metadata\\MetadataManager' => $baseDir . '/lib/private/Metadata/MetadataManager.php', - 'OC\\Metadata\\Provider\\ExifProvider' => $baseDir . '/lib/private/Metadata/Provider/ExifProvider.php', 'OC\\Migration\\BackgroundRepair' => $baseDir . '/lib/private/Migration/BackgroundRepair.php', 'OC\\Migration\\ConsoleOutput' => $baseDir . '/lib/private/Migration/ConsoleOutput.php', 'OC\\Migration\\SimpleOutput' => $baseDir . '/lib/private/Migration/SimpleOutput.php', @@ -1461,17 +1571,22 @@ return array( 'OC\\Notification\\Action' => $baseDir . '/lib/private/Notification/Action.php', 'OC\\Notification\\Manager' => $baseDir . '/lib/private/Notification/Manager.php', 'OC\\Notification\\Notification' => $baseDir . '/lib/private/Notification/Notification.php', + 'OC\\OCM\\Model\\OCMProvider' => $baseDir . '/lib/private/OCM/Model/OCMProvider.php', + 'OC\\OCM\\Model\\OCMResource' => $baseDir . '/lib/private/OCM/Model/OCMResource.php', + 'OC\\OCM\\OCMDiscoveryService' => $baseDir . '/lib/private/OCM/OCMDiscoveryService.php', 'OC\\OCS\\CoreCapabilities' => $baseDir . '/lib/private/OCS/CoreCapabilities.php', 'OC\\OCS\\DiscoveryService' => $baseDir . '/lib/private/OCS/DiscoveryService.php', 'OC\\OCS\\Exception' => $baseDir . '/lib/private/OCS/Exception.php', 'OC\\OCS\\Provider' => $baseDir . '/lib/private/OCS/Provider.php', 'OC\\OCS\\Result' => $baseDir . '/lib/private/OCS/Result.php', + 'OC\\PhoneNumberUtil' => $baseDir . '/lib/private/PhoneNumberUtil.php', 'OC\\PreviewManager' => $baseDir . '/lib/private/PreviewManager.php', 'OC\\PreviewNotAvailableException' => $baseDir . '/lib/private/PreviewNotAvailableException.php', 'OC\\Preview\\BMP' => $baseDir . '/lib/private/Preview/BMP.php', 'OC\\Preview\\BackgroundCleanupJob' => $baseDir . '/lib/private/Preview/BackgroundCleanupJob.php', 'OC\\Preview\\Bitmap' => $baseDir . '/lib/private/Preview/Bitmap.php', 'OC\\Preview\\Bundled' => $baseDir . '/lib/private/Preview/Bundled.php', + 'OC\\Preview\\EMF' => $baseDir . '/lib/private/Preview/EMF.php', 'OC\\Preview\\Font' => $baseDir . '/lib/private/Preview/Font.php', 'OC\\Preview\\GIF' => $baseDir . '/lib/private/Preview/GIF.php', 'OC\\Preview\\Generator' => $baseDir . '/lib/private/Preview/Generator.php', @@ -1533,8 +1648,10 @@ return array( 'OC\\Remote\\User' => $baseDir . '/lib/private/Remote/User.php', 'OC\\Repair' => $baseDir . '/lib/private/Repair.php', 'OC\\RepairException' => $baseDir . '/lib/private/RepairException.php', + 'OC\\Repair\\AddAppConfigLazyMigration' => $baseDir . '/lib/private/Repair/AddAppConfigLazyMigration.php', 'OC\\Repair\\AddBruteForceCleanupJob' => $baseDir . '/lib/private/Repair/AddBruteForceCleanupJob.php', 'OC\\Repair\\AddCleanupUpdaterBackupsJob' => $baseDir . '/lib/private/Repair/AddCleanupUpdaterBackupsJob.php', + 'OC\\Repair\\AddMetadataGenerationJob' => $baseDir . '/lib/private/Repair/AddMetadataGenerationJob.php', 'OC\\Repair\\AddRemoveOldTasksBackgroundJob' => $baseDir . '/lib/private/Repair/AddRemoveOldTasksBackgroundJob.php', 'OC\\Repair\\CleanTags' => $baseDir . '/lib/private/Repair/CleanTags.php', 'OC\\Repair\\CleanUpAbandonedApps' => $baseDir . '/lib/private/Repair/CleanUpAbandonedApps.php', @@ -1578,12 +1695,21 @@ return array( 'OC\\Repair\\RepairDavShares' => $baseDir . '/lib/private/Repair/RepairDavShares.php', 'OC\\Repair\\RepairInvalidShares' => $baseDir . '/lib/private/Repair/RepairInvalidShares.php', 'OC\\Repair\\RepairMimeTypes' => $baseDir . '/lib/private/Repair/RepairMimeTypes.php', - 'OC\\Repair\\SqliteAutoincrement' => $baseDir . '/lib/private/Repair/SqliteAutoincrement.php', 'OC\\RichObjectStrings\\Validator' => $baseDir . '/lib/private/RichObjectStrings/Validator.php', 'OC\\Route\\CachingRouter' => $baseDir . '/lib/private/Route/CachingRouter.php', 'OC\\Route\\Route' => $baseDir . '/lib/private/Route/Route.php', 'OC\\Route\\Router' => $baseDir . '/lib/private/Route/Router.php', 'OC\\Search' => $baseDir . '/lib/private/Search.php', + 'OC\\Search\\FilterCollection' => $baseDir . '/lib/private/Search/FilterCollection.php', + 'OC\\Search\\FilterFactory' => $baseDir . '/lib/private/Search/FilterFactory.php', + 'OC\\Search\\Filter\\BooleanFilter' => $baseDir . '/lib/private/Search/Filter/BooleanFilter.php', + 'OC\\Search\\Filter\\DateTimeFilter' => $baseDir . '/lib/private/Search/Filter/DateTimeFilter.php', + 'OC\\Search\\Filter\\FloatFilter' => $baseDir . '/lib/private/Search/Filter/FloatFilter.php', + 'OC\\Search\\Filter\\GroupFilter' => $baseDir . '/lib/private/Search/Filter/GroupFilter.php', + 'OC\\Search\\Filter\\IntegerFilter' => $baseDir . '/lib/private/Search/Filter/IntegerFilter.php', + 'OC\\Search\\Filter\\StringFilter' => $baseDir . '/lib/private/Search/Filter/StringFilter.php', + 'OC\\Search\\Filter\\StringsFilter' => $baseDir . '/lib/private/Search/Filter/StringsFilter.php', + 'OC\\Search\\Filter\\UserFilter' => $baseDir . '/lib/private/Search/Filter/UserFilter.php', 'OC\\Search\\Provider\\File' => $baseDir . '/lib/private/Search/Provider/File.php', 'OC\\Search\\Result\\Audio' => $baseDir . '/lib/private/Search/Result/Audio.php', 'OC\\Search\\Result\\File' => $baseDir . '/lib/private/Search/Result/File.php', @@ -1591,6 +1717,7 @@ return array( 'OC\\Search\\Result\\Image' => $baseDir . '/lib/private/Search/Result/Image.php', 'OC\\Search\\SearchComposer' => $baseDir . '/lib/private/Search/SearchComposer.php', 'OC\\Search\\SearchQuery' => $baseDir . '/lib/private/Search/SearchQuery.php', + 'OC\\Search\\UnsupportedFilter' => $baseDir . '/lib/private/Search/UnsupportedFilter.php', 'OC\\Security\\Bruteforce\\Backend\\DatabaseBackend' => $baseDir . '/lib/private/Security/Bruteforce/Backend/DatabaseBackend.php', 'OC\\Security\\Bruteforce\\Backend\\IBackend' => $baseDir . '/lib/private/Security/Bruteforce/Backend/IBackend.php', 'OC\\Security\\Bruteforce\\Backend\\MemoryCacheBackend' => $baseDir . '/lib/private/Security/Bruteforce/Backend/MemoryCacheBackend.php', @@ -1636,9 +1763,11 @@ return array( 'OC\\Session\\Session' => $baseDir . '/lib/private/Session/Session.php', 'OC\\Settings\\AuthorizedGroup' => $baseDir . '/lib/private/Settings/AuthorizedGroup.php', 'OC\\Settings\\AuthorizedGroupMapper' => $baseDir . '/lib/private/Settings/AuthorizedGroupMapper.php', + 'OC\\Settings\\DeclarativeManager' => $baseDir . '/lib/private/Settings/DeclarativeManager.php', 'OC\\Settings\\Manager' => $baseDir . '/lib/private/Settings/Manager.php', 'OC\\Settings\\Section' => $baseDir . '/lib/private/Settings/Section.php', 'OC\\Setup' => $baseDir . '/lib/private/Setup.php', + 'OC\\SetupCheck\\SetupCheckManager' => $baseDir . '/lib/private/SetupCheck/SetupCheckManager.php', 'OC\\Setup\\AbstractDatabase' => $baseDir . '/lib/private/Setup/AbstractDatabase.php', 'OC\\Setup\\MySQL' => $baseDir . '/lib/private/Setup/MySQL.php', 'OC\\Setup\\OCI' => $baseDir . '/lib/private/Setup/OCI.php', @@ -1655,6 +1784,7 @@ return array( 'OC\\Share20\\PublicShareTemplateFactory' => $baseDir . '/lib/private/Share20/PublicShareTemplateFactory.php', 'OC\\Share20\\Share' => $baseDir . '/lib/private/Share20/Share.php', 'OC\\Share20\\ShareAttributes' => $baseDir . '/lib/private/Share20/ShareAttributes.php', + 'OC\\Share20\\ShareDisableChecker' => $baseDir . '/lib/private/Share20/ShareDisableChecker.php', 'OC\\Share20\\ShareHelper' => $baseDir . '/lib/private/Share20/ShareHelper.php', 'OC\\Share20\\UserRemovedListener' => $baseDir . '/lib/private/Share20/UserRemovedListener.php', 'OC\\Share\\Constants' => $baseDir . '/lib/private/Share/Constants.php', @@ -1680,6 +1810,7 @@ return array( 'OC\\Tags' => $baseDir . '/lib/private/Tags.php', 'OC\\Talk\\Broker' => $baseDir . '/lib/private/Talk/Broker.php', 'OC\\Talk\\ConversationOptions' => $baseDir . '/lib/private/Talk/ConversationOptions.php', + 'OC\\Teams\\TeamManager' => $baseDir . '/lib/private/Teams/TeamManager.php', 'OC\\TempManager' => $baseDir . '/lib/private/TempManager.php', 'OC\\TemplateLayout' => $baseDir . '/lib/private/TemplateLayout.php', 'OC\\Template\\Base' => $baseDir . '/lib/private/Template/Base.php', @@ -1695,6 +1826,11 @@ return array( 'OC\\TextProcessing\\Manager' => $baseDir . '/lib/private/TextProcessing/Manager.php', 'OC\\TextProcessing\\RemoveOldTasksBackgroundJob' => $baseDir . '/lib/private/TextProcessing/RemoveOldTasksBackgroundJob.php', 'OC\\TextProcessing\\TaskBackgroundJob' => $baseDir . '/lib/private/TextProcessing/TaskBackgroundJob.php', + 'OC\\TextToImage\\Db\\Task' => $baseDir . '/lib/private/TextToImage/Db/Task.php', + 'OC\\TextToImage\\Db\\TaskMapper' => $baseDir . '/lib/private/TextToImage/Db/TaskMapper.php', + 'OC\\TextToImage\\Manager' => $baseDir . '/lib/private/TextToImage/Manager.php', + 'OC\\TextToImage\\RemoveOldTasksBackgroundJob' => $baseDir . '/lib/private/TextToImage/RemoveOldTasksBackgroundJob.php', + 'OC\\TextToImage\\TaskBackgroundJob' => $baseDir . '/lib/private/TextToImage/TaskBackgroundJob.php', 'OC\\Translation\\TranslationManager' => $baseDir . '/lib/private/Translation/TranslationManager.php', 'OC\\URLGenerator' => $baseDir . '/lib/private/URLGenerator.php', 'OC\\Updater' => $baseDir . '/lib/private/Updater.php', @@ -1704,6 +1840,7 @@ return array( 'OC\\Updater\\VersionCheck' => $baseDir . '/lib/private/Updater/VersionCheck.php', 'OC\\UserStatus\\ISettableProvider' => $baseDir . '/lib/private/UserStatus/ISettableProvider.php', 'OC\\UserStatus\\Manager' => $baseDir . '/lib/private/UserStatus/Manager.php', + 'OC\\User\\AvailabilityCoordinator' => $baseDir . '/lib/private/User/AvailabilityCoordinator.php', 'OC\\User\\Backend' => $baseDir . '/lib/private/User/Backend.php', 'OC\\User\\Database' => $baseDir . '/lib/private/User/Database.php', 'OC\\User\\DisplayNameCache' => $baseDir . '/lib/private/User/DisplayNameCache.php', @@ -1713,6 +1850,7 @@ return array( 'OC\\User\\LoginException' => $baseDir . '/lib/private/User/LoginException.php', 'OC\\User\\Manager' => $baseDir . '/lib/private/User/Manager.php', 'OC\\User\\NoUserException' => $baseDir . '/lib/private/User/NoUserException.php', + 'OC\\User\\OutOfOfficeData' => $baseDir . '/lib/private/User/OutOfOfficeData.php', 'OC\\User\\Session' => $baseDir . '/lib/private/User/Session.php', 'OC\\User\\User' => $baseDir . '/lib/private/User/User.php', 'OC_API' => $baseDir . '/lib/private/legacy/OC_API.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index fb3ef9ad3d0..21d67784322 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -71,14 +71,18 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\AppFramework\\Http' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http.php', 'OCP\\AppFramework\\Http\\Attribute\\ARateLimit' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/ARateLimit.php', 'OCP\\AppFramework\\Http\\Attribute\\AnonRateLimit' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/AnonRateLimit.php', + 'OCP\\AppFramework\\Http\\Attribute\\ApiRoute' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/ApiRoute.php', 'OCP\\AppFramework\\Http\\Attribute\\AuthorizedAdminSetting' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/AuthorizedAdminSetting.php', 'OCP\\AppFramework\\Http\\Attribute\\BruteForceProtection' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/BruteForceProtection.php', 'OCP\\AppFramework\\Http\\Attribute\\CORS' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/CORS.php', + 'OCP\\AppFramework\\Http\\Attribute\\FrontpageRoute' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php', 'OCP\\AppFramework\\Http\\Attribute\\IgnoreOpenAPI' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php', 'OCP\\AppFramework\\Http\\Attribute\\NoAdminRequired' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/NoAdminRequired.php', 'OCP\\AppFramework\\Http\\Attribute\\NoCSRFRequired' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/NoCSRFRequired.php', + 'OCP\\AppFramework\\Http\\Attribute\\OpenAPI' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/OpenAPI.php', 'OCP\\AppFramework\\Http\\Attribute\\PasswordConfirmationRequired' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php', 'OCP\\AppFramework\\Http\\Attribute\\PublicPage' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/PublicPage.php', + 'OCP\\AppFramework\\Http\\Attribute\\Route' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/Route.php', 'OCP\\AppFramework\\Http\\Attribute\\StrictCookiesRequired' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/StrictCookiesRequired.php', 'OCP\\AppFramework\\Http\\Attribute\\SubAdminRequired' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/SubAdminRequired.php', 'OCP\\AppFramework\\Http\\Attribute\\UseSession' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/UseSession.php', @@ -98,6 +102,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\AppFramework\\Http\\IOutput' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/IOutput.php', 'OCP\\AppFramework\\Http\\JSONResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/JSONResponse.php', 'OCP\\AppFramework\\Http\\NotFoundResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/NotFoundResponse.php', + 'OCP\\AppFramework\\Http\\ParameterOutOfRangeException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/ParameterOutOfRangeException.php', 'OCP\\AppFramework\\Http\\RedirectResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/RedirectResponse.php', 'OCP\\AppFramework\\Http\\RedirectToDefaultAppResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php', 'OCP\\AppFramework\\Http\\Response' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Response.php', @@ -139,13 +144,17 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Authentication\\Events\\AnyLoginFailedEvent' => __DIR__ . '/../../..' . '/lib/public/Authentication/Events/AnyLoginFailedEvent.php', 'OCP\\Authentication\\Events\\LoginFailedEvent' => __DIR__ . '/../../..' . '/lib/public/Authentication/Events/LoginFailedEvent.php', 'OCP\\Authentication\\Exceptions\\CredentialsUnavailableException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php', + 'OCP\\Authentication\\Exceptions\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/ExpiredTokenException.php', + 'OCP\\Authentication\\Exceptions\\InvalidTokenException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/InvalidTokenException.php', 'OCP\\Authentication\\Exceptions\\PasswordUnavailableException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/PasswordUnavailableException.php', + 'OCP\\Authentication\\Exceptions\\WipeTokenException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/WipeTokenException.php', 'OCP\\Authentication\\IAlternativeLogin' => __DIR__ . '/../../..' . '/lib/public/Authentication/IAlternativeLogin.php', 'OCP\\Authentication\\IApacheBackend' => __DIR__ . '/../../..' . '/lib/public/Authentication/IApacheBackend.php', 'OCP\\Authentication\\IProvideUserSecretBackend' => __DIR__ . '/../../..' . '/lib/public/Authentication/IProvideUserSecretBackend.php', 'OCP\\Authentication\\LoginCredentials\\ICredentials' => __DIR__ . '/../../..' . '/lib/public/Authentication/LoginCredentials/ICredentials.php', 'OCP\\Authentication\\LoginCredentials\\IStore' => __DIR__ . '/../../..' . '/lib/public/Authentication/LoginCredentials/IStore.php', 'OCP\\Authentication\\Token\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Authentication/Token/IProvider.php', + 'OCP\\Authentication\\Token\\IToken' => __DIR__ . '/../../..' . '/lib/public/Authentication/Token/IToken.php', 'OCP\\Authentication\\TwoFactorAuth\\ALoginSetupController' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/ALoginSetupController.php', 'OCP\\Authentication\\TwoFactorAuth\\IActivatableAtLogin' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IActivatableAtLogin.php', 'OCP\\Authentication\\TwoFactorAuth\\IActivatableByAdmin' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IActivatableByAdmin.php', @@ -198,6 +207,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Capabilities\\IInitialStateExcludedCapability' => __DIR__ . '/../../..' . '/lib/public/Capabilities/IInitialStateExcludedCapability.php', 'OCP\\Capabilities\\IPublicCapability' => __DIR__ . '/../../..' . '/lib/public/Capabilities/IPublicCapability.php', 'OCP\\Collaboration\\AutoComplete\\AutoCompleteEvent' => __DIR__ . '/../../..' . '/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php', + 'OCP\\Collaboration\\AutoComplete\\AutoCompleteFilterEvent' => __DIR__ . '/../../..' . '/lib/public/Collaboration/AutoComplete/AutoCompleteFilterEvent.php', 'OCP\\Collaboration\\AutoComplete\\IManager' => __DIR__ . '/../../..' . '/lib/public/Collaboration/AutoComplete/IManager.php', 'OCP\\Collaboration\\AutoComplete\\ISorter' => __DIR__ . '/../../..' . '/lib/public/Collaboration/AutoComplete/ISorter.php', 'OCP\\Collaboration\\Collaborators\\ISearch' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Collaborators/ISearch.php', @@ -210,6 +220,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Collaboration\\Reference\\IReferenceManager' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Reference/IReferenceManager.php', 'OCP\\Collaboration\\Reference\\IReferenceProvider' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Reference/IReferenceProvider.php', 'OCP\\Collaboration\\Reference\\ISearchableReferenceProvider' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Reference/ISearchableReferenceProvider.php', + 'OCP\\Collaboration\\Reference\\LinkReferenceProvider' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Reference/LinkReferenceProvider.php', 'OCP\\Collaboration\\Reference\\Reference' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Reference/Reference.php', 'OCP\\Collaboration\\Reference\\RenderReferenceEvent' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Reference/RenderReferenceEvent.php', 'OCP\\Collaboration\\Resources\\CollectionException' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/CollectionException.php', @@ -239,6 +250,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Constants' => __DIR__ . '/../../..' . '/lib/public/Constants.php', 'OCP\\Contacts\\ContactsMenu\\IAction' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IAction.php', 'OCP\\Contacts\\ContactsMenu\\IActionFactory' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IActionFactory.php', + 'OCP\\Contacts\\ContactsMenu\\IBulkProvider' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IBulkProvider.php', 'OCP\\Contacts\\ContactsMenu\\IContactsStore' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IContactsStore.php', 'OCP\\Contacts\\ContactsMenu\\IEntry' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IEntry.php', 'OCP\\Contacts\\ContactsMenu\\ILinkAction' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/ILinkAction.php', @@ -273,7 +285,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Dashboard\\Model\\WidgetItem' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetItem.php', 'OCP\\Dashboard\\Model\\WidgetItems' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetItems.php', 'OCP\\Dashboard\\Model\\WidgetOptions' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetOptions.php', - 'OCP\\Dashboard\\RegisterWidgetEvent' => __DIR__ . '/../../..' . '/lib/public/Dashboard/RegisterWidgetEvent.php', 'OCP\\DataCollector\\AbstractDataCollector' => __DIR__ . '/../../..' . '/lib/public/DataCollector/AbstractDataCollector.php', 'OCP\\DataCollector\\IDataCollector' => __DIR__ . '/../../..' . '/lib/public/DataCollector/IDataCollector.php', 'OCP\\Defaults' => __DIR__ . '/../../..' . '/lib/public/Defaults.php', @@ -298,6 +309,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\EventDispatcher\\GenericEvent' => __DIR__ . '/../../..' . '/lib/public/EventDispatcher/GenericEvent.php', 'OCP\\EventDispatcher\\IEventDispatcher' => __DIR__ . '/../../..' . '/lib/public/EventDispatcher/IEventDispatcher.php', 'OCP\\EventDispatcher\\IEventListener' => __DIR__ . '/../../..' . '/lib/public/EventDispatcher/IEventListener.php', + 'OCP\\Exceptions\\AbortedEventException' => __DIR__ . '/../../..' . '/lib/public/Exceptions/AbortedEventException.php', + 'OCP\\Exceptions\\AppConfigException' => __DIR__ . '/../../..' . '/lib/public/Exceptions/AppConfigException.php', + 'OCP\\Exceptions\\AppConfigIncorrectTypeException' => __DIR__ . '/../../..' . '/lib/public/Exceptions/AppConfigIncorrectTypeException.php', + 'OCP\\Exceptions\\AppConfigTypeConflictException' => __DIR__ . '/../../..' . '/lib/public/Exceptions/AppConfigTypeConflictException.php', + 'OCP\\Exceptions\\AppConfigUnknownKeyException' => __DIR__ . '/../../..' . '/lib/public/Exceptions/AppConfigUnknownKeyException.php', 'OCP\\Federation\\Events\\TrustedServerRemovedEvent' => __DIR__ . '/../../..' . '/lib/public/Federation/Events/TrustedServerRemovedEvent.php', 'OCP\\Federation\\Exceptions\\ActionNotSupportedException' => __DIR__ . '/../../..' . '/lib/public/Federation/Exceptions/ActionNotSupportedException.php', 'OCP\\Federation\\Exceptions\\AuthenticationFailedException' => __DIR__ . '/../../..' . '/lib/public/Federation/Exceptions/AuthenticationFailedException.php', @@ -313,6 +329,18 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Federation\\ICloudId' => __DIR__ . '/../../..' . '/lib/public/Federation/ICloudId.php', 'OCP\\Federation\\ICloudIdManager' => __DIR__ . '/../../..' . '/lib/public/Federation/ICloudIdManager.php', 'OCP\\Files' => __DIR__ . '/../../..' . '/lib/public/Files.php', + 'OCP\\FilesMetadata\\AMetadataEvent' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/AMetadataEvent.php', + 'OCP\\FilesMetadata\\Event\\MetadataBackgroundEvent' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php', + 'OCP\\FilesMetadata\\Event\\MetadataLiveEvent' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Event/MetadataLiveEvent.php', + 'OCP\\FilesMetadata\\Event\\MetadataNamedEvent' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Event/MetadataNamedEvent.php', + 'OCP\\FilesMetadata\\Exceptions\\FilesMetadataException' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php', + 'OCP\\FilesMetadata\\Exceptions\\FilesMetadataKeyFormatException' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Exceptions/FilesMetadataKeyFormatException.php', + 'OCP\\FilesMetadata\\Exceptions\\FilesMetadataNotFoundException' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php', + 'OCP\\FilesMetadata\\Exceptions\\FilesMetadataTypeException' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php', + 'OCP\\FilesMetadata\\IFilesMetadataManager' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/IFilesMetadataManager.php', + 'OCP\\FilesMetadata\\IMetadataQuery' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/IMetadataQuery.php', + 'OCP\\FilesMetadata\\Model\\IFilesMetadata' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Model/IFilesMetadata.php', + 'OCP\\FilesMetadata\\Model\\IMetadataValueWrapper' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Model/IMetadataValueWrapper.php', 'OCP\\Files\\AlreadyExistsException' => __DIR__ . '/../../..' . '/lib/public/Files/AlreadyExistsException.php', 'OCP\\Files\\AppData\\IAppDataFactory' => __DIR__ . '/../../..' . '/lib/public/Files/AppData/IAppDataFactory.php', 'OCP\\Files\\Cache\\AbstractCacheEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/AbstractCacheEvent.php', @@ -335,6 +363,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Files\\Config\\IMountProviderCollection' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IMountProviderCollection.php', 'OCP\\Files\\Config\\IRootMountProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IRootMountProvider.php', 'OCP\\Files\\Config\\IUserMountCache' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IUserMountCache.php', + 'OCP\\Files\\ConnectionLostException' => __DIR__ . '/../../..' . '/lib/public/Files/ConnectionLostException.php', 'OCP\\Files\\DavUtil' => __DIR__ . '/../../..' . '/lib/public/Files/DavUtil.php', 'OCP\\Files\\EmptyFileNameException' => __DIR__ . '/../../..' . '/lib/public/Files/EmptyFileNameException.php', 'OCP\\Files\\EntityTooLargeException' => __DIR__ . '/../../..' . '/lib/public/Files/EntityTooLargeException.php', @@ -434,6 +463,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Files\\UnseekableException' => __DIR__ . '/../../..' . '/lib/public/Files/UnseekableException.php', 'OCP\\Files_FullTextSearch\\Model\\AFilesDocument' => __DIR__ . '/../../..' . '/lib/public/Files_FullTextSearch/Model/AFilesDocument.php', 'OCP\\FullTextSearch\\Exceptions\\FullTextSearchAppNotAvailableException' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php', + 'OCP\\FullTextSearch\\Exceptions\\FullTextSearchIndexNotAvailableException' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Exceptions/FullTextSearchIndexNotAvailableException.php', 'OCP\\FullTextSearch\\IFullTextSearchManager' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/IFullTextSearchManager.php', 'OCP\\FullTextSearch\\IFullTextSearchPlatform' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/IFullTextSearchPlatform.php', 'OCP\\FullTextSearch\\IFullTextSearchProvider' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/IFullTextSearchProvider.php', @@ -454,6 +484,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\GroupInterface' => __DIR__ . '/../../..' . '/lib/public/GroupInterface.php', 'OCP\\Group\\Backend\\ABackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ABackend.php', 'OCP\\Group\\Backend\\IAddToGroupBackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/IAddToGroupBackend.php', + 'OCP\\Group\\Backend\\IBatchMethodsBackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/IBatchMethodsBackend.php', 'OCP\\Group\\Backend\\ICountDisabledInGroup' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ICountDisabledInGroup.php', 'OCP\\Group\\Backend\\ICountUsersBackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ICountUsersBackend.php', 'OCP\\Group\\Backend\\ICreateGroupBackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ICreateGroupBackend.php', @@ -516,6 +547,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\IMemcache' => __DIR__ . '/../../..' . '/lib/public/IMemcache.php', 'OCP\\IMemcacheTTL' => __DIR__ . '/../../..' . '/lib/public/IMemcacheTTL.php', 'OCP\\INavigationManager' => __DIR__ . '/../../..' . '/lib/public/INavigationManager.php', + 'OCP\\IPhoneNumberUtil' => __DIR__ . '/../../..' . '/lib/public/IPhoneNumberUtil.php', 'OCP\\IPreview' => __DIR__ . '/../../..' . '/lib/public/IPreview.php', 'OCP\\IRequest' => __DIR__ . '/../../..' . '/lib/public/IRequest.php', 'OCP\\IRequestId' => __DIR__ . '/../../..' . '/lib/public/IRequestId.php', @@ -567,6 +599,12 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Notification\\IManager' => __DIR__ . '/../../..' . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\INotification' => __DIR__ . '/../../..' . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => __DIR__ . '/../../..' . '/lib/public/Notification/INotifier.php', + '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\\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', 'OCP\\OCS\\IDiscoveryService' => __DIR__ . '/../../..' . '/lib/public/OCS/IDiscoveryService.php', 'OCP\\PreConditionNotMetException' => __DIR__ . '/../../..' . '/lib/public/PreConditionNotMetException.php', 'OCP\\Preview\\BeforePreviewFetchedEvent' => __DIR__ . '/../../..' . '/lib/public/Preview/BeforePreviewFetchedEvent.php', @@ -576,6 +614,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Preview\\IVersionedPreviewFile' => __DIR__ . '/../../..' . '/lib/public/Preview/IVersionedPreviewFile.php', 'OCP\\Profile\\BeforeTemplateRenderedEvent' => __DIR__ . '/../../..' . '/lib/public/Profile/BeforeTemplateRenderedEvent.php', 'OCP\\Profile\\ILinkAction' => __DIR__ . '/../../..' . '/lib/public/Profile/ILinkAction.php', + 'OCP\\Profile\\IProfileManager' => __DIR__ . '/../../..' . '/lib/public/Profile/IProfileManager.php', 'OCP\\Profile\\ParameterDoesNotExistException' => __DIR__ . '/../../..' . '/lib/public/Profile/ParameterDoesNotExistException.php', 'OCP\\Profiler\\IProfile' => __DIR__ . '/../../..' . '/lib/public/Profiler/IProfile.php', 'OCP\\Profiler\\IProfiler' => __DIR__ . '/../../..' . '/lib/public/Profiler/IProfiler.php', @@ -594,6 +633,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Route\\IRouter' => __DIR__ . '/../../..' . '/lib/public/Route/IRouter.php', 'OCP\\SabrePluginEvent' => __DIR__ . '/../../..' . '/lib/public/SabrePluginEvent.php', 'OCP\\SabrePluginException' => __DIR__ . '/../../..' . '/lib/public/SabrePluginException.php', + 'OCP\\Search\\FilterDefinition' => __DIR__ . '/../../..' . '/lib/public/Search/FilterDefinition.php', + 'OCP\\Search\\IFilter' => __DIR__ . '/../../..' . '/lib/public/Search/IFilter.php', + 'OCP\\Search\\IFilterCollection' => __DIR__ . '/../../..' . '/lib/public/Search/IFilterCollection.php', + 'OCP\\Search\\IFilteringProvider' => __DIR__ . '/../../..' . '/lib/public/Search/IFilteringProvider.php', + 'OCP\\Search\\IInAppSearch' => __DIR__ . '/../../..' . '/lib/public/Search/IInAppSearch.php', 'OCP\\Search\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Search/IProvider.php', 'OCP\\Search\\ISearchQuery' => __DIR__ . '/../../..' . '/lib/public/Search/ISearchQuery.php', 'OCP\\Search\\PagedProvider' => __DIR__ . '/../../..' . '/lib/public/Search/PagedProvider.php', @@ -614,15 +658,26 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Security\\IRemoteHostValidator' => __DIR__ . '/../../..' . '/lib/public/Security/IRemoteHostValidator.php', 'OCP\\Security\\ISecureRandom' => __DIR__ . '/../../..' . '/lib/public/Security/ISecureRandom.php', 'OCP\\Security\\ITrustedDomainHelper' => __DIR__ . '/../../..' . '/lib/public/Security/ITrustedDomainHelper.php', + 'OCP\\Security\\RateLimiting\\ILimiter' => __DIR__ . '/../../..' . '/lib/public/Security/RateLimiting/ILimiter.php', + 'OCP\\Security\\RateLimiting\\IRateLimitExceededException' => __DIR__ . '/../../..' . '/lib/public/Security/RateLimiting/IRateLimitExceededException.php', 'OCP\\Security\\VerificationToken\\IVerificationToken' => __DIR__ . '/../../..' . '/lib/public/Security/VerificationToken/IVerificationToken.php', 'OCP\\Security\\VerificationToken\\InvalidTokenException' => __DIR__ . '/../../..' . '/lib/public/Security/VerificationToken/InvalidTokenException.php', 'OCP\\Server' => __DIR__ . '/../../..' . '/lib/public/Server.php', 'OCP\\Session\\Exceptions\\SessionNotAvailableException' => __DIR__ . '/../../..' . '/lib/public/Session/Exceptions/SessionNotAvailableException.php', + 'OCP\\Settings\\DeclarativeSettingsTypes' => __DIR__ . '/../../..' . '/lib/public/Settings/DeclarativeSettingsTypes.php', + 'OCP\\Settings\\Events\\DeclarativeSettingsGetValueEvent' => __DIR__ . '/../../..' . '/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php', + 'OCP\\Settings\\Events\\DeclarativeSettingsRegisterFormEvent' => __DIR__ . '/../../..' . '/lib/public/Settings/Events/DeclarativeSettingsRegisterFormEvent.php', + 'OCP\\Settings\\Events\\DeclarativeSettingsSetValueEvent' => __DIR__ . '/../../..' . '/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php', + 'OCP\\Settings\\IDeclarativeManager' => __DIR__ . '/../../..' . '/lib/public/Settings/IDeclarativeManager.php', + 'OCP\\Settings\\IDeclarativeSettingsForm' => __DIR__ . '/../../..' . '/lib/public/Settings/IDeclarativeSettingsForm.php', 'OCP\\Settings\\IDelegatedSettings' => __DIR__ . '/../../..' . '/lib/public/Settings/IDelegatedSettings.php', 'OCP\\Settings\\IIconSection' => __DIR__ . '/../../..' . '/lib/public/Settings/IIconSection.php', 'OCP\\Settings\\IManager' => __DIR__ . '/../../..' . '/lib/public/Settings/IManager.php', 'OCP\\Settings\\ISettings' => __DIR__ . '/../../..' . '/lib/public/Settings/ISettings.php', 'OCP\\Settings\\ISubAdminSettings' => __DIR__ . '/../../..' . '/lib/public/Settings/ISubAdminSettings.php', + 'OCP\\SetupCheck\\ISetupCheck' => __DIR__ . '/../../..' . '/lib/public/SetupCheck/ISetupCheck.php', + 'OCP\\SetupCheck\\ISetupCheckManager' => __DIR__ . '/../../..' . '/lib/public/SetupCheck/ISetupCheckManager.php', + 'OCP\\SetupCheck\\SetupResult' => __DIR__ . '/../../..' . '/lib/public/SetupCheck/SetupResult.php', 'OCP\\Share' => __DIR__ . '/../../..' . '/lib/public/Share.php', 'OCP\\Share\\Events\\BeforeShareCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/BeforeShareCreatedEvent.php', 'OCP\\Share\\Events\\BeforeShareDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/BeforeShareDeletedEvent.php', @@ -651,6 +706,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\SpeechToText\\Events\\TranscriptionSuccessfulEvent' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php', 'OCP\\SpeechToText\\ISpeechToTextManager' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/ISpeechToTextManager.php', 'OCP\\SpeechToText\\ISpeechToTextProvider' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/ISpeechToTextProvider.php', + 'OCP\\SpeechToText\\ISpeechToTextProviderWithId' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/ISpeechToTextProviderWithId.php', + 'OCP\\SpeechToText\\ISpeechToTextProviderWithUserId' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/ISpeechToTextProviderWithUserId.php', 'OCP\\Support\\CrashReport\\ICollectBreadcrumbs' => __DIR__ . '/../../..' . '/lib/public/Support/CrashReport/ICollectBreadcrumbs.php', 'OCP\\Support\\CrashReport\\IMessageReporter' => __DIR__ . '/../../..' . '/lib/public/Support/CrashReport/IMessageReporter.php', 'OCP\\Support\\CrashReport\\IRegistry' => __DIR__ . '/../../..' . '/lib/public/Support/CrashReport/IRegistry.php', @@ -674,22 +731,42 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Talk\\IConversation' => __DIR__ . '/../../..' . '/lib/public/Talk/IConversation.php', 'OCP\\Talk\\IConversationOptions' => __DIR__ . '/../../..' . '/lib/public/Talk/IConversationOptions.php', 'OCP\\Talk\\ITalkBackend' => __DIR__ . '/../../..' . '/lib/public/Talk/ITalkBackend.php', + 'OCP\\Teams\\ITeamManager' => __DIR__ . '/../../..' . '/lib/public/Teams/ITeamManager.php', + 'OCP\\Teams\\ITeamResourceProvider' => __DIR__ . '/../../..' . '/lib/public/Teams/ITeamResourceProvider.php', + 'OCP\\Teams\\Team' => __DIR__ . '/../../..' . '/lib/public/Teams/Team.php', + 'OCP\\Teams\\TeamResource' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamResource.php', 'OCP\\Template' => __DIR__ . '/../../..' . '/lib/public/Template.php', 'OCP\\TextProcessing\\Events\\AbstractTextProcessingEvent' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/Events/AbstractTextProcessingEvent.php', 'OCP\\TextProcessing\\Events\\TaskFailedEvent' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/Events/TaskFailedEvent.php', 'OCP\\TextProcessing\\Events\\TaskSuccessfulEvent' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/Events/TaskSuccessfulEvent.php', + 'OCP\\TextProcessing\\Exception\\TaskFailureException' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/Exception/TaskFailureException.php', 'OCP\\TextProcessing\\FreePromptTaskType' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/FreePromptTaskType.php', 'OCP\\TextProcessing\\HeadlineTaskType' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/HeadlineTaskType.php', 'OCP\\TextProcessing\\IManager' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/IManager.php', 'OCP\\TextProcessing\\IProvider' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/IProvider.php', + 'OCP\\TextProcessing\\IProviderWithExpectedRuntime' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/IProviderWithExpectedRuntime.php', + 'OCP\\TextProcessing\\IProviderWithId' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/IProviderWithId.php', + 'OCP\\TextProcessing\\IProviderWithUserId' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/IProviderWithUserId.php', 'OCP\\TextProcessing\\ITaskType' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/ITaskType.php', 'OCP\\TextProcessing\\SummaryTaskType' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/SummaryTaskType.php', 'OCP\\TextProcessing\\Task' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/Task.php', 'OCP\\TextProcessing\\TopicsTaskType' => __DIR__ . '/../../..' . '/lib/public/TextProcessing/TopicsTaskType.php', + 'OCP\\TextToImage\\Events\\AbstractTextToImageEvent' => __DIR__ . '/../../..' . '/lib/public/TextToImage/Events/AbstractTextToImageEvent.php', + 'OCP\\TextToImage\\Events\\TaskFailedEvent' => __DIR__ . '/../../..' . '/lib/public/TextToImage/Events/TaskFailedEvent.php', + 'OCP\\TextToImage\\Events\\TaskSuccessfulEvent' => __DIR__ . '/../../..' . '/lib/public/TextToImage/Events/TaskSuccessfulEvent.php', + 'OCP\\TextToImage\\Exception\\TaskFailureException' => __DIR__ . '/../../..' . '/lib/public/TextToImage/Exception/TaskFailureException.php', + 'OCP\\TextToImage\\Exception\\TaskNotFoundException' => __DIR__ . '/../../..' . '/lib/public/TextToImage/Exception/TaskNotFoundException.php', + 'OCP\\TextToImage\\Exception\\TextToImageException' => __DIR__ . '/../../..' . '/lib/public/TextToImage/Exception/TextToImageException.php', + 'OCP\\TextToImage\\IManager' => __DIR__ . '/../../..' . '/lib/public/TextToImage/IManager.php', + 'OCP\\TextToImage\\IProvider' => __DIR__ . '/../../..' . '/lib/public/TextToImage/IProvider.php', + 'OCP\\TextToImage\\IProviderWithUserId' => __DIR__ . '/../../..' . '/lib/public/TextToImage/IProviderWithUserId.php', + 'OCP\\TextToImage\\Task' => __DIR__ . '/../../..' . '/lib/public/TextToImage/Task.php', 'OCP\\Translation\\CouldNotTranslateException' => __DIR__ . '/../../..' . '/lib/public/Translation/CouldNotTranslateException.php', 'OCP\\Translation\\IDetectLanguageProvider' => __DIR__ . '/../../..' . '/lib/public/Translation/IDetectLanguageProvider.php', 'OCP\\Translation\\ITranslationManager' => __DIR__ . '/../../..' . '/lib/public/Translation/ITranslationManager.php', 'OCP\\Translation\\ITranslationProvider' => __DIR__ . '/../../..' . '/lib/public/Translation/ITranslationProvider.php', + 'OCP\\Translation\\ITranslationProviderWithId' => __DIR__ . '/../../..' . '/lib/public/Translation/ITranslationProviderWithId.php', + 'OCP\\Translation\\ITranslationProviderWithUserId' => __DIR__ . '/../../..' . '/lib/public/Translation/ITranslationProviderWithUserId.php', 'OCP\\Translation\\LanguageTuple' => __DIR__ . '/../../..' . '/lib/public/Translation/LanguageTuple.php', 'OCP\\UserInterface' => __DIR__ . '/../../..' . '/lib/public/UserInterface.php', 'OCP\\UserMigration\\IExportDestination' => __DIR__ . '/../../..' . '/lib/public/UserMigration/IExportDestination.php', @@ -722,6 +799,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\User\\Events\\BeforeUserLoggedInEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserLoggedInEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInWithCookieEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserLoggedInWithCookieEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedOutEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserLoggedOutEvent.php', + 'OCP\\User\\Events\\OutOfOfficeChangedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/OutOfOfficeChangedEvent.php', + 'OCP\\User\\Events\\OutOfOfficeClearedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/OutOfOfficeClearedEvent.php', + 'OCP\\User\\Events\\OutOfOfficeEndedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/OutOfOfficeEndedEvent.php', + 'OCP\\User\\Events\\OutOfOfficeScheduledEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/OutOfOfficeScheduledEvent.php', + 'OCP\\User\\Events\\OutOfOfficeStartedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/OutOfOfficeStartedEvent.php', 'OCP\\User\\Events\\PasswordUpdatedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/PasswordUpdatedEvent.php', 'OCP\\User\\Events\\PostLoginEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/PostLoginEvent.php', 'OCP\\User\\Events\\UserChangedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserChangedEvent.php', @@ -733,6 +815,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\User\\Events\\UserLoggedInWithCookieEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLoggedInWithCookieEvent.php', 'OCP\\User\\Events\\UserLoggedOutEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLoggedOutEvent.php', 'OCP\\User\\GetQuotaEvent' => __DIR__ . '/../../..' . '/lib/public/User/GetQuotaEvent.php', + 'OCP\\User\\IAvailabilityCoordinator' => __DIR__ . '/../../..' . '/lib/public/User/IAvailabilityCoordinator.php', + 'OCP\\User\\IOutOfOfficeData' => __DIR__ . '/../../..' . '/lib/public/User/IOutOfOfficeData.php', 'OCP\\Util' => __DIR__ . '/../../..' . '/lib/public/Util.php', 'OCP\\WorkflowEngine\\EntityContext\\IContextPortation' => __DIR__ . '/../../..' . '/lib/public/WorkflowEngine/EntityContext/IContextPortation.php', 'OCP\\WorkflowEngine\\EntityContext\\IDisplayName' => __DIR__ . '/../../..' . '/lib/public/WorkflowEngine/EntityContext/IDisplayName.php', @@ -834,7 +918,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\App\\AppStore\\Bundles\\EnterpriseBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/EnterpriseBundle.php', 'OC\\App\\AppStore\\Bundles\\GroupwareBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/GroupwareBundle.php', 'OC\\App\\AppStore\\Bundles\\HubBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/HubBundle.php', + 'OC\\App\\AppStore\\Bundles\\PublicSectorBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/PublicSectorBundle.php', 'OC\\App\\AppStore\\Bundles\\SocialSharingBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/SocialSharingBundle.php', + 'OC\\App\\AppStore\\Fetcher\\AppDiscoverFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php', 'OC\\App\\AppStore\\Fetcher\\AppFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/AppFetcher.php', 'OC\\App\\AppStore\\Fetcher\\CategoryFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/CategoryFetcher.php', 'OC\\App\\AppStore\\Fetcher\\Fetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/Fetcher.php', @@ -920,11 +1006,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Avatar\\GuestAvatar' => __DIR__ . '/../../..' . '/lib/private/Avatar/GuestAvatar.php', 'OC\\Avatar\\PlaceholderAvatar' => __DIR__ . '/../../..' . '/lib/private/Avatar/PlaceholderAvatar.php', 'OC\\Avatar\\UserAvatar' => __DIR__ . '/../../..' . '/lib/private/Avatar/UserAvatar.php', - 'OC\\BackgroundJob\\Job' => __DIR__ . '/../../..' . '/lib/private/BackgroundJob/Job.php', 'OC\\BackgroundJob\\JobList' => __DIR__ . '/../../..' . '/lib/private/BackgroundJob/JobList.php', - 'OC\\BackgroundJob\\QueuedJob' => __DIR__ . '/../../..' . '/lib/private/BackgroundJob/QueuedJob.php', - 'OC\\BackgroundJob\\TimedJob' => __DIR__ . '/../../..' . '/lib/private/BackgroundJob/TimedJob.php', 'OC\\BinaryFinder' => __DIR__ . '/../../..' . '/lib/private/BinaryFinder.php', + 'OC\\Blurhash\\Listener\\GenerateBlurhashMetadata' => __DIR__ . '/../../..' . '/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php', 'OC\\Broadcast\\Events\\BroadcastEvent' => __DIR__ . '/../../..' . '/lib/private/Broadcast/Events/BroadcastEvent.php', 'OC\\Cache\\CappedMemoryCache' => __DIR__ . '/../../..' . '/lib/private/Cache/CappedMemoryCache.php', 'OC\\Cache\\File' => __DIR__ . '/../../..' . '/lib/private/Cache/File.php', @@ -980,6 +1064,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 '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', + 'OC\\Core\\BackgroundJobs\\GenerateMetadataJob' => __DIR__ . '/../../..' . '/core/BackgroundJobs/GenerateMetadataJob.php', 'OC\\Core\\BackgroundJobs\\LookupServerSendCheckBackgroundJob' => __DIR__ . '/../../..' . '/core/BackgroundJobs/LookupServerSendCheckBackgroundJob.php', 'OC\\Core\\Command\\App\\Disable' => __DIR__ . '/../../..' . '/core/Command/App/Disable.php', 'OC\\Core\\Command\\App\\Enable' => __DIR__ . '/../../..' . '/core/Command/App/Enable.php', @@ -991,6 +1076,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Command\\Background\\Ajax' => __DIR__ . '/../../..' . '/core/Command/Background/Ajax.php', 'OC\\Core\\Command\\Background\\Base' => __DIR__ . '/../../..' . '/core/Command/Background/Base.php', 'OC\\Core\\Command\\Background\\Cron' => __DIR__ . '/../../..' . '/core/Command/Background/Cron.php', + 'OC\\Core\\Command\\Background\\Delete' => __DIR__ . '/../../..' . '/core/Command/Background/Delete.php', 'OC\\Core\\Command\\Background\\Job' => __DIR__ . '/../../..' . '/core/Command/Background/Job.php', 'OC\\Core\\Command\\Background\\ListCommand' => __DIR__ . '/../../..' . '/core/Command/Background/ListCommand.php', 'OC\\Core\\Command\\Background\\WebCron' => __DIR__ . '/../../..' . '/core/Command/Background/WebCron.php', @@ -1027,6 +1113,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Command\\Encryption\\SetDefaultModule' => __DIR__ . '/../../..' . '/core/Command/Encryption/SetDefaultModule.php', 'OC\\Core\\Command\\Encryption\\ShowKeyStorageRoot' => __DIR__ . '/../../..' . '/core/Command/Encryption/ShowKeyStorageRoot.php', 'OC\\Core\\Command\\Encryption\\Status' => __DIR__ . '/../../..' . '/core/Command/Encryption/Status.php', + 'OC\\Core\\Command\\FilesMetadata\\Get' => __DIR__ . '/../../..' . '/core/Command/FilesMetadata/Get.php', 'OC\\Core\\Command\\Group\\Add' => __DIR__ . '/../../..' . '/core/Command/Group/Add.php', 'OC\\Core\\Command\\Group\\AddUser' => __DIR__ . '/../../..' . '/core/Command/Group/AddUser.php', 'OC\\Core\\Command\\Group\\Delete' => __DIR__ . '/../../..' . '/core/Command/Group/Delete.php', @@ -1062,6 +1149,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Command\\Security\\ImportCertificate' => __DIR__ . '/../../..' . '/core/Command/Security/ImportCertificate.php', 'OC\\Core\\Command\\Security\\ListCertificates' => __DIR__ . '/../../..' . '/core/Command/Security/ListCertificates.php', 'OC\\Core\\Command\\Security\\RemoveCertificate' => __DIR__ . '/../../..' . '/core/Command/Security/RemoveCertificate.php', + 'OC\\Core\\Command\\SetupChecks' => __DIR__ . '/../../..' . '/core/Command/SetupChecks.php', 'OC\\Core\\Command\\Status' => __DIR__ . '/../../..' . '/core/Command/Status.php', 'OC\\Core\\Command\\SystemTag\\Add' => __DIR__ . '/../../..' . '/core/Command/SystemTag/Add.php', 'OC\\Core\\Command\\SystemTag\\Delete' => __DIR__ . '/../../..' . '/core/Command/SystemTag/Delete.php', @@ -1082,6 +1170,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Command\\User\\Disable' => __DIR__ . '/../../..' . '/core/Command/User/Disable.php', 'OC\\Core\\Command\\User\\Enable' => __DIR__ . '/../../..' . '/core/Command/User/Enable.php', 'OC\\Core\\Command\\User\\Info' => __DIR__ . '/../../..' . '/core/Command/User/Info.php', + '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\\Report' => __DIR__ . '/../../..' . '/core/Command/User/Report.php', @@ -1105,6 +1194,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Controller\\LostController' => __DIR__ . '/../../..' . '/core/Controller/LostController.php', 'OC\\Core\\Controller\\NavigationController' => __DIR__ . '/../../..' . '/core/Controller/NavigationController.php', 'OC\\Core\\Controller\\OCJSController' => __DIR__ . '/../../..' . '/core/Controller/OCJSController.php', + 'OC\\Core\\Controller\\OCMController' => __DIR__ . '/../../..' . '/core/Controller/OCMController.php', 'OC\\Core\\Controller\\OCSController' => __DIR__ . '/../../..' . '/core/Controller/OCSController.php', 'OC\\Core\\Controller\\PreviewController' => __DIR__ . '/../../..' . '/core/Controller/PreviewController.php', 'OC\\Core\\Controller\\ProfileApiController' => __DIR__ . '/../../..' . '/core/Controller/ProfileApiController.php', @@ -1114,7 +1204,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Controller\\ReferenceController' => __DIR__ . '/../../..' . '/core/Controller/ReferenceController.php', 'OC\\Core\\Controller\\SearchController' => __DIR__ . '/../../..' . '/core/Controller/SearchController.php', 'OC\\Core\\Controller\\SetupController' => __DIR__ . '/../../..' . '/core/Controller/SetupController.php', + 'OC\\Core\\Controller\\TeamsApiController' => __DIR__ . '/../../..' . '/core/Controller/TeamsApiController.php', 'OC\\Core\\Controller\\TextProcessingApiController' => __DIR__ . '/../../..' . '/core/Controller/TextProcessingApiController.php', + 'OC\\Core\\Controller\\TextToImageApiController' => __DIR__ . '/../../..' . '/core/Controller/TextToImageApiController.php', 'OC\\Core\\Controller\\TranslationApiController' => __DIR__ . '/../../..' . '/core/Controller/TranslationApiController.php', 'OC\\Core\\Controller\\TwoFactorChallengeController' => __DIR__ . '/../../..' . '/core/Controller/TwoFactorChallengeController.php', 'OC\\Core\\Controller\\UnifiedSearchController' => __DIR__ . '/../../..' . '/core/Controller/UnifiedSearchController.php', @@ -1196,6 +1288,15 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Migrations\\Version28000Date20230616104802' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20230616104802.php', 'OC\\Core\\Migrations\\Version28000Date20230728104802' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20230728104802.php', 'OC\\Core\\Migrations\\Version28000Date20230803221055' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20230803221055.php', + 'OC\\Core\\Migrations\\Version28000Date20230906104802' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20230906104802.php', + 'OC\\Core\\Migrations\\Version28000Date20231004103301' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20231004103301.php', + 'OC\\Core\\Migrations\\Version28000Date20231103104802' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20231103104802.php', + 'OC\\Core\\Migrations\\Version28000Date20231126110901' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20231126110901.php', + 'OC\\Core\\Migrations\\Version29000Date20231126110901' => __DIR__ . '/../../..' . '/core/Migrations/Version29000Date20231126110901.php', + 'OC\\Core\\Migrations\\Version29000Date20231213104850' => __DIR__ . '/../../..' . '/core/Migrations/Version29000Date20231213104850.php', + 'OC\\Core\\Migrations\\Version29000Date20240124132201' => __DIR__ . '/../../..' . '/core/Migrations/Version29000Date20240124132201.php', + 'OC\\Core\\Migrations\\Version29000Date20240124132202' => __DIR__ . '/../../..' . '/core/Migrations/Version29000Date20240124132202.php', + 'OC\\Core\\Migrations\\Version29000Date20240131122720' => __DIR__ . '/../../..' . '/core/Migrations/Version29000Date20240131122720.php', 'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php', 'OC\\Core\\Service\\LoginFlowV2Service' => __DIR__ . '/../../..' . '/core/Service/LoginFlowV2Service.php', 'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php', @@ -1216,14 +1317,12 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\DB\\MissingColumnInformation' => __DIR__ . '/../../..' . '/lib/private/DB/MissingColumnInformation.php', 'OC\\DB\\MissingIndexInformation' => __DIR__ . '/../../..' . '/lib/private/DB/MissingIndexInformation.php', 'OC\\DB\\MissingPrimaryKeyInformation' => __DIR__ . '/../../..' . '/lib/private/DB/MissingPrimaryKeyInformation.php', - 'OC\\DB\\MySQLMigrator' => __DIR__ . '/../../..' . '/lib/private/DB/MySQLMigrator.php', 'OC\\DB\\MySqlTools' => __DIR__ . '/../../..' . '/lib/private/DB/MySqlTools.php', 'OC\\DB\\OCSqlitePlatform' => __DIR__ . '/../../..' . '/lib/private/DB/OCSqlitePlatform.php', 'OC\\DB\\ObjectParameter' => __DIR__ . '/../../..' . '/lib/private/DB/ObjectParameter.php', 'OC\\DB\\OracleConnection' => __DIR__ . '/../../..' . '/lib/private/DB/OracleConnection.php', 'OC\\DB\\OracleMigrator' => __DIR__ . '/../../..' . '/lib/private/DB/OracleMigrator.php', 'OC\\DB\\PgSqlTools' => __DIR__ . '/../../..' . '/lib/private/DB/PgSqlTools.php', - 'OC\\DB\\PostgreSqlMigrator' => __DIR__ . '/../../..' . '/lib/private/DB/PostgreSqlMigrator.php', 'OC\\DB\\PreparedStatement' => __DIR__ . '/../../..' . '/lib/private/DB/PreparedStatement.php', 'OC\\DB\\QueryBuilder\\CompositeExpression' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/CompositeExpression.php', 'OC\\DB\\QueryBuilder\\ExpressionBuilder\\ExpressionBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php', @@ -1282,9 +1381,19 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Federation\\CloudFederationShare' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudFederationShare.php', 'OC\\Federation\\CloudId' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudId.php', 'OC\\Federation\\CloudIdManager' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudIdManager.php', + 'OC\\FilesMetadata\\FilesMetadataManager' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/FilesMetadataManager.php', + 'OC\\FilesMetadata\\Job\\UpdateSingleMetadata' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php', + 'OC\\FilesMetadata\\Listener\\MetadataDelete' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Listener/MetadataDelete.php', + 'OC\\FilesMetadata\\Listener\\MetadataUpdate' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Listener/MetadataUpdate.php', + 'OC\\FilesMetadata\\MetadataQuery' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/MetadataQuery.php', + 'OC\\FilesMetadata\\Model\\FilesMetadata' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Model/FilesMetadata.php', + 'OC\\FilesMetadata\\Model\\MetadataValueWrapper' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Model/MetadataValueWrapper.php', + 'OC\\FilesMetadata\\Service\\IndexRequestService' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Service/IndexRequestService.php', + 'OC\\FilesMetadata\\Service\\MetadataRequestService' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Service/MetadataRequestService.php', 'OC\\Files\\AppData\\AppData' => __DIR__ . '/../../..' . '/lib/private/Files/AppData/AppData.php', 'OC\\Files\\AppData\\Factory' => __DIR__ . '/../../..' . '/lib/private/Files/AppData/Factory.php', 'OC\\Files\\Cache\\Cache' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Cache.php', + 'OC\\Files\\Cache\\CacheDependencies' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/CacheDependencies.php', 'OC\\Files\\Cache\\CacheEntry' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/CacheEntry.php', 'OC\\Files\\Cache\\CacheQueryBuilder' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/CacheQueryBuilder.php', 'OC\\Files\\Cache\\FailedCache' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/FailedCache.php', @@ -1307,6 +1416,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Files\\Cache\\Wrapper\\JailPropagator' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Wrapper/JailPropagator.php', 'OC\\Files\\Config\\CachedMountFileInfo' => __DIR__ . '/../../..' . '/lib/private/Files/Config/CachedMountFileInfo.php', 'OC\\Files\\Config\\CachedMountInfo' => __DIR__ . '/../../..' . '/lib/private/Files/Config/CachedMountInfo.php', + 'OC\\Files\\Config\\LazyPathCachedMountInfo' => __DIR__ . '/../../..' . '/lib/private/Files/Config/LazyPathCachedMountInfo.php', 'OC\\Files\\Config\\LazyStorageMountInfo' => __DIR__ . '/../../..' . '/lib/private/Files/Config/LazyStorageMountInfo.php', 'OC\\Files\\Config\\MountProviderCollection' => __DIR__ . '/../../..' . '/lib/private/Files/Config/MountProviderCollection.php', 'OC\\Files\\Config\\UserMountCache' => __DIR__ . '/../../..' . '/lib/private/Files/Config/UserMountCache.php', @@ -1315,6 +1425,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Files\\Filesystem' => __DIR__ . '/../../..' . '/lib/private/Files/Filesystem.php', 'OC\\Files\\Lock\\LockManager' => __DIR__ . '/../../..' . '/lib/private/Files/Lock/LockManager.php', 'OC\\Files\\Mount\\CacheMountProvider' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/CacheMountProvider.php', + 'OC\\Files\\Mount\\HomeMountPoint' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/HomeMountPoint.php', 'OC\\Files\\Mount\\LocalHomeMountProvider' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/LocalHomeMountProvider.php', 'OC\\Files\\Mount\\Manager' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/Manager.php', 'OC\\Files\\Mount\\MountPoint' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/MountPoint.php', @@ -1348,9 +1459,15 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Files\\ObjectStore\\Swift' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/Swift.php', 'OC\\Files\\ObjectStore\\SwiftFactory' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/SwiftFactory.php', 'OC\\Files\\ObjectStore\\SwiftV2CachingAuthService' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/SwiftV2CachingAuthService.php', + 'OC\\Files\\Search\\QueryOptimizer\\FlattenNestedBool' => __DIR__ . '/../../..' . '/lib/private/Files/Search/QueryOptimizer/FlattenNestedBool.php', + 'OC\\Files\\Search\\QueryOptimizer\\FlattenSingleArgumentBinaryOperation' => __DIR__ . '/../../..' . '/lib/private/Files/Search/QueryOptimizer/FlattenSingleArgumentBinaryOperation.php', + 'OC\\Files\\Search\\QueryOptimizer\\MergeDistributiveOperations' => __DIR__ . '/../../..' . '/lib/private/Files/Search/QueryOptimizer/MergeDistributiveOperations.php', + 'OC\\Files\\Search\\QueryOptimizer\\OrEqualsToIn' => __DIR__ . '/../../..' . '/lib/private/Files/Search/QueryOptimizer/OrEqualsToIn.php', 'OC\\Files\\Search\\QueryOptimizer\\PathPrefixOptimizer' => __DIR__ . '/../../..' . '/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php', 'OC\\Files\\Search\\QueryOptimizer\\QueryOptimizer' => __DIR__ . '/../../..' . '/lib/private/Files/Search/QueryOptimizer/QueryOptimizer.php', 'OC\\Files\\Search\\QueryOptimizer\\QueryOptimizerStep' => __DIR__ . '/../../..' . '/lib/private/Files/Search/QueryOptimizer/QueryOptimizerStep.php', + 'OC\\Files\\Search\\QueryOptimizer\\ReplacingOptimizerStep' => __DIR__ . '/../../..' . '/lib/private/Files/Search/QueryOptimizer/ReplacingOptimizerStep.php', + 'OC\\Files\\Search\\QueryOptimizer\\SplitLargeIn' => __DIR__ . '/../../..' . '/lib/private/Files/Search/QueryOptimizer/SplitLargeIn.php', 'OC\\Files\\Search\\SearchBinaryOperator' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchBinaryOperator.php', 'OC\\Files\\Search\\SearchComparison' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchComparison.php', 'OC\\Files\\Search\\SearchOrder' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchOrder.php', @@ -1377,6 +1494,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Files\\Storage\\Wrapper\\EncodingDirectoryWrapper' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/EncodingDirectoryWrapper.php', 'OC\\Files\\Storage\\Wrapper\\Encryption' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Encryption.php', 'OC\\Files\\Storage\\Wrapper\\Jail' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Jail.php', + 'OC\\Files\\Storage\\Wrapper\\KnownMtime' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/KnownMtime.php', 'OC\\Files\\Storage\\Wrapper\\PermissionsMask' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/PermissionsMask.php', 'OC\\Files\\Storage\\Wrapper\\Quota' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Quota.php', 'OC\\Files\\Storage\\Wrapper\\Wrapper' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Wrapper.php', @@ -1473,14 +1591,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Memcache\\Redis' => __DIR__ . '/../../..' . '/lib/private/Memcache/Redis.php', 'OC\\Memcache\\WithLocalCache' => __DIR__ . '/../../..' . '/lib/private/Memcache/WithLocalCache.php', 'OC\\MemoryInfo' => __DIR__ . '/../../..' . '/lib/private/MemoryInfo.php', - 'OC\\Metadata\\Capabilities' => __DIR__ . '/../../..' . '/lib/private/Metadata/Capabilities.php', - 'OC\\Metadata\\FileEventListener' => __DIR__ . '/../../..' . '/lib/private/Metadata/FileEventListener.php', - 'OC\\Metadata\\FileMetadata' => __DIR__ . '/../../..' . '/lib/private/Metadata/FileMetadata.php', - 'OC\\Metadata\\FileMetadataMapper' => __DIR__ . '/../../..' . '/lib/private/Metadata/FileMetadataMapper.php', - 'OC\\Metadata\\IMetadataManager' => __DIR__ . '/../../..' . '/lib/private/Metadata/IMetadataManager.php', - 'OC\\Metadata\\IMetadataProvider' => __DIR__ . '/../../..' . '/lib/private/Metadata/IMetadataProvider.php', - 'OC\\Metadata\\MetadataManager' => __DIR__ . '/../../..' . '/lib/private/Metadata/MetadataManager.php', - 'OC\\Metadata\\Provider\\ExifProvider' => __DIR__ . '/../../..' . '/lib/private/Metadata/Provider/ExifProvider.php', 'OC\\Migration\\BackgroundRepair' => __DIR__ . '/../../..' . '/lib/private/Migration/BackgroundRepair.php', 'OC\\Migration\\ConsoleOutput' => __DIR__ . '/../../..' . '/lib/private/Migration/ConsoleOutput.php', 'OC\\Migration\\SimpleOutput' => __DIR__ . '/../../..' . '/lib/private/Migration/SimpleOutput.php', @@ -1494,17 +1604,22 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Notification\\Action' => __DIR__ . '/../../..' . '/lib/private/Notification/Action.php', 'OC\\Notification\\Manager' => __DIR__ . '/../../..' . '/lib/private/Notification/Manager.php', 'OC\\Notification\\Notification' => __DIR__ . '/../../..' . '/lib/private/Notification/Notification.php', + 'OC\\OCM\\Model\\OCMProvider' => __DIR__ . '/../../..' . '/lib/private/OCM/Model/OCMProvider.php', + 'OC\\OCM\\Model\\OCMResource' => __DIR__ . '/../../..' . '/lib/private/OCM/Model/OCMResource.php', + 'OC\\OCM\\OCMDiscoveryService' => __DIR__ . '/../../..' . '/lib/private/OCM/OCMDiscoveryService.php', 'OC\\OCS\\CoreCapabilities' => __DIR__ . '/../../..' . '/lib/private/OCS/CoreCapabilities.php', 'OC\\OCS\\DiscoveryService' => __DIR__ . '/../../..' . '/lib/private/OCS/DiscoveryService.php', 'OC\\OCS\\Exception' => __DIR__ . '/../../..' . '/lib/private/OCS/Exception.php', 'OC\\OCS\\Provider' => __DIR__ . '/../../..' . '/lib/private/OCS/Provider.php', 'OC\\OCS\\Result' => __DIR__ . '/../../..' . '/lib/private/OCS/Result.php', + 'OC\\PhoneNumberUtil' => __DIR__ . '/../../..' . '/lib/private/PhoneNumberUtil.php', 'OC\\PreviewManager' => __DIR__ . '/../../..' . '/lib/private/PreviewManager.php', 'OC\\PreviewNotAvailableException' => __DIR__ . '/../../..' . '/lib/private/PreviewNotAvailableException.php', 'OC\\Preview\\BMP' => __DIR__ . '/../../..' . '/lib/private/Preview/BMP.php', 'OC\\Preview\\BackgroundCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Preview/BackgroundCleanupJob.php', 'OC\\Preview\\Bitmap' => __DIR__ . '/../../..' . '/lib/private/Preview/Bitmap.php', 'OC\\Preview\\Bundled' => __DIR__ . '/../../..' . '/lib/private/Preview/Bundled.php', + 'OC\\Preview\\EMF' => __DIR__ . '/../../..' . '/lib/private/Preview/EMF.php', 'OC\\Preview\\Font' => __DIR__ . '/../../..' . '/lib/private/Preview/Font.php', 'OC\\Preview\\GIF' => __DIR__ . '/../../..' . '/lib/private/Preview/GIF.php', 'OC\\Preview\\Generator' => __DIR__ . '/../../..' . '/lib/private/Preview/Generator.php', @@ -1566,8 +1681,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Remote\\User' => __DIR__ . '/../../..' . '/lib/private/Remote/User.php', 'OC\\Repair' => __DIR__ . '/../../..' . '/lib/private/Repair.php', 'OC\\RepairException' => __DIR__ . '/../../..' . '/lib/private/RepairException.php', + 'OC\\Repair\\AddAppConfigLazyMigration' => __DIR__ . '/../../..' . '/lib/private/Repair/AddAppConfigLazyMigration.php', 'OC\\Repair\\AddBruteForceCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Repair/AddBruteForceCleanupJob.php', 'OC\\Repair\\AddCleanupUpdaterBackupsJob' => __DIR__ . '/../../..' . '/lib/private/Repair/AddCleanupUpdaterBackupsJob.php', + 'OC\\Repair\\AddMetadataGenerationJob' => __DIR__ . '/../../..' . '/lib/private/Repair/AddMetadataGenerationJob.php', 'OC\\Repair\\AddRemoveOldTasksBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/Repair/AddRemoveOldTasksBackgroundJob.php', 'OC\\Repair\\CleanTags' => __DIR__ . '/../../..' . '/lib/private/Repair/CleanTags.php', 'OC\\Repair\\CleanUpAbandonedApps' => __DIR__ . '/../../..' . '/lib/private/Repair/CleanUpAbandonedApps.php', @@ -1611,12 +1728,21 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Repair\\RepairDavShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairDavShares.php', 'OC\\Repair\\RepairInvalidShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairInvalidShares.php', 'OC\\Repair\\RepairMimeTypes' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairMimeTypes.php', - 'OC\\Repair\\SqliteAutoincrement' => __DIR__ . '/../../..' . '/lib/private/Repair/SqliteAutoincrement.php', 'OC\\RichObjectStrings\\Validator' => __DIR__ . '/../../..' . '/lib/private/RichObjectStrings/Validator.php', 'OC\\Route\\CachingRouter' => __DIR__ . '/../../..' . '/lib/private/Route/CachingRouter.php', 'OC\\Route\\Route' => __DIR__ . '/../../..' . '/lib/private/Route/Route.php', 'OC\\Route\\Router' => __DIR__ . '/../../..' . '/lib/private/Route/Router.php', 'OC\\Search' => __DIR__ . '/../../..' . '/lib/private/Search.php', + 'OC\\Search\\FilterCollection' => __DIR__ . '/../../..' . '/lib/private/Search/FilterCollection.php', + 'OC\\Search\\FilterFactory' => __DIR__ . '/../../..' . '/lib/private/Search/FilterFactory.php', + 'OC\\Search\\Filter\\BooleanFilter' => __DIR__ . '/../../..' . '/lib/private/Search/Filter/BooleanFilter.php', + 'OC\\Search\\Filter\\DateTimeFilter' => __DIR__ . '/../../..' . '/lib/private/Search/Filter/DateTimeFilter.php', + 'OC\\Search\\Filter\\FloatFilter' => __DIR__ . '/../../..' . '/lib/private/Search/Filter/FloatFilter.php', + 'OC\\Search\\Filter\\GroupFilter' => __DIR__ . '/../../..' . '/lib/private/Search/Filter/GroupFilter.php', + 'OC\\Search\\Filter\\IntegerFilter' => __DIR__ . '/../../..' . '/lib/private/Search/Filter/IntegerFilter.php', + 'OC\\Search\\Filter\\StringFilter' => __DIR__ . '/../../..' . '/lib/private/Search/Filter/StringFilter.php', + 'OC\\Search\\Filter\\StringsFilter' => __DIR__ . '/../../..' . '/lib/private/Search/Filter/StringsFilter.php', + 'OC\\Search\\Filter\\UserFilter' => __DIR__ . '/../../..' . '/lib/private/Search/Filter/UserFilter.php', 'OC\\Search\\Provider\\File' => __DIR__ . '/../../..' . '/lib/private/Search/Provider/File.php', 'OC\\Search\\Result\\Audio' => __DIR__ . '/../../..' . '/lib/private/Search/Result/Audio.php', 'OC\\Search\\Result\\File' => __DIR__ . '/../../..' . '/lib/private/Search/Result/File.php', @@ -1624,6 +1750,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Search\\Result\\Image' => __DIR__ . '/../../..' . '/lib/private/Search/Result/Image.php', 'OC\\Search\\SearchComposer' => __DIR__ . '/../../..' . '/lib/private/Search/SearchComposer.php', 'OC\\Search\\SearchQuery' => __DIR__ . '/../../..' . '/lib/private/Search/SearchQuery.php', + 'OC\\Search\\UnsupportedFilter' => __DIR__ . '/../../..' . '/lib/private/Search/UnsupportedFilter.php', 'OC\\Security\\Bruteforce\\Backend\\DatabaseBackend' => __DIR__ . '/../../..' . '/lib/private/Security/Bruteforce/Backend/DatabaseBackend.php', 'OC\\Security\\Bruteforce\\Backend\\IBackend' => __DIR__ . '/../../..' . '/lib/private/Security/Bruteforce/Backend/IBackend.php', 'OC\\Security\\Bruteforce\\Backend\\MemoryCacheBackend' => __DIR__ . '/../../..' . '/lib/private/Security/Bruteforce/Backend/MemoryCacheBackend.php', @@ -1669,9 +1796,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Session\\Session' => __DIR__ . '/../../..' . '/lib/private/Session/Session.php', 'OC\\Settings\\AuthorizedGroup' => __DIR__ . '/../../..' . '/lib/private/Settings/AuthorizedGroup.php', 'OC\\Settings\\AuthorizedGroupMapper' => __DIR__ . '/../../..' . '/lib/private/Settings/AuthorizedGroupMapper.php', + 'OC\\Settings\\DeclarativeManager' => __DIR__ . '/../../..' . '/lib/private/Settings/DeclarativeManager.php', 'OC\\Settings\\Manager' => __DIR__ . '/../../..' . '/lib/private/Settings/Manager.php', 'OC\\Settings\\Section' => __DIR__ . '/../../..' . '/lib/private/Settings/Section.php', 'OC\\Setup' => __DIR__ . '/../../..' . '/lib/private/Setup.php', + 'OC\\SetupCheck\\SetupCheckManager' => __DIR__ . '/../../..' . '/lib/private/SetupCheck/SetupCheckManager.php', 'OC\\Setup\\AbstractDatabase' => __DIR__ . '/../../..' . '/lib/private/Setup/AbstractDatabase.php', 'OC\\Setup\\MySQL' => __DIR__ . '/../../..' . '/lib/private/Setup/MySQL.php', 'OC\\Setup\\OCI' => __DIR__ . '/../../..' . '/lib/private/Setup/OCI.php', @@ -1688,6 +1817,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Share20\\PublicShareTemplateFactory' => __DIR__ . '/../../..' . '/lib/private/Share20/PublicShareTemplateFactory.php', 'OC\\Share20\\Share' => __DIR__ . '/../../..' . '/lib/private/Share20/Share.php', 'OC\\Share20\\ShareAttributes' => __DIR__ . '/../../..' . '/lib/private/Share20/ShareAttributes.php', + 'OC\\Share20\\ShareDisableChecker' => __DIR__ . '/../../..' . '/lib/private/Share20/ShareDisableChecker.php', 'OC\\Share20\\ShareHelper' => __DIR__ . '/../../..' . '/lib/private/Share20/ShareHelper.php', 'OC\\Share20\\UserRemovedListener' => __DIR__ . '/../../..' . '/lib/private/Share20/UserRemovedListener.php', 'OC\\Share\\Constants' => __DIR__ . '/../../..' . '/lib/private/Share/Constants.php', @@ -1713,6 +1843,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Tags' => __DIR__ . '/../../..' . '/lib/private/Tags.php', 'OC\\Talk\\Broker' => __DIR__ . '/../../..' . '/lib/private/Talk/Broker.php', 'OC\\Talk\\ConversationOptions' => __DIR__ . '/../../..' . '/lib/private/Talk/ConversationOptions.php', + 'OC\\Teams\\TeamManager' => __DIR__ . '/../../..' . '/lib/private/Teams/TeamManager.php', 'OC\\TempManager' => __DIR__ . '/../../..' . '/lib/private/TempManager.php', 'OC\\TemplateLayout' => __DIR__ . '/../../..' . '/lib/private/TemplateLayout.php', 'OC\\Template\\Base' => __DIR__ . '/../../..' . '/lib/private/Template/Base.php', @@ -1728,6 +1859,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\TextProcessing\\Manager' => __DIR__ . '/../../..' . '/lib/private/TextProcessing/Manager.php', 'OC\\TextProcessing\\RemoveOldTasksBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/TextProcessing/RemoveOldTasksBackgroundJob.php', 'OC\\TextProcessing\\TaskBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/TextProcessing/TaskBackgroundJob.php', + 'OC\\TextToImage\\Db\\Task' => __DIR__ . '/../../..' . '/lib/private/TextToImage/Db/Task.php', + 'OC\\TextToImage\\Db\\TaskMapper' => __DIR__ . '/../../..' . '/lib/private/TextToImage/Db/TaskMapper.php', + 'OC\\TextToImage\\Manager' => __DIR__ . '/../../..' . '/lib/private/TextToImage/Manager.php', + 'OC\\TextToImage\\RemoveOldTasksBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/TextToImage/RemoveOldTasksBackgroundJob.php', + 'OC\\TextToImage\\TaskBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/TextToImage/TaskBackgroundJob.php', 'OC\\Translation\\TranslationManager' => __DIR__ . '/../../..' . '/lib/private/Translation/TranslationManager.php', 'OC\\URLGenerator' => __DIR__ . '/../../..' . '/lib/private/URLGenerator.php', 'OC\\Updater' => __DIR__ . '/../../..' . '/lib/private/Updater.php', @@ -1737,6 +1873,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Updater\\VersionCheck' => __DIR__ . '/../../..' . '/lib/private/Updater/VersionCheck.php', 'OC\\UserStatus\\ISettableProvider' => __DIR__ . '/../../..' . '/lib/private/UserStatus/ISettableProvider.php', 'OC\\UserStatus\\Manager' => __DIR__ . '/../../..' . '/lib/private/UserStatus/Manager.php', + 'OC\\User\\AvailabilityCoordinator' => __DIR__ . '/../../..' . '/lib/private/User/AvailabilityCoordinator.php', 'OC\\User\\Backend' => __DIR__ . '/../../..' . '/lib/private/User/Backend.php', 'OC\\User\\Database' => __DIR__ . '/../../..' . '/lib/private/User/Database.php', 'OC\\User\\DisplayNameCache' => __DIR__ . '/../../..' . '/lib/private/User/DisplayNameCache.php', @@ -1746,6 +1883,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\User\\LoginException' => __DIR__ . '/../../..' . '/lib/private/User/LoginException.php', 'OC\\User\\Manager' => __DIR__ . '/../../..' . '/lib/private/User/Manager.php', 'OC\\User\\NoUserException' => __DIR__ . '/../../..' . '/lib/private/User/NoUserException.php', + 'OC\\User\\OutOfOfficeData' => __DIR__ . '/../../..' . '/lib/private/User/OutOfOfficeData.php', 'OC\\User\\Session' => __DIR__ . '/../../..' . '/lib/private/User/Session.php', 'OC\\User\\User' => __DIR__ . '/../../..' . '/lib/private/User/User.php', 'OC_API' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_API.php', diff --git a/lib/composer/composer/installed.json b/lib/composer/composer/installed.json index f20a6c47c6d..13ea12dca2a 100644 --- a/lib/composer/composer/installed.json +++ b/lib/composer/composer/installed.json @@ -1,5 +1,68 @@ { - "packages": [], - "dev": false, - "dev-package-names": [] + "packages": [ + { + "name": "bamarni/composer-bin-plugin", + "version": "1.8.2", + "version_normalized": "1.8.2.0", + "source": { + "type": "git", + "url": "https://github.com/bamarni/composer-bin-plugin.git", + "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880", + "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "ext-json": "*", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.5", + "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0" + }, + "time": "2022-10-31T08:38:03+00:00", + "type": "composer-plugin", + "extra": { + "class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin" + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Bamarni\\Composer\\Bin\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "No conflicts for your bin dependencies", + "keywords": [ + "composer", + "conflict", + "dependency", + "executable", + "isolation", + "tool" + ], + "support": { + "issues": "https://github.com/bamarni/composer-bin-plugin/issues", + "source": "https://github.com/bamarni/composer-bin-plugin/tree/1.8.2" + }, + "install-path": "../bamarni/composer-bin-plugin" + } + ], + "dev": true, + "dev-package-names": [ + "bamarni/composer-bin-plugin" + ] } diff --git a/lib/composer/composer/installed.php b/lib/composer/composer/installed.php index 1f382499aeb..8189e7e4e35 100644 --- a/lib/composer/composer/installed.php +++ b/lib/composer/composer/installed.php @@ -1,23 +1,32 @@ <?php return array( 'root' => array( - 'pretty_version' => '1.0.0+no-version-set', - 'version' => '1.0.0.0', + 'name' => '__root__', + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => '4ff660ca2e0baa02440ba07296ed7e75fa544c0e', 'type' => 'library', 'install_path' => __DIR__ . '/../../../', 'aliases' => array(), - 'reference' => NULL, - 'name' => '__root__', - 'dev' => false, + 'dev' => true, ), 'versions' => array( '__root__' => array( - 'pretty_version' => '1.0.0+no-version-set', - 'version' => '1.0.0.0', + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => '4ff660ca2e0baa02440ba07296ed7e75fa544c0e', 'type' => 'library', 'install_path' => __DIR__ . '/../../../', 'aliases' => array(), - 'reference' => NULL, 'dev_requirement' => false, ), + 'bamarni/composer-bin-plugin' => array( + 'pretty_version' => '1.8.2', + 'version' => '1.8.2.0', + 'reference' => '92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880', + 'type' => 'composer-plugin', + 'install_path' => __DIR__ . '/../bamarni/composer-bin-plugin', + 'aliases' => array(), + 'dev_requirement' => true, + ), ), ); diff --git a/lib/l10n/af.js b/lib/l10n/af.js index c36eda26cb4..8da98f1f438 100644 --- a/lib/l10n/af.js +++ b/lib/l10n/af.js @@ -19,7 +19,6 @@ OC.L10N.register( "Address" : "Adres", "Profile picture" : "Profielprent", "About" : "Oor", - "Unknown user" : "Onbekende gebruiker", "Open »%s«" : "Open »%s«", "Sunday" : "Sondag", "Monday" : "Maandag", @@ -30,6 +29,7 @@ OC.L10N.register( "Saturday" : "Saterdag", "a safe home for all your data" : "’n veilige tuiste vir al u data", "Storage is temporarily not available" : "Berging is tydelik nie beskikbaar nie", - "Full name" : "Volle naam" + "Full name" : "Volle naam", + "Unknown user" : "Onbekende gebruiker" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/af.json b/lib/l10n/af.json index 48d4be15283..bfccc0bea23 100644 --- a/lib/l10n/af.json +++ b/lib/l10n/af.json @@ -17,7 +17,6 @@ "Address" : "Adres", "Profile picture" : "Profielprent", "About" : "Oor", - "Unknown user" : "Onbekende gebruiker", "Open »%s«" : "Open »%s«", "Sunday" : "Sondag", "Monday" : "Maandag", @@ -28,6 +27,7 @@ "Saturday" : "Saterdag", "a safe home for all your data" : "’n veilige tuiste vir al u data", "Storage is temporarily not available" : "Berging is tydelik nie beskikbaar nie", - "Full name" : "Volle naam" + "Full name" : "Volle naam", + "Unknown user" : "Onbekende gebruiker" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/ar.js b/lib/l10n/ar.js index bc043479d2f..f6740434e52 100644 --- a/lib/l10n/ar.js +++ b/lib/l10n/ar.js @@ -6,14 +6,13 @@ OC.L10N.register( "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." : "التطبيق %1$s غير موجود أو ليس له إصدار متطابق مع هذا الخادوم. رجاءً، راجع دليل التطبيقات apps directory.", - "Sample configuration detected" : "تمّ العثور على عيّنة إعدادات sample configuration.", + "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", - "404" : "404", "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." : "إضغط الرابط التالي لتوكيد الإيميل", + "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", @@ -22,9 +21,10 @@ OC.L10N.register( "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s، %2$s، %3$s، %4$s و %5$s", "Education Edition" : "الإصدار التعليمي", "Enterprise bundle" : "حزمة المؤسسة", - "Groupware bundle" : "حزمة أدوات العمل الجماعي Groupware", + "Groupware bundle" : "حزمة أدوات العمل الجماعي", "Hub bundle" : "حزمة الـ\"هَبْ\" Hub", - "Social sharing bundle" : "حزمة المشاركة الاجتماعية Social Sharing", + "Public sector bundle" : "حزمة القطاع العام", + "Social sharing bundle" : "حزمة المشاركة الاجتماعية", "PHP %s or higher is required." : "إصدار PHP %s أو أحدث منه مطلوب.", "PHP with a version lower than %s is required." : "PHP الإصدار %s أو أقل مطلوب.", "%sbit or higher PHP required." : "مكتبات PHP ذات %s بت أو أعلى مطلوبة.", @@ -37,9 +37,9 @@ 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 أو أقل.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "المستخدم الداخل يجب أن يكون مُشرفاً admin، أو مُشرفاً فرعيّاً sub admin، أو يحمل صلاحياتٍ خاصّةٍ للوصول إلى هذه الإعدادات.", - "Logged in user must be an admin or sub admin" : "المستخدم الداخل يجب أن يكون مُشرفاً admin، أو مُشرفاً فرعيّاً sub admin.", - "Logged in user must be an admin" : "المستخدم الداخل يجب أن يكون مُشرفاً admin.", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "الداخل للحساب يجب أن يكون مُشرفاً أو مشرفاً فرعيّاً أو يملك حقاً خاصاً للوصول إلى هذا الإعداد", + "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« بدأ المسح عن بُعدٍ", @@ -72,7 +72,7 @@ OC.L10N.register( "last year" : "السنةالماضية", "_in %n year_::_in %n years_" : ["في %n أعوام","في %nعام","في %nأعوام","في %nأعوام","في %n أعوام","في %nأعوام"], "_%n year ago_::_%n years ago_" : ["%n منذ سنوات","%n منذ سنة","%n منذ سنوات","%n منذ سنوات","%n منذ سنوات","%n منذ سنوات"], - "_in %n hour_::_in %n hours_" : ["في %nساعات","في %nساعة","في %nساعات","في %nساعات","في %n ساعات","في %n ساعات"], + "_in %n hour_::_in %n hours_" : ["في %nساعات","في %nساعة","في %n ساعات","في %n ساعات","في %n ساعات","في %n ساعات"], "_%n hour ago_::_%n hours ago_" : ["%n منذ ساعات","%n منذ ساعة","%n منذ ساعات","%n منذ ساعات","%n منذ ساعات","%n منذ ساعات"], "_in %n minute_::_in %n minutes_" : ["في %nدقائق","في %nدقيقة","في %nدقائق","في %nدقائق","في %nدقائق","في %nدقائق"], "_%n minute ago_::_%n minutes ago_" : ["%n منذ دقائق","%n منذ دقيقة","%n منذ دقائق","%n منذ دقائق","%n منذ دقائق","%n منذ دقائق"], @@ -94,7 +94,7 @@ OC.L10N.register( "__language_name__" : "اللغة العربية", "This is an automatically sent email, please do not reply." : "هذه رسالة آلية، يرجى عدم الرد عليها.", "Help" : "المساعدة", - "Appearance and accessibility" : "المظهر appearance، و سهولة الوصول accessibility", + "Appearance and accessibility" : "المظهر و سهولة الوصول.", "Apps" : "التطبيقات", "Personal settings" : "إعدادات شخصيّة", "Administration settings" : "إعدادات الإدارة", @@ -104,11 +104,11 @@ OC.L10N.register( "Email" : "البريد الإلكتروني", "Mail %s" : "بريد %s", "Fediverse" : "الشبكة اللامركزية للتواصل الاجتماعي \"فيديفيرس\" Fediverse", - "View %s on the fediverse" : "عرض %s على الفيديفيرس Fediverse", + "View %s on the fediverse" : "عرض %s على الفيديفيرس.", "Phone" : "الهاتف", "Call %s" : "إتصل بـ%s", "Twitter" : "تويتر", - "View %s on Twitter" : "عرض %s على تويتر Twitter", + "View %s on Twitter" : "عرض %s على تويتر.", "Website" : "موقع الويب", "Visit %s" : "زيارة %s", "Address" : "العنوان", @@ -118,24 +118,24 @@ OC.L10N.register( "Headline" : "عنوان ", "Organisation" : "مؤسسة", "Role" : "الدور", - "Unknown user" : "المستخدم غير معروف", + "Unknown account" : "حساب غير معروف", "Additional settings" : "الإعدادات المتقدمة", - "Enter the database username and name for %s" : "أدخل اسم المستخدم لقاعدة البيانات و اسم %s", - "Enter the database username for %s" : "أدخل اسم المستخدم لقاعدة البيانات لـ %s", + "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" : "لا يمكنك استخدام النقاط dots في اسم قاعدة البيانات %s", - "MySQL username and/or password not valid" : "اسم المستخدم لقاعدة البيانات MySQL و/أو كلمة المرور غير صحيحة", + "MySQL Login and/or password not valid" : "مُعرف تسجل الدخول او كلمة مرور MySQL غير صحيحة", "You need to enter details of an existing account." : "يلزمك إدخال تفاصيل حسابك الحالي.", "Oracle connection could not be established" : "لم تنجح محاولة اتصال Oracle", - "Oracle username and/or password not valid" : "اسم المستخدم و/أو كلمة المرور لنظام Oracle غير صحيح", - "PostgreSQL username 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! " : "نظام ماك الإصدار X غير مدعوم و %s لن يعمل بشكل صحيح على هذه المنصة. استخدمه على مسؤوليتك!", + "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! " : "نظام ماك العاشر غير مدعوم و %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 يعمل على بيئة PHP 32-Bit وكذلك تم تكوين 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 username." : "اعداد اسم مستخدم للمدير", - "Set an admin password." : "تعيين كلمة مرور للمدير", - "Cannot create or write into the data directory %s" : "لا يمكن الإنشاء أو الكتابة في data directory دليل البيانات %s", + "Set an admin Login." : "تعيين مُعرف تسجيل دخول المشرف.", + "Set an admin password." : "تعيين كلمة مرور للمشرف", + "Cannot create or write into the data directory %s" : "لا يمكن الإنشاء أو الكتابة في دليل البيانات %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "يجب أن تقوم الواجهة الخلفية للمشاركة (Sharing backend) %s بتطبيق الواجهة OCP\\Share_Backend", "Sharing backend %s not found" : "لم يتم العثور على الواجهة الخلفية (Sharing backend) %s", "Sharing backend for %s not found" : "مشاركة الخلفية لـ %s غير موجود", @@ -151,7 +151,7 @@ OC.L10N.register( "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_" : ["لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر من %n أيام في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر من %n يوم في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر %n من أيام في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر %n من أيام في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر %n من أيام في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر %n من أيام في المستقبل"], "Sharing is only allowed with group members" : "المشاركة مسموحة فقط مع أعضاء المجموعة", - "Sharing %s failed, because this item is already shared with user %s" : "المشاركة %sلم تتم لأن هذا العنصر سبقت مشاركته سلفاً مع المستخدم %s", + "Sharing %s failed, because this item is already shared with the account %s" : "فشلت مشاركة %s؛ لأن هذا العنصر سبقت مشاركته مع الحساب %s", "%1$s shared »%2$s« with you" : "%1$s شارك »%2$s« معك", "%1$s shared »%2$s« with you." : "%1$s شَارَكَ »%2$s« معك.", "Click the button below to open it." : "أنقر على الزر أدناه لفتحه.", @@ -180,40 +180,40 @@ OC.L10N.register( "Th" : "خم", "Fr" : "جم", "Sa" : "سب", - "January" : "جانفي", - "February" : "فيفري", + "January" : "يناير", + "February" : "فبراير", "March" : "مارس", - "April" : "أفريل", - "May" : "ماي", - "June" : "جوان", - "July" : "جويلية", - "August" : "أوت", + "April" : "أبريل", + "May" : "مايو", + "June" : "يونيو", + "July" : "يوليو", + "August" : "اغسطس", "September" : "سبتمبر", "October" : "أكتوبر", "November" : "نوفمبر", "December" : "ديسمبر", - "Jan." : "جان.", - "Feb." : "فيف.", + "Jan." : "ينا.", + "Feb." : "فبر.", "Mar." : "مار.", - "Apr." : "أفر.", + "Apr." : "أبر.", "May." : "ماي", - "Jun." : "جوا.", - "Jul." : "جوي.", + "Jun." : "بون.", + "Jul." : "يول.", "Aug." : "أوت", "Sep." : "سبت.", "Oct." : "أكت.", "Nov." : "نوف.", "Dec." : "ديس.", "A valid password must be provided" : "يجب ادخال كلمة مرور صحيحة", - "The username is already being used" : "اسم المستخدم قيد الاستخدام بالفعل", - "Could not create user" : "لا يمكن إنشاء المستخدم", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "الحروف التالية فقط مسموحٌ بها في اسم المستخدِم: \"a-z\"و \"A-Z\"و \"0-9\" و الفراغ و \"_.@-'\"", - "A valid username must be provided" : "يجب ادخال اسم مستخدم صحيح", - "Username contains whitespace at the beginning or at the end" : "إنّ إسم المستخدم يحتوي على مسافة بيضاء سواءا في البداية أو النهاية", - "Username must not consist of dots only" : "اسم المستخدم يجب ألاّ يتكون من نقاطٍ dots فقط", - "Username is invalid because files already exist for this user" : "اسم المستخدم غير صحيحٍ لأن هنالك ملفات موجودة سلفاً لهذا المستخدم", - "User disabled" : "المستخدم معطّل", - "Login canceled by app" : "تم إلغاء الدخول مِن طرف التطبيق", + "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" : "يجب ألّا يكون مُعرف تسجيل الدخول يحتوي فقط على نُقَطٍ", + "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" : "المكان الآمن لجميع بياناتك", "File is currently busy, please try again later" : "إنّ الملف مشغول الآمن، يرجى إعادة المحاولة لاحقًا", @@ -226,8 +226,8 @@ OC.L10N.register( "This can usually be fixed by giving the web server write access to the config directory. See %s" : "يمكن إصلاح هذا عادةً بمنح خادوم الوب صلاحية الوصول إلى الدليل \"config\". للمزيد، أنظر: %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." : "لا يمكن الكتابة في الدليل \"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." : "يمكن إصلاح ذلك عادةً عن طريق منح خادم الويب حق الكتابة في دليل التطبيقات apps dicrectory أو تعطيل متجر التطبيقات App store في الملف config.", - "Cannot create \"data\" directory." : "لا يمكن إنشاء دليل data 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." : "يمكن إصلاح ذلك عادةً عن طريق منح خادم الويب حق الكتابة في دليل التطبيقات في الملف او تعطيل متجر تطبيقات ابل في ملف \"config\".", + "Cannot create \"data\" directory." : "لا يمكن إنشاء ملف بيانات", "This can usually be fixed by giving the web server write access to the root directory. See %s" : "يمكن إصلاح ذلك عادةً عن طريق منح خادم الويب حق الكتابة في الدليل الجذري root directory. أنطر:%s", "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "الأذونات يمكن إصلاحها عادةً عن طريق منح خادم الويب حق الكتابة في الدليل الجذري root directory. أنظر:%s.", "Your data directory is not writable." : "دليل البيانات data directory لا يمكن الكتابة فيه.", @@ -245,8 +245,8 @@ OC.L10N.register( "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 configuration.", - "Your data directory is readable by other users." : "دليل بياناتك data directory يُمكن قراءته من مستخدمين آخرين.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "الرجاء تغيير الصلاحيات إلى 0770 حتى لا يتمكن المستخدمون الآخرون من عرض محتويات المجلد.", + "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." : "مسار دليل بياناتك data directory يجب أن يكون مساراً مُطلقاً absolute path.", "Check the value of \"datadirectory\" in your configuration." : "راجع قيمة \"datadirectory\" في تهيئتك.", "Your data directory is invalid." : "دليل بياناتك data directory غير صحيح.", @@ -271,12 +271,32 @@ OC.L10N.register( "Extract topics" : "إستخلاص الموضوعات", "Extracts topics from a text and outputs them separated by commas." : "يستخلص المواضيع من النص و إخراجها مفصولة بفواصل.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "ملفات التطبيق %1$s لم يتم استبدالها مؤخّراً. تأكد من تطابق إصدارها مع الخادوم.", + "404" : "لم يتم العثور على الصفحة خطأ عدد 404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "المستخدم الداخل يجب أن يكون مُشرفاً admin، أو مُشرفاً فرعيّاً sub admin، أو يحمل صلاحياتٍ خاصّةٍ للوصول إلى هذه الإعدادات.", + "Logged in user must be an admin or sub admin" : "المستخدم الداخل يجب أن يكون مُشرفاً admin، أو مُشرفاً فرعيّاً sub admin.", + "Logged in user must be an admin" : "المستخدم الداخل يجب أن يكون مُشرفاً admin.", "Full name" : "الاسم الكامل", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "بسبب الوصول إلى الحدّ الأقصى من عدد المستخدمين، لم يتم إنشا المستخدم. رجاءً، راجع إشعاراتك لمزيد المعلومات.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "مسموح باستخدام الأحرف التالية فقط في اسم المستخدم: \"a-z\" و \"A-Z\" و \"0-9\" و \"_. @ - '\"", + "Unknown user" : "المستخدم غير معروف", + "Enter the database username and name for %s" : "أدخل اسم المستخدم و اسم قاعدة البيانات %s", + "Enter the database username for %s" : "أدخل اسم المستخدم لقاعدة البيانات لـ %s", + "MySQL username and/or password not valid" : "اسم المستخدم لقاعدة البيانات MySQL و/أو كلمة المرور غير صحيحة", + "Oracle username and/or password not valid" : "اسم المستخدم و/أو كلمة المرور لنظام Oracle غير صحيح", + "PostgreSQL username and/or password not valid" : "اسم المستخدم / أو كلمة المرور الخاصة بـPostgreSQL غير صحيحة", + "Set an admin username." : "اعداد اسم مستخدم المشرف", + "Sharing %s failed, because this item is already shared with user %s" : "المشاركة %sلم تتم لأن هذا العنصر سبقت مشاركته سلفاً مع المستخدم %s", + "The username is already being used" : "اسم المستخدم قيد الاستخدام بالفعل", + "Could not create user" : "لا يمكن إنشاء المستخدم", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "الحروف التالية فقط مسموحٌ بها في اسم المستخدِم: \"a-z\"و \"A-Z\"و \"0-9\" و الفراغ و \"_.@-'\"", + "A valid username must be provided" : "يجب ادخال اسم مستخدم صحيح", + "Username contains whitespace at the beginning or at the end" : "إنّ إسم المستخدم يحتوي على مسافة بيضاء سواءا في البداية أو النهاية", + "Username must not consist of dots only" : "اسم المستخدم يجب ألاّ يتكون من نقاطٍ dots فقط", + "Username is invalid because files already exist for this user" : "اسم المستخدم غير صحيحٍ لأن هنالك ملفات موجودة سلفاً لهذا المستخدم", + "User disabled" : "المستخدم معطّل", "libxml2 2.7.0 is at least required. Currently %s is installed." : "نحتاج النسخة 2.7.0 من libxml2 على الأقل. النسخة المتوافرة حالياً هي %s", "To fix this issue update your libxml2 version and restart your web server." : "لإصلاح هذه المشكلة، قم بتحديث إصدار libxml2 الخاص بك وأعد تشغيل خادم الويب.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 مطلوبة.", - "Please upgrade your database version." : "رجاءً، قم بترقية إصدار قاعدة بياناتك." + "Please upgrade your database version." : "رجاءً، قم بترقية إصدار قاعدة بياناتك.", + "Your data directory is readable by other users." : "دليل بياناتك data directory يُمكن قراءته من مستخدمين آخرين.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "الرجاء تغيير الصلاحيات إلى 0770 حتى لا يتمكن المستخدمون الآخرون من عرض محتويات المجلد." }, "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"); diff --git a/lib/l10n/ar.json b/lib/l10n/ar.json index 5ac53142dee..c93794cbd1e 100644 --- a/lib/l10n/ar.json +++ b/lib/l10n/ar.json @@ -4,14 +4,13 @@ "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." : "التطبيق %1$s غير موجود أو ليس له إصدار متطابق مع هذا الخادوم. رجاءً، راجع دليل التطبيقات apps directory.", - "Sample configuration detected" : "تمّ العثور على عيّنة إعدادات sample configuration.", + "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", - "404" : "404", "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." : "إضغط الرابط التالي لتوكيد الإيميل", + "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", @@ -20,9 +19,10 @@ "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s، %2$s، %3$s، %4$s و %5$s", "Education Edition" : "الإصدار التعليمي", "Enterprise bundle" : "حزمة المؤسسة", - "Groupware bundle" : "حزمة أدوات العمل الجماعي Groupware", + "Groupware bundle" : "حزمة أدوات العمل الجماعي", "Hub bundle" : "حزمة الـ\"هَبْ\" Hub", - "Social sharing bundle" : "حزمة المشاركة الاجتماعية Social Sharing", + "Public sector bundle" : "حزمة القطاع العام", + "Social sharing bundle" : "حزمة المشاركة الاجتماعية", "PHP %s or higher is required." : "إصدار PHP %s أو أحدث منه مطلوب.", "PHP with a version lower than %s is required." : "PHP الإصدار %s أو أقل مطلوب.", "%sbit or higher PHP required." : "مكتبات PHP ذات %s بت أو أعلى مطلوبة.", @@ -35,9 +35,9 @@ "The following platforms are supported: %s" : "المنصّات التالية مدعومة: %s", "Server version %s or higher is required." : "مطلوب إصدار الخادم %s أو أعلى.", "Server version %s or lower is required." : "مطلوب إصدار الخادم %s أو أقل.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "المستخدم الداخل يجب أن يكون مُشرفاً admin، أو مُشرفاً فرعيّاً sub admin، أو يحمل صلاحياتٍ خاصّةٍ للوصول إلى هذه الإعدادات.", - "Logged in user must be an admin or sub admin" : "المستخدم الداخل يجب أن يكون مُشرفاً admin، أو مُشرفاً فرعيّاً sub admin.", - "Logged in user must be an admin" : "المستخدم الداخل يجب أن يكون مُشرفاً admin.", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "الداخل للحساب يجب أن يكون مُشرفاً أو مشرفاً فرعيّاً أو يملك حقاً خاصاً للوصول إلى هذا الإعداد", + "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« بدأ المسح عن بُعدٍ", @@ -70,7 +70,7 @@ "last year" : "السنةالماضية", "_in %n year_::_in %n years_" : ["في %n أعوام","في %nعام","في %nأعوام","في %nأعوام","في %n أعوام","في %nأعوام"], "_%n year ago_::_%n years ago_" : ["%n منذ سنوات","%n منذ سنة","%n منذ سنوات","%n منذ سنوات","%n منذ سنوات","%n منذ سنوات"], - "_in %n hour_::_in %n hours_" : ["في %nساعات","في %nساعة","في %nساعات","في %nساعات","في %n ساعات","في %n ساعات"], + "_in %n hour_::_in %n hours_" : ["في %nساعات","في %nساعة","في %n ساعات","في %n ساعات","في %n ساعات","في %n ساعات"], "_%n hour ago_::_%n hours ago_" : ["%n منذ ساعات","%n منذ ساعة","%n منذ ساعات","%n منذ ساعات","%n منذ ساعات","%n منذ ساعات"], "_in %n minute_::_in %n minutes_" : ["في %nدقائق","في %nدقيقة","في %nدقائق","في %nدقائق","في %nدقائق","في %nدقائق"], "_%n minute ago_::_%n minutes ago_" : ["%n منذ دقائق","%n منذ دقيقة","%n منذ دقائق","%n منذ دقائق","%n منذ دقائق","%n منذ دقائق"], @@ -92,7 +92,7 @@ "__language_name__" : "اللغة العربية", "This is an automatically sent email, please do not reply." : "هذه رسالة آلية، يرجى عدم الرد عليها.", "Help" : "المساعدة", - "Appearance and accessibility" : "المظهر appearance، و سهولة الوصول accessibility", + "Appearance and accessibility" : "المظهر و سهولة الوصول.", "Apps" : "التطبيقات", "Personal settings" : "إعدادات شخصيّة", "Administration settings" : "إعدادات الإدارة", @@ -102,11 +102,11 @@ "Email" : "البريد الإلكتروني", "Mail %s" : "بريد %s", "Fediverse" : "الشبكة اللامركزية للتواصل الاجتماعي \"فيديفيرس\" Fediverse", - "View %s on the fediverse" : "عرض %s على الفيديفيرس Fediverse", + "View %s on the fediverse" : "عرض %s على الفيديفيرس.", "Phone" : "الهاتف", "Call %s" : "إتصل بـ%s", "Twitter" : "تويتر", - "View %s on Twitter" : "عرض %s على تويتر Twitter", + "View %s on Twitter" : "عرض %s على تويتر.", "Website" : "موقع الويب", "Visit %s" : "زيارة %s", "Address" : "العنوان", @@ -116,24 +116,24 @@ "Headline" : "عنوان ", "Organisation" : "مؤسسة", "Role" : "الدور", - "Unknown user" : "المستخدم غير معروف", + "Unknown account" : "حساب غير معروف", "Additional settings" : "الإعدادات المتقدمة", - "Enter the database username and name for %s" : "أدخل اسم المستخدم لقاعدة البيانات و اسم %s", - "Enter the database username for %s" : "أدخل اسم المستخدم لقاعدة البيانات لـ %s", + "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" : "لا يمكنك استخدام النقاط dots في اسم قاعدة البيانات %s", - "MySQL username and/or password not valid" : "اسم المستخدم لقاعدة البيانات MySQL و/أو كلمة المرور غير صحيحة", + "MySQL Login and/or password not valid" : "مُعرف تسجل الدخول او كلمة مرور MySQL غير صحيحة", "You need to enter details of an existing account." : "يلزمك إدخال تفاصيل حسابك الحالي.", "Oracle connection could not be established" : "لم تنجح محاولة اتصال Oracle", - "Oracle username and/or password not valid" : "اسم المستخدم و/أو كلمة المرور لنظام Oracle غير صحيح", - "PostgreSQL username 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! " : "نظام ماك الإصدار X غير مدعوم و %s لن يعمل بشكل صحيح على هذه المنصة. استخدمه على مسؤوليتك!", + "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! " : "نظام ماك العاشر غير مدعوم و %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 يعمل على بيئة PHP 32-Bit وكذلك تم تكوين 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 username." : "اعداد اسم مستخدم للمدير", - "Set an admin password." : "تعيين كلمة مرور للمدير", - "Cannot create or write into the data directory %s" : "لا يمكن الإنشاء أو الكتابة في data directory دليل البيانات %s", + "Set an admin Login." : "تعيين مُعرف تسجيل دخول المشرف.", + "Set an admin password." : "تعيين كلمة مرور للمشرف", + "Cannot create or write into the data directory %s" : "لا يمكن الإنشاء أو الكتابة في دليل البيانات %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "يجب أن تقوم الواجهة الخلفية للمشاركة (Sharing backend) %s بتطبيق الواجهة OCP\\Share_Backend", "Sharing backend %s not found" : "لم يتم العثور على الواجهة الخلفية (Sharing backend) %s", "Sharing backend for %s not found" : "مشاركة الخلفية لـ %s غير موجود", @@ -149,7 +149,7 @@ "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_" : ["لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر من %n أيام في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر من %n يوم في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر %n من أيام في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر %n من أيام في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر %n من أيام في المستقبل","لا يمكن تعيين تاريخ انتهاء الصلاحية لأكثر %n من أيام في المستقبل"], "Sharing is only allowed with group members" : "المشاركة مسموحة فقط مع أعضاء المجموعة", - "Sharing %s failed, because this item is already shared with user %s" : "المشاركة %sلم تتم لأن هذا العنصر سبقت مشاركته سلفاً مع المستخدم %s", + "Sharing %s failed, because this item is already shared with the account %s" : "فشلت مشاركة %s؛ لأن هذا العنصر سبقت مشاركته مع الحساب %s", "%1$s shared »%2$s« with you" : "%1$s شارك »%2$s« معك", "%1$s shared »%2$s« with you." : "%1$s شَارَكَ »%2$s« معك.", "Click the button below to open it." : "أنقر على الزر أدناه لفتحه.", @@ -178,40 +178,40 @@ "Th" : "خم", "Fr" : "جم", "Sa" : "سب", - "January" : "جانفي", - "February" : "فيفري", + "January" : "يناير", + "February" : "فبراير", "March" : "مارس", - "April" : "أفريل", - "May" : "ماي", - "June" : "جوان", - "July" : "جويلية", - "August" : "أوت", + "April" : "أبريل", + "May" : "مايو", + "June" : "يونيو", + "July" : "يوليو", + "August" : "اغسطس", "September" : "سبتمبر", "October" : "أكتوبر", "November" : "نوفمبر", "December" : "ديسمبر", - "Jan." : "جان.", - "Feb." : "فيف.", + "Jan." : "ينا.", + "Feb." : "فبر.", "Mar." : "مار.", - "Apr." : "أفر.", + "Apr." : "أبر.", "May." : "ماي", - "Jun." : "جوا.", - "Jul." : "جوي.", + "Jun." : "بون.", + "Jul." : "يول.", "Aug." : "أوت", "Sep." : "سبت.", "Oct." : "أكت.", "Nov." : "نوف.", "Dec." : "ديس.", "A valid password must be provided" : "يجب ادخال كلمة مرور صحيحة", - "The username is already being used" : "اسم المستخدم قيد الاستخدام بالفعل", - "Could not create user" : "لا يمكن إنشاء المستخدم", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "الحروف التالية فقط مسموحٌ بها في اسم المستخدِم: \"a-z\"و \"A-Z\"و \"0-9\" و الفراغ و \"_.@-'\"", - "A valid username must be provided" : "يجب ادخال اسم مستخدم صحيح", - "Username contains whitespace at the beginning or at the end" : "إنّ إسم المستخدم يحتوي على مسافة بيضاء سواءا في البداية أو النهاية", - "Username must not consist of dots only" : "اسم المستخدم يجب ألاّ يتكون من نقاطٍ dots فقط", - "Username is invalid because files already exist for this user" : "اسم المستخدم غير صحيحٍ لأن هنالك ملفات موجودة سلفاً لهذا المستخدم", - "User disabled" : "المستخدم معطّل", - "Login canceled by app" : "تم إلغاء الدخول مِن طرف التطبيق", + "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" : "يجب ألّا يكون مُعرف تسجيل الدخول يحتوي فقط على نُقَطٍ", + "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" : "المكان الآمن لجميع بياناتك", "File is currently busy, please try again later" : "إنّ الملف مشغول الآمن، يرجى إعادة المحاولة لاحقًا", @@ -224,8 +224,8 @@ "This can usually be fixed by giving the web server write access to the config directory. See %s" : "يمكن إصلاح هذا عادةً بمنح خادوم الوب صلاحية الوصول إلى الدليل \"config\". للمزيد، أنظر: %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." : "لا يمكن الكتابة في الدليل \"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." : "يمكن إصلاح ذلك عادةً عن طريق منح خادم الويب حق الكتابة في دليل التطبيقات apps dicrectory أو تعطيل متجر التطبيقات App store في الملف config.", - "Cannot create \"data\" directory." : "لا يمكن إنشاء دليل data 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." : "يمكن إصلاح ذلك عادةً عن طريق منح خادم الويب حق الكتابة في دليل التطبيقات في الملف او تعطيل متجر تطبيقات ابل في ملف \"config\".", + "Cannot create \"data\" directory." : "لا يمكن إنشاء ملف بيانات", "This can usually be fixed by giving the web server write access to the root directory. See %s" : "يمكن إصلاح ذلك عادةً عن طريق منح خادم الويب حق الكتابة في الدليل الجذري root directory. أنطر:%s", "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "الأذونات يمكن إصلاحها عادةً عن طريق منح خادم الويب حق الكتابة في الدليل الجذري root directory. أنظر:%s.", "Your data directory is not writable." : "دليل البيانات data directory لا يمكن الكتابة فيه.", @@ -243,8 +243,8 @@ "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 configuration.", - "Your data directory is readable by other users." : "دليل بياناتك data directory يُمكن قراءته من مستخدمين آخرين.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "الرجاء تغيير الصلاحيات إلى 0770 حتى لا يتمكن المستخدمون الآخرون من عرض محتويات المجلد.", + "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." : "مسار دليل بياناتك data directory يجب أن يكون مساراً مُطلقاً absolute path.", "Check the value of \"datadirectory\" in your configuration." : "راجع قيمة \"datadirectory\" في تهيئتك.", "Your data directory is invalid." : "دليل بياناتك data directory غير صحيح.", @@ -269,12 +269,32 @@ "Extract topics" : "إستخلاص الموضوعات", "Extracts topics from a text and outputs them separated by commas." : "يستخلص المواضيع من النص و إخراجها مفصولة بفواصل.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "ملفات التطبيق %1$s لم يتم استبدالها مؤخّراً. تأكد من تطابق إصدارها مع الخادوم.", + "404" : "لم يتم العثور على الصفحة خطأ عدد 404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "المستخدم الداخل يجب أن يكون مُشرفاً admin، أو مُشرفاً فرعيّاً sub admin، أو يحمل صلاحياتٍ خاصّةٍ للوصول إلى هذه الإعدادات.", + "Logged in user must be an admin or sub admin" : "المستخدم الداخل يجب أن يكون مُشرفاً admin، أو مُشرفاً فرعيّاً sub admin.", + "Logged in user must be an admin" : "المستخدم الداخل يجب أن يكون مُشرفاً admin.", "Full name" : "الاسم الكامل", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "بسبب الوصول إلى الحدّ الأقصى من عدد المستخدمين، لم يتم إنشا المستخدم. رجاءً، راجع إشعاراتك لمزيد المعلومات.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "مسموح باستخدام الأحرف التالية فقط في اسم المستخدم: \"a-z\" و \"A-Z\" و \"0-9\" و \"_. @ - '\"", + "Unknown user" : "المستخدم غير معروف", + "Enter the database username and name for %s" : "أدخل اسم المستخدم و اسم قاعدة البيانات %s", + "Enter the database username for %s" : "أدخل اسم المستخدم لقاعدة البيانات لـ %s", + "MySQL username and/or password not valid" : "اسم المستخدم لقاعدة البيانات MySQL و/أو كلمة المرور غير صحيحة", + "Oracle username and/or password not valid" : "اسم المستخدم و/أو كلمة المرور لنظام Oracle غير صحيح", + "PostgreSQL username and/or password not valid" : "اسم المستخدم / أو كلمة المرور الخاصة بـPostgreSQL غير صحيحة", + "Set an admin username." : "اعداد اسم مستخدم المشرف", + "Sharing %s failed, because this item is already shared with user %s" : "المشاركة %sلم تتم لأن هذا العنصر سبقت مشاركته سلفاً مع المستخدم %s", + "The username is already being used" : "اسم المستخدم قيد الاستخدام بالفعل", + "Could not create user" : "لا يمكن إنشاء المستخدم", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "الحروف التالية فقط مسموحٌ بها في اسم المستخدِم: \"a-z\"و \"A-Z\"و \"0-9\" و الفراغ و \"_.@-'\"", + "A valid username must be provided" : "يجب ادخال اسم مستخدم صحيح", + "Username contains whitespace at the beginning or at the end" : "إنّ إسم المستخدم يحتوي على مسافة بيضاء سواءا في البداية أو النهاية", + "Username must not consist of dots only" : "اسم المستخدم يجب ألاّ يتكون من نقاطٍ dots فقط", + "Username is invalid because files already exist for this user" : "اسم المستخدم غير صحيحٍ لأن هنالك ملفات موجودة سلفاً لهذا المستخدم", + "User disabled" : "المستخدم معطّل", "libxml2 2.7.0 is at least required. Currently %s is installed." : "نحتاج النسخة 2.7.0 من libxml2 على الأقل. النسخة المتوافرة حالياً هي %s", "To fix this issue update your libxml2 version and restart your web server." : "لإصلاح هذه المشكلة، قم بتحديث إصدار libxml2 الخاص بك وأعد تشغيل خادم الويب.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 مطلوبة.", - "Please upgrade your database version." : "رجاءً، قم بترقية إصدار قاعدة بياناتك." + "Please upgrade your database version." : "رجاءً، قم بترقية إصدار قاعدة بياناتك.", + "Your data directory is readable by other users." : "دليل بياناتك data directory يُمكن قراءته من مستخدمين آخرين.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "الرجاء تغيير الصلاحيات إلى 0770 حتى لا يتمكن المستخدمون الآخرون من عرض محتويات المجلد." },"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;" }
\ No newline at end of file diff --git a/lib/l10n/ast.js b/lib/l10n/ast.js index 330901f03c3..7446b1e06e7 100644 --- a/lib/l10n/ast.js +++ b/lib/l10n/ast.js @@ -1,26 +1,85 @@ OC.L10N.register( "lib", { + "Cannot write into \"config\" directory!" : "¡Nun se pue escribir nel direutoriu «config»!", + "This can usually be fixed by giving the web server write access to the config directory." : "Normalmente, esto pue solucionase dando l'accesu d'escritura al sirvidor web nel direutoriu de configuración.", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "L'aplicación «%1$s» nun ta presente o tien una versión incompatible con esti sirvidor. Revisa'l direutoriu de les aplicaciones.", + "Sample configuration detected" : "Configuración d'exemplu detectada", + "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" : "Detectóse que se copió la configuración d'exemplu. Esto pue estropiar la to instalación y nun ta sofitao. Llei la documentación enantes de facer cambeos nel ficheru config.php", + "The page could not be found on the server." : "Nun se pudo atopar la páxina nel sirvidor.", + "Email verification" : "Verificación per corréu electrónicu", + "Click the following button to confirm your email." : "Calca nel botón siguiente pa confirmar la to direición de corréu electrónicu.", + "Click the following link to confirm your email." : "Calca nel enllaz siguiente pa confirmar la to direición de corréu electrónicu.", "Other activities" : "Otres actividaes", + "%1$s and %2$s" : "%1$s y %2$s", + "%1$s, %2$s and %3$s" : "%1$s, %2$s y %3$s", + "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s y %4$s", + "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s y %5$s", + "Education Edition" : "Edición educativa", "The library %s is not available." : "La biblioteca «%s» nun ta disponible.", "Authentication" : "Autenticación", + "Unknown filetype" : "El tipu de ficheru ye inválidu", + "Invalid image" : "La imaxe ye inválida", + "Files" : "Ficheros", + "View profile" : "Ver el perfil", "today" : "güei", "tomorrow" : "mañana", "yesterday" : "ayeri", + "next month" : "el mes que vien", + "last month" : "el mes pasáu", + "_in %n month_::_in %n months_" : ["en %n mes","en %n meses"], + "_%n month ago_::_%n months ago_" : ["hai %n mes","hai %n meses"], + "next year" : "l'añu pasáu", + "last year" : "l'añu que vien", + "_in %n year_::_in %n years_" : ["en %n añu","en %n años"], + "_%n year ago_::_%n years ago_" : ["hai %n añu","hai %n años"], + "_in %n hour_::_in %n hours_" : ["en %n hora","en %n hores"], + "_%n hour ago_::_%n hours ago_" : ["hai %n hora","hai %n hores"], + "_in %n minute_::_in %n minutes_" : ["en %n minutu","en %n minutos"], + "_%n minute ago_::_%n minutes ago_" : ["hai %n minutu","hai %n minutos"], + "in a few seconds" : "en dellos segundos", + "seconds ago" : "hai segundos", + "Empty file" : "Ficheru baleru", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "El módulu cola ID %s nun esiste. Actívalu na configuración de les aplicaciones o ponte en contautu cola alminsitración.", + "File already exists" : "El ficheru yá esiste", + "Invalid path" : "El camín ye inválidu", + "Failed to create file from template" : "Nun se pudo crear el ficheru de la plantía", "Templates" : "Plantíes", + "File name is a reserved word" : "El nome de ficheru ye una pallabra acutada", + "File name contains at least one invalid character" : "El nome del ficheru contién polo menos un caráuter inváldu", + "File name is too long" : "El nome del ficheru ye mui llongu", + "Dot files are not allowed" : "Nun se permiten los ficheros que comiencen per un puntu", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "Nun se pue instalar l'aplicación «%s» porque nun se pue lleer el ficheru appinfo", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Nun se pue instalar l'aplicación «%s» porque nun ye compatible con esta versión del sirvidor.", + "__language_name__" : "Asturianu", "Help" : "Ayuda", "Appearance and accessibility" : "Aspeutu ya accesibilidá", "Apps" : "Aplicaciones", "Personal settings" : "Configuración personal", "Settings" : "Configuración", + "Log out" : "Zarrar la sesión", + "Users" : "Usuarios", + "Email" : "Corréu electrónicu", "Fediverse" : "Fediversu", "Twitter" : "Twitter", "Website" : "Sitiu web", + "Address" : "Direición", + "Profile picture" : "Semeya del perfil", + "Display name" : "Nome visible", "Organisation" : "Organización", "Role" : "Rol", + "Unknown account" : "Cuenta desconocida", "Additional settings" : "Configuración adicional", + "»%s« added a note to a file shared with you" : "«%s» amestó una nota a un ficheru compartío contigo", + "Open »%s«" : "Abrir «%s»", "%1$s via %2$s" : "%1$s per %2$s", "You are not allowed to share %s" : "Nun tienes permisu pa compartir «%s»", + "Files cannot be shared with create permissions" : "Los ficheros nun se pue compartir colos permisos de creación", + "Expiration date is in the past" : "La data de caducidá ta nel pasáu", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Nun se pue afitar una data de caducidá de más de %n día nel futuru","Nun se pue afitar una data de caducidá de más de %n díes nel futuru"], + "%1$s shared »%2$s« with you" : "%1$s compartió «%2$s» contigo", + "%1$s shared »%2$s« with you." : "%1$s compartió «%2$s» contigo.", + "Click the button below to open it." : "Calca nel botón p'abrilo.", "Sunday" : "Domingu", "Monday" : "Llunes", "Tuesday" : "Martes", @@ -66,9 +125,36 @@ OC.L10N.register( "Oct." : "Och.", "Nov." : "Pay.", "Dec." : "Avi.", + "A valid password must be provided" : "Ha fornise una contraseña válida", "a safe home for all your data" : "un llugar seguru pa los datos personales", "Application is not enabled" : "L'aplicación nun ta activada", + "Your data directory is not writable." : "Nun se pue escribir nel to direutoriu de datos.", "Please ask your server administrator to install the module." : "Pidi a l'alministración del sirvidor qu'instale'l módulu.", - "Full name" : "Nome completu" + "Your data directory is invalid." : "El to direutoriu de datos ye inválidu.", + "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegúrate de que'l ficheru llamáu «.ocdata» ta nel raigañu del direutoriu de datos.", + "Action \"%s\" not supported or implemented." : "L'aición «%s» nun ta sofitada o implementada.", + "Authentication failed, wrong token or provider ID given" : "L'autenticación falló, apurriéronse un pase o una ID de fornidor incorreutos", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Falten parámetros pa completar la solicitú. Los parámetros que falten: «%s»", + "Storage is temporarily not available" : "L'almacenamientu nun ta disponible temporalmente", + "Summarize" : "Resume", + "Summarizes text by reducing its length without losing key information." : "Resume'l testu amenorgando la so llongura ensin perder la información importante.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Los ficheros de l'aplicación «%1$s» nun se trocaron correutamente. Asegúrate de que la versión ye compatible col sirvidor.", + "404" : "404", + "Full name" : "Nome completu", + "MySQL username and/or password not valid" : "El nome d'usuariu y/o la contraseña de MySQL son inválidos", + "Oracle username and/or password not valid" : "El nome d'usuariu y/o la contraseña d'Oracle son inválidos", + "PostgreSQL username and/or password not valid" : "El nome d'usuariu y/o la contraseña de PostgreSQL son inválidos", + "The username is already being used" : "El nome d'usuariu yá ta n'usu", + "Could not create user" : "Nun se pudo crear l'usuariu", + "A valid username must be provided" : "Ha fornise un nome d'usuariu válidu", + "Username contains whitespace at the beginning or at the end" : "El nome d'usuariu contién un espaciu nel comienzu o al final", + "Username must not consist of dots only" : "El nome d'usuariu nun ha tar formáu namás por puntos", + "Username is invalid because files already exist for this user" : "El nome d'usuariu ye inválidu porque yá esisten los ficheros pa esti ficheru", + "User disabled" : "L'usuariu ta desactiváu", + "To fix this issue update your libxml2 version and restart your web server." : "Pa iguar esti problema, anueva la versión de libxml2 y reanicia'l sirvidor web.", + "PostgreSQL >= 9 required." : "Ríquese PostgreSQL >= 9.", + "Please upgrade your database version." : "Anueva la versión de la base de datos.", + "Your data directory is readable by other users." : "Los demás usuarios puen lleer el to direutoriu de datos.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Camuda los permisos a 0770 y, polo tanto, los demás usuarios nun puen llistar el direutoriu." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/ast.json b/lib/l10n/ast.json index 5780dd94141..b34c0ce9f26 100644 --- a/lib/l10n/ast.json +++ b/lib/l10n/ast.json @@ -1,24 +1,83 @@ { "translations": { + "Cannot write into \"config\" directory!" : "¡Nun se pue escribir nel direutoriu «config»!", + "This can usually be fixed by giving the web server write access to the config directory." : "Normalmente, esto pue solucionase dando l'accesu d'escritura al sirvidor web nel direutoriu de configuración.", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "L'aplicación «%1$s» nun ta presente o tien una versión incompatible con esti sirvidor. Revisa'l direutoriu de les aplicaciones.", + "Sample configuration detected" : "Configuración d'exemplu detectada", + "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" : "Detectóse que se copió la configuración d'exemplu. Esto pue estropiar la to instalación y nun ta sofitao. Llei la documentación enantes de facer cambeos nel ficheru config.php", + "The page could not be found on the server." : "Nun se pudo atopar la páxina nel sirvidor.", + "Email verification" : "Verificación per corréu electrónicu", + "Click the following button to confirm your email." : "Calca nel botón siguiente pa confirmar la to direición de corréu electrónicu.", + "Click the following link to confirm your email." : "Calca nel enllaz siguiente pa confirmar la to direición de corréu electrónicu.", "Other activities" : "Otres actividaes", + "%1$s and %2$s" : "%1$s y %2$s", + "%1$s, %2$s and %3$s" : "%1$s, %2$s y %3$s", + "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s y %4$s", + "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s y %5$s", + "Education Edition" : "Edición educativa", "The library %s is not available." : "La biblioteca «%s» nun ta disponible.", "Authentication" : "Autenticación", + "Unknown filetype" : "El tipu de ficheru ye inválidu", + "Invalid image" : "La imaxe ye inválida", + "Files" : "Ficheros", + "View profile" : "Ver el perfil", "today" : "güei", "tomorrow" : "mañana", "yesterday" : "ayeri", + "next month" : "el mes que vien", + "last month" : "el mes pasáu", + "_in %n month_::_in %n months_" : ["en %n mes","en %n meses"], + "_%n month ago_::_%n months ago_" : ["hai %n mes","hai %n meses"], + "next year" : "l'añu pasáu", + "last year" : "l'añu que vien", + "_in %n year_::_in %n years_" : ["en %n añu","en %n años"], + "_%n year ago_::_%n years ago_" : ["hai %n añu","hai %n años"], + "_in %n hour_::_in %n hours_" : ["en %n hora","en %n hores"], + "_%n hour ago_::_%n hours ago_" : ["hai %n hora","hai %n hores"], + "_in %n minute_::_in %n minutes_" : ["en %n minutu","en %n minutos"], + "_%n minute ago_::_%n minutes ago_" : ["hai %n minutu","hai %n minutos"], + "in a few seconds" : "en dellos segundos", + "seconds ago" : "hai segundos", + "Empty file" : "Ficheru baleru", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "El módulu cola ID %s nun esiste. Actívalu na configuración de les aplicaciones o ponte en contautu cola alminsitración.", + "File already exists" : "El ficheru yá esiste", + "Invalid path" : "El camín ye inválidu", + "Failed to create file from template" : "Nun se pudo crear el ficheru de la plantía", "Templates" : "Plantíes", + "File name is a reserved word" : "El nome de ficheru ye una pallabra acutada", + "File name contains at least one invalid character" : "El nome del ficheru contién polo menos un caráuter inváldu", + "File name is too long" : "El nome del ficheru ye mui llongu", + "Dot files are not allowed" : "Nun se permiten los ficheros que comiencen per un puntu", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "Nun se pue instalar l'aplicación «%s» porque nun se pue lleer el ficheru appinfo", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Nun se pue instalar l'aplicación «%s» porque nun ye compatible con esta versión del sirvidor.", + "__language_name__" : "Asturianu", "Help" : "Ayuda", "Appearance and accessibility" : "Aspeutu ya accesibilidá", "Apps" : "Aplicaciones", "Personal settings" : "Configuración personal", "Settings" : "Configuración", + "Log out" : "Zarrar la sesión", + "Users" : "Usuarios", + "Email" : "Corréu electrónicu", "Fediverse" : "Fediversu", "Twitter" : "Twitter", "Website" : "Sitiu web", + "Address" : "Direición", + "Profile picture" : "Semeya del perfil", + "Display name" : "Nome visible", "Organisation" : "Organización", "Role" : "Rol", + "Unknown account" : "Cuenta desconocida", "Additional settings" : "Configuración adicional", + "»%s« added a note to a file shared with you" : "«%s» amestó una nota a un ficheru compartío contigo", + "Open »%s«" : "Abrir «%s»", "%1$s via %2$s" : "%1$s per %2$s", "You are not allowed to share %s" : "Nun tienes permisu pa compartir «%s»", + "Files cannot be shared with create permissions" : "Los ficheros nun se pue compartir colos permisos de creación", + "Expiration date is in the past" : "La data de caducidá ta nel pasáu", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Nun se pue afitar una data de caducidá de más de %n día nel futuru","Nun se pue afitar una data de caducidá de más de %n díes nel futuru"], + "%1$s shared »%2$s« with you" : "%1$s compartió «%2$s» contigo", + "%1$s shared »%2$s« with you." : "%1$s compartió «%2$s» contigo.", + "Click the button below to open it." : "Calca nel botón p'abrilo.", "Sunday" : "Domingu", "Monday" : "Llunes", "Tuesday" : "Martes", @@ -64,9 +123,36 @@ "Oct." : "Och.", "Nov." : "Pay.", "Dec." : "Avi.", + "A valid password must be provided" : "Ha fornise una contraseña válida", "a safe home for all your data" : "un llugar seguru pa los datos personales", "Application is not enabled" : "L'aplicación nun ta activada", + "Your data directory is not writable." : "Nun se pue escribir nel to direutoriu de datos.", "Please ask your server administrator to install the module." : "Pidi a l'alministración del sirvidor qu'instale'l módulu.", - "Full name" : "Nome completu" + "Your data directory is invalid." : "El to direutoriu de datos ye inválidu.", + "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegúrate de que'l ficheru llamáu «.ocdata» ta nel raigañu del direutoriu de datos.", + "Action \"%s\" not supported or implemented." : "L'aición «%s» nun ta sofitada o implementada.", + "Authentication failed, wrong token or provider ID given" : "L'autenticación falló, apurriéronse un pase o una ID de fornidor incorreutos", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Falten parámetros pa completar la solicitú. Los parámetros que falten: «%s»", + "Storage is temporarily not available" : "L'almacenamientu nun ta disponible temporalmente", + "Summarize" : "Resume", + "Summarizes text by reducing its length without losing key information." : "Resume'l testu amenorgando la so llongura ensin perder la información importante.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Los ficheros de l'aplicación «%1$s» nun se trocaron correutamente. Asegúrate de que la versión ye compatible col sirvidor.", + "404" : "404", + "Full name" : "Nome completu", + "MySQL username and/or password not valid" : "El nome d'usuariu y/o la contraseña de MySQL son inválidos", + "Oracle username and/or password not valid" : "El nome d'usuariu y/o la contraseña d'Oracle son inválidos", + "PostgreSQL username and/or password not valid" : "El nome d'usuariu y/o la contraseña de PostgreSQL son inválidos", + "The username is already being used" : "El nome d'usuariu yá ta n'usu", + "Could not create user" : "Nun se pudo crear l'usuariu", + "A valid username must be provided" : "Ha fornise un nome d'usuariu válidu", + "Username contains whitespace at the beginning or at the end" : "El nome d'usuariu contién un espaciu nel comienzu o al final", + "Username must not consist of dots only" : "El nome d'usuariu nun ha tar formáu namás por puntos", + "Username is invalid because files already exist for this user" : "El nome d'usuariu ye inválidu porque yá esisten los ficheros pa esti ficheru", + "User disabled" : "L'usuariu ta desactiváu", + "To fix this issue update your libxml2 version and restart your web server." : "Pa iguar esti problema, anueva la versión de libxml2 y reanicia'l sirvidor web.", + "PostgreSQL >= 9 required." : "Ríquese PostgreSQL >= 9.", + "Please upgrade your database version." : "Anueva la versión de la base de datos.", + "Your data directory is readable by other users." : "Los demás usuarios puen lleer el to direutoriu de datos.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Camuda los permisos a 0770 y, polo tanto, los demás usuarios nun puen llistar el direutoriu." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/az.js b/lib/l10n/az.js index 20d1ce300a1..638d785686a 100644 --- a/lib/l10n/az.js +++ b/lib/l10n/az.js @@ -4,10 +4,12 @@ OC.L10N.register( "Cannot write into \"config\" directory!" : "\"configurasiya\" direktoriyasının daxilində yazmaq mümkün deyil", "See %s" : "Bax %s", "Sample configuration detected" : "Konfiqurasiya nüsxəsi təyin edildi", + "Authentication" : "Autentifikasiya", "Unknown filetype" : "Fayl tipi bəlli deyil.", "Invalid image" : "Yalnış şəkil", "Files" : "Fayllar", "today" : "Bu gün", + "yesterday" : "dünən", "seconds ago" : "saniyələr öncə", "__language_name__" : "Azərbaycan dili", "Help" : "Kömək", @@ -18,11 +20,8 @@ OC.L10N.register( "Address" : "Ünvan", "Profile picture" : "Profil şəkli", "About" : "Haqqında", - "Unknown user" : "Istifadəçi tanınmır ", "Additional settings" : "Əlavə parametrlər", "Oracle connection could not be established" : "Oracle qoşulması alınmır", - "Oracle username and/or password not valid" : "Oracle istifadəçi adı və/ya şifrəsi düzgün deyil", - "Set an admin username." : "İnzibatçı istifadəçi adını təyin et.", "Set an admin password." : "İnzibatçı şifrəsini təyin et.", "You are not allowed to share %s" : "%s-in yayimlanmasına sizə izin verilmir", "Sunday" : "Bazar", @@ -64,11 +63,14 @@ OC.L10N.register( "Nov." : "Noy.", "Dec." : "Dek.", "A valid password must be provided" : "Düzgün şifrə daxil edilməlidir", - "A valid username must be provided" : "Düzgün istifadəçi adı daxil edilməlidir", "Application is not enabled" : "Proqram təminatı aktiv edilməyib", "Authentication error" : "Təyinat metodikası", "Token expired. Please reload page." : "Token vaxtı bitib. Xahiş olunur səhifəni yenidən yükləyəsiniz.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Bu ola bilər ki, cache/accelerator such tərəfindən cağırılıb hansi ki, Zend OPcache və eAccelerator-da olduğu kimidir.", - "Full name" : "Tam ad" + "Full name" : "Tam ad", + "Unknown user" : "Istifadəçi tanınmır ", + "Oracle username and/or password not valid" : "Oracle istifadəçi adı və/ya şifrəsi düzgün deyil", + "Set an admin username." : "İnzibatçı istifadəçi adını təyin et.", + "A valid username must be provided" : "Düzgün istifadəçi adı daxil edilməlidir" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/az.json b/lib/l10n/az.json index b88fbb1337d..fb05288b33d 100644 --- a/lib/l10n/az.json +++ b/lib/l10n/az.json @@ -2,10 +2,12 @@ "Cannot write into \"config\" directory!" : "\"configurasiya\" direktoriyasının daxilində yazmaq mümkün deyil", "See %s" : "Bax %s", "Sample configuration detected" : "Konfiqurasiya nüsxəsi təyin edildi", + "Authentication" : "Autentifikasiya", "Unknown filetype" : "Fayl tipi bəlli deyil.", "Invalid image" : "Yalnış şəkil", "Files" : "Fayllar", "today" : "Bu gün", + "yesterday" : "dünən", "seconds ago" : "saniyələr öncə", "__language_name__" : "Azərbaycan dili", "Help" : "Kömək", @@ -16,11 +18,8 @@ "Address" : "Ünvan", "Profile picture" : "Profil şəkli", "About" : "Haqqında", - "Unknown user" : "Istifadəçi tanınmır ", "Additional settings" : "Əlavə parametrlər", "Oracle connection could not be established" : "Oracle qoşulması alınmır", - "Oracle username and/or password not valid" : "Oracle istifadəçi adı və/ya şifrəsi düzgün deyil", - "Set an admin username." : "İnzibatçı istifadəçi adını təyin et.", "Set an admin password." : "İnzibatçı şifrəsini təyin et.", "You are not allowed to share %s" : "%s-in yayimlanmasına sizə izin verilmir", "Sunday" : "Bazar", @@ -62,11 +61,14 @@ "Nov." : "Noy.", "Dec." : "Dek.", "A valid password must be provided" : "Düzgün şifrə daxil edilməlidir", - "A valid username must be provided" : "Düzgün istifadəçi adı daxil edilməlidir", "Application is not enabled" : "Proqram təminatı aktiv edilməyib", "Authentication error" : "Təyinat metodikası", "Token expired. Please reload page." : "Token vaxtı bitib. Xahiş olunur səhifəni yenidən yükləyəsiniz.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Bu ola bilər ki, cache/accelerator such tərəfindən cağırılıb hansi ki, Zend OPcache və eAccelerator-da olduğu kimidir.", - "Full name" : "Tam ad" + "Full name" : "Tam ad", + "Unknown user" : "Istifadəçi tanınmır ", + "Oracle username and/or password not valid" : "Oracle istifadəçi adı və/ya şifrəsi düzgün deyil", + "Set an admin username." : "İnzibatçı istifadəçi adını təyin et.", + "A valid username must be provided" : "Düzgün istifadəçi adı daxil edilməlidir" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/bg.js b/lib/l10n/bg.js index a6532e5be26..00541edd5b2 100644 --- a/lib/l10n/bg.js +++ b/lib/l10n/bg.js @@ -7,7 +7,6 @@ OC.L10N.register( "See %s" : "Вижте %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", - "404" : "404", "The page could not be found on the server." : "Страницата не е намерена на сървъра.", "%s email verification" : "%s имейл потвърждение", "Email verification" : "Имейл потвърждение", @@ -36,9 +35,6 @@ 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 или по-ниска.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Влезлият потребител трябва да е администратор, подадминистратор или да е получил специално право за достъп до тази настройка", - "Logged in user must be an admin or sub admin" : "Влезлият потребител трябва да е администратор или подадминистратор ", - "Logged in user must be an admin" : "Влезлият потребител трябва да е администратор", "Wiping of device %s has started" : "Започна изтриването на устройството %s", "Wiping of device »%s« has started" : "»%s« Започна изтриването на устройството ", "»%s« started remote wipe" : "»%s« започна отдалечено изтриване", @@ -117,22 +113,15 @@ OC.L10N.register( "Headline" : "Заглавие", "Organisation" : "Организация", "Role" : "Роля", - "Unknown user" : "Непознат потребител", "Additional settings" : "Допълнителни настройки", - "Enter the database username and name for %s" : "Въведете името на потребител на базата данни и име за %s", - "Enter the database username for %s" : "Въведете името на потребител на базата данни за %s", "Enter the database name for %s" : "Въведете името на базата данни за %s", "You cannot use dots in the database name %s" : "Не можете да използвате точки в името на базата данни %s", - "MySQL username and/or password not valid" : "Име на потребител и/или паролата на MySQL не са валидни", "You need to enter details of an existing account." : "Трябва да въведете подробности за съществуващ профил.", "Oracle connection could not be established" : "Не можа да се установи връзка с Oracle", - "Oracle username and/or password not valid" : "Невалидно Oracle потребителско име и/или парола.", - "PostgreSQL username 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 среда и open_basedir е конфигуриран в php.ini. Това ще доведе до проблеми с файлове над 4 GB и е силно обезкуражено.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Моля, премахтене настройката за open_basedir от вашия php.ini или преминете към 64-битово PHP.", - "Set an admin username." : "Задайте потребителско име за администратор.", "Set an admin password." : "Задай парола за администратор.", "Cannot create or write into the data directory %s" : "Неуспешно създаване или записване в директорията с данни \"data\" %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Споделянето на сървърния %s трябва да поддържа OCP\\Share_Backend интерфейс.", @@ -150,7 +139,6 @@ OC.L10N.register( "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_" : ["Не може да се зададе срок на валидност повече от %n дни в бъдещето","Не може да се зададе срок на валидност повече от %n дни в бъдещето"], "Sharing is only allowed with group members" : "Споделянето е разрешено само с членове на групата", - "Sharing %s failed, because this item is already shared with user %s" : "Неуспешно споделяне на %s, защото този елемент вече е споделен с потребителя %s", "%1$s shared »%2$s« with you" : "%1$s сподели »%2$s« с вас", "%1$s shared »%2$s« with you." : "%1$s сподели »%2$s« с вас.", "Click the button below to open it." : "Щракнете върху бутона по-долу, за да го отворите.", @@ -203,14 +191,6 @@ OC.L10N.register( "Nov." : "ное", "Dec." : "дек", "A valid password must be provided" : "Трябва да въведете валидна парола.", - "The username is already being used" : "Потребителското име е вече заето.", - "Could not create user" : "Неуспешно създаване на потребител", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Потребителските имена може да съдържат само следните знаци: \"a-z\", \"A-Z\", \"0-9\" и \"_.@-'\"", - "A valid username must be provided" : "Трябва да въведете валидно потребителско.", - "Username contains whitespace at the beginning or at the end" : "Потребителското име започва или завършва с интервал.", - "Username must not consist of dots only" : "Името на потребител не трябва да се състои само от точки", - "Username is invalid because files already exist for this user" : "Името на потребител е невалидно, тъй като файловете вече съществуват за този потребител", - "User 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" : "безопасен дом за всички ваши данни", @@ -243,8 +223,6 @@ OC.L10N.register( "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 users." : "Вашата директория с данни може да се чете от други потребители.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Моля, променете правата за достъп на 0770, за да не може директорията да бъде видяна от други потребители.", "Your data directory must be an absolute path." : "Вашата директория с данни трябва да е абсолютен път.", "Check the value of \"datadirectory\" in your configuration." : "Проверете стойността на \"datadirectory\" във вашата конфигурация.", "Your data directory is invalid." : "Вашата директория с данни е невалидна.", @@ -261,12 +239,32 @@ OC.L10N.register( "Storage is temporarily not available" : "Временно хранилището не е налично", "Storage connection timeout. %s" : "Време за изчакване при свързването с хранилище. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Файловете на приложението %1$s не бяха заменени правилно. Уверете се, че версията е съвместима със сървъра.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Влезлият потребител трябва да е администратор, подадминистратор или да е получил специално право за достъп до тази настройка", + "Logged in user must be an admin or sub admin" : "Влезлият потребител трябва да е администратор или подадминистратор ", + "Logged in user must be an admin" : "Влезлият потребител трябва да е администратор", "Full name" : "Пълно име", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Потребителският лимит е достигнат и потребителят не е създаден. Проверете вашите известия, за да научите повече.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Потребителските имена може да съдържат следните знаци: \"a-z\", \"A-Z\", \"0-9\" и \"_.@-'\"", + "Unknown user" : "Непознат потребител", + "Enter the database username and name for %s" : "Въведете името на потребител на базата данни и име за %s", + "Enter the database username for %s" : "Въведете името на потребител на базата данни за %s", + "MySQL username and/or password not valid" : "Име на потребител и/или паролата на MySQL не са валидни", + "Oracle username and/or password not valid" : "Невалидно Oracle потребителско име и/или парола.", + "PostgreSQL username and/or password not valid" : "Невалидно PostgreSQL потребителско име и/или парола.", + "Set an admin username." : "Задайте потребителско име за администратор.", + "Sharing %s failed, because this item is already shared with user %s" : "Неуспешно споделяне на %s, защото този елемент вече е споделен с потребителя %s", + "The username is already being used" : "Потребителското име е вече заето.", + "Could not create user" : "Неуспешно създаване на потребител", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Потребителските имена може да съдържат само следните знаци: \"a-z\", \"A-Z\", \"0-9\" и \"_.@-'\"", + "A valid username must be provided" : "Трябва да въведете валидно потребителско.", + "Username contains whitespace at the beginning or at the end" : "Потребителското име започва или завършва с интервал.", + "Username must not consist of dots only" : "Името на потребител не трябва да се състои само от точки", + "Username is invalid because files already exist for this user" : "Името на потребител е невалидно, тъй като файловете вече съществуват за този потребител", + "User disabled" : "Потребителят е деактивиран", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Нужно е поне libxml2 2.7.0. В момента са инсталирани %s.", "To fix this issue update your libxml2 version and restart your web server." : "За да отстраните този проблем, актуализирайте версията на libxml2 и рестартирайте вашия уеб сървър.", "PostgreSQL >= 9 required." : "Нужно е PostgreSQL >= 9", - "Please upgrade your database version." : "Моля, надстройте версията на вашата база данни." + "Please upgrade your database version." : "Моля, надстройте версията на вашата база данни.", + "Your data directory is readable by other users." : "Вашата директория с данни може да се чете от други потребители.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Моля, променете правата за достъп на 0770, за да не може директорията да бъде видяна от други потребители." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/bg.json b/lib/l10n/bg.json index 6bc6ae317c6..938d3fa5f97 100644 --- a/lib/l10n/bg.json +++ b/lib/l10n/bg.json @@ -5,7 +5,6 @@ "See %s" : "Вижте %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", - "404" : "404", "The page could not be found on the server." : "Страницата не е намерена на сървъра.", "%s email verification" : "%s имейл потвърждение", "Email verification" : "Имейл потвърждение", @@ -34,9 +33,6 @@ "The following platforms are supported: %s" : "Поддържани са следните платформи: %s", "Server version %s or higher is required." : "Нужна е версия на сървъра %s или по-нова.", "Server version %s or lower is required." : "Нужна е версия на сървъра %s или по-ниска.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Влезлият потребител трябва да е администратор, подадминистратор или да е получил специално право за достъп до тази настройка", - "Logged in user must be an admin or sub admin" : "Влезлият потребител трябва да е администратор или подадминистратор ", - "Logged in user must be an admin" : "Влезлият потребител трябва да е администратор", "Wiping of device %s has started" : "Започна изтриването на устройството %s", "Wiping of device »%s« has started" : "»%s« Започна изтриването на устройството ", "»%s« started remote wipe" : "»%s« започна отдалечено изтриване", @@ -115,22 +111,15 @@ "Headline" : "Заглавие", "Organisation" : "Организация", "Role" : "Роля", - "Unknown user" : "Непознат потребител", "Additional settings" : "Допълнителни настройки", - "Enter the database username and name for %s" : "Въведете името на потребител на базата данни и име за %s", - "Enter the database username for %s" : "Въведете името на потребител на базата данни за %s", "Enter the database name for %s" : "Въведете името на базата данни за %s", "You cannot use dots in the database name %s" : "Не можете да използвате точки в името на базата данни %s", - "MySQL username and/or password not valid" : "Име на потребител и/или паролата на MySQL не са валидни", "You need to enter details of an existing account." : "Трябва да въведете подробности за съществуващ профил.", "Oracle connection could not be established" : "Не можа да се установи връзка с Oracle", - "Oracle username and/or password not valid" : "Невалидно Oracle потребителско име и/или парола.", - "PostgreSQL username 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 среда и open_basedir е конфигуриран в php.ini. Това ще доведе до проблеми с файлове над 4 GB и е силно обезкуражено.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Моля, премахтене настройката за open_basedir от вашия php.ini или преминете към 64-битово PHP.", - "Set an admin username." : "Задайте потребителско име за администратор.", "Set an admin password." : "Задай парола за администратор.", "Cannot create or write into the data directory %s" : "Неуспешно създаване или записване в директорията с данни \"data\" %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Споделянето на сървърния %s трябва да поддържа OCP\\Share_Backend интерфейс.", @@ -148,7 +137,6 @@ "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_" : ["Не може да се зададе срок на валидност повече от %n дни в бъдещето","Не може да се зададе срок на валидност повече от %n дни в бъдещето"], "Sharing is only allowed with group members" : "Споделянето е разрешено само с членове на групата", - "Sharing %s failed, because this item is already shared with user %s" : "Неуспешно споделяне на %s, защото този елемент вече е споделен с потребителя %s", "%1$s shared »%2$s« with you" : "%1$s сподели »%2$s« с вас", "%1$s shared »%2$s« with you." : "%1$s сподели »%2$s« с вас.", "Click the button below to open it." : "Щракнете върху бутона по-долу, за да го отворите.", @@ -201,14 +189,6 @@ "Nov." : "ное", "Dec." : "дек", "A valid password must be provided" : "Трябва да въведете валидна парола.", - "The username is already being used" : "Потребителското име е вече заето.", - "Could not create user" : "Неуспешно създаване на потребител", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Потребителските имена може да съдържат само следните знаци: \"a-z\", \"A-Z\", \"0-9\" и \"_.@-'\"", - "A valid username must be provided" : "Трябва да въведете валидно потребителско.", - "Username contains whitespace at the beginning or at the end" : "Потребителското име започва или завършва с интервал.", - "Username must not consist of dots only" : "Името на потребител не трябва да се състои само от точки", - "Username is invalid because files already exist for this user" : "Името на потребител е невалидно, тъй като файловете вече съществуват за този потребител", - "User 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" : "безопасен дом за всички ваши данни", @@ -241,8 +221,6 @@ "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 users." : "Вашата директория с данни може да се чете от други потребители.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Моля, променете правата за достъп на 0770, за да не може директорията да бъде видяна от други потребители.", "Your data directory must be an absolute path." : "Вашата директория с данни трябва да е абсолютен път.", "Check the value of \"datadirectory\" in your configuration." : "Проверете стойността на \"datadirectory\" във вашата конфигурация.", "Your data directory is invalid." : "Вашата директория с данни е невалидна.", @@ -259,12 +237,32 @@ "Storage is temporarily not available" : "Временно хранилището не е налично", "Storage connection timeout. %s" : "Време за изчакване при свързването с хранилище. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Файловете на приложението %1$s не бяха заменени правилно. Уверете се, че версията е съвместима със сървъра.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Влезлият потребител трябва да е администратор, подадминистратор или да е получил специално право за достъп до тази настройка", + "Logged in user must be an admin or sub admin" : "Влезлият потребител трябва да е администратор или подадминистратор ", + "Logged in user must be an admin" : "Влезлият потребител трябва да е администратор", "Full name" : "Пълно име", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Потребителският лимит е достигнат и потребителят не е създаден. Проверете вашите известия, за да научите повече.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Потребителските имена може да съдържат следните знаци: \"a-z\", \"A-Z\", \"0-9\" и \"_.@-'\"", + "Unknown user" : "Непознат потребител", + "Enter the database username and name for %s" : "Въведете името на потребител на базата данни и име за %s", + "Enter the database username for %s" : "Въведете името на потребител на базата данни за %s", + "MySQL username and/or password not valid" : "Име на потребител и/или паролата на MySQL не са валидни", + "Oracle username and/or password not valid" : "Невалидно Oracle потребителско име и/или парола.", + "PostgreSQL username and/or password not valid" : "Невалидно PostgreSQL потребителско име и/или парола.", + "Set an admin username." : "Задайте потребителско име за администратор.", + "Sharing %s failed, because this item is already shared with user %s" : "Неуспешно споделяне на %s, защото този елемент вече е споделен с потребителя %s", + "The username is already being used" : "Потребителското име е вече заето.", + "Could not create user" : "Неуспешно създаване на потребител", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Потребителските имена може да съдържат само следните знаци: \"a-z\", \"A-Z\", \"0-9\" и \"_.@-'\"", + "A valid username must be provided" : "Трябва да въведете валидно потребителско.", + "Username contains whitespace at the beginning or at the end" : "Потребителското име започва или завършва с интервал.", + "Username must not consist of dots only" : "Името на потребител не трябва да се състои само от точки", + "Username is invalid because files already exist for this user" : "Името на потребител е невалидно, тъй като файловете вече съществуват за този потребител", + "User disabled" : "Потребителят е деактивиран", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Нужно е поне libxml2 2.7.0. В момента са инсталирани %s.", "To fix this issue update your libxml2 version and restart your web server." : "За да отстраните този проблем, актуализирайте версията на libxml2 и рестартирайте вашия уеб сървър.", "PostgreSQL >= 9 required." : "Нужно е PostgreSQL >= 9", - "Please upgrade your database version." : "Моля, надстройте версията на вашата база данни." + "Please upgrade your database version." : "Моля, надстройте версията на вашата база данни.", + "Your data directory is readable by other users." : "Вашата директория с данни може да се чете от други потребители.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Моля, променете правата за достъп на 0770, за да не може директорията да бъде видяна от други потребители." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/bn_BD.js b/lib/l10n/bn_BD.js index 7c8ffd8c670..5b263d18017 100644 --- a/lib/l10n/bn_BD.js +++ b/lib/l10n/bn_BD.js @@ -23,7 +23,6 @@ OC.L10N.register( "Website" : "ওয়েবসাইট", "Address" : "ঠিকানা", "About" : "সমপরকে", - "Unknown user" : "অপরিচিত ব্যবহারকারী", "You are not allowed to share %s" : "আপনি %s ভাগাভাগি করতে পারবেননা", "Sunday" : "রবিবার", "Monday" : "সোমবার", @@ -65,6 +64,7 @@ OC.L10N.register( "Dec." : "ডিসে.", "Application is not enabled" : "অ্যাপ্লিকেসনটি সক্রিয় নয়", "Authentication error" : "অনুমোদন ঘটিত সমস্যা", - "Token expired. Please reload page." : "টোকেন মেয়াদোত্তীর্ণ। দয়া করে পৃষ্ঠাটি পূনরায় লোড করুন।" + "Token expired. Please reload page." : "টোকেন মেয়াদোত্তীর্ণ। দয়া করে পৃষ্ঠাটি পূনরায় লোড করুন।", + "Unknown user" : "অপরিচিত ব্যবহারকারী" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/bn_BD.json b/lib/l10n/bn_BD.json index 60977f6baad..bb21bc9a618 100644 --- a/lib/l10n/bn_BD.json +++ b/lib/l10n/bn_BD.json @@ -21,7 +21,6 @@ "Website" : "ওয়েবসাইট", "Address" : "ঠিকানা", "About" : "সমপরকে", - "Unknown user" : "অপরিচিত ব্যবহারকারী", "You are not allowed to share %s" : "আপনি %s ভাগাভাগি করতে পারবেননা", "Sunday" : "রবিবার", "Monday" : "সোমবার", @@ -63,6 +62,7 @@ "Dec." : "ডিসে.", "Application is not enabled" : "অ্যাপ্লিকেসনটি সক্রিয় নয়", "Authentication error" : "অনুমোদন ঘটিত সমস্যা", - "Token expired. Please reload page." : "টোকেন মেয়াদোত্তীর্ণ। দয়া করে পৃষ্ঠাটি পূনরায় লোড করুন।" + "Token expired. Please reload page." : "টোকেন মেয়াদোত্তীর্ণ। দয়া করে পৃষ্ঠাটি পূনরায় লোড করুন।", + "Unknown user" : "অপরিচিত ব্যবহারকারী" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/br.js b/lib/l10n/br.js index 691cfd12615..6619163b806 100644 --- a/lib/l10n/br.js +++ b/lib/l10n/br.js @@ -38,15 +38,11 @@ OC.L10N.register( "About" : "Diwar-benn", "Display name" : "Anv ardivink", "Role" : "Roll", - "Unknown user" : "Implijer dianv", "Additional settings" : "Stummoù ouzhpenn", - "Set an admin username." : "Lakaat un anv-impljer merour.", "Set an admin password." : "Lakaat ur ger-tremenn merour.", "Sharing backend for %s not found" : "Rannadenn backend evit %s n'eo ket bet kavet", "Open »%s«" : "Digeriñ »%s«", "Monday" : "Lun", - "The username is already being used" : "An anv-implijet a zo dija implijet", - "User disabled" : "Implijer disaotreet", "Login canceled by app" : "Mont tre arrestet gant ar meziant", "Application is not enabled" : "N'eo ket aotreet ar meziant", "Authentication error" : "Fazi dilesa", @@ -54,6 +50,10 @@ OC.L10N.register( "PHP module %s not installed." : "Modul %s PHPn n'eo ket staliet.", "Storage connection error. %s" : "Fazi renkañ kenstag. %s", "Storage is temporarily not available" : "N'haller ket tizhout ar skor roadennoù evit ar poent", - "Full name" : "Tout an anv" + "Full name" : "Tout an anv", + "Unknown user" : "Implijer dianv", + "Set an admin username." : "Lakaat un anv-impljer merour.", + "The username is already being used" : "An anv-implijet a zo dija implijet", + "User disabled" : "Implijer disaotreet" }, "nplurals=5; plural=((n%10 == 1) && (n%100 != 11) && (n%100 !=71) && (n%100 !=91) ? 0 :(n%10 == 2) && (n%100 != 12) && (n%100 !=72) && (n%100 !=92) ? 1 :(n%10 ==3 || n%10==4 || n%10==9) && (n%100 < 10 || n% 100 > 19) && (n%100 < 70 || n%100 > 79) && (n%100 < 90 || n%100 > 99) ? 2 :(n != 0 && n % 1000000 == 0) ? 3 : 4);"); diff --git a/lib/l10n/br.json b/lib/l10n/br.json index 8170e542f2c..5d565491203 100644 --- a/lib/l10n/br.json +++ b/lib/l10n/br.json @@ -36,15 +36,11 @@ "About" : "Diwar-benn", "Display name" : "Anv ardivink", "Role" : "Roll", - "Unknown user" : "Implijer dianv", "Additional settings" : "Stummoù ouzhpenn", - "Set an admin username." : "Lakaat un anv-impljer merour.", "Set an admin password." : "Lakaat ur ger-tremenn merour.", "Sharing backend for %s not found" : "Rannadenn backend evit %s n'eo ket bet kavet", "Open »%s«" : "Digeriñ »%s«", "Monday" : "Lun", - "The username is already being used" : "An anv-implijet a zo dija implijet", - "User disabled" : "Implijer disaotreet", "Login canceled by app" : "Mont tre arrestet gant ar meziant", "Application is not enabled" : "N'eo ket aotreet ar meziant", "Authentication error" : "Fazi dilesa", @@ -52,6 +48,10 @@ "PHP module %s not installed." : "Modul %s PHPn n'eo ket staliet.", "Storage connection error. %s" : "Fazi renkañ kenstag. %s", "Storage is temporarily not available" : "N'haller ket tizhout ar skor roadennoù evit ar poent", - "Full name" : "Tout an anv" + "Full name" : "Tout an anv", + "Unknown user" : "Implijer dianv", + "Set an admin username." : "Lakaat un anv-impljer merour.", + "The username is already being used" : "An anv-implijet a zo dija implijet", + "User disabled" : "Implijer disaotreet" },"pluralForm" :"nplurals=5; plural=((n%10 == 1) && (n%100 != 11) && (n%100 !=71) && (n%100 !=91) ? 0 :(n%10 == 2) && (n%100 != 12) && (n%100 !=72) && (n%100 !=92) ? 1 :(n%10 ==3 || n%10==4 || n%10==9) && (n%100 < 10 || n% 100 > 19) && (n%100 < 70 || n%100 > 79) && (n%100 < 90 || n%100 > 99) ? 2 :(n != 0 && n % 1000000 == 0) ? 3 : 4);" }
\ No newline at end of file diff --git a/lib/l10n/bs.js b/lib/l10n/bs.js index 1a11afaf30d..0e8d423e93f 100644 --- a/lib/l10n/bs.js +++ b/lib/l10n/bs.js @@ -56,8 +56,8 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Nužno je navesti valjanu lozinku", - "A valid username must be provided" : "Nužno je navesti valjano korisničko ime", "Authentication error" : "Grešna autentifikacije", - "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Uzrok tome je vjerojatno neki ubrzivač predmemorisanja kao što je Zend OPcache ili eAccelerator." + "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Uzrok tome je vjerojatno neki ubrzivač predmemorisanja kao što je Zend OPcache ili eAccelerator.", + "A valid username must be provided" : "Nužno je navesti valjano korisničko ime" }, "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/bs.json b/lib/l10n/bs.json index 93163ceaa07..870b01387e8 100644 --- a/lib/l10n/bs.json +++ b/lib/l10n/bs.json @@ -54,8 +54,8 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Nužno je navesti valjanu lozinku", - "A valid username must be provided" : "Nužno je navesti valjano korisničko ime", "Authentication error" : "Grešna autentifikacije", - "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Uzrok tome je vjerojatno neki ubrzivač predmemorisanja kao što je Zend OPcache ili eAccelerator." + "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Uzrok tome je vjerojatno neki ubrzivač predmemorisanja kao što je Zend OPcache ili eAccelerator.", + "A valid username must be provided" : "Nužno je navesti valjano korisničko ime" },"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/ca.js b/lib/l10n/ca.js index 421f7e69652..641bc74984e 100644 --- a/lib/l10n/ca.js +++ b/lib/l10n/ca.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Falta l'aplicació %1$s o té una versió no compatible amb aquest servidor. Comproveu la carpeta d'aplicacions.", "Sample configuration detected" : "S'ha detectat una configuració d'exemple", "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" : "S'ha detectat que s'ha copiat la configuració d'exemple. Això no s'admet i pot malmetre la instal·lació. Llegiu la documentació abans d'aplicar cap canvi al fitxer config.php", - "404" : "404", "The page could not be found on the server." : "No s'ha pogut trobar la pàgina en el servidor.", "%s email verification" : "Verificació de l'adreça electrònica del %s", "Email verification" : "Verificació de l'adreça electrònica", @@ -24,6 +23,7 @@ OC.L10N.register( "Enterprise bundle" : "Paquet empresarial", "Groupware bundle" : "Paquet de treball en grup", "Hub bundle" : "Paquet Hub", + "Public sector bundle" : "Paquet del sector públic", "Social sharing bundle" : "Paquet social", "PHP %s or higher is required." : "Cal el PHP %s o superior.", "PHP with a version lower than %s is required." : "Cal el PHP amb una versió inferior a la %s.", @@ -37,9 +37,9 @@ OC.L10N.register( "The following platforms are supported: %s" : "S'admeten les plataformes següents: %s", "Server version %s or higher is required." : "Cal la versió del servidor %s o superior.", "Server version %s or lower is required." : "Cal una versió del servidor %s o inferior.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'usuari que ha iniciat la sessió ha de ser administrador, subadministrador o tenir un dret especial per a accedir a aquest paràmetre", - "Logged in user must be an admin or sub admin" : "L'usuari que ha iniciat la sessió ha de ser administrador o subadministrador", - "Logged in user must be an admin" : "L'usuari que ha iniciat la sessió ha de ser administrador", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "El compte que ha iniciat la sessió ha de ser administrador, subadministrador o tenir un dret especial per a accedir a aquest paràmetre", + "Logged in account must be an admin or sub admin" : "El compte que ha iniciat la sessió ha de ser administrador o subadministrador", + "Logged in account must be an admin" : "El compte que ha iniciat la sessió ha de ser administrador", "Wiping of device %s has started" : "S'ha començat a esborrar el dispositiu %s", "Wiping of device »%s« has started" : "S'ha començat a esborrar el dispositiu «%s»", "»%s« started remote wipe" : "«%s» ha començat a esborrar dades en remot", @@ -118,22 +118,22 @@ OC.L10N.register( "Headline" : "Capçalera", "Organisation" : "Organització", "Role" : "Càrrec", - "Unknown user" : "Usuari desconegut", + "Unknown account" : "Compte desconegut", "Additional settings" : "Paràmetres addicionals", - "Enter the database username and name for %s" : "Introduïu el nom d'usuari i el nom de la base de dades per a %s", - "Enter the database username for %s" : "Introduïu el nom d'usuari de la base de dades per a %s", + "Enter the database Login and name for %s" : "Introduïu l'inici de sessió i el nom de la base de dades per a %s", + "Enter the database Login for %s" : "Introduïu l'inici de sessió de la base de dades per a %s", "Enter the database name for %s" : "Introduïu el nom de la base de dades per a %s", "You cannot use dots in the database name %s" : "No podeu utilitzar punts en el nom de la base de dades %s", - "MySQL username and/or password not valid" : "El nom d'usuari o la contrasenya del MySQL no són vàlids", + "MySQL Login and/or password not valid" : "L'inici de sessió o la contrasenya del MySQL no són vàlids", "You need to enter details of an existing account." : "Heu d'introduir els detalls d'un compte existent.", "Oracle connection could not be established" : "No s'ha pogut establir la connexió amb Oracle", - "Oracle username and/or password not valid" : "El nom d'usuari o la contrasenya d'Oracle no són vàlids", - "PostgreSQL username and/or password not valid" : "El nom d'usuari o la contrasenya del PostgreSQL no són vàlids", + "Oracle Login and/or password not valid" : "L'inici de sessió o la contrasenya d'Oracle no són vàlids", + "PostgreSQL Login and/or password not valid" : "L'inici de sessió o la contrasenya del PostgreSQL no són vàlids", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "El Mac OS X no s'admet i el %s no funcionarà correctament en aquesta plataforma. Utilitzeu-lo sota el vostre propi risc! ", "For the best results, please consider using a GNU/Linux server instead." : "Per a obtenir els millors resultats, considereu la possibilitat d'utilitzar un servidor amb 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." : "Sembla que aquesta instància del %s s'està executant en un entorn del PHP de 32 bits i que s'ha configurat open_basedir en el fitxer php.ini. Això comportarà problemes amb els fitxers de més de 4 GB i és molt poc recomanable.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Suprimiu el paràmetre open_basedir del fitxer php.ini o canvieu al PHP de 64 bits.", - "Set an admin username." : "Definiu un nom d'usuari per a l'administrador.", + "Set an admin Login." : "Definiu un inici de sessió per a l'administrador.", "Set an admin password." : "Definiu una contrasenya per a l'administrador.", "Cannot create or write into the data directory %s" : "No es pot crear la carpeta de dades %s ni escriure-hi", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El rerefons d'ús compartit %s ha d'implementar la interfície OCP\\Share_Backend", @@ -151,7 +151,7 @@ OC.L10N.register( "Expiration date is in the past" : "La data de caducitat ja ha passat", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No es pot establir la data de caducitat més d'%n dia en el futur","No es pot establir la data de caducitat més de %n dies en el futur"], "Sharing is only allowed with group members" : "Només es permet l'ús compartit amb membres del grup", - "Sharing %s failed, because this item is already shared with user %s" : "No s'ha pogut compartir %s perquè l'element ja està compartit amb l'usuari %s", + "Sharing %s failed, because this item is already shared with the account %s" : "No s'ha pogut compartir %s perquè l'element ja està compartit amb el compte %s", "%1$s shared »%2$s« with you" : "%1$s ha compartit «%2$s» amb vós", "%1$s shared »%2$s« with you." : "%1$s ha compartit «%2$s» amb vós.", "Click the button below to open it." : "Feu clic en el botó següent per a obrir-ho.", @@ -205,14 +205,14 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Des.", "A valid password must be provided" : "Heu de proporcionar una contrasenya vàlida", - "The username is already being used" : "El nom d'usuari ja està en ús", - "Could not create user" : "No s'ha pogut crear l'usuari", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Només es permeten els caràcters següents en un nom d'usuari: «a-z», «A-Z», «0-9», espais i «_.@-'»", - "A valid username must be provided" : "Heu de proporcionar un nom d'usuari vàlid", - "Username contains whitespace at the beginning or at the end" : "El nom d'usuari conté espais en blanc al principi o al final", - "Username must not consist of dots only" : "El nom d'usuari no pot estar format només per punts", - "Username is invalid because files already exist for this user" : "El nom d'usuari no és vàlid perquè ja existeixen fitxers per a aquest usuari", - "User disabled" : "Usuari inhabilitat", + "The Login is already being used" : "L'inici de sessió ja està en ús", + "Could not create account" : "No s'ha pogut crear el compte", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Només es permeten els caràcters següents en un inici de sessió: «a-z», «A-Z», «0-9», espais i «_.@-'»", + "A valid Login must be provided" : "Heu de proporcionar un inici de sessió vàlid", + "Login contains whitespace at the beginning or at the end" : "L'inici de sessió conté espais en blanc al principi o al final", + "Login must not consist of dots only" : "L'inici de sessió no pot estar format només per punts", + "Login is invalid because files already exist for this user" : "L'inici de sessió no és vàlid perquè ja existeixen fitxers per a aquest usuari", + "Account disabled" : "El compte està inhabilitat", "Login canceled by app" : "L'aplicació ha cancel·lat l'inici de sessió", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "L'aplicació «%1$s» no es pot instal·lar perquè no es compleixen les dependències següents: %2$s", "a safe home for all your data" : "Un lloc segur per a totes les vostres dades", @@ -245,8 +245,8 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Demaneu a l'administrador que reiniciï el servidor web.", "The required %s config variable is not configured in the config.php file." : "No s'ha configurat la variable obligatòria %s en el fitxer config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Demaneu a l'administrador del servidor que comprovi la configuració del Nextcloud.", - "Your data directory is readable by other users." : "Els altres usuaris poden llegir la carpeta de dades.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Canvieu els permisos a 0770 perquè els altres usuaris no puguin veure el contingut de la carpeta.", + "Your data directory is readable by other people." : "Altres persones poden llegir la carpeta de dades.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Canvieu els permisos a 0770 perquè altres persones no puguin veure el contingut de la carpeta.", "Your data directory must be an absolute path." : "La carpeta de dades ha de ser un camí absolut.", "Check the value of \"datadirectory\" in your configuration." : "Comproveu el valor de «datadirectory» en la configuració.", "Your data directory is invalid." : "La carpeta de dades no és vàlida.", @@ -271,12 +271,32 @@ OC.L10N.register( "Extract topics" : "Extreu els temes", "Extracts topics from a text and outputs them separated by commas." : "Extreu els temes d'un text i els retorna separats per comes.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Els fitxers de l'aplicació %1$s no s'han substituït correctament. Assegureu-vos que sigui una versió compatible amb el servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'usuari que ha iniciat la sessió ha de ser administrador, subadministrador o tenir un dret especial per a accedir a aquest paràmetre", + "Logged in user must be an admin or sub admin" : "L'usuari que ha iniciat la sessió ha de ser administrador o subadministrador", + "Logged in user must be an admin" : "L'usuari que ha iniciat la sessió ha de ser administrador", "Full name" : "Nom complet", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "S'ha assolit el límit d'usuaris i no s'ha creat l'usuari. Consulteu les notificacions per a obtenir més informació.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Només es permeten els caràcters següents en un nom d'usuari: «a-z», «A-Z», «0-9» i «_.@-'»", + "Unknown user" : "Usuari desconegut", + "Enter the database username and name for %s" : "Introduïu el nom d'usuari i el nom de la base de dades per a %s", + "Enter the database username for %s" : "Introduïu el nom d'usuari de la base de dades per a %s", + "MySQL username and/or password not valid" : "El nom d'usuari o la contrasenya del MySQL no són vàlids", + "Oracle username and/or password not valid" : "El nom d'usuari o la contrasenya d'Oracle no són vàlids", + "PostgreSQL username and/or password not valid" : "El nom d'usuari o la contrasenya del PostgreSQL no són vàlids", + "Set an admin username." : "Definiu un nom d'usuari per a l'administrador.", + "Sharing %s failed, because this item is already shared with user %s" : "No s'ha pogut compartir %s perquè l'element ja està compartit amb l'usuari %s", + "The username is already being used" : "El nom d'usuari ja està en ús", + "Could not create user" : "No s'ha pogut crear l'usuari", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Només es permeten els caràcters següents en un nom d'usuari: «a-z», «A-Z», «0-9», espais i «_.@-'»", + "A valid username must be provided" : "Heu de proporcionar un nom d'usuari vàlid", + "Username contains whitespace at the beginning or at the end" : "El nom d'usuari conté espais en blanc al principi o al final", + "Username must not consist of dots only" : "El nom d'usuari no pot estar format només per punts", + "Username is invalid because files already exist for this user" : "El nom d'usuari no és vàlid perquè ja existeixen fitxers per a aquest usuari", + "User disabled" : "Usuari inhabilitat", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Cal almenys libxml2 2.7.0. Actualment s'ha instal·lat %s.", "To fix this issue update your libxml2 version and restart your web server." : "Per a resoldre aquest problema, actualitzeu la versió de libxml2 i reinicieu el servidor web.", "PostgreSQL >= 9 required." : "Cal el PostgreSQL >= 9.", - "Please upgrade your database version." : "Actualitzeu la versió de la base de dades." + "Please upgrade your database version." : "Actualitzeu la versió de la base de dades.", + "Your data directory is readable by other users." : "Els altres usuaris poden llegir la carpeta de dades.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Canvieu els permisos a 0770 perquè els altres usuaris no puguin veure el contingut de la carpeta." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/ca.json b/lib/l10n/ca.json index e18f5be8c9d..e2115aa2e38 100644 --- a/lib/l10n/ca.json +++ b/lib/l10n/ca.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Falta l'aplicació %1$s o té una versió no compatible amb aquest servidor. Comproveu la carpeta d'aplicacions.", "Sample configuration detected" : "S'ha detectat una configuració d'exemple", "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" : "S'ha detectat que s'ha copiat la configuració d'exemple. Això no s'admet i pot malmetre la instal·lació. Llegiu la documentació abans d'aplicar cap canvi al fitxer config.php", - "404" : "404", "The page could not be found on the server." : "No s'ha pogut trobar la pàgina en el servidor.", "%s email verification" : "Verificació de l'adreça electrònica del %s", "Email verification" : "Verificació de l'adreça electrònica", @@ -22,6 +21,7 @@ "Enterprise bundle" : "Paquet empresarial", "Groupware bundle" : "Paquet de treball en grup", "Hub bundle" : "Paquet Hub", + "Public sector bundle" : "Paquet del sector públic", "Social sharing bundle" : "Paquet social", "PHP %s or higher is required." : "Cal el PHP %s o superior.", "PHP with a version lower than %s is required." : "Cal el PHP amb una versió inferior a la %s.", @@ -35,9 +35,9 @@ "The following platforms are supported: %s" : "S'admeten les plataformes següents: %s", "Server version %s or higher is required." : "Cal la versió del servidor %s o superior.", "Server version %s or lower is required." : "Cal una versió del servidor %s o inferior.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'usuari que ha iniciat la sessió ha de ser administrador, subadministrador o tenir un dret especial per a accedir a aquest paràmetre", - "Logged in user must be an admin or sub admin" : "L'usuari que ha iniciat la sessió ha de ser administrador o subadministrador", - "Logged in user must be an admin" : "L'usuari que ha iniciat la sessió ha de ser administrador", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "El compte que ha iniciat la sessió ha de ser administrador, subadministrador o tenir un dret especial per a accedir a aquest paràmetre", + "Logged in account must be an admin or sub admin" : "El compte que ha iniciat la sessió ha de ser administrador o subadministrador", + "Logged in account must be an admin" : "El compte que ha iniciat la sessió ha de ser administrador", "Wiping of device %s has started" : "S'ha començat a esborrar el dispositiu %s", "Wiping of device »%s« has started" : "S'ha començat a esborrar el dispositiu «%s»", "»%s« started remote wipe" : "«%s» ha començat a esborrar dades en remot", @@ -116,22 +116,22 @@ "Headline" : "Capçalera", "Organisation" : "Organització", "Role" : "Càrrec", - "Unknown user" : "Usuari desconegut", + "Unknown account" : "Compte desconegut", "Additional settings" : "Paràmetres addicionals", - "Enter the database username and name for %s" : "Introduïu el nom d'usuari i el nom de la base de dades per a %s", - "Enter the database username for %s" : "Introduïu el nom d'usuari de la base de dades per a %s", + "Enter the database Login and name for %s" : "Introduïu l'inici de sessió i el nom de la base de dades per a %s", + "Enter the database Login for %s" : "Introduïu l'inici de sessió de la base de dades per a %s", "Enter the database name for %s" : "Introduïu el nom de la base de dades per a %s", "You cannot use dots in the database name %s" : "No podeu utilitzar punts en el nom de la base de dades %s", - "MySQL username and/or password not valid" : "El nom d'usuari o la contrasenya del MySQL no són vàlids", + "MySQL Login and/or password not valid" : "L'inici de sessió o la contrasenya del MySQL no són vàlids", "You need to enter details of an existing account." : "Heu d'introduir els detalls d'un compte existent.", "Oracle connection could not be established" : "No s'ha pogut establir la connexió amb Oracle", - "Oracle username and/or password not valid" : "El nom d'usuari o la contrasenya d'Oracle no són vàlids", - "PostgreSQL username and/or password not valid" : "El nom d'usuari o la contrasenya del PostgreSQL no són vàlids", + "Oracle Login and/or password not valid" : "L'inici de sessió o la contrasenya d'Oracle no són vàlids", + "PostgreSQL Login and/or password not valid" : "L'inici de sessió o la contrasenya del PostgreSQL no són vàlids", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "El Mac OS X no s'admet i el %s no funcionarà correctament en aquesta plataforma. Utilitzeu-lo sota el vostre propi risc! ", "For the best results, please consider using a GNU/Linux server instead." : "Per a obtenir els millors resultats, considereu la possibilitat d'utilitzar un servidor amb 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." : "Sembla que aquesta instància del %s s'està executant en un entorn del PHP de 32 bits i que s'ha configurat open_basedir en el fitxer php.ini. Això comportarà problemes amb els fitxers de més de 4 GB i és molt poc recomanable.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Suprimiu el paràmetre open_basedir del fitxer php.ini o canvieu al PHP de 64 bits.", - "Set an admin username." : "Definiu un nom d'usuari per a l'administrador.", + "Set an admin Login." : "Definiu un inici de sessió per a l'administrador.", "Set an admin password." : "Definiu una contrasenya per a l'administrador.", "Cannot create or write into the data directory %s" : "No es pot crear la carpeta de dades %s ni escriure-hi", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El rerefons d'ús compartit %s ha d'implementar la interfície OCP\\Share_Backend", @@ -149,7 +149,7 @@ "Expiration date is in the past" : "La data de caducitat ja ha passat", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No es pot establir la data de caducitat més d'%n dia en el futur","No es pot establir la data de caducitat més de %n dies en el futur"], "Sharing is only allowed with group members" : "Només es permet l'ús compartit amb membres del grup", - "Sharing %s failed, because this item is already shared with user %s" : "No s'ha pogut compartir %s perquè l'element ja està compartit amb l'usuari %s", + "Sharing %s failed, because this item is already shared with the account %s" : "No s'ha pogut compartir %s perquè l'element ja està compartit amb el compte %s", "%1$s shared »%2$s« with you" : "%1$s ha compartit «%2$s» amb vós", "%1$s shared »%2$s« with you." : "%1$s ha compartit «%2$s» amb vós.", "Click the button below to open it." : "Feu clic en el botó següent per a obrir-ho.", @@ -203,14 +203,14 @@ "Nov." : "Nov.", "Dec." : "Des.", "A valid password must be provided" : "Heu de proporcionar una contrasenya vàlida", - "The username is already being used" : "El nom d'usuari ja està en ús", - "Could not create user" : "No s'ha pogut crear l'usuari", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Només es permeten els caràcters següents en un nom d'usuari: «a-z», «A-Z», «0-9», espais i «_.@-'»", - "A valid username must be provided" : "Heu de proporcionar un nom d'usuari vàlid", - "Username contains whitespace at the beginning or at the end" : "El nom d'usuari conté espais en blanc al principi o al final", - "Username must not consist of dots only" : "El nom d'usuari no pot estar format només per punts", - "Username is invalid because files already exist for this user" : "El nom d'usuari no és vàlid perquè ja existeixen fitxers per a aquest usuari", - "User disabled" : "Usuari inhabilitat", + "The Login is already being used" : "L'inici de sessió ja està en ús", + "Could not create account" : "No s'ha pogut crear el compte", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Només es permeten els caràcters següents en un inici de sessió: «a-z», «A-Z», «0-9», espais i «_.@-'»", + "A valid Login must be provided" : "Heu de proporcionar un inici de sessió vàlid", + "Login contains whitespace at the beginning or at the end" : "L'inici de sessió conté espais en blanc al principi o al final", + "Login must not consist of dots only" : "L'inici de sessió no pot estar format només per punts", + "Login is invalid because files already exist for this user" : "L'inici de sessió no és vàlid perquè ja existeixen fitxers per a aquest usuari", + "Account disabled" : "El compte està inhabilitat", "Login canceled by app" : "L'aplicació ha cancel·lat l'inici de sessió", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "L'aplicació «%1$s» no es pot instal·lar perquè no es compleixen les dependències següents: %2$s", "a safe home for all your data" : "Un lloc segur per a totes les vostres dades", @@ -243,8 +243,8 @@ "Please ask your server administrator to restart the web server." : "Demaneu a l'administrador que reiniciï el servidor web.", "The required %s config variable is not configured in the config.php file." : "No s'ha configurat la variable obligatòria %s en el fitxer config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Demaneu a l'administrador del servidor que comprovi la configuració del Nextcloud.", - "Your data directory is readable by other users." : "Els altres usuaris poden llegir la carpeta de dades.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Canvieu els permisos a 0770 perquè els altres usuaris no puguin veure el contingut de la carpeta.", + "Your data directory is readable by other people." : "Altres persones poden llegir la carpeta de dades.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Canvieu els permisos a 0770 perquè altres persones no puguin veure el contingut de la carpeta.", "Your data directory must be an absolute path." : "La carpeta de dades ha de ser un camí absolut.", "Check the value of \"datadirectory\" in your configuration." : "Comproveu el valor de «datadirectory» en la configuració.", "Your data directory is invalid." : "La carpeta de dades no és vàlida.", @@ -269,12 +269,32 @@ "Extract topics" : "Extreu els temes", "Extracts topics from a text and outputs them separated by commas." : "Extreu els temes d'un text i els retorna separats per comes.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Els fitxers de l'aplicació %1$s no s'han substituït correctament. Assegureu-vos que sigui una versió compatible amb el servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'usuari que ha iniciat la sessió ha de ser administrador, subadministrador o tenir un dret especial per a accedir a aquest paràmetre", + "Logged in user must be an admin or sub admin" : "L'usuari que ha iniciat la sessió ha de ser administrador o subadministrador", + "Logged in user must be an admin" : "L'usuari que ha iniciat la sessió ha de ser administrador", "Full name" : "Nom complet", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "S'ha assolit el límit d'usuaris i no s'ha creat l'usuari. Consulteu les notificacions per a obtenir més informació.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Només es permeten els caràcters següents en un nom d'usuari: «a-z», «A-Z», «0-9» i «_.@-'»", + "Unknown user" : "Usuari desconegut", + "Enter the database username and name for %s" : "Introduïu el nom d'usuari i el nom de la base de dades per a %s", + "Enter the database username for %s" : "Introduïu el nom d'usuari de la base de dades per a %s", + "MySQL username and/or password not valid" : "El nom d'usuari o la contrasenya del MySQL no són vàlids", + "Oracle username and/or password not valid" : "El nom d'usuari o la contrasenya d'Oracle no són vàlids", + "PostgreSQL username and/or password not valid" : "El nom d'usuari o la contrasenya del PostgreSQL no són vàlids", + "Set an admin username." : "Definiu un nom d'usuari per a l'administrador.", + "Sharing %s failed, because this item is already shared with user %s" : "No s'ha pogut compartir %s perquè l'element ja està compartit amb l'usuari %s", + "The username is already being used" : "El nom d'usuari ja està en ús", + "Could not create user" : "No s'ha pogut crear l'usuari", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Només es permeten els caràcters següents en un nom d'usuari: «a-z», «A-Z», «0-9», espais i «_.@-'»", + "A valid username must be provided" : "Heu de proporcionar un nom d'usuari vàlid", + "Username contains whitespace at the beginning or at the end" : "El nom d'usuari conté espais en blanc al principi o al final", + "Username must not consist of dots only" : "El nom d'usuari no pot estar format només per punts", + "Username is invalid because files already exist for this user" : "El nom d'usuari no és vàlid perquè ja existeixen fitxers per a aquest usuari", + "User disabled" : "Usuari inhabilitat", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Cal almenys libxml2 2.7.0. Actualment s'ha instal·lat %s.", "To fix this issue update your libxml2 version and restart your web server." : "Per a resoldre aquest problema, actualitzeu la versió de libxml2 i reinicieu el servidor web.", "PostgreSQL >= 9 required." : "Cal el PostgreSQL >= 9.", - "Please upgrade your database version." : "Actualitzeu la versió de la base de dades." + "Please upgrade your database version." : "Actualitzeu la versió de la base de dades.", + "Your data directory is readable by other users." : "Els altres usuaris poden llegir la carpeta de dades.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Canvieu els permisos a 0770 perquè els altres usuaris no puguin veure el contingut de la carpeta." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/cs.js b/lib/l10n/cs.js index 422c9e0cee5..41c2961eeb5 100644 --- a/lib/l10n/cs.js +++ b/lib/l10n/cs.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplikace %1$s není přítomná nebo její verze není kompatibilní s tímto serverem. Zkontrolujte složku s aplikacemi. ", "Sample configuration detected" : "Bylo zjištěno setrvání u předváděcího nastavení", "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" : "Pravděpodobně byla zkopírována nastavení ze vzorových souborů. Toto není podporováno a může poškodit vaši instalaci. Před prováděním změn v souboru config.php si přečtěte dokumentaci", - "404" : "404", "The page could not be found on the server." : "Stránka nebyla na serveru nalezena.", "%s email verification" : "%s ověřování e-mailem", "Email verification" : "Ověřování e-mailem", @@ -37,9 +36,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Jsou podporovány následující systémy: %s", "Server version %s or higher is required." : "Je potřeba verze serveru %s nebo novější.", "Server version %s or lower is required." : "Je potřeba verze serveru %s nebo starší.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Aby mohl přistupovat k tomuto nastavení je třeba, aby přihlášený uživatel byl správce, dílčí správce nebo obdržel speciální oprávnění", - "Logged in user must be an admin or sub admin" : "Je třeba, aby přihlášený uživatel byl správcem či správcem pro dílčí oblast", - "Logged in user must be an admin" : "Je třeba, aby přihlášený uživatel byl správce", "Wiping of device %s has started" : "Vymazávání ze zařízení %s zahájeno", "Wiping of device »%s« has started" : "Vymazávání ze zařízení „%s“ zahájeno", "»%s« started remote wipe" : "„%s“ zahájilo vymazávání na dálku", @@ -118,26 +114,19 @@ OC.L10N.register( "Headline" : "Nadpis", "Organisation" : "Organizace", "Role" : "Role", - "Unknown user" : "Neznámý uživatel", "Additional settings" : "Další nastavení", - "Enter the database username and name for %s" : "Zadejte uživatelské jméno v databázi a název pro %s", - "Enter the database username for %s" : "Zadejte uživatelské jméno v databázi pro %s", "Enter the database name for %s" : "Zadejte název databáze pro %s", "You cannot use dots in the database name %s" : "V názvu databáze %s není možné použít tečky", - "MySQL username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do MySQL", "You need to enter details of an existing account." : "Je třeba zadat podrobnosti existujícího účtu.", "Oracle connection could not be established" : "Spojení s Oracle nemohlo být navázáno", - "Oracle username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do Oracle", - "PostgreSQL username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do PostgreSQL", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "macOS není podporován a %s nebude na této platformě správně fungovat. Používejte pouze na vlastní nebezpečí!", "For the best results, please consider using a GNU/Linux server instead." : "Místo toho zvažte pro nejlepší funkčnost použití GNU/Linux serveru.", "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." : "Zdá se, že tato instance %s je provozována v 32-bitovém PHP prostředí a v php.ini je nastavena volba open_basedir. Toto povede k problémům se soubory většími než 4 GB a silně není doporučováno.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Odstraňte z php.ini nastavení volby open_basedir nebo přejděte na 64-bitové PHP.", - "Set an admin username." : "Nastavte uživatelské jméno správce.", "Set an admin password." : "Nastavte heslo pro účet správce.", "Cannot create or write into the data directory %s" : "Nedaří se vytvořit nebo zapisovat do datového adresáře %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Je třeba, aby podpůrná vrstva pro sdílení %s implementovala rozhraní OCP\\Share_Backend", - "Sharing backend %s not found" : "Úložiště sdílení %s nenalezeno", + "Sharing backend %s not found" : "Podpůrná vrstva pro sdílení %s nenalezena", "Sharing backend for %s not found" : "Úložiště sdílení pro %s nenalezeno", "%1$s shared »%2$s« with you and wants to add:" : "%1$s sdílí „%2$s“ a dodává:", "%1$s shared »%2$s« with you and wants to add" : "%1$s sdílí „%2$s“ a dodává", @@ -151,11 +140,11 @@ OC.L10N.register( "Expiration date is in the past" : "Datum skončení platnosti je v minulosti", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Datum vypršení nelze nastavit na více než %n den do budoucnosti","Datum vypršení nelze nastavit na více než %n dny do budoucnosti","Datum vypršení nelze nastavit na více než %n dnů do budoucnosti","Datum vypršení nelze nastavit na více než %n dny do budoucnosti"], "Sharing is only allowed with group members" : "Je povoleno pouze sdílení s členy skupiny", - "Sharing %s failed, because this item is already shared with user %s" : "Sdílení %s se nezdařilo, protože tato položka už je sdílena s uživatelem %s", "%1$s shared »%2$s« with you" : "%1$s vám sdílí „%2$s“", "%1$s shared »%2$s« with you." : "%1$s vám nasdílel(a) „%2$s“.", "Click the button below to open it." : "Pro otevření klikněte na tlačítko níže.", "The requested share does not exist anymore" : "Požadované sdílení už neexistuje", + "The requested share comes from a disabled user" : "Požadované sdílení pochází od vypnutého uživatelského účtu", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Uživatel nebyl vytvořen protože bylo dosaženo limitu počtu uživatelů. Více se dozvíte v upozorněních.", "Could not find category \"%s\"" : "Nedaří se nalézt kategorii „%s“", "Sunday" : "neděle", @@ -204,14 +193,6 @@ OC.L10N.register( "Nov." : "list.", "Dec." : "pro.", "A valid password must be provided" : "Je třeba zadat platné heslo", - "The username is already being used" : "Uživatelské jméno už je využíváno", - "Could not create user" : "Nepodařilo se vytvořit uživatele", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Pouze následující znaky jsou povoleny pro uživatelské jméno: „a-z“, „A-Z“, „0-9“, mezery a „_.@-'“", - "A valid username must be provided" : "Je třeba zadat platné uživatelské jméno", - "Username contains whitespace at the beginning or at the end" : "Uživatelské jméno je chybné – na jeho začátku či konci se nachází prázdný znak (mezera, tabulátor, atp.)", - "Username must not consist of dots only" : "Uživatelské jméno se nemůže skládat pouze ze samých teček", - "Username is invalid because files already exist for this user" : "Uživatelské jméno není platné, protože protože pro tohoto uživatele už existují soubory", - "User disabled" : "Uživatel zakázán", "Login canceled by app" : "Přihlášení zrušeno aplikací", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Aplikaci „%1$s“ nelze nainstalovat, protože nejsou splněny následující závislosti: %2$s", "a safe home for all your data" : "bezpečný domov pro všechna vaše data", @@ -240,12 +221,10 @@ OC.L10N.register( "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Pro nápravu nastavte v souboru php.ini parametr <code>mbstring.func_overload</code> na <code>0</code>.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP je patrně nastaveno tak, aby odstraňovalo bloky komentářů. Toto bude mít za následek znepřístupnění mnoha důležitých aplikací.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Toto je pravděpodobně způsobeno aplikacemi pro urychlení načítání jako jsou Zend OPcache nebo eAccelerator.", - "PHP modules have been installed, but they are still listed as missing?" : "PHP moduly jsou nainstalovány, ale stále se tváří jako chybějící?", + "PHP modules have been installed, but they are still listed as missing?" : "PHP moduly jsou nainstalovány, přesto jsou uváděny jako chybějící?", "Please ask your server administrator to restart the web server." : "Požádejte správce serveru, který využíváte o restart webového serveru.", "The required %s config variable is not configured in the config.php file." : "Požadovaná proměnná nastavení %s není v souboru s nastaveními config.php nastavena.", "Please ask your server administrator to check the Nextcloud configuration." : "Požádejte správce serveru, který využíváte, aby zkontroloval nastavení serveru.", - "Your data directory is readable by other users." : "Váš adresář data je čitelný ostatním uživatelům.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Změňte práva na 0770, aby obsah adresáře nemohl být vypisován ostatními uživateli.", "Your data directory must be an absolute path." : "Je třeba, aby váš adresář data byl zadán jako úplný popis umístění.", "Check the value of \"datadirectory\" in your configuration." : "Zkontrolujte hodnotu „datadirectory“ ve svém nastavení.", "Your data directory is invalid." : "Váš adresář data není platný.", @@ -270,12 +249,32 @@ OC.L10N.register( "Extract topics" : "Vyzískat témata", "Extracts topics from a text and outputs them separated by commas." : "Vyzíská témata z textu a vypíše je oddělované čárkami.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Soubory aplikace %1$s nebyly nahrazeny řádně. Ověřte, že se jedná o verzi, která je kompatibilní se serverem.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Aby mohl přistupovat k tomuto nastavení je třeba, aby přihlášený uživatel byl správce, dílčí správce nebo obdržel speciální oprávnění", + "Logged in user must be an admin or sub admin" : "Je třeba, aby přihlášený uživatel byl správcem či správcem pro dílčí oblast", + "Logged in user must be an admin" : "Je třeba, aby přihlášený uživatel byl správce", "Full name" : "Celé jméno", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Bylo dosaženo limitu počtu uživatelů a uživatel proto nebyl vytvořen. Podrobnosti viz upozornění pro vás.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Pouze následující znaky jsou povoleny pro uživatelské jméno: „a-z“, „A-Z“, „0-9“, a „_.@-'“", + "Unknown user" : "Neznámý uživatel", + "Enter the database username and name for %s" : "Zadejte uživatelské jméno v databázi a název pro %s", + "Enter the database username for %s" : "Zadejte uživatelské jméno v databázi pro %s", + "MySQL username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do MySQL", + "Oracle username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do Oracle", + "PostgreSQL username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do PostgreSQL", + "Set an admin username." : "Nastavte uživatelské jméno správce.", + "Sharing %s failed, because this item is already shared with user %s" : "Sdílení %s se nezdařilo, protože tato položka už je sdílena s uživatelem %s", + "The username is already being used" : "Uživatelské jméno už je využíváno", + "Could not create user" : "Nepodařilo se vytvořit uživatele", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Pouze následující znaky jsou povoleny pro uživatelské jméno: „a-z“, „A-Z“, „0-9“, mezery a „_.@-'“", + "A valid username must be provided" : "Je třeba zadat platné uživatelské jméno", + "Username contains whitespace at the beginning or at the end" : "Uživatelské jméno je chybné – na jeho začátku či konci se nachází prázdný znak (mezera, tabulátor, atp.)", + "Username must not consist of dots only" : "Uživatelské jméno se nemůže skládat pouze ze samých teček", + "Username is invalid because files already exist for this user" : "Uživatelské jméno není platné, protože protože pro tohoto uživatele už existují soubory", + "User disabled" : "Uživatel zakázán", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Je zapotřebí verze softwarové knihovny libxml2 přinejmenším 2.7.0. Nyní je nainstalována verze %s.", "To fix this issue update your libxml2 version and restart your web server." : "Tento problém opravíte instalací novější verze knihovny libxml2 a restartem webového serveru.", "PostgreSQL >= 9 required." : "Je vyžadováno PostgreSQL verze 9 a novější.", - "Please upgrade your database version." : "Aktualizujte verzi vámi využívané databáze." + "Please upgrade your database version." : "Aktualizujte verzi vámi využívané databáze.", + "Your data directory is readable by other users." : "Váš adresář data je čitelný ostatním uživatelům.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Změňte práva na 0770, aby obsah adresáře nemohl být vypisován ostatními uživateli." }, "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 164c56f7e47..360807213f9 100644 --- a/lib/l10n/cs.json +++ b/lib/l10n/cs.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplikace %1$s není přítomná nebo její verze není kompatibilní s tímto serverem. Zkontrolujte složku s aplikacemi. ", "Sample configuration detected" : "Bylo zjištěno setrvání u předváděcího nastavení", "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" : "Pravděpodobně byla zkopírována nastavení ze vzorových souborů. Toto není podporováno a může poškodit vaši instalaci. Před prováděním změn v souboru config.php si přečtěte dokumentaci", - "404" : "404", "The page could not be found on the server." : "Stránka nebyla na serveru nalezena.", "%s email verification" : "%s ověřování e-mailem", "Email verification" : "Ověřování e-mailem", @@ -35,9 +34,6 @@ "The following platforms are supported: %s" : "Jsou podporovány následující systémy: %s", "Server version %s or higher is required." : "Je potřeba verze serveru %s nebo novější.", "Server version %s or lower is required." : "Je potřeba verze serveru %s nebo starší.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Aby mohl přistupovat k tomuto nastavení je třeba, aby přihlášený uživatel byl správce, dílčí správce nebo obdržel speciální oprávnění", - "Logged in user must be an admin or sub admin" : "Je třeba, aby přihlášený uživatel byl správcem či správcem pro dílčí oblast", - "Logged in user must be an admin" : "Je třeba, aby přihlášený uživatel byl správce", "Wiping of device %s has started" : "Vymazávání ze zařízení %s zahájeno", "Wiping of device »%s« has started" : "Vymazávání ze zařízení „%s“ zahájeno", "»%s« started remote wipe" : "„%s“ zahájilo vymazávání na dálku", @@ -116,26 +112,19 @@ "Headline" : "Nadpis", "Organisation" : "Organizace", "Role" : "Role", - "Unknown user" : "Neznámý uživatel", "Additional settings" : "Další nastavení", - "Enter the database username and name for %s" : "Zadejte uživatelské jméno v databázi a název pro %s", - "Enter the database username for %s" : "Zadejte uživatelské jméno v databázi pro %s", "Enter the database name for %s" : "Zadejte název databáze pro %s", "You cannot use dots in the database name %s" : "V názvu databáze %s není možné použít tečky", - "MySQL username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do MySQL", "You need to enter details of an existing account." : "Je třeba zadat podrobnosti existujícího účtu.", "Oracle connection could not be established" : "Spojení s Oracle nemohlo být navázáno", - "Oracle username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do Oracle", - "PostgreSQL username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do PostgreSQL", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "macOS není podporován a %s nebude na této platformě správně fungovat. Používejte pouze na vlastní nebezpečí!", "For the best results, please consider using a GNU/Linux server instead." : "Místo toho zvažte pro nejlepší funkčnost použití GNU/Linux serveru.", "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." : "Zdá se, že tato instance %s je provozována v 32-bitovém PHP prostředí a v php.ini je nastavena volba open_basedir. Toto povede k problémům se soubory většími než 4 GB a silně není doporučováno.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Odstraňte z php.ini nastavení volby open_basedir nebo přejděte na 64-bitové PHP.", - "Set an admin username." : "Nastavte uživatelské jméno správce.", "Set an admin password." : "Nastavte heslo pro účet správce.", "Cannot create or write into the data directory %s" : "Nedaří se vytvořit nebo zapisovat do datového adresáře %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Je třeba, aby podpůrná vrstva pro sdílení %s implementovala rozhraní OCP\\Share_Backend", - "Sharing backend %s not found" : "Úložiště sdílení %s nenalezeno", + "Sharing backend %s not found" : "Podpůrná vrstva pro sdílení %s nenalezena", "Sharing backend for %s not found" : "Úložiště sdílení pro %s nenalezeno", "%1$s shared »%2$s« with you and wants to add:" : "%1$s sdílí „%2$s“ a dodává:", "%1$s shared »%2$s« with you and wants to add" : "%1$s sdílí „%2$s“ a dodává", @@ -149,11 +138,11 @@ "Expiration date is in the past" : "Datum skončení platnosti je v minulosti", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Datum vypršení nelze nastavit na více než %n den do budoucnosti","Datum vypršení nelze nastavit na více než %n dny do budoucnosti","Datum vypršení nelze nastavit na více než %n dnů do budoucnosti","Datum vypršení nelze nastavit na více než %n dny do budoucnosti"], "Sharing is only allowed with group members" : "Je povoleno pouze sdílení s členy skupiny", - "Sharing %s failed, because this item is already shared with user %s" : "Sdílení %s se nezdařilo, protože tato položka už je sdílena s uživatelem %s", "%1$s shared »%2$s« with you" : "%1$s vám sdílí „%2$s“", "%1$s shared »%2$s« with you." : "%1$s vám nasdílel(a) „%2$s“.", "Click the button below to open it." : "Pro otevření klikněte na tlačítko níže.", "The requested share does not exist anymore" : "Požadované sdílení už neexistuje", + "The requested share comes from a disabled user" : "Požadované sdílení pochází od vypnutého uživatelského účtu", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Uživatel nebyl vytvořen protože bylo dosaženo limitu počtu uživatelů. Více se dozvíte v upozorněních.", "Could not find category \"%s\"" : "Nedaří se nalézt kategorii „%s“", "Sunday" : "neděle", @@ -202,14 +191,6 @@ "Nov." : "list.", "Dec." : "pro.", "A valid password must be provided" : "Je třeba zadat platné heslo", - "The username is already being used" : "Uživatelské jméno už je využíváno", - "Could not create user" : "Nepodařilo se vytvořit uživatele", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Pouze následující znaky jsou povoleny pro uživatelské jméno: „a-z“, „A-Z“, „0-9“, mezery a „_.@-'“", - "A valid username must be provided" : "Je třeba zadat platné uživatelské jméno", - "Username contains whitespace at the beginning or at the end" : "Uživatelské jméno je chybné – na jeho začátku či konci se nachází prázdný znak (mezera, tabulátor, atp.)", - "Username must not consist of dots only" : "Uživatelské jméno se nemůže skládat pouze ze samých teček", - "Username is invalid because files already exist for this user" : "Uživatelské jméno není platné, protože protože pro tohoto uživatele už existují soubory", - "User disabled" : "Uživatel zakázán", "Login canceled by app" : "Přihlášení zrušeno aplikací", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Aplikaci „%1$s“ nelze nainstalovat, protože nejsou splněny následující závislosti: %2$s", "a safe home for all your data" : "bezpečný domov pro všechna vaše data", @@ -238,12 +219,10 @@ "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Pro nápravu nastavte v souboru php.ini parametr <code>mbstring.func_overload</code> na <code>0</code>.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP je patrně nastaveno tak, aby odstraňovalo bloky komentářů. Toto bude mít za následek znepřístupnění mnoha důležitých aplikací.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Toto je pravděpodobně způsobeno aplikacemi pro urychlení načítání jako jsou Zend OPcache nebo eAccelerator.", - "PHP modules have been installed, but they are still listed as missing?" : "PHP moduly jsou nainstalovány, ale stále se tváří jako chybějící?", + "PHP modules have been installed, but they are still listed as missing?" : "PHP moduly jsou nainstalovány, přesto jsou uváděny jako chybějící?", "Please ask your server administrator to restart the web server." : "Požádejte správce serveru, který využíváte o restart webového serveru.", "The required %s config variable is not configured in the config.php file." : "Požadovaná proměnná nastavení %s není v souboru s nastaveními config.php nastavena.", "Please ask your server administrator to check the Nextcloud configuration." : "Požádejte správce serveru, který využíváte, aby zkontroloval nastavení serveru.", - "Your data directory is readable by other users." : "Váš adresář data je čitelný ostatním uživatelům.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Změňte práva na 0770, aby obsah adresáře nemohl být vypisován ostatními uživateli.", "Your data directory must be an absolute path." : "Je třeba, aby váš adresář data byl zadán jako úplný popis umístění.", "Check the value of \"datadirectory\" in your configuration." : "Zkontrolujte hodnotu „datadirectory“ ve svém nastavení.", "Your data directory is invalid." : "Váš adresář data není platný.", @@ -268,12 +247,32 @@ "Extract topics" : "Vyzískat témata", "Extracts topics from a text and outputs them separated by commas." : "Vyzíská témata z textu a vypíše je oddělované čárkami.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Soubory aplikace %1$s nebyly nahrazeny řádně. Ověřte, že se jedná o verzi, která je kompatibilní se serverem.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Aby mohl přistupovat k tomuto nastavení je třeba, aby přihlášený uživatel byl správce, dílčí správce nebo obdržel speciální oprávnění", + "Logged in user must be an admin or sub admin" : "Je třeba, aby přihlášený uživatel byl správcem či správcem pro dílčí oblast", + "Logged in user must be an admin" : "Je třeba, aby přihlášený uživatel byl správce", "Full name" : "Celé jméno", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Bylo dosaženo limitu počtu uživatelů a uživatel proto nebyl vytvořen. Podrobnosti viz upozornění pro vás.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Pouze následující znaky jsou povoleny pro uživatelské jméno: „a-z“, „A-Z“, „0-9“, a „_.@-'“", + "Unknown user" : "Neznámý uživatel", + "Enter the database username and name for %s" : "Zadejte uživatelské jméno v databázi a název pro %s", + "Enter the database username for %s" : "Zadejte uživatelské jméno v databázi pro %s", + "MySQL username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do MySQL", + "Oracle username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do Oracle", + "PostgreSQL username and/or password not valid" : "Neplatné uživatelské jméno a/nebo heslo do PostgreSQL", + "Set an admin username." : "Nastavte uživatelské jméno správce.", + "Sharing %s failed, because this item is already shared with user %s" : "Sdílení %s se nezdařilo, protože tato položka už je sdílena s uživatelem %s", + "The username is already being used" : "Uživatelské jméno už je využíváno", + "Could not create user" : "Nepodařilo se vytvořit uživatele", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Pouze následující znaky jsou povoleny pro uživatelské jméno: „a-z“, „A-Z“, „0-9“, mezery a „_.@-'“", + "A valid username must be provided" : "Je třeba zadat platné uživatelské jméno", + "Username contains whitespace at the beginning or at the end" : "Uživatelské jméno je chybné – na jeho začátku či konci se nachází prázdný znak (mezera, tabulátor, atp.)", + "Username must not consist of dots only" : "Uživatelské jméno se nemůže skládat pouze ze samých teček", + "Username is invalid because files already exist for this user" : "Uživatelské jméno není platné, protože protože pro tohoto uživatele už existují soubory", + "User disabled" : "Uživatel zakázán", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Je zapotřebí verze softwarové knihovny libxml2 přinejmenším 2.7.0. Nyní je nainstalována verze %s.", "To fix this issue update your libxml2 version and restart your web server." : "Tento problém opravíte instalací novější verze knihovny libxml2 a restartem webového serveru.", "PostgreSQL >= 9 required." : "Je vyžadováno PostgreSQL verze 9 a novější.", - "Please upgrade your database version." : "Aktualizujte verzi vámi využívané databáze." + "Please upgrade your database version." : "Aktualizujte verzi vámi využívané databáze.", + "Your data directory is readable by other users." : "Váš adresář data je čitelný ostatním uživatelům.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Změňte práva na 0770, aby obsah adresáře nemohl být vypisován ostatními uživateli." },"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/cy_GB.js b/lib/l10n/cy_GB.js index 43d76a38ee2..7884fe7e18a 100644 --- a/lib/l10n/cy_GB.js +++ b/lib/l10n/cy_GB.js @@ -17,11 +17,10 @@ OC.L10N.register( "Website" : "Gwefan", "Address" : "Cyfeiriad", "About" : "Ynghylch", - "Oracle username and/or password not valid" : "Enw a/neu gyfrinair Oracle annilys", - "PostgreSQL username and/or password not valid" : "Enw a/neu gyfrinair PostgreSQL annilys", - "Set an admin username." : "Creu enw defnyddiwr i'r gweinyddwr.", "Set an admin password." : "Gosod cyfrinair y gweinyddwr.", "Open »%s«" : "Agor »%s«", + "%1$s via %2$s" : "%1$s trwy %2$s", + "Click the button below to open it." : "Cliciwch ar y botwm isod i'w agor.", "Could not find category \"%s\"" : "Methu canfod categori \"%s\"", "Sunday" : "Sul", "Monday" : "Llun", @@ -63,6 +62,10 @@ OC.L10N.register( "Dec." : "Rhag.", "Application is not enabled" : "Nid yw'r pecyn wedi'i alluogi", "Authentication error" : "Gwall dilysu", - "Token expired. Please reload page." : "Tocyn wedi dod i ben. Ail-lwythwch y dudalen." + "Token expired. Please reload page." : "Tocyn wedi dod i ben. Ail-lwythwch y dudalen.", + "Full name" : "Enw llawn", + "Oracle username and/or password not valid" : "Enw a/neu gyfrinair Oracle annilys", + "PostgreSQL username and/or password not valid" : "Enw a/neu gyfrinair PostgreSQL annilys", + "Set an admin username." : "Creu enw defnyddiwr i'r gweinyddwr." }, "nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;"); diff --git a/lib/l10n/cy_GB.json b/lib/l10n/cy_GB.json index e2a8fb651ad..596994974dd 100644 --- a/lib/l10n/cy_GB.json +++ b/lib/l10n/cy_GB.json @@ -15,11 +15,10 @@ "Website" : "Gwefan", "Address" : "Cyfeiriad", "About" : "Ynghylch", - "Oracle username and/or password not valid" : "Enw a/neu gyfrinair Oracle annilys", - "PostgreSQL username and/or password not valid" : "Enw a/neu gyfrinair PostgreSQL annilys", - "Set an admin username." : "Creu enw defnyddiwr i'r gweinyddwr.", "Set an admin password." : "Gosod cyfrinair y gweinyddwr.", "Open »%s«" : "Agor »%s«", + "%1$s via %2$s" : "%1$s trwy %2$s", + "Click the button below to open it." : "Cliciwch ar y botwm isod i'w agor.", "Could not find category \"%s\"" : "Methu canfod categori \"%s\"", "Sunday" : "Sul", "Monday" : "Llun", @@ -61,6 +60,10 @@ "Dec." : "Rhag.", "Application is not enabled" : "Nid yw'r pecyn wedi'i alluogi", "Authentication error" : "Gwall dilysu", - "Token expired. Please reload page." : "Tocyn wedi dod i ben. Ail-lwythwch y dudalen." + "Token expired. Please reload page." : "Tocyn wedi dod i ben. Ail-lwythwch y dudalen.", + "Full name" : "Enw llawn", + "Oracle username and/or password not valid" : "Enw a/neu gyfrinair Oracle annilys", + "PostgreSQL username and/or password not valid" : "Enw a/neu gyfrinair PostgreSQL annilys", + "Set an admin username." : "Creu enw defnyddiwr i'r gweinyddwr." },"pluralForm" :"nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;" }
\ No newline at end of file diff --git a/lib/l10n/da.js b/lib/l10n/da.js index c549f68b3f3..6f39616a2b4 100644 --- a/lib/l10n/da.js +++ b/lib/l10n/da.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Applikationen %1$s er ikke til stede eller har en ikke-kompatibel version med denne server. Tjek venligst apps mappen.", "Sample configuration detected" : "Eksempel for konfiguration registreret", "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" : "Der er registreret at konfigurations eksemplet er blevet kopieret direkte. Dette kan ødelægge din installation og understøttes ikke. Læs venligst dokumentationen før der foretages ændringer i config.php", - "404" : "404", "The page could not be found on the server." : "Siden kunne ikke findes på serveren.", "%s email verification" : "%s email verifikation", "Email verification" : "Email verifikation", @@ -37,9 +36,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Følgende platforme understøttes: %s", "Server version %s or higher is required." : "Du skal have server version %s eller nyere.", "Server version %s or lower is required." : "Du skal have server version %s eller ældre.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Bruger skal være administrator, underadministrator eller have tildelt specielle rettigheder for at have adgang til denne indstilling", - "Logged in user must be an admin or sub admin" : "Bruger skal være administrator eller underadministrator", - "Logged in user must be an admin" : "Brugeren skal være administrator", "Wiping of device %s has started" : "Komplet sletning af enhed %s er påbegyndt", "Wiping of device »%s« has started" : "Komplet sletning af enhed »%s« er påbegyndt", "»%s« started remote wipe" : "Fjernsletning påbegyndt af »%s« ", @@ -77,7 +73,7 @@ OC.L10N.register( "_in %n minute_::_in %n minutes_" : ["om %n minut","om %n minutter"], "_%n minute ago_::_%n minutes ago_" : ["%n minut siden","%n minutter siden"], "in a few seconds" : "om få sekunder", - "seconds ago" : "sekunder siden", + "seconds ago" : "få sekunder siden", "Empty file" : "Tom fil", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Modulet med ID: %s eksisterer ikke. Aktiver det venligst i dine indstillinger eller kontakt din administrator.", "File already exists" : "Filen findes allerede", @@ -118,22 +114,15 @@ OC.L10N.register( "Headline" : "Overskrift", "Organisation" : "Organisation", "Role" : "Rolle", - "Unknown user" : "Ukendt bruger", "Additional settings" : "Yderligere indstillinger", - "Enter the database username and name for %s" : "Indtast navn til databasen og brugernavn for %s", - "Enter the database username for %s" : "Indtast brugernavn til databasen for %s", "Enter the database name for %s" : "Indtast databasenavnet for %s", "You cannot use dots in the database name %s" : "Du må ikke bruge punktummer i databasenavnet %s", - "MySQL username and/or password not valid" : "MySQL brugernavn og/eller kodeord er ikke gyldigt", "You need to enter details of an existing account." : "Du skal indtaste detaljerne for en eksisterende konto.", "Oracle connection could not be established" : "Oracle forbindelsen kunne ikke etableres", - "Oracle username and/or password not valid" : "Oracle brugernavn og/eller kodeord er ikke gyldigt.", - "PostgreSQL username and/or password not valid" : "PostgreSQL brugernavn og/eller kodeord er ikke gyldigt.", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X understøttes ikke og %s vil ikke virke optimalt på denne platform. Anvend på eget ansvar!", "For the best results, please consider using a GNU/Linux server instead." : "For de bedste resultater, overvej venligst at bruge en GNU/Linux-server i stedet.", "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." : "Det ser ud til, at denne %s-instans kører på et 32-bit PHP-miljø, samt at open_basedir er blevet konfigureret gennem php.ini. Dette vil føre til problemer med filer som er større end 4GB, og frarådes kraftigt.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Fjern venligst indstillingen for open_basedir inde i din php.ini eller skift til 64-bit PHP.", - "Set an admin username." : "Angiv et admin brugernavn.", "Set an admin password." : "Angiv et admin kodeord.", "Cannot create or write into the data directory %s" : "Kan ikke oprette eller skrive ind i datamappen %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Delingsbackend'en %s skal implementere grænsefladen OCP\\Share_Backend", @@ -151,7 +140,6 @@ OC.L10N.register( "Expiration date is in the past" : "Udløbsdatoen ligger tilbage i tid", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Udløbsdato kan ikke sættes mere end %n dag ud i fremtiden","Udløbsdato kan ikke sættes mere end %n dage ud i fremtiden"], "Sharing is only allowed with group members" : "Deling er kun tilladt med gruppemedlemmer", - "Sharing %s failed, because this item is already shared with user %s" : "Deling af %s mislykkedes, fordi dette element allerede er delt med brugeren %s", "%1$s shared »%2$s« with you" : "%1$s delte »%2$s« med dig", "%1$s shared »%2$s« with you." : "%1$s delte »%2$s« med dig", "Click the button below to open it." : "Klik på knappen nedenunder for at åbne.", @@ -204,14 +192,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "En gyldig adgangskode skal angives", - "The username is already being used" : "Brugernavnet er allerede i brug", - "Could not create user" : "Kunne ikke oprette bruger", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kun følgende tegn kan indgå i et brugernavn: \"a-z\", \"A-Z\", \"0-9\", mellemrum and \"_.@-'\"", - "A valid username must be provided" : "Et gyldigt brugernavn skal angives", - "Username contains whitespace at the beginning or at the end" : "Brugernavnet har et mellemrum i starten eller slutningen", - "Username must not consist of dots only" : "Brugernavnet må ikke bestå af rene prikker/punktummer", - "Username is invalid because files already exist for this user" : "Brugernavnet er ugyldigt, da der allerede eksisterer filer for denne bruger", - "User disabled" : "Bruger deaktiveret", "Login canceled by app" : "Login annulleret af app", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Appen \"%1$s\" kan ikke installeres, da følgende afhængigheder ikke imødekommes: %2$s", "a safe home for all your data" : "et sikkert hjem til alle dine data", @@ -244,8 +224,6 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Du bedes anmode din serveradministrator om at genstarte webserveren.", "The required %s config variable is not configured in the config.php file." : "Den krævede config variabel %s er ikke konfigureret i config.php filen.", "Please ask your server administrator to check the Nextcloud configuration." : "Du bedes anmode din serveradministrator om at kontrollere Nextcloud konfigurationen.", - "Your data directory is readable by other users." : "Datamappen kan læses af andre brugere.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Tilpas venligst rettigheder til 0770, så mappen ikke fremvises for andre brugere.", "Your data directory must be an absolute path." : "Datamappen skal have en absolut sti.", "Check the value of \"datadirectory\" in your configuration." : "Tjek værdien for \"datadictionary\" i din konfiguration.", "Your data directory is invalid." : "Datamappen er ugyldig.", @@ -270,12 +248,32 @@ OC.L10N.register( "Extract topics" : "Uddrag emner", "Extracts topics from a text and outputs them separated by commas." : "Uddrager emner fra en tekst og skriver dem adskilt af kommaer.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Filerne tilhørende appen %1$s blev ikke erstattet korrekt. Check at versionen er kompatibel med serveren.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Bruger skal være administrator, underadministrator eller have tildelt specielle rettigheder for at have adgang til denne indstilling", + "Logged in user must be an admin or sub admin" : "Bruger skal være administrator eller underadministrator", + "Logged in user must be an admin" : "Brugeren skal være administrator", "Full name" : "Fulde navn", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Grænsen for brugere er nået, og den nye bruger er ikke blevet oprettet. Læs dine notifikationer for at lære mere.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Kun følgende tegn kan indgå i et brugernavn: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Ukendt bruger", + "Enter the database username and name for %s" : "Indtast navn til databasen og brugernavn for %s", + "Enter the database username for %s" : "Indtast brugernavn til databasen for %s", + "MySQL username and/or password not valid" : "MySQL brugernavn og/eller kodeord er ikke gyldigt", + "Oracle username and/or password not valid" : "Oracle brugernavn og/eller kodeord er ikke gyldigt.", + "PostgreSQL username and/or password not valid" : "PostgreSQL brugernavn og/eller kodeord er ikke gyldigt.", + "Set an admin username." : "Angiv et admin brugernavn.", + "Sharing %s failed, because this item is already shared with user %s" : "Deling af %s mislykkedes, fordi dette element allerede er delt med brugeren %s", + "The username is already being used" : "Brugernavnet er allerede i brug", + "Could not create user" : "Kunne ikke oprette bruger", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kun følgende tegn kan indgå i et brugernavn: \"a-z\", \"A-Z\", \"0-9\", mellemrum and \"_.@-'\"", + "A valid username must be provided" : "Et gyldigt brugernavn skal angives", + "Username contains whitespace at the beginning or at the end" : "Brugernavnet har et mellemrum i starten eller slutningen", + "Username must not consist of dots only" : "Brugernavnet må ikke bestå af rene prikker/punktummer", + "Username is invalid because files already exist for this user" : "Brugernavnet er ugyldigt, da der allerede eksisterer filer for denne bruger", + "User disabled" : "Bruger deaktiveret", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 skal mindst være version 2.7.0. Du har version %s installeret.", "To fix this issue update your libxml2 version and restart your web server." : "Opdater din libxml2 version og genstart webserveren for at løse problemet.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 kræves.", - "Please upgrade your database version." : "Opgradér venligst din databaseversion." + "Please upgrade your database version." : "Opgradér venligst din databaseversion.", + "Your data directory is readable by other users." : "Datamappen kan læses af andre brugere.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Tilpas venligst rettigheder til 0770, så mappen ikke fremvises for andre brugere." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/da.json b/lib/l10n/da.json index 24b42a7ac5e..3f42b8b14ff 100644 --- a/lib/l10n/da.json +++ b/lib/l10n/da.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Applikationen %1$s er ikke til stede eller har en ikke-kompatibel version med denne server. Tjek venligst apps mappen.", "Sample configuration detected" : "Eksempel for konfiguration registreret", "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" : "Der er registreret at konfigurations eksemplet er blevet kopieret direkte. Dette kan ødelægge din installation og understøttes ikke. Læs venligst dokumentationen før der foretages ændringer i config.php", - "404" : "404", "The page could not be found on the server." : "Siden kunne ikke findes på serveren.", "%s email verification" : "%s email verifikation", "Email verification" : "Email verifikation", @@ -35,9 +34,6 @@ "The following platforms are supported: %s" : "Følgende platforme understøttes: %s", "Server version %s or higher is required." : "Du skal have server version %s eller nyere.", "Server version %s or lower is required." : "Du skal have server version %s eller ældre.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Bruger skal være administrator, underadministrator eller have tildelt specielle rettigheder for at have adgang til denne indstilling", - "Logged in user must be an admin or sub admin" : "Bruger skal være administrator eller underadministrator", - "Logged in user must be an admin" : "Brugeren skal være administrator", "Wiping of device %s has started" : "Komplet sletning af enhed %s er påbegyndt", "Wiping of device »%s« has started" : "Komplet sletning af enhed »%s« er påbegyndt", "»%s« started remote wipe" : "Fjernsletning påbegyndt af »%s« ", @@ -75,7 +71,7 @@ "_in %n minute_::_in %n minutes_" : ["om %n minut","om %n minutter"], "_%n minute ago_::_%n minutes ago_" : ["%n minut siden","%n minutter siden"], "in a few seconds" : "om få sekunder", - "seconds ago" : "sekunder siden", + "seconds ago" : "få sekunder siden", "Empty file" : "Tom fil", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Modulet med ID: %s eksisterer ikke. Aktiver det venligst i dine indstillinger eller kontakt din administrator.", "File already exists" : "Filen findes allerede", @@ -116,22 +112,15 @@ "Headline" : "Overskrift", "Organisation" : "Organisation", "Role" : "Rolle", - "Unknown user" : "Ukendt bruger", "Additional settings" : "Yderligere indstillinger", - "Enter the database username and name for %s" : "Indtast navn til databasen og brugernavn for %s", - "Enter the database username for %s" : "Indtast brugernavn til databasen for %s", "Enter the database name for %s" : "Indtast databasenavnet for %s", "You cannot use dots in the database name %s" : "Du må ikke bruge punktummer i databasenavnet %s", - "MySQL username and/or password not valid" : "MySQL brugernavn og/eller kodeord er ikke gyldigt", "You need to enter details of an existing account." : "Du skal indtaste detaljerne for en eksisterende konto.", "Oracle connection could not be established" : "Oracle forbindelsen kunne ikke etableres", - "Oracle username and/or password not valid" : "Oracle brugernavn og/eller kodeord er ikke gyldigt.", - "PostgreSQL username and/or password not valid" : "PostgreSQL brugernavn og/eller kodeord er ikke gyldigt.", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X understøttes ikke og %s vil ikke virke optimalt på denne platform. Anvend på eget ansvar!", "For the best results, please consider using a GNU/Linux server instead." : "For de bedste resultater, overvej venligst at bruge en GNU/Linux-server i stedet.", "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." : "Det ser ud til, at denne %s-instans kører på et 32-bit PHP-miljø, samt at open_basedir er blevet konfigureret gennem php.ini. Dette vil føre til problemer med filer som er større end 4GB, og frarådes kraftigt.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Fjern venligst indstillingen for open_basedir inde i din php.ini eller skift til 64-bit PHP.", - "Set an admin username." : "Angiv et admin brugernavn.", "Set an admin password." : "Angiv et admin kodeord.", "Cannot create or write into the data directory %s" : "Kan ikke oprette eller skrive ind i datamappen %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Delingsbackend'en %s skal implementere grænsefladen OCP\\Share_Backend", @@ -149,7 +138,6 @@ "Expiration date is in the past" : "Udløbsdatoen ligger tilbage i tid", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Udløbsdato kan ikke sættes mere end %n dag ud i fremtiden","Udløbsdato kan ikke sættes mere end %n dage ud i fremtiden"], "Sharing is only allowed with group members" : "Deling er kun tilladt med gruppemedlemmer", - "Sharing %s failed, because this item is already shared with user %s" : "Deling af %s mislykkedes, fordi dette element allerede er delt med brugeren %s", "%1$s shared »%2$s« with you" : "%1$s delte »%2$s« med dig", "%1$s shared »%2$s« with you." : "%1$s delte »%2$s« med dig", "Click the button below to open it." : "Klik på knappen nedenunder for at åbne.", @@ -202,14 +190,6 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "En gyldig adgangskode skal angives", - "The username is already being used" : "Brugernavnet er allerede i brug", - "Could not create user" : "Kunne ikke oprette bruger", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kun følgende tegn kan indgå i et brugernavn: \"a-z\", \"A-Z\", \"0-9\", mellemrum and \"_.@-'\"", - "A valid username must be provided" : "Et gyldigt brugernavn skal angives", - "Username contains whitespace at the beginning or at the end" : "Brugernavnet har et mellemrum i starten eller slutningen", - "Username must not consist of dots only" : "Brugernavnet må ikke bestå af rene prikker/punktummer", - "Username is invalid because files already exist for this user" : "Brugernavnet er ugyldigt, da der allerede eksisterer filer for denne bruger", - "User disabled" : "Bruger deaktiveret", "Login canceled by app" : "Login annulleret af app", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Appen \"%1$s\" kan ikke installeres, da følgende afhængigheder ikke imødekommes: %2$s", "a safe home for all your data" : "et sikkert hjem til alle dine data", @@ -242,8 +222,6 @@ "Please ask your server administrator to restart the web server." : "Du bedes anmode din serveradministrator om at genstarte webserveren.", "The required %s config variable is not configured in the config.php file." : "Den krævede config variabel %s er ikke konfigureret i config.php filen.", "Please ask your server administrator to check the Nextcloud configuration." : "Du bedes anmode din serveradministrator om at kontrollere Nextcloud konfigurationen.", - "Your data directory is readable by other users." : "Datamappen kan læses af andre brugere.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Tilpas venligst rettigheder til 0770, så mappen ikke fremvises for andre brugere.", "Your data directory must be an absolute path." : "Datamappen skal have en absolut sti.", "Check the value of \"datadirectory\" in your configuration." : "Tjek værdien for \"datadictionary\" i din konfiguration.", "Your data directory is invalid." : "Datamappen er ugyldig.", @@ -268,12 +246,32 @@ "Extract topics" : "Uddrag emner", "Extracts topics from a text and outputs them separated by commas." : "Uddrager emner fra en tekst og skriver dem adskilt af kommaer.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Filerne tilhørende appen %1$s blev ikke erstattet korrekt. Check at versionen er kompatibel med serveren.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Bruger skal være administrator, underadministrator eller have tildelt specielle rettigheder for at have adgang til denne indstilling", + "Logged in user must be an admin or sub admin" : "Bruger skal være administrator eller underadministrator", + "Logged in user must be an admin" : "Brugeren skal være administrator", "Full name" : "Fulde navn", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Grænsen for brugere er nået, og den nye bruger er ikke blevet oprettet. Læs dine notifikationer for at lære mere.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Kun følgende tegn kan indgå i et brugernavn: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Ukendt bruger", + "Enter the database username and name for %s" : "Indtast navn til databasen og brugernavn for %s", + "Enter the database username for %s" : "Indtast brugernavn til databasen for %s", + "MySQL username and/or password not valid" : "MySQL brugernavn og/eller kodeord er ikke gyldigt", + "Oracle username and/or password not valid" : "Oracle brugernavn og/eller kodeord er ikke gyldigt.", + "PostgreSQL username and/or password not valid" : "PostgreSQL brugernavn og/eller kodeord er ikke gyldigt.", + "Set an admin username." : "Angiv et admin brugernavn.", + "Sharing %s failed, because this item is already shared with user %s" : "Deling af %s mislykkedes, fordi dette element allerede er delt med brugeren %s", + "The username is already being used" : "Brugernavnet er allerede i brug", + "Could not create user" : "Kunne ikke oprette bruger", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kun følgende tegn kan indgå i et brugernavn: \"a-z\", \"A-Z\", \"0-9\", mellemrum and \"_.@-'\"", + "A valid username must be provided" : "Et gyldigt brugernavn skal angives", + "Username contains whitespace at the beginning or at the end" : "Brugernavnet har et mellemrum i starten eller slutningen", + "Username must not consist of dots only" : "Brugernavnet må ikke bestå af rene prikker/punktummer", + "Username is invalid because files already exist for this user" : "Brugernavnet er ugyldigt, da der allerede eksisterer filer for denne bruger", + "User disabled" : "Bruger deaktiveret", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 skal mindst være version 2.7.0. Du har version %s installeret.", "To fix this issue update your libxml2 version and restart your web server." : "Opdater din libxml2 version og genstart webserveren for at løse problemet.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 kræves.", - "Please upgrade your database version." : "Opgradér venligst din databaseversion." + "Please upgrade your database version." : "Opgradér venligst din databaseversion.", + "Your data directory is readable by other users." : "Datamappen kan læses af andre brugere.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Tilpas venligst rettigheder til 0770, så mappen ikke fremvises for andre brugere." },"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 4adbe25257c..b6e17bd7824 100644 --- a/lib/l10n/de.js +++ b/lib/l10n/de.js @@ -5,9 +5,9 @@ OC.L10N.register( "This can usually be fixed by giving the web server write access to the config directory." : "Dies kann normalerweise behoben werden, indem dem Webserver Schreibzugriff auf das config-Verzeichnis gegeben wird.", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Wenn du jedoch möchtest dass die Datei config.php schreibgeschützt bleiben soll, dann setze die Option \"config_is_read_only\" in der Datei auf true.", "See %s" : "Siehe %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Die Anwendung %1$s ist nicht vorhanden oder hat eine mit diesem Server nicht kompatible Version. Bitte überprüfe das Apps-Verzeichnis.", "Sample configuration detected" : "Beispielkonfiguration gefunden", "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" : "Es wurde festgestellt, dass die Beispielkonfiguration kopiert wurde. Dies kann deine Installation zerstören und wird nicht unterstützt. Bitte die Dokumentation lesen, bevor Änderungen an der config.php vorgenommen werden.", - "404" : "404", "The page could not be found on the server." : "Die Seite konnte auf dem Server nicht gefunden werden.", "%s email verification" : "%s E-Mail-Überprüfung", "Email verification" : "E-Mail-Überprüfung", @@ -36,9 +36,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Die folgenden Plattformen werden unterstützt: %s", "Server version %s or higher is required." : "Server Version %s oder höher wird benötigt.", "Server version %s or lower is required." : "Server Version %s oder niedriger wird benötigt.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Der angemeldete Benutzer muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen. ", - "Logged in user must be an admin or sub admin" : "Der angemeldete Benutzer muss ein (Sub-)Administrator sein", - "Logged in user must be an admin" : "Der angemeldete Benutzer muss ein Administrator sein", "Wiping of device %s has started" : "Löschen von Gerät %s wurde gestartet", "Wiping of device »%s« has started" : "Löschen von Gerät »%s« wurde gestartet", "»%s« started remote wipe" : "»%s« hat das Löschen aus der Ferne gestartet", @@ -96,7 +93,7 @@ OC.L10N.register( "Appearance and accessibility" : "Erscheinungsbild und Barrierefreiheit", "Apps" : "Apps", "Personal settings" : "Persönliche Einstellungen", - "Administration settings" : "Verwaltungs-Einstellungen", + "Administration settings" : "Verwaltungseinstellungen", "Settings" : "Einstellungen", "Log out" : "Abmelden", "Users" : "Benutzer", @@ -106,8 +103,8 @@ OC.L10N.register( "View %s on the fediverse" : "Zeige %s auf dem Fediverse", "Phone" : "Telefon", "Call %s" : "%s anrufen", - "Twitter" : "Twitter", - "View %s on Twitter" : "%s auf Twitter anzeigen", + "Twitter" : "X", + "View %s on Twitter" : "%s auf X anzeigen", "Website" : "Webseite", "Visit %s" : "%s besuchen", "Address" : "Adresse", @@ -117,22 +114,15 @@ OC.L10N.register( "Headline" : "Überschrift", "Organisation" : "Organisation", "Role" : "Funktion", - "Unknown user" : "Unbekannter Benutzer", "Additional settings" : "Zusätzliche Einstellungen", - "Enter the database username and name for %s" : "Den Datenbankbenutzernamen und den Namen eingeben für %s", - "Enter the database username for %s" : "Den Datenbankbenutzernamen eingeben für %s", "Enter the database name for %s" : "Den Datenbanknamen eingeben für %s", "You cannot use dots in the database name %s" : "Du kannst keine Punkte im Datenbanknamen %s verwenden.", - "MySQL username and/or password not valid" : "MySQL-Benutzername und/oder Passwort ungültig", "You need to enter details of an existing account." : "Du musst Details von einem existierenden Benutzer einfügen.", "Oracle connection could not be established" : "Es konnte keine Verbindung zur Oracle-Datenbank hergestellt werden", - "Oracle username and/or password not valid" : "Oracle-Benutzername und/oder -Passwort ungültig", - "PostgreSQL username and/or password not valid" : "PostgreSQL-Benutzername und/oder -Passwort ungültig", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X wird nicht unterstützt und %s wird auf dieser Plattform nicht richtig funktionieren. Die Benutzung erfolgt auf eigene Gefahr!", "For the best results, please consider using a GNU/Linux server instead." : "Zur Gewährleistung eines optimalen Betriebs sollte stattdessen ein GNU/Linux-Server verwendet werden.", "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." : "Es scheint, dass diese %s-Instanz unter einer 32-Bit-PHP-Umgebung läuft und open_basedir in der Datei php.ini konfiguriert worden ist. Von einem solchen Betrieb wird dringend abgeraten, weil es dabei zu Problemen mit Dateien kommt, deren Größe 4 GB übersteigt.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Bitte entferne die open_basedir-Einstellung in deiner php.ini oder wechsele zu 64-Bit-PHP.", - "Set an admin username." : "Einen Administrator-Benutzernamen setzen.", "Set an admin password." : "Ein Administrator-Passwort setzen.", "Cannot create or write into the data directory %s" : "Das Datenverzeichnis %s kann nicht erstellt oder es kann darin nicht geschrieben werden.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Freigabe-Backend %s muss in der OCP\\Share_Backend - Schnittstelle implementiert werden", @@ -150,11 +140,11 @@ OC.L10N.register( "Expiration date is in the past" : "Das Ablaufdatum liegt in der Vergangenheit.", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Das Ablaufdatum kann nicht mehr als %n Tag in der Zukunft liegen","Das Ablaufdatum kann nicht mehr als %n Tage in der Zukunft liegen"], "Sharing is only allowed with group members" : "Teilen ist nur mit Gruppenmitgliedern erlaubt", - "Sharing %s failed, because this item is already shared with user %s" : "Freigabe von %s fehlgeschlagen, da dieses Element schon mit dem Benutzer %s geteilt wird", "%1$s shared »%2$s« with you" : "%1$s hat »%2$s« mit dir geteilt", "%1$s shared »%2$s« with you." : "%1$s hat »%2$s« mit dir geteilt.", "Click the button below to open it." : "Klicke zum Öffnen auf die untere Schaltfläche.", "The requested share does not exist anymore" : "Die angeforderte Freigabe existiert nicht mehr", + "The requested share comes from a disabled user" : "Die angeforderte Freigabe stammt von einem deaktivierten Benutzer", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Der Benutzer wurde nicht erstellt, da das Benutzerlimit erreicht wurde. Überprüfe deine Benachrichtigungen, um mehr zu erfahren.", "Could not find category \"%s\"" : "Die Kategorie \"%s“ konnte nicht gefunden werden", "Sunday" : "Sonntag", @@ -203,14 +193,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dez.", "A valid password must be provided" : "Es muss ein gültiges Passwort eingegeben werden", - "The username is already being used" : "Dieser Benutzername existiert bereits", - "Could not create user" : "Benutzer konnte nicht erstellt werden", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“, Leerzeichen und „_.@-'“", - "A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden", - "Username contains whitespace at the beginning or at the end" : "Der Benutzername enthält Leerzeichen am Anfang oder am Ende", - "Username must not consist of dots only" : "Der Benutzername darf nicht nur aus Punkten bestehen", - "Username is invalid because files already exist for this user" : "Der Benutzer ist ungültig, da bereits Dateien von diesem Benutzer existieren", - "User disabled" : "Benutzer deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Die App „%1$s“ kann nicht installiert werden, da die folgenden Abhängigkeiten nicht erfüllt sind: %2$s", "a safe home for all your data" : "ein sicherer Ort für all deine Daten", @@ -243,8 +225,6 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Bitte kontaktiere deinen Server-Administrator und bitte um den Neustart des Webservers.", "The required %s config variable is not configured in the config.php file." : "Die erforderliche %s Konfigurationsvariable ist in der config.php nicht konfiguriert.", "Please ask your server administrator to check the Nextcloud configuration." : "Bitte deinen Server-Administrator, die Nextcloud-Konfiguration zu überprüfen.", - "Your data directory is readable by other users." : "Dein Datenverzeichnis kann von anderen Benutzern gelesen werden", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändere die Berechtigungen auf 0770, sodass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann.", "Your data directory must be an absolute path." : "Dein Datenverzeichnis muss einen eindeutigen Pfad haben", "Check the value of \"datadirectory\" in your configuration." : "Überprüfe bitte die Angabe unter „datadirectory“ in deiner Konfiguration", "Your data directory is invalid." : "Dein Datenverzeichnis ist ungültig", @@ -260,13 +240,41 @@ OC.L10N.register( "Storage connection error. %s" : "Verbindungsfehler zum Speicherplatz. %s", "Storage is temporarily not available" : "Speicher ist vorübergehend nicht verfügbar", "Storage connection timeout. %s" : "Zeitüberschreitung der Verbindung zum Speicherplatz. %s", + "Free prompt" : "Freie Eingabeaufforderung", + "Runs an arbitrary prompt through the language model." : "Führt eine beliebige Eingabeaufforderung über das Sprachmodell aus.", + "Generate headline" : "Überschrift erzeugen", + "Generates a possible headline for a text." : "Erzeugt eine mögliche Überschrift für einen Text.", + "Summarize" : "Zusammenfassen", + "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.", + "Extract topics" : "Themen extrahieren", + "Extracts topics from a text and outputs them separated by commas." : "Extrahiert Themen aus einem Text und gibt sie durch Kommas getrennt aus.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Die Dateien der App %1$swurden nicht korrekt ersetzt. Stelle sicher, dass es sich um eine mit dem Server kompatible Version handelt.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Der angemeldete Benutzer muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen. ", + "Logged in user must be an admin or sub admin" : "Der angemeldete Benutzer muss ein (Sub-)Administrator sein", + "Logged in user must be an admin" : "Der angemeldete Benutzer muss ein Administrator sein", "Full name" : "Vollständiger Name", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Das Benutzerlimit wurde erreicht und der Benutzer wurde nicht erstellt. Überprüfe deine Benachrichtigungen, um mehr zu erfahren.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“ und „_.@-'“", + "Unknown user" : "Unbekannter Benutzer", + "Enter the database username and name for %s" : "Den Datenbankbenutzernamen und den Namen eingeben für %s", + "Enter the database username for %s" : "Den Datenbankbenutzernamen eingeben für %s", + "MySQL username and/or password not valid" : "MySQL-Benutzername und/oder Passwort ungültig", + "Oracle username and/or password not valid" : "Oracle-Benutzername und/oder -Passwort ungültig", + "PostgreSQL username and/or password not valid" : "PostgreSQL-Benutzername und/oder -Passwort ungültig", + "Set an admin username." : "Einen Administrator-Benutzernamen setzen.", + "Sharing %s failed, because this item is already shared with user %s" : "Freigabe von %s fehlgeschlagen, da dieses Element schon mit dem Benutzer %s geteilt wird", + "The username is already being used" : "Dieser Benutzername existiert bereits", + "Could not create user" : "Benutzer konnte nicht erstellt werden", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“, Leerzeichen und „_.@-'“", + "A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden", + "Username contains whitespace at the beginning or at the end" : "Der Benutzername enthält Leerzeichen am Anfang oder am Ende", + "Username must not consist of dots only" : "Der Benutzername darf nicht nur aus Punkten bestehen", + "Username is invalid because files already exist for this user" : "Der Benutzer ist ungültig, da bereits Dateien von diesem Benutzer existieren", + "User disabled" : "Benutzer deaktiviert", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 ist mindestestens erforderlich. Im Moment ist %s installiert.", "To fix this issue update your libxml2 version and restart your web server." : "Um den Fehler zu beheben, musst du die libxml2 Version aktualisieren und den Webserver neustarten.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 benötigt", - "Please upgrade your database version." : "Bitte aktualisiere deine Datenbankversion" + "Please upgrade your database version." : "Bitte aktualisiere deine Datenbankversion", + "Your data directory is readable by other users." : "Dein Datenverzeichnis kann von anderen Benutzern gelesen werden", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändere die Berechtigungen auf 0770, sodass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/de.json b/lib/l10n/de.json index 1356295ad32..1d5032b1df2 100644 --- a/lib/l10n/de.json +++ b/lib/l10n/de.json @@ -3,9 +3,9 @@ "This can usually be fixed by giving the web server write access to the config directory." : "Dies kann normalerweise behoben werden, indem dem Webserver Schreibzugriff auf das config-Verzeichnis gegeben wird.", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Wenn du jedoch möchtest dass die Datei config.php schreibgeschützt bleiben soll, dann setze die Option \"config_is_read_only\" in der Datei auf true.", "See %s" : "Siehe %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Die Anwendung %1$s ist nicht vorhanden oder hat eine mit diesem Server nicht kompatible Version. Bitte überprüfe das Apps-Verzeichnis.", "Sample configuration detected" : "Beispielkonfiguration gefunden", "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" : "Es wurde festgestellt, dass die Beispielkonfiguration kopiert wurde. Dies kann deine Installation zerstören und wird nicht unterstützt. Bitte die Dokumentation lesen, bevor Änderungen an der config.php vorgenommen werden.", - "404" : "404", "The page could not be found on the server." : "Die Seite konnte auf dem Server nicht gefunden werden.", "%s email verification" : "%s E-Mail-Überprüfung", "Email verification" : "E-Mail-Überprüfung", @@ -34,9 +34,6 @@ "The following platforms are supported: %s" : "Die folgenden Plattformen werden unterstützt: %s", "Server version %s or higher is required." : "Server Version %s oder höher wird benötigt.", "Server version %s or lower is required." : "Server Version %s oder niedriger wird benötigt.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Der angemeldete Benutzer muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen. ", - "Logged in user must be an admin or sub admin" : "Der angemeldete Benutzer muss ein (Sub-)Administrator sein", - "Logged in user must be an admin" : "Der angemeldete Benutzer muss ein Administrator sein", "Wiping of device %s has started" : "Löschen von Gerät %s wurde gestartet", "Wiping of device »%s« has started" : "Löschen von Gerät »%s« wurde gestartet", "»%s« started remote wipe" : "»%s« hat das Löschen aus der Ferne gestartet", @@ -94,7 +91,7 @@ "Appearance and accessibility" : "Erscheinungsbild und Barrierefreiheit", "Apps" : "Apps", "Personal settings" : "Persönliche Einstellungen", - "Administration settings" : "Verwaltungs-Einstellungen", + "Administration settings" : "Verwaltungseinstellungen", "Settings" : "Einstellungen", "Log out" : "Abmelden", "Users" : "Benutzer", @@ -104,8 +101,8 @@ "View %s on the fediverse" : "Zeige %s auf dem Fediverse", "Phone" : "Telefon", "Call %s" : "%s anrufen", - "Twitter" : "Twitter", - "View %s on Twitter" : "%s auf Twitter anzeigen", + "Twitter" : "X", + "View %s on Twitter" : "%s auf X anzeigen", "Website" : "Webseite", "Visit %s" : "%s besuchen", "Address" : "Adresse", @@ -115,22 +112,15 @@ "Headline" : "Überschrift", "Organisation" : "Organisation", "Role" : "Funktion", - "Unknown user" : "Unbekannter Benutzer", "Additional settings" : "Zusätzliche Einstellungen", - "Enter the database username and name for %s" : "Den Datenbankbenutzernamen und den Namen eingeben für %s", - "Enter the database username for %s" : "Den Datenbankbenutzernamen eingeben für %s", "Enter the database name for %s" : "Den Datenbanknamen eingeben für %s", "You cannot use dots in the database name %s" : "Du kannst keine Punkte im Datenbanknamen %s verwenden.", - "MySQL username and/or password not valid" : "MySQL-Benutzername und/oder Passwort ungültig", "You need to enter details of an existing account." : "Du musst Details von einem existierenden Benutzer einfügen.", "Oracle connection could not be established" : "Es konnte keine Verbindung zur Oracle-Datenbank hergestellt werden", - "Oracle username and/or password not valid" : "Oracle-Benutzername und/oder -Passwort ungültig", - "PostgreSQL username and/or password not valid" : "PostgreSQL-Benutzername und/oder -Passwort ungültig", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X wird nicht unterstützt und %s wird auf dieser Plattform nicht richtig funktionieren. Die Benutzung erfolgt auf eigene Gefahr!", "For the best results, please consider using a GNU/Linux server instead." : "Zur Gewährleistung eines optimalen Betriebs sollte stattdessen ein GNU/Linux-Server verwendet werden.", "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." : "Es scheint, dass diese %s-Instanz unter einer 32-Bit-PHP-Umgebung läuft und open_basedir in der Datei php.ini konfiguriert worden ist. Von einem solchen Betrieb wird dringend abgeraten, weil es dabei zu Problemen mit Dateien kommt, deren Größe 4 GB übersteigt.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Bitte entferne die open_basedir-Einstellung in deiner php.ini oder wechsele zu 64-Bit-PHP.", - "Set an admin username." : "Einen Administrator-Benutzernamen setzen.", "Set an admin password." : "Ein Administrator-Passwort setzen.", "Cannot create or write into the data directory %s" : "Das Datenverzeichnis %s kann nicht erstellt oder es kann darin nicht geschrieben werden.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Freigabe-Backend %s muss in der OCP\\Share_Backend - Schnittstelle implementiert werden", @@ -148,11 +138,11 @@ "Expiration date is in the past" : "Das Ablaufdatum liegt in der Vergangenheit.", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Das Ablaufdatum kann nicht mehr als %n Tag in der Zukunft liegen","Das Ablaufdatum kann nicht mehr als %n Tage in der Zukunft liegen"], "Sharing is only allowed with group members" : "Teilen ist nur mit Gruppenmitgliedern erlaubt", - "Sharing %s failed, because this item is already shared with user %s" : "Freigabe von %s fehlgeschlagen, da dieses Element schon mit dem Benutzer %s geteilt wird", "%1$s shared »%2$s« with you" : "%1$s hat »%2$s« mit dir geteilt", "%1$s shared »%2$s« with you." : "%1$s hat »%2$s« mit dir geteilt.", "Click the button below to open it." : "Klicke zum Öffnen auf die untere Schaltfläche.", "The requested share does not exist anymore" : "Die angeforderte Freigabe existiert nicht mehr", + "The requested share comes from a disabled user" : "Die angeforderte Freigabe stammt von einem deaktivierten Benutzer", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Der Benutzer wurde nicht erstellt, da das Benutzerlimit erreicht wurde. Überprüfe deine Benachrichtigungen, um mehr zu erfahren.", "Could not find category \"%s\"" : "Die Kategorie \"%s“ konnte nicht gefunden werden", "Sunday" : "Sonntag", @@ -201,14 +191,6 @@ "Nov." : "Nov.", "Dec." : "Dez.", "A valid password must be provided" : "Es muss ein gültiges Passwort eingegeben werden", - "The username is already being used" : "Dieser Benutzername existiert bereits", - "Could not create user" : "Benutzer konnte nicht erstellt werden", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“, Leerzeichen und „_.@-'“", - "A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden", - "Username contains whitespace at the beginning or at the end" : "Der Benutzername enthält Leerzeichen am Anfang oder am Ende", - "Username must not consist of dots only" : "Der Benutzername darf nicht nur aus Punkten bestehen", - "Username is invalid because files already exist for this user" : "Der Benutzer ist ungültig, da bereits Dateien von diesem Benutzer existieren", - "User disabled" : "Benutzer deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Die App „%1$s“ kann nicht installiert werden, da die folgenden Abhängigkeiten nicht erfüllt sind: %2$s", "a safe home for all your data" : "ein sicherer Ort für all deine Daten", @@ -241,8 +223,6 @@ "Please ask your server administrator to restart the web server." : "Bitte kontaktiere deinen Server-Administrator und bitte um den Neustart des Webservers.", "The required %s config variable is not configured in the config.php file." : "Die erforderliche %s Konfigurationsvariable ist in der config.php nicht konfiguriert.", "Please ask your server administrator to check the Nextcloud configuration." : "Bitte deinen Server-Administrator, die Nextcloud-Konfiguration zu überprüfen.", - "Your data directory is readable by other users." : "Dein Datenverzeichnis kann von anderen Benutzern gelesen werden", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändere die Berechtigungen auf 0770, sodass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann.", "Your data directory must be an absolute path." : "Dein Datenverzeichnis muss einen eindeutigen Pfad haben", "Check the value of \"datadirectory\" in your configuration." : "Überprüfe bitte die Angabe unter „datadirectory“ in deiner Konfiguration", "Your data directory is invalid." : "Dein Datenverzeichnis ist ungültig", @@ -258,13 +238,41 @@ "Storage connection error. %s" : "Verbindungsfehler zum Speicherplatz. %s", "Storage is temporarily not available" : "Speicher ist vorübergehend nicht verfügbar", "Storage connection timeout. %s" : "Zeitüberschreitung der Verbindung zum Speicherplatz. %s", + "Free prompt" : "Freie Eingabeaufforderung", + "Runs an arbitrary prompt through the language model." : "Führt eine beliebige Eingabeaufforderung über das Sprachmodell aus.", + "Generate headline" : "Überschrift erzeugen", + "Generates a possible headline for a text." : "Erzeugt eine mögliche Überschrift für einen Text.", + "Summarize" : "Zusammenfassen", + "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.", + "Extract topics" : "Themen extrahieren", + "Extracts topics from a text and outputs them separated by commas." : "Extrahiert Themen aus einem Text und gibt sie durch Kommas getrennt aus.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Die Dateien der App %1$swurden nicht korrekt ersetzt. Stelle sicher, dass es sich um eine mit dem Server kompatible Version handelt.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Der angemeldete Benutzer muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen. ", + "Logged in user must be an admin or sub admin" : "Der angemeldete Benutzer muss ein (Sub-)Administrator sein", + "Logged in user must be an admin" : "Der angemeldete Benutzer muss ein Administrator sein", "Full name" : "Vollständiger Name", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Das Benutzerlimit wurde erreicht und der Benutzer wurde nicht erstellt. Überprüfe deine Benachrichtigungen, um mehr zu erfahren.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“ und „_.@-'“", + "Unknown user" : "Unbekannter Benutzer", + "Enter the database username and name for %s" : "Den Datenbankbenutzernamen und den Namen eingeben für %s", + "Enter the database username for %s" : "Den Datenbankbenutzernamen eingeben für %s", + "MySQL username and/or password not valid" : "MySQL-Benutzername und/oder Passwort ungültig", + "Oracle username and/or password not valid" : "Oracle-Benutzername und/oder -Passwort ungültig", + "PostgreSQL username and/or password not valid" : "PostgreSQL-Benutzername und/oder -Passwort ungültig", + "Set an admin username." : "Einen Administrator-Benutzernamen setzen.", + "Sharing %s failed, because this item is already shared with user %s" : "Freigabe von %s fehlgeschlagen, da dieses Element schon mit dem Benutzer %s geteilt wird", + "The username is already being used" : "Dieser Benutzername existiert bereits", + "Could not create user" : "Benutzer konnte nicht erstellt werden", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“, Leerzeichen und „_.@-'“", + "A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden", + "Username contains whitespace at the beginning or at the end" : "Der Benutzername enthält Leerzeichen am Anfang oder am Ende", + "Username must not consist of dots only" : "Der Benutzername darf nicht nur aus Punkten bestehen", + "Username is invalid because files already exist for this user" : "Der Benutzer ist ungültig, da bereits Dateien von diesem Benutzer existieren", + "User disabled" : "Benutzer deaktiviert", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 ist mindestestens erforderlich. Im Moment ist %s installiert.", "To fix this issue update your libxml2 version and restart your web server." : "Um den Fehler zu beheben, musst du die libxml2 Version aktualisieren und den Webserver neustarten.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 benötigt", - "Please upgrade your database version." : "Bitte aktualisiere deine Datenbankversion" + "Please upgrade your database version." : "Bitte aktualisiere deine Datenbankversion", + "Your data directory is readable by other users." : "Dein Datenverzeichnis kann von anderen Benutzern gelesen werden", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändere die Berechtigungen auf 0770, sodass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann." },"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 4b1a4c4c274..833d0979032 100644 --- a/lib/l10n/de_DE.js +++ b/lib/l10n/de_DE.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Die Anwendung %1$s ist nicht vorhanden oder hat eine mit diesem Server nicht kompatible Version. Bitte überprüfen Sie das Apps-Verzeichnis.", "Sample configuration detected" : "Beispielkonfiguration gefunden", "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" : "Es wurde festgestellt, dass die Beispielkonfiguration kopiert wurde. Dies kann Ihre Installation zerstören und wird nicht unterstützt. Bitte die Dokumentation lesen, bevor Änderungen an der config.php vorgenommen werden.", - "404" : "404", "The page could not be found on the server." : "Die Seite konnte auf dem Server nicht gefunden werden.", "%s email verification" : "%s E-Mail-Überprüfung", "Email verification" : "E-Mail-Überprüfung", @@ -24,6 +23,7 @@ OC.L10N.register( "Enterprise bundle" : "Firmen-Paket", "Groupware bundle" : "Groupware-Paket", "Hub bundle" : "Hub-Paket", + "Public sector bundle" : "Paket für den öffentlichen Sektor", "Social sharing bundle" : "Paket für das Teilen in sozialen Medien", "PHP %s or higher is required." : "PHP %s oder höher wird benötigt.", "PHP with a version lower than %s is required." : "PHP wird in einer früheren Version als %s benötigt.", @@ -37,9 +37,9 @@ OC.L10N.register( "The following platforms are supported: %s" : "Folgende Plattformen werden unterstützt: %s", "Server version %s or higher is required." : "Server Version %s oder höher wird benötigt.", "Server version %s or lower is required." : "Server Version %s oder niedriger wird benötigt.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Der angemeldete Benutzer muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen. ", - "Logged in user must be an admin or sub admin" : "Der angemeldete Benutzer muss ein (Sub-)Administrator sein", - "Logged in user must be an admin" : "Der angemeldete Benutzer muss ein Administrator sein", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Das angemeldete Konto muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen", + "Logged in account must be an admin or sub admin" : "Das angemeldete Konto muss ein (Sub-)Administrator sein", + "Logged in account must be an admin" : "Das angemeldete Konto muss ein Administrator sein", "Wiping of device %s has started" : "Löschen von Gerät %s wurde gestartet", "Wiping of device »%s« has started" : "Löschen von Gerät »%s« wurde gestartet", "»%s« started remote wipe" : "»%s« hat das Löschen aus der Ferne gestartet", @@ -118,22 +118,22 @@ OC.L10N.register( "Headline" : "Überschrift", "Organisation" : "Organisation", "Role" : "Funktion", - "Unknown user" : "Unbekannter Benutzer", + "Unknown account" : "Unbekanntes Konto", "Additional settings" : "Zusätzliche Einstellungen", - "Enter the database username and name for %s" : "Den Datenbankbenutzernamen und den Namen eingeben für %s", - "Enter the database username for %s" : "Den Datenbankbenutzernamen eingeben für %s", + "Enter the database Login and name for %s" : "Den Datenbankanmeldenamen und den Namen für %s eingeben", + "Enter the database Login for %s" : "Anmeldenamen für die Datenbank für %s eingeben", "Enter the database name for %s" : "Den Datenbanknamen eingeben für %s", "You cannot use dots in the database name %s" : "Sie dürfen keine Punkte im Datenbanknamen %s verwenden", - "MySQL username and/or password not valid" : "MySQL-Benutzername und/oder Passwort ungültig", + "MySQL Login and/or password not valid" : "MySQL Anmeldename und/oder Passwort ungültig", "You need to enter details of an existing account." : "Sie müssen Details von einem existierenden Benutzer einfügen.", "Oracle connection could not be established" : "Es konnte keine Verbindung zur Oracle-Datenbank hergestellt werden", - "Oracle username and/or password not valid" : "Oracle-Benutzername und/oder -Passwort ungültig", - "PostgreSQL username and/or password not valid" : "PostgreSQL-Benutzername und/oder -Passwort ungültig", + "Oracle Login and/or password not valid" : "Oracle-Anmeldename und/oder -Passwort ungültig", + "PostgreSQL Login and/or password not valid" : "PostgreSQL-Anmeldename und/oder Passwort ungültig", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X wird nicht unterstützt und %s wird auf dieser Plattform nicht richtig funktionieren. Die Benutzung erfolgt auf eigene Gefahr!", "For the best results, please consider using a GNU/Linux server instead." : "Zur Gewährleistung eines optimalen Betriebs sollte stattdessen ein GNU/Linux-Server verwendet werden.", "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." : "Es scheint, dass diese %s-Instanz unter einer 32-Bit-PHP-Umgebung läuft und open_basedir in der Datei php.ini konfiguriert worden ist. Von einem solchen Betrieb wird dringend abgeraten, weil es dabei zu Problemen mit Dateien kommt, deren Größe 4 GB übersteigt.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Bitte entfernen Sie die open_basedir-Einstellung in Ihrer php.ini oder wechseln Sie zu 64-Bit-PHP.", - "Set an admin username." : "Einen Administrations-Benutzernamen setzen.", + "Set an admin Login." : "Anmeldename für Andministration setzen.", "Set an admin password." : "Ein Administrationspasswort setzen.", "Cannot create or write into the data directory %s" : "Das Datenverzeichnis %s kann nicht erstellt oder es kann darin nicht geschrieben werden.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Freigabe-Backend %s muss in der OCP\\Share_Backend - Schnittstelle implementiert werden", @@ -151,7 +151,7 @@ OC.L10N.register( "Expiration date is in the past" : "Das Ablaufdatum liegt in der Vergangenheit.", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Das Ablaufdatum kann nicht mehr als %n Tag in der Zukunft liegen","Das Ablaufdatum kann nicht mehr als %n Tage in der Zukunft liegen"], "Sharing is only allowed with group members" : "Teilen ist nur mit Gruppenmitgliedern erlaubt", - "Sharing %s failed, because this item is already shared with user %s" : "Freigabe von %s fehlgeschlagen, da dieses Element schon mit dem Benutzer %s geteilt wird", + "Sharing %s failed, because this item is already shared with the account %s" : "Freigeben von %s ist fehlgeschlagen, da dieses Element schon mit dem Konto %s geteilt wurde", "%1$s shared »%2$s« with you" : "%1$s hat »%2$s« mit Ihnen geteilt", "%1$s shared »%2$s« with you." : "%1$s hat »%2$s« mit Ihnen geteilt.", "Click the button below to open it." : "Klicken Sie zum Öffnen auf die untere Schaltfläche.", @@ -205,14 +205,14 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dez.", "A valid password must be provided" : "Es muss ein gültiges Passwort eingegeben werden", - "The username is already being used" : "Dieser Benutzername existiert bereits", - "Could not create user" : "Benutzer konnte nicht erstellt werden", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“, Leerzeichen und „_.@-'“", - "A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden", - "Username contains whitespace at the beginning or at the end" : "Der Benutzername enthält Leerzeichen am Anfang oder am Ende", - "Username must not consist of dots only" : "Der Benutzername darf nicht nur aus Punkten bestehen", - "Username is invalid because files already exist for this user" : "Der Benutzer ist ungültig, da bereits Dateien von diesem Benutzer existieren", - "User disabled" : "Benutzer deaktiviert", + "The Login is already being used" : "Dieser Anmeldename wird bereits verwendet", + "Could not create account" : "Konto konnte nicht erstellt werden", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Nur die folgenden Zeichen sind in einem Anmeldenamen erlaubt: \"a-z\", \"A-Z\", \"0-9\", Leerzeichen und \"_.@-'\"", + "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 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", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Die App „%1$s“ kann nicht installiert werden, da die folgenden Abhängigkeiten nicht erfüllt sind: %2$s", "a safe home for all your data" : "ein sicherer Ort für all Ihre Daten", @@ -245,8 +245,8 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Bitte kontaktieren Sie Ihre Server-Administration und bitten Sie um den Neustart des Webservers.", "The required %s config variable is not configured in the config.php file." : "Die erforderliche %s Konfigurationsvariable ist in der config.php nicht konfiguriert.", "Please ask your server administrator to check the Nextcloud configuration." : "Bitten Sie Ihre Server-Administration, die Nextcloud-Konfiguration zu überprüfen.", - "Your data directory is readable by other users." : "Ihr Datenverzeichnis kann von anderen Benutzern gelesen werden.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändern Sie die Berechtigungen auf 0770, so dass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann.", + "Your data directory is readable by other people." : "Ihr Datenverzeichnis kann von Anderen gelesen werden.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Bitte ändern Sie die Berechtigungen auf 0770, so dass das Verzeichnis nicht von Anderen angezeigt werden kann.", "Your data directory must be an absolute path." : "Ihr Datenverzeichnis muss einen absoluten Pfad haben.", "Check the value of \"datadirectory\" in your configuration." : "Überprüfen Sie den Wert von „datadirectory“ in Ihrer Konfiguration.", "Your data directory is invalid." : "Ihr Datenverzeichnis ist ungültig.", @@ -271,12 +271,32 @@ OC.L10N.register( "Extract topics" : "Themen extrahieren", "Extracts topics from a text and outputs them separated by commas." : "Extrahiert Themen aus einem Text und gibt sie durch Kommas getrennt aus.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Die Dateien der App %1$s wurden nicht korrekt ersetzt. Stellen Sie sicher, dass es sich um eine mit dem Server kompatible Version handelt.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Der angemeldete Benutzer muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen. ", + "Logged in user must be an admin or sub admin" : "Der angemeldete Benutzer muss ein (Sub-)Administrator sein", + "Logged in user must be an admin" : "Der angemeldete Benutzer muss ein Administrator sein", "Full name" : "Vollständiger Name", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Das Benutzerlimit wurde erreicht und der Benutzer wurde nicht erstellt. Überprüfen Sie Ihre Benachrichtigungen, um mehr zu erfahren.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“ und „_.@-'“", + "Unknown user" : "Unbekannter Benutzer", + "Enter the database username and name for %s" : "Den Datenbankbenutzernamen und den Namen eingeben für %s", + "Enter the database username for %s" : "Den Datenbankbenutzernamen eingeben für %s", + "MySQL username and/or password not valid" : "MySQL-Benutzername und/oder Passwort ungültig", + "Oracle username and/or password not valid" : "Oracle-Benutzername und/oder -Passwort ungültig", + "PostgreSQL username and/or password not valid" : "PostgreSQL-Benutzername und/oder -Passwort ungültig", + "Set an admin username." : "Einen Administrations-Benutzernamen setzen.", + "Sharing %s failed, because this item is already shared with user %s" : "Freigabe von %s fehlgeschlagen, da dieses Element schon mit dem Benutzer %s geteilt wird", + "The username is already being used" : "Dieser Benutzername existiert bereits", + "Could not create user" : "Benutzer konnte nicht erstellt werden", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“, Leerzeichen und „_.@-'“", + "A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden", + "Username contains whitespace at the beginning or at the end" : "Der Benutzername enthält Leerzeichen am Anfang oder am Ende", + "Username must not consist of dots only" : "Der Benutzername darf nicht nur aus Punkten bestehen", + "Username is invalid because files already exist for this user" : "Der Benutzer ist ungültig, da bereits Dateien von diesem Benutzer existieren", + "User disabled" : "Benutzer deaktiviert", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 ist mindestestens erforderlich. Im Moment ist %s installiert.", "To fix this issue update your libxml2 version and restart your web server." : "Um den Fehler zu beheben, müssen Sie die libxml2 Version aktualisieren und den Webserver neustarten.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 benötigt.", - "Please upgrade your database version." : "Bitte aktualisieren Sie Ihre Datenbankversion." + "Please upgrade your database version." : "Bitte aktualisieren Sie Ihre Datenbankversion.", + "Your data directory is readable by other users." : "Ihr Datenverzeichnis kann von anderen Benutzern gelesen werden.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändern Sie die Berechtigungen auf 0770, so dass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/de_DE.json b/lib/l10n/de_DE.json index 98681f76384..2a1fb948003 100644 --- a/lib/l10n/de_DE.json +++ b/lib/l10n/de_DE.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Die Anwendung %1$s ist nicht vorhanden oder hat eine mit diesem Server nicht kompatible Version. Bitte überprüfen Sie das Apps-Verzeichnis.", "Sample configuration detected" : "Beispielkonfiguration gefunden", "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" : "Es wurde festgestellt, dass die Beispielkonfiguration kopiert wurde. Dies kann Ihre Installation zerstören und wird nicht unterstützt. Bitte die Dokumentation lesen, bevor Änderungen an der config.php vorgenommen werden.", - "404" : "404", "The page could not be found on the server." : "Die Seite konnte auf dem Server nicht gefunden werden.", "%s email verification" : "%s E-Mail-Überprüfung", "Email verification" : "E-Mail-Überprüfung", @@ -22,6 +21,7 @@ "Enterprise bundle" : "Firmen-Paket", "Groupware bundle" : "Groupware-Paket", "Hub bundle" : "Hub-Paket", + "Public sector bundle" : "Paket für den öffentlichen Sektor", "Social sharing bundle" : "Paket für das Teilen in sozialen Medien", "PHP %s or higher is required." : "PHP %s oder höher wird benötigt.", "PHP with a version lower than %s is required." : "PHP wird in einer früheren Version als %s benötigt.", @@ -35,9 +35,9 @@ "The following platforms are supported: %s" : "Folgende Plattformen werden unterstützt: %s", "Server version %s or higher is required." : "Server Version %s oder höher wird benötigt.", "Server version %s or lower is required." : "Server Version %s oder niedriger wird benötigt.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Der angemeldete Benutzer muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen. ", - "Logged in user must be an admin or sub admin" : "Der angemeldete Benutzer muss ein (Sub-)Administrator sein", - "Logged in user must be an admin" : "Der angemeldete Benutzer muss ein Administrator sein", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Das angemeldete Konto muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen", + "Logged in account must be an admin or sub admin" : "Das angemeldete Konto muss ein (Sub-)Administrator sein", + "Logged in account must be an admin" : "Das angemeldete Konto muss ein Administrator sein", "Wiping of device %s has started" : "Löschen von Gerät %s wurde gestartet", "Wiping of device »%s« has started" : "Löschen von Gerät »%s« wurde gestartet", "»%s« started remote wipe" : "»%s« hat das Löschen aus der Ferne gestartet", @@ -116,22 +116,22 @@ "Headline" : "Überschrift", "Organisation" : "Organisation", "Role" : "Funktion", - "Unknown user" : "Unbekannter Benutzer", + "Unknown account" : "Unbekanntes Konto", "Additional settings" : "Zusätzliche Einstellungen", - "Enter the database username and name for %s" : "Den Datenbankbenutzernamen und den Namen eingeben für %s", - "Enter the database username for %s" : "Den Datenbankbenutzernamen eingeben für %s", + "Enter the database Login and name for %s" : "Den Datenbankanmeldenamen und den Namen für %s eingeben", + "Enter the database Login for %s" : "Anmeldenamen für die Datenbank für %s eingeben", "Enter the database name for %s" : "Den Datenbanknamen eingeben für %s", "You cannot use dots in the database name %s" : "Sie dürfen keine Punkte im Datenbanknamen %s verwenden", - "MySQL username and/or password not valid" : "MySQL-Benutzername und/oder Passwort ungültig", + "MySQL Login and/or password not valid" : "MySQL Anmeldename und/oder Passwort ungültig", "You need to enter details of an existing account." : "Sie müssen Details von einem existierenden Benutzer einfügen.", "Oracle connection could not be established" : "Es konnte keine Verbindung zur Oracle-Datenbank hergestellt werden", - "Oracle username and/or password not valid" : "Oracle-Benutzername und/oder -Passwort ungültig", - "PostgreSQL username and/or password not valid" : "PostgreSQL-Benutzername und/oder -Passwort ungültig", + "Oracle Login and/or password not valid" : "Oracle-Anmeldename und/oder -Passwort ungültig", + "PostgreSQL Login and/or password not valid" : "PostgreSQL-Anmeldename und/oder Passwort ungültig", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X wird nicht unterstützt und %s wird auf dieser Plattform nicht richtig funktionieren. Die Benutzung erfolgt auf eigene Gefahr!", "For the best results, please consider using a GNU/Linux server instead." : "Zur Gewährleistung eines optimalen Betriebs sollte stattdessen ein GNU/Linux-Server verwendet werden.", "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." : "Es scheint, dass diese %s-Instanz unter einer 32-Bit-PHP-Umgebung läuft und open_basedir in der Datei php.ini konfiguriert worden ist. Von einem solchen Betrieb wird dringend abgeraten, weil es dabei zu Problemen mit Dateien kommt, deren Größe 4 GB übersteigt.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Bitte entfernen Sie die open_basedir-Einstellung in Ihrer php.ini oder wechseln Sie zu 64-Bit-PHP.", - "Set an admin username." : "Einen Administrations-Benutzernamen setzen.", + "Set an admin Login." : "Anmeldename für Andministration setzen.", "Set an admin password." : "Ein Administrationspasswort setzen.", "Cannot create or write into the data directory %s" : "Das Datenverzeichnis %s kann nicht erstellt oder es kann darin nicht geschrieben werden.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Freigabe-Backend %s muss in der OCP\\Share_Backend - Schnittstelle implementiert werden", @@ -149,7 +149,7 @@ "Expiration date is in the past" : "Das Ablaufdatum liegt in der Vergangenheit.", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Das Ablaufdatum kann nicht mehr als %n Tag in der Zukunft liegen","Das Ablaufdatum kann nicht mehr als %n Tage in der Zukunft liegen"], "Sharing is only allowed with group members" : "Teilen ist nur mit Gruppenmitgliedern erlaubt", - "Sharing %s failed, because this item is already shared with user %s" : "Freigabe von %s fehlgeschlagen, da dieses Element schon mit dem Benutzer %s geteilt wird", + "Sharing %s failed, because this item is already shared with the account %s" : "Freigeben von %s ist fehlgeschlagen, da dieses Element schon mit dem Konto %s geteilt wurde", "%1$s shared »%2$s« with you" : "%1$s hat »%2$s« mit Ihnen geteilt", "%1$s shared »%2$s« with you." : "%1$s hat »%2$s« mit Ihnen geteilt.", "Click the button below to open it." : "Klicken Sie zum Öffnen auf die untere Schaltfläche.", @@ -203,14 +203,14 @@ "Nov." : "Nov.", "Dec." : "Dez.", "A valid password must be provided" : "Es muss ein gültiges Passwort eingegeben werden", - "The username is already being used" : "Dieser Benutzername existiert bereits", - "Could not create user" : "Benutzer konnte nicht erstellt werden", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“, Leerzeichen und „_.@-'“", - "A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden", - "Username contains whitespace at the beginning or at the end" : "Der Benutzername enthält Leerzeichen am Anfang oder am Ende", - "Username must not consist of dots only" : "Der Benutzername darf nicht nur aus Punkten bestehen", - "Username is invalid because files already exist for this user" : "Der Benutzer ist ungültig, da bereits Dateien von diesem Benutzer existieren", - "User disabled" : "Benutzer deaktiviert", + "The Login is already being used" : "Dieser Anmeldename wird bereits verwendet", + "Could not create account" : "Konto konnte nicht erstellt werden", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Nur die folgenden Zeichen sind in einem Anmeldenamen erlaubt: \"a-z\", \"A-Z\", \"0-9\", Leerzeichen und \"_.@-'\"", + "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 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", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Die App „%1$s“ kann nicht installiert werden, da die folgenden Abhängigkeiten nicht erfüllt sind: %2$s", "a safe home for all your data" : "ein sicherer Ort für all Ihre Daten", @@ -243,8 +243,8 @@ "Please ask your server administrator to restart the web server." : "Bitte kontaktieren Sie Ihre Server-Administration und bitten Sie um den Neustart des Webservers.", "The required %s config variable is not configured in the config.php file." : "Die erforderliche %s Konfigurationsvariable ist in der config.php nicht konfiguriert.", "Please ask your server administrator to check the Nextcloud configuration." : "Bitten Sie Ihre Server-Administration, die Nextcloud-Konfiguration zu überprüfen.", - "Your data directory is readable by other users." : "Ihr Datenverzeichnis kann von anderen Benutzern gelesen werden.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändern Sie die Berechtigungen auf 0770, so dass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann.", + "Your data directory is readable by other people." : "Ihr Datenverzeichnis kann von Anderen gelesen werden.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Bitte ändern Sie die Berechtigungen auf 0770, so dass das Verzeichnis nicht von Anderen angezeigt werden kann.", "Your data directory must be an absolute path." : "Ihr Datenverzeichnis muss einen absoluten Pfad haben.", "Check the value of \"datadirectory\" in your configuration." : "Überprüfen Sie den Wert von „datadirectory“ in Ihrer Konfiguration.", "Your data directory is invalid." : "Ihr Datenverzeichnis ist ungültig.", @@ -269,12 +269,32 @@ "Extract topics" : "Themen extrahieren", "Extracts topics from a text and outputs them separated by commas." : "Extrahiert Themen aus einem Text und gibt sie durch Kommas getrennt aus.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Die Dateien der App %1$s wurden nicht korrekt ersetzt. Stellen Sie sicher, dass es sich um eine mit dem Server kompatible Version handelt.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Der angemeldete Benutzer muss ein Administrator, ein Teil-Administrator sein oder ein Sonderrecht haben, um auf diese Einstellung zuzugreifen. ", + "Logged in user must be an admin or sub admin" : "Der angemeldete Benutzer muss ein (Sub-)Administrator sein", + "Logged in user must be an admin" : "Der angemeldete Benutzer muss ein Administrator sein", "Full name" : "Vollständiger Name", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Das Benutzerlimit wurde erreicht und der Benutzer wurde nicht erstellt. Überprüfen Sie Ihre Benachrichtigungen, um mehr zu erfahren.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“ und „_.@-'“", + "Unknown user" : "Unbekannter Benutzer", + "Enter the database username and name for %s" : "Den Datenbankbenutzernamen und den Namen eingeben für %s", + "Enter the database username for %s" : "Den Datenbankbenutzernamen eingeben für %s", + "MySQL username and/or password not valid" : "MySQL-Benutzername und/oder Passwort ungültig", + "Oracle username and/or password not valid" : "Oracle-Benutzername und/oder -Passwort ungültig", + "PostgreSQL username and/or password not valid" : "PostgreSQL-Benutzername und/oder -Passwort ungültig", + "Set an admin username." : "Einen Administrations-Benutzernamen setzen.", + "Sharing %s failed, because this item is already shared with user %s" : "Freigabe von %s fehlgeschlagen, da dieses Element schon mit dem Benutzer %s geteilt wird", + "The username is already being used" : "Dieser Benutzername existiert bereits", + "Could not create user" : "Benutzer konnte nicht erstellt werden", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Folgende Zeichen sind im Benutzernamen erlaubt: „a-z“, „A-Z“, „0-9“, Leerzeichen und „_.@-'“", + "A valid username must be provided" : "Es muss ein gültiger Benutzername angegeben werden", + "Username contains whitespace at the beginning or at the end" : "Der Benutzername enthält Leerzeichen am Anfang oder am Ende", + "Username must not consist of dots only" : "Der Benutzername darf nicht nur aus Punkten bestehen", + "Username is invalid because files already exist for this user" : "Der Benutzer ist ungültig, da bereits Dateien von diesem Benutzer existieren", + "User disabled" : "Benutzer deaktiviert", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 ist mindestestens erforderlich. Im Moment ist %s installiert.", "To fix this issue update your libxml2 version and restart your web server." : "Um den Fehler zu beheben, müssen Sie die libxml2 Version aktualisieren und den Webserver neustarten.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 benötigt.", - "Please upgrade your database version." : "Bitte aktualisieren Sie Ihre Datenbankversion." + "Please upgrade your database version." : "Bitte aktualisieren Sie Ihre Datenbankversion.", + "Your data directory is readable by other users." : "Ihr Datenverzeichnis kann von anderen Benutzern gelesen werden.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bitte ändern Sie die Berechtigungen auf 0770, so dass das Verzeichnis nicht von anderen Benutzern angezeigt werden kann." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/el.js b/lib/l10n/el.js index fe2cea83496..d3a533d5f4c 100644 --- a/lib/l10n/el.js +++ b/lib/l10n/el.js @@ -35,9 +35,6 @@ 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 ή παλαιότερη.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Ο συνδεδεμένος χρήστης πρέπει να είναι διαχειριστής, υποδιαχειριστής ή να έχει ειδικό δικαίωμα πρόσβασης σε αυτήν τη ρύθμιση", - "Logged in user must be an admin or sub admin" : "Ο συνδεδεμένος χρήστης πρέπει να είναι admin ή subadmin", - "Logged in user must be an admin" : "Ο συνδεδεμένος χρήστης πρέπει να είναι διαχειριστής", "Wiping of device %s has started" : "Η εκκαθάριση συσκευής %s ξεκίνησε", "Wiping of device »%s« has started" : "Η εκκαθάριση συσκευής »%s« ξεκίνησε", "»%s« started remote wipe" : "»%s« ξεκίνησε η απομακρυσμένη εκκαθάριση", @@ -113,18 +110,13 @@ OC.L10N.register( "Headline" : "Τίτλος", "Organisation" : "Οργανισμός", "Role" : "Ρόλος/Θέση", - "Unknown user" : "Άγνωστος χρήστης", "Additional settings" : "Επιπρόσθετες ρυθμίσεις", - "MySQL username and/or password not valid" : "Το όνομα χρήστη και/'η ο κωδικός πρόσβασης MySQL δεν είναι σωστά", "You need to enter details of an existing account." : "Χρειάζεται να εισάγετε λεπτομέρειες από υπάρχοντα λογαριασμό.", "Oracle connection could not be established" : "Αδυναμία σύνδεσης Oracle", - "Oracle username and/or password not valid" : "Μη έγκυρος χρήστης και/ή συνθηματικό της Oracle", - "PostgreSQL username 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-bit PHP και η επιλογή open_basedir έχει ρυθμιστεί στο αρχείο php.ini. Αυτό θα οδηγήσει σε προβλήματα με αρχεία πάνω από 4 GB και δεν συνίσταται.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Παρακαλούμε αφαιρέστε την ρύθμιση open_basedir μέσα στο αρχείο php.ini ή αλλάξτε σε 64-bit PHP.", - "Set an admin username." : "Εισάγετε όνομα χρήστη διαχειριστή.", "Set an admin password." : "Εισάγετε συνθηματικό διαχειριστή.", "Cannot create or write into the data directory %s" : "Δεν είναι δυνατή η δημιουργία ή εγγραφή στον κατάλογο δεδομένων %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Το σύστημα διαμοιρασμού %s πρέπει να υλοποιεί την διεπαφή OCP\\Share_Backend", @@ -142,7 +134,6 @@ OC.L10N.register( "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_" : ["Δεν είναι δυνατός ο ορισμός ημερομηνίας λήξης για περισσότερο από %n ημέρα στο μέλλον","Δεν είναι δυνατός ο ορισμός ημερομηνίας λήξης για περισσότερες από %n ημέρες στο μέλλον"], "Sharing is only allowed with group members" : "Η κοινή χρήση επιτρέπεται μόνο με μέλη της ομάδας", - "Sharing %s failed, because this item is already shared with user %s" : "Η κοινή χρήση του %s απέτυχε, επειδή αυτό το στοιχείο είναι ήδη κοινόχρηστο με τον χρήστη %s", "%1$s shared »%2$s« with you" : "Ο/η %1$s διαμοιράστηκε το »%2$s« με εσάς.", "%1$s shared »%2$s« with you." : "Ο/η %1$s διαμοιράστηκε »%2$s« με εσάς.", "Click the button below to open it." : "Κάντε κλικ στο παρακάτω κουμπί για να το ανοίξετε.", @@ -194,13 +185,6 @@ OC.L10N.register( "Nov." : "Νοε.", "Dec." : "Δεκ.", "A valid password must be provided" : "Πρέπει να δοθεί έγκυρο συνθηματικό", - "The username is already being used" : "Το όνομα χρήστη είναι κατειλημμένο", - "Could not create user" : "Αδυναμία δημιουργίας χρήστη", - "A valid username must be provided" : "Πρέπει να δοθεί έγκυρο όνομα χρήστη", - "Username contains whitespace at the beginning or at the end" : "Το όνομα χρήστη περιέχει κενό διάστημα στην αρχή ή στο τέλος", - "Username must not consist of dots only" : "Το όνομα χρήστη δεν πρέπει να περιέχει μόνο τελείες", - "Username is invalid because files already exist for this user" : "Το όνομα χρήστη δεν είναι έγκυρο, επειδή υπάρχουν ήδη αρχεία για αυτόν τον χρήστη", - "User 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" : "ένα ασφαλές μέρος για όλα τα δεδομένα σας", @@ -232,8 +216,6 @@ OC.L10N.register( "PHP modules have been installed, but they are still listed as missing?" : "Κάποια αρθρώματα της PHP έχουν εγκατασταθεί, αλλά είναι ακόμα καταγεγραμμένες ως εκλιπόντα;", "Please ask your server administrator to restart the web server." : "Παρακαλούμε ζητήστε από το διαχειριστή του διακομιστή σας να επανεκκινήσει το διακομιστή δικτύου σας.", "Please ask your server administrator to check the Nextcloud configuration." : "Παρακαλούμε ζητήστε από το διαχειριστή του διακομιστή σας να ελέγξει τη διαμόρφωση του Nextcloud.", - "Your data directory is readable by other users." : "Ο κατάλογος δεδομένων σας είναι αναγνώσιμος από άλλους χρήστες.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Παρακαλούμε αλλάξτε τις ρυθμίσεις σε 0770 έτσι ώστε ο κατάλογος να μην μπορεί να προβάλλεται από άλλους χρήστες.", "Your data directory must be an absolute path." : "Ο κατάλογος δεδομένων σας πρέπει να είναι μια απόλυτη διαδρομή.", "Check the value of \"datadirectory\" in your configuration." : "Ελέγξτε την τιμή του \"datadirectory\" στις ρυθμίσεις σας.", "Your data directory is invalid." : "Ο κατάλογος δεδομένων σας δεν είναι έγκυρος.", @@ -250,11 +232,28 @@ OC.L10N.register( "Storage is temporarily not available" : "Ο χώρος αποθήκευσης δεν είναι διαθέσιμος προσωρινά", "Storage connection timeout. %s" : "Λήξη χρονικού ορίου σύνδεσης με αποθηκευτικό χώρο.%s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Τα αρχεία της εφαρμογής %1$s δεν αντικαταστάθηκαν σωστά. Βεβαιωθείτε ότι πρόκειται για συμβατή έκδοση με το διακομιστή.", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Ο συνδεδεμένος χρήστης πρέπει να είναι διαχειριστής, υποδιαχειριστής ή να έχει ειδικό δικαίωμα πρόσβασης σε αυτήν τη ρύθμιση", + "Logged in user must be an admin or sub admin" : "Ο συνδεδεμένος χρήστης πρέπει να είναι admin ή subadmin", + "Logged in user must be an admin" : "Ο συνδεδεμένος χρήστης πρέπει να είναι διαχειριστής", "Full name" : "Πλήρες όνομα", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Μόνο οι ακόλουθοι χαρακτήρες επιτρέπονται στο όνομα χρήστη; \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Άγνωστος χρήστης", + "MySQL username and/or password not valid" : "Το όνομα χρήστη και/'η ο κωδικός πρόσβασης MySQL δεν είναι σωστά", + "Oracle username and/or password not valid" : "Μη έγκυρος χρήστης και/ή συνθηματικό της Oracle", + "PostgreSQL username and/or password not valid" : "Μη έγκυρος χρήστης και/ή συνθηματικό της PostgreSQL", + "Set an admin username." : "Εισάγετε όνομα χρήστη διαχειριστή.", + "Sharing %s failed, because this item is already shared with user %s" : "Η κοινή χρήση του %s απέτυχε, επειδή αυτό το στοιχείο είναι ήδη κοινόχρηστο με τον χρήστη %s", + "The username is already being used" : "Το όνομα χρήστη είναι κατειλημμένο", + "Could not create user" : "Αδυναμία δημιουργίας χρήστη", + "A valid username must be provided" : "Πρέπει να δοθεί έγκυρο όνομα χρήστη", + "Username contains whitespace at the beginning or at the end" : "Το όνομα χρήστη περιέχει κενό διάστημα στην αρχή ή στο τέλος", + "Username must not consist of dots only" : "Το όνομα χρήστη δεν πρέπει να περιέχει μόνο τελείες", + "Username is invalid because files already exist for this user" : "Το όνομα χρήστη δεν είναι έγκυρο, επειδή υπάρχουν ήδη αρχεία για αυτόν τον χρήστη", + "User disabled" : "Ο χρήστης απενεργοποιήθηκε", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Απαιτείται τουλάχιστον το libxml2 2.7.0. Αυτή τη στιγμή είναι εγκατεστημένο το %s.", "To fix this issue update your libxml2 version and restart your web server." : "Για να διορθώσετε το σφάλμα ενημερώστε την έκδοση του libxml2 και επανεκκινήστε τον διακομιστή.", "PostgreSQL >= 9 required." : "Απαιτείται PostgreSQL >= 9.", - "Please upgrade your database version." : "Παρακαλούμε αναβαθμίστε την έκδοση της βάσης δεδομένων σας." + "Please upgrade your database version." : "Παρακαλούμε αναβαθμίστε την έκδοση της βάσης δεδομένων σας.", + "Your data directory is readable by other users." : "Ο κατάλογος δεδομένων σας είναι αναγνώσιμος από άλλους χρήστες.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Παρακαλούμε αλλάξτε τις ρυθμίσεις σε 0770 έτσι ώστε ο κατάλογος να μην μπορεί να προβάλλεται από άλλους χρήστες." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/el.json b/lib/l10n/el.json index 5d8e3e87a85..83315348a13 100644 --- a/lib/l10n/el.json +++ b/lib/l10n/el.json @@ -33,9 +33,6 @@ "The following platforms are supported: %s" : "Υποστηρίζονται οι ακόλουθες πλατφόρμες: %s", "Server version %s or higher is required." : "Απαιτείται έκδοση διακομιστή %s ή νεότερη.", "Server version %s or lower is required." : "Απαιτείται έκδοση διακομιστή %s ή παλαιότερη.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Ο συνδεδεμένος χρήστης πρέπει να είναι διαχειριστής, υποδιαχειριστής ή να έχει ειδικό δικαίωμα πρόσβασης σε αυτήν τη ρύθμιση", - "Logged in user must be an admin or sub admin" : "Ο συνδεδεμένος χρήστης πρέπει να είναι admin ή subadmin", - "Logged in user must be an admin" : "Ο συνδεδεμένος χρήστης πρέπει να είναι διαχειριστής", "Wiping of device %s has started" : "Η εκκαθάριση συσκευής %s ξεκίνησε", "Wiping of device »%s« has started" : "Η εκκαθάριση συσκευής »%s« ξεκίνησε", "»%s« started remote wipe" : "»%s« ξεκίνησε η απομακρυσμένη εκκαθάριση", @@ -111,18 +108,13 @@ "Headline" : "Τίτλος", "Organisation" : "Οργανισμός", "Role" : "Ρόλος/Θέση", - "Unknown user" : "Άγνωστος χρήστης", "Additional settings" : "Επιπρόσθετες ρυθμίσεις", - "MySQL username and/or password not valid" : "Το όνομα χρήστη και/'η ο κωδικός πρόσβασης MySQL δεν είναι σωστά", "You need to enter details of an existing account." : "Χρειάζεται να εισάγετε λεπτομέρειες από υπάρχοντα λογαριασμό.", "Oracle connection could not be established" : "Αδυναμία σύνδεσης Oracle", - "Oracle username and/or password not valid" : "Μη έγκυρος χρήστης και/ή συνθηματικό της Oracle", - "PostgreSQL username 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-bit PHP και η επιλογή open_basedir έχει ρυθμιστεί στο αρχείο php.ini. Αυτό θα οδηγήσει σε προβλήματα με αρχεία πάνω από 4 GB και δεν συνίσταται.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Παρακαλούμε αφαιρέστε την ρύθμιση open_basedir μέσα στο αρχείο php.ini ή αλλάξτε σε 64-bit PHP.", - "Set an admin username." : "Εισάγετε όνομα χρήστη διαχειριστή.", "Set an admin password." : "Εισάγετε συνθηματικό διαχειριστή.", "Cannot create or write into the data directory %s" : "Δεν είναι δυνατή η δημιουργία ή εγγραφή στον κατάλογο δεδομένων %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Το σύστημα διαμοιρασμού %s πρέπει να υλοποιεί την διεπαφή OCP\\Share_Backend", @@ -140,7 +132,6 @@ "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_" : ["Δεν είναι δυνατός ο ορισμός ημερομηνίας λήξης για περισσότερο από %n ημέρα στο μέλλον","Δεν είναι δυνατός ο ορισμός ημερομηνίας λήξης για περισσότερες από %n ημέρες στο μέλλον"], "Sharing is only allowed with group members" : "Η κοινή χρήση επιτρέπεται μόνο με μέλη της ομάδας", - "Sharing %s failed, because this item is already shared with user %s" : "Η κοινή χρήση του %s απέτυχε, επειδή αυτό το στοιχείο είναι ήδη κοινόχρηστο με τον χρήστη %s", "%1$s shared »%2$s« with you" : "Ο/η %1$s διαμοιράστηκε το »%2$s« με εσάς.", "%1$s shared »%2$s« with you." : "Ο/η %1$s διαμοιράστηκε »%2$s« με εσάς.", "Click the button below to open it." : "Κάντε κλικ στο παρακάτω κουμπί για να το ανοίξετε.", @@ -192,13 +183,6 @@ "Nov." : "Νοε.", "Dec." : "Δεκ.", "A valid password must be provided" : "Πρέπει να δοθεί έγκυρο συνθηματικό", - "The username is already being used" : "Το όνομα χρήστη είναι κατειλημμένο", - "Could not create user" : "Αδυναμία δημιουργίας χρήστη", - "A valid username must be provided" : "Πρέπει να δοθεί έγκυρο όνομα χρήστη", - "Username contains whitespace at the beginning or at the end" : "Το όνομα χρήστη περιέχει κενό διάστημα στην αρχή ή στο τέλος", - "Username must not consist of dots only" : "Το όνομα χρήστη δεν πρέπει να περιέχει μόνο τελείες", - "Username is invalid because files already exist for this user" : "Το όνομα χρήστη δεν είναι έγκυρο, επειδή υπάρχουν ήδη αρχεία για αυτόν τον χρήστη", - "User 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" : "ένα ασφαλές μέρος για όλα τα δεδομένα σας", @@ -230,8 +214,6 @@ "PHP modules have been installed, but they are still listed as missing?" : "Κάποια αρθρώματα της PHP έχουν εγκατασταθεί, αλλά είναι ακόμα καταγεγραμμένες ως εκλιπόντα;", "Please ask your server administrator to restart the web server." : "Παρακαλούμε ζητήστε από το διαχειριστή του διακομιστή σας να επανεκκινήσει το διακομιστή δικτύου σας.", "Please ask your server administrator to check the Nextcloud configuration." : "Παρακαλούμε ζητήστε από το διαχειριστή του διακομιστή σας να ελέγξει τη διαμόρφωση του Nextcloud.", - "Your data directory is readable by other users." : "Ο κατάλογος δεδομένων σας είναι αναγνώσιμος από άλλους χρήστες.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Παρακαλούμε αλλάξτε τις ρυθμίσεις σε 0770 έτσι ώστε ο κατάλογος να μην μπορεί να προβάλλεται από άλλους χρήστες.", "Your data directory must be an absolute path." : "Ο κατάλογος δεδομένων σας πρέπει να είναι μια απόλυτη διαδρομή.", "Check the value of \"datadirectory\" in your configuration." : "Ελέγξτε την τιμή του \"datadirectory\" στις ρυθμίσεις σας.", "Your data directory is invalid." : "Ο κατάλογος δεδομένων σας δεν είναι έγκυρος.", @@ -248,11 +230,28 @@ "Storage is temporarily not available" : "Ο χώρος αποθήκευσης δεν είναι διαθέσιμος προσωρινά", "Storage connection timeout. %s" : "Λήξη χρονικού ορίου σύνδεσης με αποθηκευτικό χώρο.%s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Τα αρχεία της εφαρμογής %1$s δεν αντικαταστάθηκαν σωστά. Βεβαιωθείτε ότι πρόκειται για συμβατή έκδοση με το διακομιστή.", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Ο συνδεδεμένος χρήστης πρέπει να είναι διαχειριστής, υποδιαχειριστής ή να έχει ειδικό δικαίωμα πρόσβασης σε αυτήν τη ρύθμιση", + "Logged in user must be an admin or sub admin" : "Ο συνδεδεμένος χρήστης πρέπει να είναι admin ή subadmin", + "Logged in user must be an admin" : "Ο συνδεδεμένος χρήστης πρέπει να είναι διαχειριστής", "Full name" : "Πλήρες όνομα", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Μόνο οι ακόλουθοι χαρακτήρες επιτρέπονται στο όνομα χρήστη; \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Άγνωστος χρήστης", + "MySQL username and/or password not valid" : "Το όνομα χρήστη και/'η ο κωδικός πρόσβασης MySQL δεν είναι σωστά", + "Oracle username and/or password not valid" : "Μη έγκυρος χρήστης και/ή συνθηματικό της Oracle", + "PostgreSQL username and/or password not valid" : "Μη έγκυρος χρήστης και/ή συνθηματικό της PostgreSQL", + "Set an admin username." : "Εισάγετε όνομα χρήστη διαχειριστή.", + "Sharing %s failed, because this item is already shared with user %s" : "Η κοινή χρήση του %s απέτυχε, επειδή αυτό το στοιχείο είναι ήδη κοινόχρηστο με τον χρήστη %s", + "The username is already being used" : "Το όνομα χρήστη είναι κατειλημμένο", + "Could not create user" : "Αδυναμία δημιουργίας χρήστη", + "A valid username must be provided" : "Πρέπει να δοθεί έγκυρο όνομα χρήστη", + "Username contains whitespace at the beginning or at the end" : "Το όνομα χρήστη περιέχει κενό διάστημα στην αρχή ή στο τέλος", + "Username must not consist of dots only" : "Το όνομα χρήστη δεν πρέπει να περιέχει μόνο τελείες", + "Username is invalid because files already exist for this user" : "Το όνομα χρήστη δεν είναι έγκυρο, επειδή υπάρχουν ήδη αρχεία για αυτόν τον χρήστη", + "User disabled" : "Ο χρήστης απενεργοποιήθηκε", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Απαιτείται τουλάχιστον το libxml2 2.7.0. Αυτή τη στιγμή είναι εγκατεστημένο το %s.", "To fix this issue update your libxml2 version and restart your web server." : "Για να διορθώσετε το σφάλμα ενημερώστε την έκδοση του libxml2 και επανεκκινήστε τον διακομιστή.", "PostgreSQL >= 9 required." : "Απαιτείται PostgreSQL >= 9.", - "Please upgrade your database version." : "Παρακαλούμε αναβαθμίστε την έκδοση της βάσης δεδομένων σας." + "Please upgrade your database version." : "Παρακαλούμε αναβαθμίστε την έκδοση της βάσης δεδομένων σας.", + "Your data directory is readable by other users." : "Ο κατάλογος δεδομένων σας είναι αναγνώσιμος από άλλους χρήστες.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Παρακαλούμε αλλάξτε τις ρυθμίσεις σε 0770 έτσι ώστε ο κατάλογος να μην μπορεί να προβάλλεται από άλλους χρήστες." },"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 ed51e1fd5fc..21ad4ecba46 100644 --- a/lib/l10n/en_GB.js +++ b/lib/l10n/en_GB.js @@ -8,7 +8,6 @@ OC.L10N.register( "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.", "Sample configuration detected" : "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" : "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", - "404" : "404", "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", @@ -37,9 +36,9 @@ OC.L10N.register( "The following platforms are supported: %s" : "The following platforms are supported: %s", "Server version %s or higher is required." : "Server version %s or higher is required.", "Server version %s or lower is required." : "Server version %s or lower is required.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub-admin or has special right to access this setting", - "Logged in user must be an admin or sub admin" : "Logged in user must be an admin or sub admin", - "Logged in user must be an admin" : "Logged in user must be an admin", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Logged in account must be an admin, a sub admin or gotten special right to access this setting", + "Logged in account must be an admin or sub admin" : "Logged in account must be an admin or sub admin", + "Logged in account must be an admin" : "Logged in account must be an admin", "Wiping of device %s has started" : "Wiping of device %s has started", "Wiping of device »%s« has started" : "Wiping of device »%s« has started", "»%s« started remote wipe" : "»%s« started remote wipe", @@ -118,22 +117,22 @@ OC.L10N.register( "Headline" : "Headline", "Organisation" : "Organisation", "Role" : "Role", - "Unknown user" : "Unknown user", + "Unknown account" : "Unknown account", "Additional settings" : "Additional settings", - "Enter the database username and name for %s" : "Enter the database username and name for %s", - "Enter the database username for %s" : "Enter the database username for %s", + "Enter the database Login and name for %s" : "Enter the database Login and name for %s", + "Enter the database Login for %s" : "Enter the database Login for %s", "Enter the database name for %s" : "Enter the database name for %s", "You cannot use dots in the database name %s" : "You cannot use dots in the database name %s", - "MySQL username and/or password not valid" : "MySQL username and/or password not valid", + "MySQL Login and/or password not valid" : "MySQL Login and/or password not valid", "You need to enter details of an existing account." : "You need to enter details of an existing account.", "Oracle connection could not be established" : "Oracle connection could not be established", - "Oracle username and/or password not valid" : "Oracle username and/or password not valid", - "PostgreSQL username and/or password not valid" : "PostgreSQL username and/or password not valid", + "Oracle Login and/or password not valid" : "Oracle Login and/or password not valid", + "PostgreSQL Login and/or password not valid" : "PostgreSQL Login and/or password not valid", "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! ", "For the best results, please consider using a GNU/Linux server instead." : "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." : "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir setting has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP.", - "Set an admin username." : "Set an admin username.", + "Set an admin Login." : "Set an admin Login.", "Set an admin password." : "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" : "Sharing backend %s must implement the interface OCP\\Share_Backend", @@ -151,7 +150,7 @@ OC.L10N.register( "Expiration date is in the past" : "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", - "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Sharing %s failed, because this item is already shared with the account %s", "%1$s shared »%2$s« with you" : "%1$s shared »%2$s« with you", "%1$s shared »%2$s« with you." : "%1$s shared »%2$s« with you.", "Click the button below to open it." : "Click the button below to open it.", @@ -205,14 +204,14 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "A valid password must be provided", - "The username is already being used" : "The username is already being used", - "Could not create user" : "Could not create user", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", - "A valid username must be provided" : "A valid username must be provided", - "Username contains whitespace at the beginning or at the end" : "Username contains whitespace at the beginning or at the end", - "Username must not consist of dots only" : "Username must not consist of dots only", - "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", - "User disabled" : "User disabled", + "The Login is already being used" : "The Login is already being used", + "Could not create account" : "Could not create account", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", + "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 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", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s", "a safe home for all your data" : "a safe home for all your data", @@ -245,8 +244,8 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "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 is readable by other users." : "Your data directory is readable by other users.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Please change the permissions to 0770 so that the directory cannot be listed by other users.", + "Your data directory is readable by other people." : "Your data directory is readable by other people.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Please change the permissions to 0770 so that the directory cannot be listed by other people.", "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.", @@ -271,12 +270,32 @@ OC.L10N.register( "Extract topics" : "Extract topics", "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub-admin or has special right to access this setting", + "Logged in user must be an admin or sub admin" : "Logged in user must be an admin or sub admin", + "Logged in user must be an admin" : "Logged in user must be an admin", "Full name" : "Full name", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "The user limit has been reached and the user was not created. Check your notifications to learn more.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Unknown user", + "Enter the database username and name for %s" : "Enter the database username and name for %s", + "Enter the database username for %s" : "Enter the database username for %s", + "MySQL username and/or password not valid" : "MySQL username and/or password not valid", + "Oracle username and/or password not valid" : "Oracle username and/or password not valid", + "PostgreSQL username and/or password not valid" : "PostgreSQL username and/or password not valid", + "Set an admin username." : "Set an admin username.", + "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", + "The username is already being used" : "The username is already being used", + "Could not create user" : "Could not create user", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", + "A valid username must be provided" : "A valid username must be provided", + "Username contains whitespace at the beginning or at the end" : "Username contains whitespace at the beginning or at the end", + "Username must not consist of dots only" : "Username must not consist of dots only", + "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", + "User disabled" : "User disabled", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 is at least required. Currently %s is installed.", "To fix this issue update your libxml2 version and restart your web server." : "To fix this issue update your libxml2 version and restart your web server.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 required.", - "Please upgrade your database version." : "Please upgrade your database version." + "Please upgrade your database version." : "Please upgrade your database version.", + "Your data directory is readable by other users." : "Your data directory is readable by other users.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Please change the permissions to 0770 so that the directory cannot be listed by other users." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/en_GB.json b/lib/l10n/en_GB.json index 40563e1980e..f836cdd3096 100644 --- a/lib/l10n/en_GB.json +++ b/lib/l10n/en_GB.json @@ -6,7 +6,6 @@ "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.", "Sample configuration detected" : "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" : "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", - "404" : "404", "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", @@ -35,9 +34,9 @@ "The following platforms are supported: %s" : "The following platforms are supported: %s", "Server version %s or higher is required." : "Server version %s or higher is required.", "Server version %s or lower is required." : "Server version %s or lower is required.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub-admin or has special right to access this setting", - "Logged in user must be an admin or sub admin" : "Logged in user must be an admin or sub admin", - "Logged in user must be an admin" : "Logged in user must be an admin", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Logged in account must be an admin, a sub admin or gotten special right to access this setting", + "Logged in account must be an admin or sub admin" : "Logged in account must be an admin or sub admin", + "Logged in account must be an admin" : "Logged in account must be an admin", "Wiping of device %s has started" : "Wiping of device %s has started", "Wiping of device »%s« has started" : "Wiping of device »%s« has started", "»%s« started remote wipe" : "»%s« started remote wipe", @@ -116,22 +115,22 @@ "Headline" : "Headline", "Organisation" : "Organisation", "Role" : "Role", - "Unknown user" : "Unknown user", + "Unknown account" : "Unknown account", "Additional settings" : "Additional settings", - "Enter the database username and name for %s" : "Enter the database username and name for %s", - "Enter the database username for %s" : "Enter the database username for %s", + "Enter the database Login and name for %s" : "Enter the database Login and name for %s", + "Enter the database Login for %s" : "Enter the database Login for %s", "Enter the database name for %s" : "Enter the database name for %s", "You cannot use dots in the database name %s" : "You cannot use dots in the database name %s", - "MySQL username and/or password not valid" : "MySQL username and/or password not valid", + "MySQL Login and/or password not valid" : "MySQL Login and/or password not valid", "You need to enter details of an existing account." : "You need to enter details of an existing account.", "Oracle connection could not be established" : "Oracle connection could not be established", - "Oracle username and/or password not valid" : "Oracle username and/or password not valid", - "PostgreSQL username and/or password not valid" : "PostgreSQL username and/or password not valid", + "Oracle Login and/or password not valid" : "Oracle Login and/or password not valid", + "PostgreSQL Login and/or password not valid" : "PostgreSQL Login and/or password not valid", "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! ", "For the best results, please consider using a GNU/Linux server instead." : "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." : "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir setting has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP.", - "Set an admin username." : "Set an admin username.", + "Set an admin Login." : "Set an admin Login.", "Set an admin password." : "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" : "Sharing backend %s must implement the interface OCP\\Share_Backend", @@ -149,7 +148,7 @@ "Expiration date is in the past" : "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", - "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Sharing %s failed, because this item is already shared with the account %s", "%1$s shared »%2$s« with you" : "%1$s shared »%2$s« with you", "%1$s shared »%2$s« with you." : "%1$s shared »%2$s« with you.", "Click the button below to open it." : "Click the button below to open it.", @@ -203,14 +202,14 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "A valid password must be provided", - "The username is already being used" : "The username is already being used", - "Could not create user" : "Could not create user", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", - "A valid username must be provided" : "A valid username must be provided", - "Username contains whitespace at the beginning or at the end" : "Username contains whitespace at the beginning or at the end", - "Username must not consist of dots only" : "Username must not consist of dots only", - "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", - "User disabled" : "User disabled", + "The Login is already being used" : "The Login is already being used", + "Could not create account" : "Could not create account", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", + "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 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", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s", "a safe home for all your data" : "a safe home for all your data", @@ -243,8 +242,8 @@ "Please ask your server administrator to restart the web server." : "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 is readable by other users." : "Your data directory is readable by other users.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Please change the permissions to 0770 so that the directory cannot be listed by other users.", + "Your data directory is readable by other people." : "Your data directory is readable by other people.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Please change the permissions to 0770 so that the directory cannot be listed by other people.", "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.", @@ -269,12 +268,32 @@ "Extract topics" : "Extract topics", "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub-admin or has special right to access this setting", + "Logged in user must be an admin or sub admin" : "Logged in user must be an admin or sub admin", + "Logged in user must be an admin" : "Logged in user must be an admin", "Full name" : "Full name", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "The user limit has been reached and the user was not created. Check your notifications to learn more.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Unknown user", + "Enter the database username and name for %s" : "Enter the database username and name for %s", + "Enter the database username for %s" : "Enter the database username for %s", + "MySQL username and/or password not valid" : "MySQL username and/or password not valid", + "Oracle username and/or password not valid" : "Oracle username and/or password not valid", + "PostgreSQL username and/or password not valid" : "PostgreSQL username and/or password not valid", + "Set an admin username." : "Set an admin username.", + "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", + "The username is already being used" : "The username is already being used", + "Could not create user" : "Could not create user", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", + "A valid username must be provided" : "A valid username must be provided", + "Username contains whitespace at the beginning or at the end" : "Username contains whitespace at the beginning or at the end", + "Username must not consist of dots only" : "Username must not consist of dots only", + "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", + "User disabled" : "User disabled", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 is at least required. Currently %s is installed.", "To fix this issue update your libxml2 version and restart your web server." : "To fix this issue update your libxml2 version and restart your web server.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 required.", - "Please upgrade your database version." : "Please upgrade your database version." + "Please upgrade your database version." : "Please upgrade your database version.", + "Your data directory is readable by other users." : "Your data directory is readable by other users.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Please change the permissions to 0770 so that the directory cannot be listed by other users." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/eo.js b/lib/l10n/eo.js index 69e5688c25c..a7cbc3fffe9 100644 --- a/lib/l10n/eo.js +++ b/lib/l10n/eo.js @@ -5,6 +5,7 @@ OC.L10N.register( "See %s" : "Vidi %s", "Sample configuration detected" : "Ekzempla agordo trovita", "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" : "Ekzempla agordo estis kopiita en via sistemo. Tio povas paneigi vian instalaĵon, kaj ne estas subtenata. Bv. legi la dokumentaron antaŭ ol fari ŝanĝojn en config.php", + "The page could not be found on the server." : "La paĝo ne povis esti trovita en la servilo.", "Other activities" : "Alia aktivado", "%1$s and %2$s" : "%1$s kaj %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s kaj %3$s", @@ -27,8 +28,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "La sekvaj platformoj estas subtenataj: %s", "Server version %s or higher is required." : "Servilo kun versio %s aŭ pli bezoniĝas.", "Server version %s or lower is required." : "Servilo kun versio %s aŭ malpli bezoniĝas.", - "Logged in user must be an admin or sub admin" : "La ensalutanta uzanto estu administranto aŭ subadministranto", - "Logged in user must be an admin" : "La ensalutanta uzanto estu administranto", "Wiping of device %s has started" : "Forviŝado de la aparato %s komencis", "Wiping of device »%s« has started" : "Forviŝado de la aparato „%s“ komencis", "»%s« started remote wipe" : "„%s“ komencis foran forviŝadon", @@ -46,6 +45,7 @@ OC.L10N.register( "Invalid image" : "Nevalida bildo", "Avatar image is not square" : "Avatarbildo ne estas kvadrata", "Files" : "Dosieroj", + "View profile" : "Vidi profilon", "today" : "hodiaŭ", "tomorrow" : "morgaŭ", "yesterday" : "hieraŭ", @@ -91,18 +91,13 @@ OC.L10N.register( "Profile picture" : "Profila bildo", "About" : "Pri", "Display name" : "Vidiga nomo", - "Unknown user" : "Nekonata uzanto", "Additional settings" : "Plia agordo", - "MySQL username and/or password not valid" : "La uzantnomo kaj/aŭ pasvorto de MySQL ne estas valida", "You need to enter details of an existing account." : "Vi entajpu detalojn pri ekzistanta konto.", "Oracle connection could not be established" : "Konekto al Oracle ne povis stariĝi", - "Oracle username and/or password not valid" : "La uzantnomo kaj/aŭ la pasvorto de Oracle ne estas valida", - "PostgreSQL username and/or password not valid" : "La uzantnomo aŭ la pasvorto de PostgreSQL ne validas", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "MacOS X ne estas subtenata kaj %s ne bone funkcios ĉe ĝi. Uzu ĝin je via risko!", "For the best results, please consider using a GNU/Linux server instead." : "Por pli bona funkciado, bv. pripensi uzi GNU-Linuksan servilon anstataŭe.", "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." : "Ŝajnas, ke tiu servilo %s uzas 32-bitan PHP-version, kaj ke la agordo „open_basedir“ ekzistas. Tio kaŭzos problemojn pri dosieroj pli grandaj ol 4 GB, kaj do estas tre malrekomendita.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Bv. forigi la agordon „open_basedir“ de via php.ini, aŭ uzu 64-bitan version de PHP.", - "Set an admin username." : "Agordi uzantnomon de administranto.", "Set an admin password." : "Agordi pasvorton de administranto.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Kunhava interna servo %s devas realigi la interfacon „OCP\\Share_Backend“", "Sharing backend %s not found" : "Kunhava interna servo %s ne troviĝas", @@ -115,7 +110,6 @@ OC.L10N.register( "You are not allowed to share %s" : "Vi ne permesatas kunhavigi %s", "Cannot increase permissions of %s" : "Ne eblas pliigi permesojn de %s", "Expiration date is in the past" : "Limdato troviĝas en la estinteco", - "Sharing %s failed, because this item is already shared with user %s" : "Kunhavigo de %s malsukcesis, ĉar la ero jam kunhaviĝis kun %s", "%1$s shared »%2$s« with you" : "%1$s kunhavigis „%2$s“ kun vi", "%1$s shared »%2$s« with you." : "%1$s kunhavigis „%2$s“ kun vi.", "Click the button below to open it." : "Alklaku la butonon ĉi-sube por malfermi ĝin.", @@ -167,13 +161,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Valida pasvorto devas esti provizita", - "The username is already being used" : "La uzantnomo jam estas uzata", - "Could not create user" : "Ne povis krei uzanton", - "A valid username must be provided" : "Valida uzantnomo devas esti provizita", - "Username contains whitespace at the beginning or at the end" : "Uzantnomo enhavas spaceton ĉe la komenco aŭ la fino", - "Username must not consist of dots only" : "Uzantnomo ne povas enhavi nur punktojn", - "Username is invalid because files already exist for this user" : "La uzantnomo ne estas valida pro dosieroj por la uzanto jam ekzistas", - "User disabled" : "Uzanto malebligita", "Login canceled by app" : "Ensaluto estis nuligita de aplikaĵo", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "La aplikaĵo „%1$s“ ne instaliĝas, ĉar la jenaj dependecoj ne plenumiĝas: %2$s", "a safe home for all your data" : "sekura hejmo por ĉiuj viaj datumoj", @@ -191,7 +178,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Tion kaŭzas probable kaŝilo aŭ plirapidigilo kiel „Zend OPcache“ aŭ „eAccelerator“.", "PHP modules have been installed, but they are still listed as missing?" : "Ĉu PHP-moduloj estas instalitaj, sed ĉiam montritaj kiel mankantaj?", "Please ask your server administrator to restart the web server." : "Bonvolu peti vian serviladministranton, ke ŝi aŭ li restartigu la TTT-servilon.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bv. ŝanĝi la permesojn al 0770, tiel la dosierujo ne listigeblas de aliaj uzantoj.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Certigu, ke estas dosiero nomata „.ocdata“ en la radiko de la dosierujo de datumoj.", "Action \"%s\" not supported or implemented." : "Ago „%s“ ne estas subtenata aŭ realigita.", "Authentication failed, wrong token or provider ID given" : "Aŭtentigo malsukcesis: neĝusta ĵetono aŭ provizanto-identigilo specifita", @@ -205,9 +191,24 @@ OC.L10N.register( "Storage is temporarily not available" : "Konservejo provizore ne disponeblas", "Storage connection timeout. %s" : "Konekto al konservejo eltempiĝis. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "La dosieroj de la aplikaĵo %1$s ne estis ĝuste anstataŭigitaj. Certigu, ke tiu aplikaĵa versio kongruas la servilon.", + "Logged in user must be an admin or sub admin" : "La ensalutanta uzanto estu administranto aŭ subadministranto", + "Logged in user must be an admin" : "La ensalutanta uzanto estu administranto", "Full name" : "Plena nomo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Nur sekvaj signoj estas permesitaj en uzantnomo: \"a-z“, \"A-Z“, \"0-9“ kaj \"_“ (substreko), \"@“ (ĉe), \"-“ (streketo), \"'“ (apostrofo), \".“ (punkto)", + "Unknown user" : "Nekonata uzanto", + "MySQL username and/or password not valid" : "La uzantnomo kaj/aŭ pasvorto de MySQL ne estas valida", + "Oracle username and/or password not valid" : "La uzantnomo kaj/aŭ la pasvorto de Oracle ne estas valida", + "PostgreSQL username and/or password not valid" : "La uzantnomo aŭ la pasvorto de PostgreSQL ne validas", + "Set an admin username." : "Agordi uzantnomon de administranto.", + "Sharing %s failed, because this item is already shared with user %s" : "Kunhavigo de %s malsukcesis, ĉar la ero jam kunhaviĝis kun %s", + "The username is already being used" : "La uzantnomo jam estas uzata", + "Could not create user" : "Ne povis krei uzanton", + "A valid username must be provided" : "Valida uzantnomo devas esti provizita", + "Username contains whitespace at the beginning or at the end" : "Uzantnomo enhavas spaceton ĉe la komenco aŭ la fino", + "Username must not consist of dots only" : "Uzantnomo ne povas enhavi nur punktojn", + "Username is invalid because files already exist for this user" : "La uzantnomo ne estas valida pro dosieroj por la uzanto jam ekzistas", + "User disabled" : "Uzanto malebligita", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 almenaŭ necesas. Nun %s estas instalita.", - "To fix this issue update your libxml2 version and restart your web server." : "Por ripari tiun problemon, ĝisdatigu vian version de libxml2, kaj restartigu la TTT-servilon." + "To fix this issue update your libxml2 version and restart your web server." : "Por ripari tiun problemon, ĝisdatigu vian version de libxml2, kaj restartigu la TTT-servilon.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bv. ŝanĝi la permesojn al 0770, tiel la dosierujo ne listigeblas de aliaj uzantoj." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/eo.json b/lib/l10n/eo.json index 6c06f5cae1a..0152c810d21 100644 --- a/lib/l10n/eo.json +++ b/lib/l10n/eo.json @@ -3,6 +3,7 @@ "See %s" : "Vidi %s", "Sample configuration detected" : "Ekzempla agordo trovita", "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" : "Ekzempla agordo estis kopiita en via sistemo. Tio povas paneigi vian instalaĵon, kaj ne estas subtenata. Bv. legi la dokumentaron antaŭ ol fari ŝanĝojn en config.php", + "The page could not be found on the server." : "La paĝo ne povis esti trovita en la servilo.", "Other activities" : "Alia aktivado", "%1$s and %2$s" : "%1$s kaj %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s kaj %3$s", @@ -25,8 +26,6 @@ "The following platforms are supported: %s" : "La sekvaj platformoj estas subtenataj: %s", "Server version %s or higher is required." : "Servilo kun versio %s aŭ pli bezoniĝas.", "Server version %s or lower is required." : "Servilo kun versio %s aŭ malpli bezoniĝas.", - "Logged in user must be an admin or sub admin" : "La ensalutanta uzanto estu administranto aŭ subadministranto", - "Logged in user must be an admin" : "La ensalutanta uzanto estu administranto", "Wiping of device %s has started" : "Forviŝado de la aparato %s komencis", "Wiping of device »%s« has started" : "Forviŝado de la aparato „%s“ komencis", "»%s« started remote wipe" : "„%s“ komencis foran forviŝadon", @@ -44,6 +43,7 @@ "Invalid image" : "Nevalida bildo", "Avatar image is not square" : "Avatarbildo ne estas kvadrata", "Files" : "Dosieroj", + "View profile" : "Vidi profilon", "today" : "hodiaŭ", "tomorrow" : "morgaŭ", "yesterday" : "hieraŭ", @@ -89,18 +89,13 @@ "Profile picture" : "Profila bildo", "About" : "Pri", "Display name" : "Vidiga nomo", - "Unknown user" : "Nekonata uzanto", "Additional settings" : "Plia agordo", - "MySQL username and/or password not valid" : "La uzantnomo kaj/aŭ pasvorto de MySQL ne estas valida", "You need to enter details of an existing account." : "Vi entajpu detalojn pri ekzistanta konto.", "Oracle connection could not be established" : "Konekto al Oracle ne povis stariĝi", - "Oracle username and/or password not valid" : "La uzantnomo kaj/aŭ la pasvorto de Oracle ne estas valida", - "PostgreSQL username and/or password not valid" : "La uzantnomo aŭ la pasvorto de PostgreSQL ne validas", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "MacOS X ne estas subtenata kaj %s ne bone funkcios ĉe ĝi. Uzu ĝin je via risko!", "For the best results, please consider using a GNU/Linux server instead." : "Por pli bona funkciado, bv. pripensi uzi GNU-Linuksan servilon anstataŭe.", "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." : "Ŝajnas, ke tiu servilo %s uzas 32-bitan PHP-version, kaj ke la agordo „open_basedir“ ekzistas. Tio kaŭzos problemojn pri dosieroj pli grandaj ol 4 GB, kaj do estas tre malrekomendita.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Bv. forigi la agordon „open_basedir“ de via php.ini, aŭ uzu 64-bitan version de PHP.", - "Set an admin username." : "Agordi uzantnomon de administranto.", "Set an admin password." : "Agordi pasvorton de administranto.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Kunhava interna servo %s devas realigi la interfacon „OCP\\Share_Backend“", "Sharing backend %s not found" : "Kunhava interna servo %s ne troviĝas", @@ -113,7 +108,6 @@ "You are not allowed to share %s" : "Vi ne permesatas kunhavigi %s", "Cannot increase permissions of %s" : "Ne eblas pliigi permesojn de %s", "Expiration date is in the past" : "Limdato troviĝas en la estinteco", - "Sharing %s failed, because this item is already shared with user %s" : "Kunhavigo de %s malsukcesis, ĉar la ero jam kunhaviĝis kun %s", "%1$s shared »%2$s« with you" : "%1$s kunhavigis „%2$s“ kun vi", "%1$s shared »%2$s« with you." : "%1$s kunhavigis „%2$s“ kun vi.", "Click the button below to open it." : "Alklaku la butonon ĉi-sube por malfermi ĝin.", @@ -165,13 +159,6 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Valida pasvorto devas esti provizita", - "The username is already being used" : "La uzantnomo jam estas uzata", - "Could not create user" : "Ne povis krei uzanton", - "A valid username must be provided" : "Valida uzantnomo devas esti provizita", - "Username contains whitespace at the beginning or at the end" : "Uzantnomo enhavas spaceton ĉe la komenco aŭ la fino", - "Username must not consist of dots only" : "Uzantnomo ne povas enhavi nur punktojn", - "Username is invalid because files already exist for this user" : "La uzantnomo ne estas valida pro dosieroj por la uzanto jam ekzistas", - "User disabled" : "Uzanto malebligita", "Login canceled by app" : "Ensaluto estis nuligita de aplikaĵo", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "La aplikaĵo „%1$s“ ne instaliĝas, ĉar la jenaj dependecoj ne plenumiĝas: %2$s", "a safe home for all your data" : "sekura hejmo por ĉiuj viaj datumoj", @@ -189,7 +176,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Tion kaŭzas probable kaŝilo aŭ plirapidigilo kiel „Zend OPcache“ aŭ „eAccelerator“.", "PHP modules have been installed, but they are still listed as missing?" : "Ĉu PHP-moduloj estas instalitaj, sed ĉiam montritaj kiel mankantaj?", "Please ask your server administrator to restart the web server." : "Bonvolu peti vian serviladministranton, ke ŝi aŭ li restartigu la TTT-servilon.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bv. ŝanĝi la permesojn al 0770, tiel la dosierujo ne listigeblas de aliaj uzantoj.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Certigu, ke estas dosiero nomata „.ocdata“ en la radiko de la dosierujo de datumoj.", "Action \"%s\" not supported or implemented." : "Ago „%s“ ne estas subtenata aŭ realigita.", "Authentication failed, wrong token or provider ID given" : "Aŭtentigo malsukcesis: neĝusta ĵetono aŭ provizanto-identigilo specifita", @@ -203,9 +189,24 @@ "Storage is temporarily not available" : "Konservejo provizore ne disponeblas", "Storage connection timeout. %s" : "Konekto al konservejo eltempiĝis. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "La dosieroj de la aplikaĵo %1$s ne estis ĝuste anstataŭigitaj. Certigu, ke tiu aplikaĵa versio kongruas la servilon.", + "Logged in user must be an admin or sub admin" : "La ensalutanta uzanto estu administranto aŭ subadministranto", + "Logged in user must be an admin" : "La ensalutanta uzanto estu administranto", "Full name" : "Plena nomo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Nur sekvaj signoj estas permesitaj en uzantnomo: \"a-z“, \"A-Z“, \"0-9“ kaj \"_“ (substreko), \"@“ (ĉe), \"-“ (streketo), \"'“ (apostrofo), \".“ (punkto)", + "Unknown user" : "Nekonata uzanto", + "MySQL username and/or password not valid" : "La uzantnomo kaj/aŭ pasvorto de MySQL ne estas valida", + "Oracle username and/or password not valid" : "La uzantnomo kaj/aŭ la pasvorto de Oracle ne estas valida", + "PostgreSQL username and/or password not valid" : "La uzantnomo aŭ la pasvorto de PostgreSQL ne validas", + "Set an admin username." : "Agordi uzantnomon de administranto.", + "Sharing %s failed, because this item is already shared with user %s" : "Kunhavigo de %s malsukcesis, ĉar la ero jam kunhaviĝis kun %s", + "The username is already being used" : "La uzantnomo jam estas uzata", + "Could not create user" : "Ne povis krei uzanton", + "A valid username must be provided" : "Valida uzantnomo devas esti provizita", + "Username contains whitespace at the beginning or at the end" : "Uzantnomo enhavas spaceton ĉe la komenco aŭ la fino", + "Username must not consist of dots only" : "Uzantnomo ne povas enhavi nur punktojn", + "Username is invalid because files already exist for this user" : "La uzantnomo ne estas valida pro dosieroj por la uzanto jam ekzistas", + "User disabled" : "Uzanto malebligita", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 almenaŭ necesas. Nun %s estas instalita.", - "To fix this issue update your libxml2 version and restart your web server." : "Por ripari tiun problemon, ĝisdatigu vian version de libxml2, kaj restartigu la TTT-servilon." + "To fix this issue update your libxml2 version and restart your web server." : "Por ripari tiun problemon, ĝisdatigu vian version de libxml2, kaj restartigu la TTT-servilon.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Bv. ŝanĝi la permesojn al 0770, tiel la dosierujo ne listigeblas de aliaj uzantoj." },"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 b80753e6e10..02a836be52e 100644 --- a/lib/l10n/es.js +++ b/lib/l10n/es.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "La aplicación %1$s no está presente o tiene una versión que no es compatible con este servidor. Por favor, chequee la carpeta de apps.", "Sample configuration detected" : "Configuración de ejemplo detectada", "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" : "Se ha detectado que el ejemplo de configuración ha sido copiado. Esto podría afectar a su instalación, por lo que no tiene soporte. Lea la documentación antes de hacer cambios en config.php", - "404" : "404", "The page could not be found on the server." : "La página no se ha encontrado en el servidor.", "%s email verification" : "%s verificación del correo electrónico", "Email verification" : "Verificación del correo electrónico", @@ -37,9 +36,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Las siguientes plataformas están soportadas: %s", "Server version %s or higher is required." : "Se necesita la versión %s o superior del servidor.", "Server version %s or lower is required." : "Se necesita la versión %s o inferior del servidor. ", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "La sesión del usuario debe corresponder a un administrador, subadministrador, o debe tener derechos especiales para acceder a esta configuración.", - "Logged in user must be an admin or sub admin" : "El usuario activo debe ser un administrador o subadministrador", - "Logged in user must be an admin" : "El usuario registrado debe ser un administrador", "Wiping of device %s has started" : "El borrado del dispositivo %s ha empezado", "Wiping of device »%s« has started" : "El borrado del dispositivo »%s« ha empezado", "»%s« started remote wipe" : "»%s« ha empezado el borrado a distancia", @@ -118,22 +114,15 @@ OC.L10N.register( "Headline" : "Titular", "Organisation" : "Organización", "Role" : "Puesto", - "Unknown user" : "Usuario desconocido", "Additional settings" : "Configuración adicional", - "Enter the database username and name for %s" : "Introduzca el nombre de usuario y la contraseña para la base de datos %s", - "Enter the database username for %s" : "Introduzca el nombre de usuario para la base datos %s", "Enter the database name for %s" : "Introduzca el nombre de la base de datos %s", "You cannot use dots in the database name %s" : "No puede utilizar puntos para el nombre de base de datos 1%s ", - "MySQL username and/or password not valid" : "Usuario y/o contraseña de MySQL no válidos", "You need to enter details of an existing account." : "Tienes que introducir los datos de una cuenta existente.", "Oracle connection could not be established" : "No se pudo establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle no válidos", - "PostgreSQL username and/or password not valid" : "Usuario y/o contraseña de PostgreSQL no válidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X no está soportado y %s no funcionará bien en esta plataforma. ¡Úsala bajo tu propio riesgo! ", "For the best results, please consider using a GNU/Linux server instead." : "Para obtener los mejores resultados, considera utilizar un servidor 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." : "Parece que esta instancia %s está funcionando en un entorno PHP de 32-bits y el open_basedir se ha configurado en php.ini. Esto acarreará problemas con archivos de tamaño superior a 4GB y resulta totalmente desaconsejado.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor, quite el ajuste de open_basedir —dentro de su php.ini— o pásese a PHP de 64 bits.", - "Set an admin username." : "Configurar un nombre de usuario del administrador", "Set an admin password." : "Configurar la contraseña del administrador.", "Cannot create or write into the data directory %s" : "No se puede crear o escribir en la carpeta de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El motor compartido %s debe implementar la interfaz OCP\\Share_Backend", @@ -151,7 +140,6 @@ OC.L10N.register( "Expiration date is in the past" : "Ha pasado la fecha de caducidad", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No se puede fijar la fecha de caducidad más de %n día en el futuro.","No se puede fijar la fecha de caducidad más de %n días en el futuro.","No se puede fijar la fecha de caducidad más de %n días en el futuro."], "Sharing is only allowed with group members" : "Sólo está permitido compartir a los integrantes del grupo", - "Sharing %s failed, because this item is already shared with user %s" : "No se pudo compartir %s, porque este elemento ya está compartido con el usuario %s", "%1$s shared »%2$s« with you" : "%1$s ha compartido «%2$s» contigo", "%1$s shared »%2$s« with you." : "%1$s ha compartido «%2$s» contigo.", "Click the button below to open it." : "Haz clic en el botón de abajo para abrirlo.", @@ -205,14 +193,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "El nombre de usuario ya está en uso", - "Could not create user" : "No se ha podido crear el usuario", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", - "A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El nombre de usuario contiene espacios en blanco al principio o al final", - "Username must not consist of dots only" : "El nombre de usuario no debe consistir solo de puntos", - "Username is invalid because files already exist for this user" : "El nombre de usuario es incorrecto debido a a que los archivos ya existen para este usuario", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Login cancelado por la app", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "No se ha podido instlaar la app «%1$s» porque no se cumplen las siguientes dependencias: %2$s", "a safe home for all your data" : "un hogar seguro para todos tus datos", @@ -238,15 +218,13 @@ OC.L10N.register( "PHP setting \"%s\" is not set to \"%s\"." : "La opción PHP \"%s\" no es \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ajustar esta configuración en php.ini hará que Nextcloud funcione de nuevo", "<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á establecida como <code>%s</code> en lugar del valor esperado: <code>0</code>.", - "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para arreglar este problema, establece <code>mbstring.func_overload</code> en<code>0</code> en tu php.ini.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para arreglar este problema, establezca <code>mbstring.func_overload</code> en<code>0</code> en su php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP está aparentemente configurado para eliminar bloques de documentos en línea. Esto hará que varias aplicaciones principales estén inaccesibles.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Probablemente esto venga a causa de la caché o un acelerador, tales como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Los módulos PHP se han instalado, pero aparecen listados como si faltaran", "Please ask your server administrator to restart the web server." : "Consulte al administrador de su servidor para reiniciar el servidor web.", "The required %s config variable is not configured in the config.php file." : "La variable de configuración %s requerida no está configurada en el archivo config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Por favor, pida al administrador de su servidor que compruebe la configuración de Nextcloud.", - "Your data directory is readable by other users." : "Tu carpeta de datos puede ser leído por otros usuarios.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor, cambia los permisos a 0770 para que el directorio no se pueda mostrar a otros usuarios.", "Your data directory must be an absolute path." : "Tu carpeta de datos debe ser una ruta absoluta.", "Check the value of \"datadirectory\" in your configuration." : "Comprueba el valor de «datadirectory» en tu configuración.", "Your data directory is invalid." : "Tu carpeta de datos es inválida.", @@ -271,12 +249,32 @@ OC.L10N.register( "Extract topics" : "Extraer tópicos", "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. ", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Los archivos de la app %1$s no se han reemplazado correctamente. Asegúrate de que es una versión compatible con el servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "La sesión del usuario debe corresponder a un administrador, subadministrador, o debe tener derechos especiales para acceder a esta configuración.", + "Logged in user must be an admin or sub admin" : "El usuario activo debe ser un administrador o subadministrador", + "Logged in user must be an admin" : "El usuario registrado debe ser un administrador", "Full name" : "Nombre completo", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "El límite de usuarios fue alcanzado y el usuario no fue creado. Compruebe sus notificaciones para aprender más.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Solo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Usuario desconocido", + "Enter the database username and name for %s" : "Introduzca el nombre de usuario y la contraseña para la base de datos %s", + "Enter the database username for %s" : "Introduzca el nombre de usuario para la base datos %s", + "MySQL username and/or password not valid" : "Usuario y/o contraseña de MySQL no válidos", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle no válidos", + "PostgreSQL username and/or password not valid" : "Usuario y/o contraseña de PostgreSQL no válidos", + "Set an admin username." : "Configurar un nombre de usuario del administrador", + "Sharing %s failed, because this item is already shared with user %s" : "No se pudo compartir %s, porque este elemento ya está compartido con el usuario %s", + "The username is already being used" : "El nombre de usuario ya está en uso", + "Could not create user" : "No se ha podido crear el usuario", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", + "A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El nombre de usuario contiene espacios en blanco al principio o al final", + "Username must not consist of dots only" : "El nombre de usuario no debe consistir solo de puntos", + "Username is invalid because files already exist for this user" : "El nombre de usuario es incorrecto debido a a que los archivos ya existen para este usuario", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 es requerido en esta o en versiones superiores. Ahora mismo tienes instalada %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este error, actualiza la versión de tu libxml2 y reinicia el servidor web.", + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este problema, actualice su versión de libxml2 y reinicie el servidor web.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 requerido.", - "Please upgrade your database version." : "Por favor, actualiza la versión de tu base de datos." + "Please upgrade your database version." : "Por favor, actualiza la versión de tu base de datos.", + "Your data directory is readable by other users." : "Tu carpeta de datos puede ser leído por otros usuarios.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor, cambia los permisos a 0770 para que el directorio no se pueda mostrar a otros usuarios." }, "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 a4870ed898d..8e5ae4e6915 100644 --- a/lib/l10n/es.json +++ b/lib/l10n/es.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "La aplicación %1$s no está presente o tiene una versión que no es compatible con este servidor. Por favor, chequee la carpeta de apps.", "Sample configuration detected" : "Configuración de ejemplo detectada", "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" : "Se ha detectado que el ejemplo de configuración ha sido copiado. Esto podría afectar a su instalación, por lo que no tiene soporte. Lea la documentación antes de hacer cambios en config.php", - "404" : "404", "The page could not be found on the server." : "La página no se ha encontrado en el servidor.", "%s email verification" : "%s verificación del correo electrónico", "Email verification" : "Verificación del correo electrónico", @@ -35,9 +34,6 @@ "The following platforms are supported: %s" : "Las siguientes plataformas están soportadas: %s", "Server version %s or higher is required." : "Se necesita la versión %s o superior del servidor.", "Server version %s or lower is required." : "Se necesita la versión %s o inferior del servidor. ", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "La sesión del usuario debe corresponder a un administrador, subadministrador, o debe tener derechos especiales para acceder a esta configuración.", - "Logged in user must be an admin or sub admin" : "El usuario activo debe ser un administrador o subadministrador", - "Logged in user must be an admin" : "El usuario registrado debe ser un administrador", "Wiping of device %s has started" : "El borrado del dispositivo %s ha empezado", "Wiping of device »%s« has started" : "El borrado del dispositivo »%s« ha empezado", "»%s« started remote wipe" : "»%s« ha empezado el borrado a distancia", @@ -116,22 +112,15 @@ "Headline" : "Titular", "Organisation" : "Organización", "Role" : "Puesto", - "Unknown user" : "Usuario desconocido", "Additional settings" : "Configuración adicional", - "Enter the database username and name for %s" : "Introduzca el nombre de usuario y la contraseña para la base de datos %s", - "Enter the database username for %s" : "Introduzca el nombre de usuario para la base datos %s", "Enter the database name for %s" : "Introduzca el nombre de la base de datos %s", "You cannot use dots in the database name %s" : "No puede utilizar puntos para el nombre de base de datos 1%s ", - "MySQL username and/or password not valid" : "Usuario y/o contraseña de MySQL no válidos", "You need to enter details of an existing account." : "Tienes que introducir los datos de una cuenta existente.", "Oracle connection could not be established" : "No se pudo establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle no válidos", - "PostgreSQL username and/or password not valid" : "Usuario y/o contraseña de PostgreSQL no válidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X no está soportado y %s no funcionará bien en esta plataforma. ¡Úsala bajo tu propio riesgo! ", "For the best results, please consider using a GNU/Linux server instead." : "Para obtener los mejores resultados, considera utilizar un servidor 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." : "Parece que esta instancia %s está funcionando en un entorno PHP de 32-bits y el open_basedir se ha configurado en php.ini. Esto acarreará problemas con archivos de tamaño superior a 4GB y resulta totalmente desaconsejado.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor, quite el ajuste de open_basedir —dentro de su php.ini— o pásese a PHP de 64 bits.", - "Set an admin username." : "Configurar un nombre de usuario del administrador", "Set an admin password." : "Configurar la contraseña del administrador.", "Cannot create or write into the data directory %s" : "No se puede crear o escribir en la carpeta de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El motor compartido %s debe implementar la interfaz OCP\\Share_Backend", @@ -149,7 +138,6 @@ "Expiration date is in the past" : "Ha pasado la fecha de caducidad", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No se puede fijar la fecha de caducidad más de %n día en el futuro.","No se puede fijar la fecha de caducidad más de %n días en el futuro.","No se puede fijar la fecha de caducidad más de %n días en el futuro."], "Sharing is only allowed with group members" : "Sólo está permitido compartir a los integrantes del grupo", - "Sharing %s failed, because this item is already shared with user %s" : "No se pudo compartir %s, porque este elemento ya está compartido con el usuario %s", "%1$s shared »%2$s« with you" : "%1$s ha compartido «%2$s» contigo", "%1$s shared »%2$s« with you." : "%1$s ha compartido «%2$s» contigo.", "Click the button below to open it." : "Haz clic en el botón de abajo para abrirlo.", @@ -203,14 +191,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "El nombre de usuario ya está en uso", - "Could not create user" : "No se ha podido crear el usuario", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", - "A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El nombre de usuario contiene espacios en blanco al principio o al final", - "Username must not consist of dots only" : "El nombre de usuario no debe consistir solo de puntos", - "Username is invalid because files already exist for this user" : "El nombre de usuario es incorrecto debido a a que los archivos ya existen para este usuario", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Login cancelado por la app", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "No se ha podido instlaar la app «%1$s» porque no se cumplen las siguientes dependencias: %2$s", "a safe home for all your data" : "un hogar seguro para todos tus datos", @@ -236,15 +216,13 @@ "PHP setting \"%s\" is not set to \"%s\"." : "La opción PHP \"%s\" no es \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ajustar esta configuración en php.ini hará que Nextcloud funcione de nuevo", "<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á establecida como <code>%s</code> en lugar del valor esperado: <code>0</code>.", - "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para arreglar este problema, establece <code>mbstring.func_overload</code> en<code>0</code> en tu php.ini.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para arreglar este problema, establezca <code>mbstring.func_overload</code> en<code>0</code> en su php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP está aparentemente configurado para eliminar bloques de documentos en línea. Esto hará que varias aplicaciones principales estén inaccesibles.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Probablemente esto venga a causa de la caché o un acelerador, tales como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Los módulos PHP se han instalado, pero aparecen listados como si faltaran", "Please ask your server administrator to restart the web server." : "Consulte al administrador de su servidor para reiniciar el servidor web.", "The required %s config variable is not configured in the config.php file." : "La variable de configuración %s requerida no está configurada en el archivo config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Por favor, pida al administrador de su servidor que compruebe la configuración de Nextcloud.", - "Your data directory is readable by other users." : "Tu carpeta de datos puede ser leído por otros usuarios.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor, cambia los permisos a 0770 para que el directorio no se pueda mostrar a otros usuarios.", "Your data directory must be an absolute path." : "Tu carpeta de datos debe ser una ruta absoluta.", "Check the value of \"datadirectory\" in your configuration." : "Comprueba el valor de «datadirectory» en tu configuración.", "Your data directory is invalid." : "Tu carpeta de datos es inválida.", @@ -269,12 +247,32 @@ "Extract topics" : "Extraer tópicos", "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. ", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Los archivos de la app %1$s no se han reemplazado correctamente. Asegúrate de que es una versión compatible con el servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "La sesión del usuario debe corresponder a un administrador, subadministrador, o debe tener derechos especiales para acceder a esta configuración.", + "Logged in user must be an admin or sub admin" : "El usuario activo debe ser un administrador o subadministrador", + "Logged in user must be an admin" : "El usuario registrado debe ser un administrador", "Full name" : "Nombre completo", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "El límite de usuarios fue alcanzado y el usuario no fue creado. Compruebe sus notificaciones para aprender más.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Solo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Usuario desconocido", + "Enter the database username and name for %s" : "Introduzca el nombre de usuario y la contraseña para la base de datos %s", + "Enter the database username for %s" : "Introduzca el nombre de usuario para la base datos %s", + "MySQL username and/or password not valid" : "Usuario y/o contraseña de MySQL no válidos", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle no válidos", + "PostgreSQL username and/or password not valid" : "Usuario y/o contraseña de PostgreSQL no válidos", + "Set an admin username." : "Configurar un nombre de usuario del administrador", + "Sharing %s failed, because this item is already shared with user %s" : "No se pudo compartir %s, porque este elemento ya está compartido con el usuario %s", + "The username is already being used" : "El nombre de usuario ya está en uso", + "Could not create user" : "No se ha podido crear el usuario", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", + "A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El nombre de usuario contiene espacios en blanco al principio o al final", + "Username must not consist of dots only" : "El nombre de usuario no debe consistir solo de puntos", + "Username is invalid because files already exist for this user" : "El nombre de usuario es incorrecto debido a a que los archivos ya existen para este usuario", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 es requerido en esta o en versiones superiores. Ahora mismo tienes instalada %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este error, actualiza la versión de tu libxml2 y reinicia el servidor web.", + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este problema, actualice su versión de libxml2 y reinicie el servidor web.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 requerido.", - "Please upgrade your database version." : "Por favor, actualiza la versión de tu base de datos." + "Please upgrade your database version." : "Por favor, actualiza la versión de tu base de datos.", + "Your data directory is readable by other users." : "Tu carpeta de datos puede ser leído por otros usuarios.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor, cambia los permisos a 0770 para que el directorio no se pueda mostrar a otros usuarios." },"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/es_419.js b/lib/l10n/es_419.js index 86516d683c5..0bce4d9f558 100644 --- a/lib/l10n/es_419.js +++ b/lib/l10n/es_419.js @@ -67,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -86,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -136,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -157,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,8 +154,19 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_419.json b/lib/l10n/es_419.json index b28ccc86df2..e100fbeacfd 100644 --- a/lib/l10n/es_419.json +++ b/lib/l10n/es_419.json @@ -65,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -84,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -134,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -155,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,8 +152,19 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_AR.js b/lib/l10n/es_AR.js index 04215531e00..f60b5587e68 100644 --- a/lib/l10n/es_AR.js +++ b/lib/l10n/es_AR.js @@ -56,17 +56,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesita ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "El nombre de usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El nombre de usuario y/o contraseña de PostgreSQL inválidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Uselo bajo su propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, favor de cosiderar usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Favor de eliminar el ajuste open_basedir de su archivo php.ini o cambie a PHP de 64 bits. ", - "Set an admin username." : "Configurar un nombre de usuario del administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -75,7 +71,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tiene permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración ya ha pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haga click en el botón de abajo para abrirlo.", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", "Sunday" : "Domingo", @@ -124,11 +119,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese nombre de usuario ya está en uso", - "A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El nombre del usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El nombre de usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos sus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, favor de intentarlo más tarde. ", @@ -144,7 +134,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Favor de solicitar al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Favor de cambiar los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", "Storage incomplete configuration. %s" : "Configuración incompleta del almacenamiento. %s", @@ -152,8 +141,18 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "Se agotó el tiempo de conexión del almacenamiento. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el nombre de usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "El nombre de usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El nombre de usuario y/o contraseña de PostgreSQL inválidos", + "Set an admin username." : "Configurar un nombre de usuario del administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese nombre de usuario ya está en uso", + "A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El nombre del usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El nombre de usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s esta instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, favor de actualizar la versión de su libxml2 y reinicie su servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, favor de actualizar la versión de su libxml2 y reinicie su servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Favor de cambiar los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_AR.json b/lib/l10n/es_AR.json index 70d428a358a..8312950270c 100644 --- a/lib/l10n/es_AR.json +++ b/lib/l10n/es_AR.json @@ -54,17 +54,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesita ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "El nombre de usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El nombre de usuario y/o contraseña de PostgreSQL inválidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Uselo bajo su propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, favor de cosiderar usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Favor de eliminar el ajuste open_basedir de su archivo php.ini o cambie a PHP de 64 bits. ", - "Set an admin username." : "Configurar un nombre de usuario del administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -73,7 +69,6 @@ "You are not allowed to share %s" : "No tiene permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración ya ha pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haga click en el botón de abajo para abrirlo.", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", "Sunday" : "Domingo", @@ -122,11 +117,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese nombre de usuario ya está en uso", - "A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El nombre del usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El nombre de usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos sus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, favor de intentarlo más tarde. ", @@ -142,7 +132,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Favor de solicitar al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Favor de cambiar los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", "Storage incomplete configuration. %s" : "Configuración incompleta del almacenamiento. %s", @@ -150,8 +139,18 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "Se agotó el tiempo de conexión del almacenamiento. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el nombre de usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "El nombre de usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El nombre de usuario y/o contraseña de PostgreSQL inválidos", + "Set an admin username." : "Configurar un nombre de usuario del administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese nombre de usuario ya está en uso", + "A valid username must be provided" : "Se debe proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El nombre del usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El nombre de usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s esta instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, favor de actualizar la versión de su libxml2 y reinicie su servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, favor de actualizar la versión de su libxml2 y reinicie su servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Favor de cambiar los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_CL.js b/lib/l10n/es_CL.js index c2e7ed869a7..7a718a587f0 100644 --- a/lib/l10n/es_CL.js +++ b/lib/l10n/es_CL.js @@ -20,7 +20,6 @@ OC.L10N.register( "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -68,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -87,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -137,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -158,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,9 +153,21 @@ OC.L10N.register( "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_CL.json b/lib/l10n/es_CL.json index 3588d3dc997..17956a1fa01 100644 --- a/lib/l10n/es_CL.json +++ b/lib/l10n/es_CL.json @@ -18,7 +18,6 @@ "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -66,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -85,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -135,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -156,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,9 +151,21 @@ "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_CO.js b/lib/l10n/es_CO.js index 5ed6e885be4..4a43f409bb4 100644 --- a/lib/l10n/es_CO.js +++ b/lib/l10n/es_CO.js @@ -20,7 +20,6 @@ OC.L10N.register( "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -68,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -87,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -137,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -158,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,9 +153,21 @@ OC.L10N.register( "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_CO.json b/lib/l10n/es_CO.json index 8a09a43010e..9f2c35c2693 100644 --- a/lib/l10n/es_CO.json +++ b/lib/l10n/es_CO.json @@ -18,7 +18,6 @@ "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -66,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -85,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -135,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -156,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,9 +151,21 @@ "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_CR.js b/lib/l10n/es_CR.js index dfe7bf48830..ef3bf376f19 100644 --- a/lib/l10n/es_CR.js +++ b/lib/l10n/es_CR.js @@ -20,7 +20,6 @@ OC.L10N.register( "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -68,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -87,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -137,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -158,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,9 +153,21 @@ OC.L10N.register( "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_CR.json b/lib/l10n/es_CR.json index 3965d35193b..a8731ba1d7e 100644 --- a/lib/l10n/es_CR.json +++ b/lib/l10n/es_CR.json @@ -18,7 +18,6 @@ "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -66,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -85,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -135,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -156,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,9 +151,21 @@ "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_DO.js b/lib/l10n/es_DO.js index d283c462ee5..8002355bb6d 100644 --- a/lib/l10n/es_DO.js +++ b/lib/l10n/es_DO.js @@ -20,7 +20,6 @@ OC.L10N.register( "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -68,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -87,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -137,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -158,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,9 +153,21 @@ OC.L10N.register( "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_DO.json b/lib/l10n/es_DO.json index 9fe1811cf68..fa8e71e5e9a 100644 --- a/lib/l10n/es_DO.json +++ b/lib/l10n/es_DO.json @@ -18,7 +18,6 @@ "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -66,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -85,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -135,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -156,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,9 +151,21 @@ "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_EC.js b/lib/l10n/es_EC.js index dd170b3d912..9e7ba6fcc06 100644 --- a/lib/l10n/es_EC.js +++ b/lib/l10n/es_EC.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "La aplicación %1$s no está presente o tiene una versión no compatible con este servidor. Por favor, revisa el directorio de aplicaciones.", "Sample configuration detected" : "Se ha detectado la configuración de muestra", "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" : "Se ha detectado que la configuración de muestra ha sido copiada. Esto puede arruiniar tu instalacón y no está soportado. Por favor lee la documentación antes de hacer cambios en el archivo config.php", - "404" : "404", "The page could not be found on the server." : "No se pudo encontrar la página en el servidor.", "%s email verification" : "%s verificación de correo electrónico", "Email verification" : "Verificación de correo electrónico", @@ -37,9 +36,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Las siguientes plataformas son compatibles: %s", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "El usuario que ha iniciado sesión debe ser un administrador, un subadministrador o tener permisos especiales para acceder a esta configuración.", - "Logged in user must be an admin or sub admin" : "El usuario que ha iniciado sesión debe ser un administrador o un subadministrador.", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Wiping of device %s has started" : "El borrado del dispositivo %s ha comenzado", "Wiping of device »%s« has started" : "El borrado del dispositivo »%s« ha comenzado", "»%s« started remote wipe" : "»%s« ha iniciado el borrado remoto", @@ -118,22 +114,15 @@ OC.L10N.register( "Headline" : "Título", "Organisation" : "Organización", "Role" : "Rol", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", - "Enter the database username and name for %s" : "Introduce el nombre de usuario y el nombre de la base de datos para %s", - "Enter the database username for %s" : "Introduce el nombre de usuario de la base de datos para %s", "Enter the database name for %s" : "Introduce el nombre de la base de datos para %s", "You cannot use dots in the database name %s" : "No se pueden utilizar puntos en el nombre de la base de datos %s", - "MySQL username and/or password not valid" : "Nombre de usuario y/o contraseña de MySQL no válidos", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Cannot create or write into the data directory %s" : "No se puede crear ni escribir en el directorio de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", @@ -151,7 +140,6 @@ OC.L10N.register( "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No se puede establecer una fecha de caducidad más de %n día en el futuro","No se puede establecer una fecha de caducidad más de %n días en el futuro","No se puede establecer una fecha de caducidad más de %n días en el futuro"], "Sharing is only allowed with group members" : "Solo se permite compartir con miembros del grupo", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "%1$s shared »%2$s« with you" : "%1$s compartió »%2$s« contigo", "%1$s shared »%2$s« with you." : "%1$s compartió »%2$s« contigo.", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", @@ -204,14 +192,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo se permiten los siguientes caracteres en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "Username is invalid because files already exist for this user" : "El nombre de usuario no es válido porque ya existen archivos para este usuario", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "No se puede instalar la aplicación \"%1$s\" porque no se cumplen las siguientes dependencias: %2$s", "a safe home for all your data" : "un lugar seguro para todos tus datos", @@ -244,8 +224,6 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", "The required %s config variable is not configured in the config.php file." : "No se ha configurado la variable de configuración %s requerida en el archivo config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Pide a tu administrador del servidor que verifique la configuración de Nextcloud.", - "Your data directory is readable by other users." : "Tu directorio de datos es legible por otros usuarios.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Your data directory must be an absolute path." : "Tu directorio de datos debe ser una ruta absoluta.", "Check the value of \"datadirectory\" in your configuration." : "Verifica el valor de \"datadirectory\" en tu configuración.", "Your data directory is invalid." : "Tu directorio de datos no es válido.", @@ -262,12 +240,32 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Los archivos de la aplicación %1$s no se reemplazaron correctamente. Asegúrate de que sea una versión compatible con el servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "El usuario que ha iniciado sesión debe ser un administrador, un subadministrador o tener permisos especiales para acceder a esta configuración.", + "Logged in user must be an admin or sub admin" : "El usuario que ha iniciado sesión debe ser un administrador o un subadministrador.", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Se ha alcanzado el límite de usuarios y no se creó el usuario. Consulta tus notificaciones para obtener más información.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Enter the database username and name for %s" : "Introduce el nombre de usuario y el nombre de la base de datos para %s", + "Enter the database username for %s" : "Introduce el nombre de usuario de la base de datos para %s", + "MySQL username and/or password not valid" : "Nombre de usuario y/o contraseña de MySQL no válidos", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo se permiten los siguientes caracteres en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "Username is invalid because files already exist for this user" : "El nombre de usuario no es válido porque ya existen archivos para este usuario", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", "PostgreSQL >= 9 required." : "Se requiere PostgreSQL >= 9.", - "Please upgrade your database version." : "Actualiza la versión de tu base de datos." + "Please upgrade your database version." : "Actualiza la versión de tu base de datos.", + "Your data directory is readable by other users." : "Tu directorio de datos es legible por otros usuarios.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_EC.json b/lib/l10n/es_EC.json index 55b7dcd4d84..e5f9afaa04b 100644 --- a/lib/l10n/es_EC.json +++ b/lib/l10n/es_EC.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "La aplicación %1$s no está presente o tiene una versión no compatible con este servidor. Por favor, revisa el directorio de aplicaciones.", "Sample configuration detected" : "Se ha detectado la configuración de muestra", "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" : "Se ha detectado que la configuración de muestra ha sido copiada. Esto puede arruiniar tu instalacón y no está soportado. Por favor lee la documentación antes de hacer cambios en el archivo config.php", - "404" : "404", "The page could not be found on the server." : "No se pudo encontrar la página en el servidor.", "%s email verification" : "%s verificación de correo electrónico", "Email verification" : "Verificación de correo electrónico", @@ -35,9 +34,6 @@ "The following platforms are supported: %s" : "Las siguientes plataformas son compatibles: %s", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "El usuario que ha iniciado sesión debe ser un administrador, un subadministrador o tener permisos especiales para acceder a esta configuración.", - "Logged in user must be an admin or sub admin" : "El usuario que ha iniciado sesión debe ser un administrador o un subadministrador.", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Wiping of device %s has started" : "El borrado del dispositivo %s ha comenzado", "Wiping of device »%s« has started" : "El borrado del dispositivo »%s« ha comenzado", "»%s« started remote wipe" : "»%s« ha iniciado el borrado remoto", @@ -116,22 +112,15 @@ "Headline" : "Título", "Organisation" : "Organización", "Role" : "Rol", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", - "Enter the database username and name for %s" : "Introduce el nombre de usuario y el nombre de la base de datos para %s", - "Enter the database username for %s" : "Introduce el nombre de usuario de la base de datos para %s", "Enter the database name for %s" : "Introduce el nombre de la base de datos para %s", "You cannot use dots in the database name %s" : "No se pueden utilizar puntos en el nombre de la base de datos %s", - "MySQL username and/or password not valid" : "Nombre de usuario y/o contraseña de MySQL no válidos", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Cannot create or write into the data directory %s" : "No se puede crear ni escribir en el directorio de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", @@ -149,7 +138,6 @@ "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No se puede establecer una fecha de caducidad más de %n día en el futuro","No se puede establecer una fecha de caducidad más de %n días en el futuro","No se puede establecer una fecha de caducidad más de %n días en el futuro"], "Sharing is only allowed with group members" : "Solo se permite compartir con miembros del grupo", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "%1$s shared »%2$s« with you" : "%1$s compartió »%2$s« contigo", "%1$s shared »%2$s« with you." : "%1$s compartió »%2$s« contigo.", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", @@ -202,14 +190,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo se permiten los siguientes caracteres en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "Username is invalid because files already exist for this user" : "El nombre de usuario no es válido porque ya existen archivos para este usuario", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "No se puede instalar la aplicación \"%1$s\" porque no se cumplen las siguientes dependencias: %2$s", "a safe home for all your data" : "un lugar seguro para todos tus datos", @@ -242,8 +222,6 @@ "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", "The required %s config variable is not configured in the config.php file." : "No se ha configurado la variable de configuración %s requerida en el archivo config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Pide a tu administrador del servidor que verifique la configuración de Nextcloud.", - "Your data directory is readable by other users." : "Tu directorio de datos es legible por otros usuarios.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Your data directory must be an absolute path." : "Tu directorio de datos debe ser una ruta absoluta.", "Check the value of \"datadirectory\" in your configuration." : "Verifica el valor de \"datadirectory\" en tu configuración.", "Your data directory is invalid." : "Tu directorio de datos no es válido.", @@ -260,12 +238,32 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Los archivos de la aplicación %1$s no se reemplazaron correctamente. Asegúrate de que sea una versión compatible con el servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "El usuario que ha iniciado sesión debe ser un administrador, un subadministrador o tener permisos especiales para acceder a esta configuración.", + "Logged in user must be an admin or sub admin" : "El usuario que ha iniciado sesión debe ser un administrador o un subadministrador.", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Se ha alcanzado el límite de usuarios y no se creó el usuario. Consulta tus notificaciones para obtener más información.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Enter the database username and name for %s" : "Introduce el nombre de usuario y el nombre de la base de datos para %s", + "Enter the database username for %s" : "Introduce el nombre de usuario de la base de datos para %s", + "MySQL username and/or password not valid" : "Nombre de usuario y/o contraseña de MySQL no válidos", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo se permiten los siguientes caracteres en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "Username is invalid because files already exist for this user" : "El nombre de usuario no es válido porque ya existen archivos para este usuario", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", "PostgreSQL >= 9 required." : "Se requiere PostgreSQL >= 9.", - "Please upgrade your database version." : "Actualiza la versión de tu base de datos." + "Please upgrade your database version." : "Actualiza la versión de tu base de datos.", + "Your data directory is readable by other users." : "Tu directorio de datos es legible por otros usuarios.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_GT.js b/lib/l10n/es_GT.js index fa48c1305cf..964a6e24b60 100644 --- a/lib/l10n/es_GT.js +++ b/lib/l10n/es_GT.js @@ -20,7 +20,6 @@ OC.L10N.register( "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -68,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -87,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -137,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -158,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,9 +153,21 @@ OC.L10N.register( "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_GT.json b/lib/l10n/es_GT.json index a00bb9cdb3f..821418179d1 100644 --- a/lib/l10n/es_GT.json +++ b/lib/l10n/es_GT.json @@ -18,7 +18,6 @@ "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -66,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -85,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -135,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -156,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,9 +151,21 @@ "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_HN.js b/lib/l10n/es_HN.js index a45690ad4df..5ea7544e4e2 100644 --- a/lib/l10n/es_HN.js +++ b/lib/l10n/es_HN.js @@ -67,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -86,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -136,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -157,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,8 +154,19 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_HN.json b/lib/l10n/es_HN.json index b98ec283c56..51b2ad2a6ac 100644 --- a/lib/l10n/es_HN.json +++ b/lib/l10n/es_HN.json @@ -65,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -84,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -134,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -155,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,8 +152,19 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_MX.js b/lib/l10n/es_MX.js index 4aeedbb5b2b..e781a9539ea 100644 --- a/lib/l10n/es_MX.js +++ b/lib/l10n/es_MX.js @@ -2,9 +2,19 @@ OC.L10N.register( "lib", { "Cannot write into \"config\" directory!" : "¡No se puede escribir en el directorio \"config\"!", + "This can usually be fixed by giving the web server write access to the config directory." : "Normalmente, esto se puede arreglar dando al servidor web permiso de escritura al directorio de configuración.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Sin embargo, si prefiere mantener el archivo config.php como sólo lectura, establezca la opción \"config_is_read_only\" como verdadero.", "See %s" : "Ver %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "La aplicación %1$s no está presente o tiene una versión no compatible con este servidor. Por favor, revise el directorio de aplicaciones.", "Sample configuration detected" : "Se ha detectado la configuración de muestra", "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" : "Se ha detectado que la configuración de muestra ha sido copiada. Esto puede arruiniar tu instalacón y no está soportado. Por favor lee la documentación antes de hacer cambios en el archivo config.php", + "The page could not be found on the server." : "No se pudo encontrar la página en el servidor.", + "%s email verification" : "%s verificación de correo electrónico", + "Email verification" : "Verificación de correo electrónico", + "Click the following button to confirm your email." : "Haga clic en el siguiente botón para confirmar su correo electrónico.", + "Click the following link to confirm your email." : "Haga clic en el siguiente enlace para confirmar su correo electrónico.", + "Confirm your email" : "Confirmar su correo electrónico", + "Other activities" : "Otras actividades", "%1$s and %2$s" : "%1$s y %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s y %3$s", "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s y %4$s", @@ -12,20 +22,42 @@ OC.L10N.register( "Education Edition" : "Edición Educativa", "Enterprise bundle" : "Paquete empresarial", "Groupware bundle" : "Paquete de Groupware", + "Hub bundle" : "Paquete Hub", "Social sharing bundle" : "Paquete para compartir en redes sociales", "PHP %s or higher is required." : "Se requiere de PHP %s o superior.", "PHP with a version lower than %s is required." : "PHP con una versión inferiror a la %s es requerido. ", "%sbit or higher PHP required." : "se requiere PHP para %sbit o superior.", + "The following architectures are supported: %s" : "Las siguientes arquitecturas están soportadas: %s", + "The following databases are supported: %s" : "Las siguientes bases de datos están soportadas: %s", "The command line tool %s could not be found" : "No fue posible encontar la herramienta de línea de comando %s", "The library %s is not available." : "La biblioteca %s no está disponible. ", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Se requiere la librería %1$scon una versión superior a %2$s- versión disponible %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Se requiere la librería %1$s con una versión inferior a %2$s- versión disponible %3$s.", + "The following platforms are supported: %s" : "Las siguientes plataformas están soportadas: %s", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "El usuario que ha iniciado sesión debe ser un administrador, un subadministrador o tener permisos especiales para acceder a esta configuración", + "Logged in account must be an admin or sub admin" : "El usuario conectado debe ser un administrador o un subadministrador", + "Logged in account must be an admin" : "El usuario conectado debe ser un administrador", + "Wiping of device %s has started" : "La limpieza del dispositivo %s ha comenzado", + "Wiping of device »%s« has started" : "La limpieza del dispositivo »%s« ha comenzado", + "»%s« started remote wipe" : "»%s« ha iniciado la limpieza remota", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "El dispositivo o la aplicación »%s« ha iniciado el proceso de limpieza remoto. Recibirá otro correo electrónico cuando el proceso haya finalizado", + "Wiping of device %s has finished" : "La limpieza del dispositivo %s ha finalizado", + "Wiping of device »%s« has finished" : "La limpieza del dispositivo »%s« ha finalizado", + "»%s« finished remote wipe" : "»%s« ha finalizado la limpieza remota", + "Device or application »%s« has finished the remote wipe process." : "El dispositivo o la aplicación »%s« ha finalizado el proceso de limpieza remoto.", + "Remote wipe started" : "La limpieza remota ha iniciado", + "A remote wipe was started on device %s" : "Se ha iniciado la limpieza remota en el dispositivo %s", + "Remote wipe finished" : "La limpieza remota ha finalizado", + "The remote wipe on %s has finished" : "La limpieza remota en %s ha finalizado", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", "Avatar image is not square" : "La imagen del avatar no es un cuadrado", "Files" : "Archivos", + "View profile" : "Ver perfil", + "Local time: %s" : "Hora local: %s", "today" : "hoy", "tomorrow" : "mañana", "yesterday" : "ayer", @@ -45,8 +77,11 @@ OC.L10N.register( "_%n minute ago_::_%n minutes ago_" : ["Hace %n minuto","Hace %n minutos","Hace %n minutos"], "in a few seconds" : "en algunos segundos", "seconds ago" : "hace segundos", + "Empty file" : "Archivo vacío", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "El módulo con ID: %sno existe. Por favor hablíitalo en tus configuraciones de aplicación o contacta a tu administrador. ", "File already exists" : "El archivo ya existe", + "Invalid path" : "Ruta inválida", + "Failed to create file from template" : "No se pudo crear un archivo desde la plantilla", "Templates" : "Plantillas", "File name is a reserved word" : "Nombre de archivo es una palabra reservada", "File name contains at least one invalid character" : "El nombre del archivo contiene al menos un caracter inválido", @@ -58,39 +93,70 @@ OC.L10N.register( "__language_name__" : "Español (México)", "This is an automatically sent email, please do not reply." : "Este es un correo enviado automáticamente, por favor no lo contestes. ", "Help" : "Ayuda", + "Appearance and accessibility" : "Apariencia y accesibilidad", "Apps" : "Aplicaciones", + "Personal settings" : "Configuración personal", + "Administration settings" : "Configuración de administración", "Settings" : "Ajustes", "Log out" : "Cerrar sesión", "Users" : "Usuarios", "Email" : "Correo electrónico", + "Mail %s" : "Correo %s", + "Fediverse" : "Fediverso", + "View %s on the fediverse" : "Ver %s en el fediverso", "Phone" : "Teléfono fijo", + "Call %s" : "Llamar a %s", "Twitter" : "Twitter", + "View %s on Twitter" : "Ver %s en Twitter", "Website" : "Sitio web", + "Visit %s" : "Visitar %s", "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", + "Display name" : "Nombre para mostrar", + "Headline" : "Título", + "Organisation" : "Organización", + "Role" : "Cargo", + "Unknown account" : "Cuenta desconocida", "Additional settings" : "Configuraciones adicionales", + "Enter the database Login and name for %s" : "Introduzca el usuario y el nombre para la base de datos %s", + "Enter the database Login for %s" : "Introduzca el usuario de la base de datos %s", + "Enter the database name for %s" : "Introduzca el nombre de la base de datos %s", + "You cannot use dots in the database name %s" : "No puede utilizar puntos para el nombre de base de datos %s ", + "MySQL Login and/or password not valid" : "Usuario y/o contraseña de MySQL inválidos", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Oracle Login and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL Login and/or password not valid" : "Usuario y/o contraseña de PostgreSQL inválidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", + "Set an admin Login." : "Establecer un usuario administrador.", "Set an admin password." : "Establecer la contraseña del administrador.", + "Cannot create or write into the data directory %s" : "No se puede crear o escribir en el directorio de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", "Sharing backend for %s not found" : "No fue encontrado el Backend que comparte para %s", + "%1$s shared »%2$s« with you and wants to add:" : "%1$s compartió »%2$s« contigo y quiere añadir:", + "%1$s shared »%2$s« with you and wants to add" : "%1$s compartió »%2$s« contigo y quiere añadir", + "»%s« added a note to a file shared with you" : "»%s« añadió una nota a un archivo compartido contigo", "Open »%s«" : "Abrir »%s«", + "%1$s via %2$s" : "%1$s vía %2$s", "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", + "Files cannot be shared with delete permissions" : "No se pueden compartir archivos con permisos de eliminación", + "Files cannot be shared with create permissions" : "No se pueden compartir archivos con permisos de creación", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No se puede fijar la fecha de caducidad más de %n día en el futuro","No se puede fijar la fecha de caducidad más de %n días en el futuro","No se puede fijar la fecha de caducidad más de %n días en el futuro"], + "Sharing is only allowed with group members" : "Sólo está permitido compartir a los miembros del grupo", + "Sharing %s failed, because this item is already shared with the account %s" : "No se pudo compartir %s porque este elemento ya está compartido con el usuario %s", + "%1$s shared »%2$s« with you" : "%1$s compartió »%2$s« contigo", + "%1$s shared »%2$s« with you." : "%1$s compartió »%2$s« contigo.", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", + "The requested share comes from a disabled user" : "El recurso compartido solicitado proviene de un usuario deshabilitado", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "No se creó el usuario porque se ha alcanzado el límite de usuarios. Consulta tus notificaciones para obtener más información.", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", "Sunday" : "Domingo", "Monday" : "Lunes", @@ -138,38 +204,95 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", + "The Login is already being used" : "El usuario ya está en uso", + "Could not create account" : "No se pudo crear la cuenta", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Sólo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", + "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 invalid because files already exist for this user" : "El usuario es inválido porque ya existen archivos para éste", + "Account disabled" : "Cuenta deshabilitada", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "No se puede instalar la aplicación \"%1$s\" porque no se cumple con las siguientes dependencias: %2$s ", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", + "Cannot download file" : "No se puede descargar el archivo", "Application is not enabled" : "La aplicación está deshabilitada", "Authentication error" : "Error de autenticación", "Token expired. Please reload page." : "La ficha ha expirado. Por favor recarga la página.", "No database drivers (sqlite, mysql, or postgresql) installed." : "No cuentas con controladores de base de datos (sqlite, mysql o postgresql) instalados. ", + "Cannot write into \"config\" directory." : "No se puede escribir en el directorio \"config\".", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Normalmente, esto se puede arreglar al darle al servidor web permiso de escritura al directorio de configuración. Vea %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" : "Sin embargo, si prefiere mantener el archivo config.php como sólo lectura, establezca la opción \"config_is_read_only\" como verdadero. Vea %s", + "Cannot write into \"apps\" directory." : "No se puede escribir en el directorio \"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." : "Normalmente, esto se puede arreglar al darle al servidor web permiso de escritura al directorio de aplicaciones o deshabilitando la tienda de aplicaciones del archivo de configuración.", + "Cannot create \"data\" directory." : "No se puede crear el directorio \"data\".", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Normalmente, esto se puede arreglar dando al servidor web permiso de escritura al directorio raíz. Vea %s", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Los permisos normalmente se pueden arreglar dando al servidor web permiso de escritura al directorio raíz. Vea %s.", + "Your data directory is not writable." : "No se puede escribir en su carpeta de datos.", + "Setting locale to %s failed." : "Falló al establecer la configuración regional a %s.", + "Please install one of these locales on your system and restart your web server." : "Por favor, instale una de estas configuraciones regionales en su sistema y reinicie el servidor web.", "PHP module %s not installed." : "El módulo de PHP %s no está instalado. ", "Please ask your server administrator to install the module." : "Por favor solicita a tu adminsitrador la instalación del módulo. ", "PHP setting \"%s\" is not set to \"%s\"." : "El ajuste PHP \"%s\" no esta establecido a \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "El cambiar este ajuste del archivo php.ini hará que Nextcloud corra de nuevo.", + "<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 como <code>%s</code> en lugar del valor esperado <code>0</code>.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para arreglar este problema, establezca <code>mbstring.func_overload</code> como<code>0</code> en su php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Al parecer PHP está configurado para quitar los bloques de comentarios internos. Esto hará que varias aplicaciones principales sean inaccesibles. ", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", + "The required %s config variable is not configured in the config.php file." : "La variable de configuración requerida %s no está configurada en el archivo config.php.", + "Please ask your server administrator to check the Nextcloud configuration." : "Por favor, pida al administrador del servidor que verifique la configuración de Nextcloud.", + "Your data directory is readable by other people." : "Su directorio de datos puede ser leído por otros usuarios.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Por favor, cambie los permisos a 0770 para que el directorio no se pueda listar por otros usuarios.", + "Your data directory must be an absolute path." : "Su directorio de datos debe ser una ruta absoluta.", + "Check the value of \"datadirectory\" in your configuration." : "Revise el valor de \"datadirectory\" en su configuración.", + "Your data directory is invalid." : "Su directorio de datos es inválido.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", + "Action \"%s\" not supported or implemented." : "La acción \"%s\" no está soportada o no está implementada.", + "Authentication failed, wrong token or provider ID given" : "Falló la autentificación, se proporcionó un token o un identificador de proveedor incorrecto", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Faltan parámetros para completar la solicitud. Parámetros faltantes: \"%s\"", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "El identificador \"%1$s\" ya está en uso por el proveedor de federación de la nube \"%2$s\"", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "El proveedor de federación de la nube con identificador \"%s\" no existe.", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", "Storage incomplete configuration. %s" : "Configuración incompleta del almacenamiento. %s", "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Free prompt" : "Liberar prompt", + "Runs an arbitrary prompt through the language model." : "Ejecuta un prompt arbitrario a través del modelo de lenguaje.", + "Generate headline" : "Generar titular", + "Generates a possible headline for a text." : "Genera un posible titular para un texto.", + "Summarize" : "Resumir", + "Summarizes text by reducing its length without losing key information." : "Resume el texto reduciendo su longitud sin perder información clave.", + "Extract topics" : "Extraer temas", + "Extracts topics from a text and outputs them separated by commas." : "Extrae los temas de un texto y genera una salida separada por comas. ", + "404" : "404", + "Logged in user must be an admin or sub admin" : "El usuario conectado debe ser un administrador o un subadministrador", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Enter the database username and name for %s" : "Introduzca el usuario y el nombre para la base de datos %s", + "Enter the database username for %s" : "Introduzca el usuario de la base de datos %s", + "MySQL username and/or password not valid" : "Usuario y/o contraseña de MySQL inválidos", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "Username is invalid because files already exist for this user" : "El nombre de usuario es inválido porque ya existen archivos para éste", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "PostgreSQL >= 9 required." : "Se requiere PostgreSQL >= 9.", + "Please upgrade your database version." : "Por favor, actualice la versión de la base de datos.", + "Your data directory is readable by other users." : "Su directorio de datos puede ser leído por otros usuarios.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_MX.json b/lib/l10n/es_MX.json index 3e336401cee..0af9308d2fc 100644 --- a/lib/l10n/es_MX.json +++ b/lib/l10n/es_MX.json @@ -1,8 +1,18 @@ { "translations": { "Cannot write into \"config\" directory!" : "¡No se puede escribir en el directorio \"config\"!", + "This can usually be fixed by giving the web server write access to the config directory." : "Normalmente, esto se puede arreglar dando al servidor web permiso de escritura al directorio de configuración.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Sin embargo, si prefiere mantener el archivo config.php como sólo lectura, establezca la opción \"config_is_read_only\" como verdadero.", "See %s" : "Ver %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "La aplicación %1$s no está presente o tiene una versión no compatible con este servidor. Por favor, revise el directorio de aplicaciones.", "Sample configuration detected" : "Se ha detectado la configuración de muestra", "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" : "Se ha detectado que la configuración de muestra ha sido copiada. Esto puede arruiniar tu instalacón y no está soportado. Por favor lee la documentación antes de hacer cambios en el archivo config.php", + "The page could not be found on the server." : "No se pudo encontrar la página en el servidor.", + "%s email verification" : "%s verificación de correo electrónico", + "Email verification" : "Verificación de correo electrónico", + "Click the following button to confirm your email." : "Haga clic en el siguiente botón para confirmar su correo electrónico.", + "Click the following link to confirm your email." : "Haga clic en el siguiente enlace para confirmar su correo electrónico.", + "Confirm your email" : "Confirmar su correo electrónico", + "Other activities" : "Otras actividades", "%1$s and %2$s" : "%1$s y %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s y %3$s", "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s y %4$s", @@ -10,20 +20,42 @@ "Education Edition" : "Edición Educativa", "Enterprise bundle" : "Paquete empresarial", "Groupware bundle" : "Paquete de Groupware", + "Hub bundle" : "Paquete Hub", "Social sharing bundle" : "Paquete para compartir en redes sociales", "PHP %s or higher is required." : "Se requiere de PHP %s o superior.", "PHP with a version lower than %s is required." : "PHP con una versión inferiror a la %s es requerido. ", "%sbit or higher PHP required." : "se requiere PHP para %sbit o superior.", + "The following architectures are supported: %s" : "Las siguientes arquitecturas están soportadas: %s", + "The following databases are supported: %s" : "Las siguientes bases de datos están soportadas: %s", "The command line tool %s could not be found" : "No fue posible encontar la herramienta de línea de comando %s", "The library %s is not available." : "La biblioteca %s no está disponible. ", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Se requiere la librería %1$scon una versión superior a %2$s- versión disponible %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Se requiere la librería %1$s con una versión inferior a %2$s- versión disponible %3$s.", + "The following platforms are supported: %s" : "Las siguientes plataformas están soportadas: %s", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "El usuario que ha iniciado sesión debe ser un administrador, un subadministrador o tener permisos especiales para acceder a esta configuración", + "Logged in account must be an admin or sub admin" : "El usuario conectado debe ser un administrador o un subadministrador", + "Logged in account must be an admin" : "El usuario conectado debe ser un administrador", + "Wiping of device %s has started" : "La limpieza del dispositivo %s ha comenzado", + "Wiping of device »%s« has started" : "La limpieza del dispositivo »%s« ha comenzado", + "»%s« started remote wipe" : "»%s« ha iniciado la limpieza remota", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "El dispositivo o la aplicación »%s« ha iniciado el proceso de limpieza remoto. Recibirá otro correo electrónico cuando el proceso haya finalizado", + "Wiping of device %s has finished" : "La limpieza del dispositivo %s ha finalizado", + "Wiping of device »%s« has finished" : "La limpieza del dispositivo »%s« ha finalizado", + "»%s« finished remote wipe" : "»%s« ha finalizado la limpieza remota", + "Device or application »%s« has finished the remote wipe process." : "El dispositivo o la aplicación »%s« ha finalizado el proceso de limpieza remoto.", + "Remote wipe started" : "La limpieza remota ha iniciado", + "A remote wipe was started on device %s" : "Se ha iniciado la limpieza remota en el dispositivo %s", + "Remote wipe finished" : "La limpieza remota ha finalizado", + "The remote wipe on %s has finished" : "La limpieza remota en %s ha finalizado", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", "Avatar image is not square" : "La imagen del avatar no es un cuadrado", "Files" : "Archivos", + "View profile" : "Ver perfil", + "Local time: %s" : "Hora local: %s", "today" : "hoy", "tomorrow" : "mañana", "yesterday" : "ayer", @@ -43,8 +75,11 @@ "_%n minute ago_::_%n minutes ago_" : ["Hace %n minuto","Hace %n minutos","Hace %n minutos"], "in a few seconds" : "en algunos segundos", "seconds ago" : "hace segundos", + "Empty file" : "Archivo vacío", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "El módulo con ID: %sno existe. Por favor hablíitalo en tus configuraciones de aplicación o contacta a tu administrador. ", "File already exists" : "El archivo ya existe", + "Invalid path" : "Ruta inválida", + "Failed to create file from template" : "No se pudo crear un archivo desde la plantilla", "Templates" : "Plantillas", "File name is a reserved word" : "Nombre de archivo es una palabra reservada", "File name contains at least one invalid character" : "El nombre del archivo contiene al menos un caracter inválido", @@ -56,39 +91,70 @@ "__language_name__" : "Español (México)", "This is an automatically sent email, please do not reply." : "Este es un correo enviado automáticamente, por favor no lo contestes. ", "Help" : "Ayuda", + "Appearance and accessibility" : "Apariencia y accesibilidad", "Apps" : "Aplicaciones", + "Personal settings" : "Configuración personal", + "Administration settings" : "Configuración de administración", "Settings" : "Ajustes", "Log out" : "Cerrar sesión", "Users" : "Usuarios", "Email" : "Correo electrónico", + "Mail %s" : "Correo %s", + "Fediverse" : "Fediverso", + "View %s on the fediverse" : "Ver %s en el fediverso", "Phone" : "Teléfono fijo", + "Call %s" : "Llamar a %s", "Twitter" : "Twitter", + "View %s on Twitter" : "Ver %s en Twitter", "Website" : "Sitio web", + "Visit %s" : "Visitar %s", "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", + "Display name" : "Nombre para mostrar", + "Headline" : "Título", + "Organisation" : "Organización", + "Role" : "Cargo", + "Unknown account" : "Cuenta desconocida", "Additional settings" : "Configuraciones adicionales", + "Enter the database Login and name for %s" : "Introduzca el usuario y el nombre para la base de datos %s", + "Enter the database Login for %s" : "Introduzca el usuario de la base de datos %s", + "Enter the database name for %s" : "Introduzca el nombre de la base de datos %s", + "You cannot use dots in the database name %s" : "No puede utilizar puntos para el nombre de base de datos %s ", + "MySQL Login and/or password not valid" : "Usuario y/o contraseña de MySQL inválidos", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Oracle Login and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL Login and/or password not valid" : "Usuario y/o contraseña de PostgreSQL inválidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", + "Set an admin Login." : "Establecer un usuario administrador.", "Set an admin password." : "Establecer la contraseña del administrador.", + "Cannot create or write into the data directory %s" : "No se puede crear o escribir en el directorio de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", "Sharing backend for %s not found" : "No fue encontrado el Backend que comparte para %s", + "%1$s shared »%2$s« with you and wants to add:" : "%1$s compartió »%2$s« contigo y quiere añadir:", + "%1$s shared »%2$s« with you and wants to add" : "%1$s compartió »%2$s« contigo y quiere añadir", + "»%s« added a note to a file shared with you" : "»%s« añadió una nota a un archivo compartido contigo", "Open »%s«" : "Abrir »%s«", + "%1$s via %2$s" : "%1$s vía %2$s", "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", + "Files cannot be shared with delete permissions" : "No se pueden compartir archivos con permisos de eliminación", + "Files cannot be shared with create permissions" : "No se pueden compartir archivos con permisos de creación", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No se puede fijar la fecha de caducidad más de %n día en el futuro","No se puede fijar la fecha de caducidad más de %n días en el futuro","No se puede fijar la fecha de caducidad más de %n días en el futuro"], + "Sharing is only allowed with group members" : "Sólo está permitido compartir a los miembros del grupo", + "Sharing %s failed, because this item is already shared with the account %s" : "No se pudo compartir %s porque este elemento ya está compartido con el usuario %s", + "%1$s shared »%2$s« with you" : "%1$s compartió »%2$s« contigo", + "%1$s shared »%2$s« with you." : "%1$s compartió »%2$s« contigo.", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", + "The requested share comes from a disabled user" : "El recurso compartido solicitado proviene de un usuario deshabilitado", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "No se creó el usuario porque se ha alcanzado el límite de usuarios. Consulta tus notificaciones para obtener más información.", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", "Sunday" : "Domingo", "Monday" : "Lunes", @@ -136,38 +202,95 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", + "The Login is already being used" : "El usuario ya está en uso", + "Could not create account" : "No se pudo crear la cuenta", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Sólo los siguientes caracteres están permitidos en un nombre de usuario: \"a-z\", \"A-Z\", \"0-9\", espacios y \"_.@-'\"", + "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 invalid because files already exist for this user" : "El usuario es inválido porque ya existen archivos para éste", + "Account disabled" : "Cuenta deshabilitada", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "No se puede instalar la aplicación \"%1$s\" porque no se cumple con las siguientes dependencias: %2$s ", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", + "Cannot download file" : "No se puede descargar el archivo", "Application is not enabled" : "La aplicación está deshabilitada", "Authentication error" : "Error de autenticación", "Token expired. Please reload page." : "La ficha ha expirado. Por favor recarga la página.", "No database drivers (sqlite, mysql, or postgresql) installed." : "No cuentas con controladores de base de datos (sqlite, mysql o postgresql) instalados. ", + "Cannot write into \"config\" directory." : "No se puede escribir en el directorio \"config\".", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Normalmente, esto se puede arreglar al darle al servidor web permiso de escritura al directorio de configuración. Vea %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" : "Sin embargo, si prefiere mantener el archivo config.php como sólo lectura, establezca la opción \"config_is_read_only\" como verdadero. Vea %s", + "Cannot write into \"apps\" directory." : "No se puede escribir en el directorio \"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." : "Normalmente, esto se puede arreglar al darle al servidor web permiso de escritura al directorio de aplicaciones o deshabilitando la tienda de aplicaciones del archivo de configuración.", + "Cannot create \"data\" directory." : "No se puede crear el directorio \"data\".", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Normalmente, esto se puede arreglar dando al servidor web permiso de escritura al directorio raíz. Vea %s", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Los permisos normalmente se pueden arreglar dando al servidor web permiso de escritura al directorio raíz. Vea %s.", + "Your data directory is not writable." : "No se puede escribir en su carpeta de datos.", + "Setting locale to %s failed." : "Falló al establecer la configuración regional a %s.", + "Please install one of these locales on your system and restart your web server." : "Por favor, instale una de estas configuraciones regionales en su sistema y reinicie el servidor web.", "PHP module %s not installed." : "El módulo de PHP %s no está instalado. ", "Please ask your server administrator to install the module." : "Por favor solicita a tu adminsitrador la instalación del módulo. ", "PHP setting \"%s\" is not set to \"%s\"." : "El ajuste PHP \"%s\" no esta establecido a \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "El cambiar este ajuste del archivo php.ini hará que Nextcloud corra de nuevo.", + "<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 como <code>%s</code> en lugar del valor esperado <code>0</code>.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para arreglar este problema, establezca <code>mbstring.func_overload</code> como<code>0</code> en su php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Al parecer PHP está configurado para quitar los bloques de comentarios internos. Esto hará que varias aplicaciones principales sean inaccesibles. ", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", + "The required %s config variable is not configured in the config.php file." : "La variable de configuración requerida %s no está configurada en el archivo config.php.", + "Please ask your server administrator to check the Nextcloud configuration." : "Por favor, pida al administrador del servidor que verifique la configuración de Nextcloud.", + "Your data directory is readable by other people." : "Su directorio de datos puede ser leído por otros usuarios.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Por favor, cambie los permisos a 0770 para que el directorio no se pueda listar por otros usuarios.", + "Your data directory must be an absolute path." : "Su directorio de datos debe ser una ruta absoluta.", + "Check the value of \"datadirectory\" in your configuration." : "Revise el valor de \"datadirectory\" en su configuración.", + "Your data directory is invalid." : "Su directorio de datos es inválido.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", + "Action \"%s\" not supported or implemented." : "La acción \"%s\" no está soportada o no está implementada.", + "Authentication failed, wrong token or provider ID given" : "Falló la autentificación, se proporcionó un token o un identificador de proveedor incorrecto", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Faltan parámetros para completar la solicitud. Parámetros faltantes: \"%s\"", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "El identificador \"%1$s\" ya está en uso por el proveedor de federación de la nube \"%2$s\"", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "El proveedor de federación de la nube con identificador \"%s\" no existe.", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", "Storage incomplete configuration. %s" : "Configuración incompleta del almacenamiento. %s", "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Free prompt" : "Liberar prompt", + "Runs an arbitrary prompt through the language model." : "Ejecuta un prompt arbitrario a través del modelo de lenguaje.", + "Generate headline" : "Generar titular", + "Generates a possible headline for a text." : "Genera un posible titular para un texto.", + "Summarize" : "Resumir", + "Summarizes text by reducing its length without losing key information." : "Resume el texto reduciendo su longitud sin perder información clave.", + "Extract topics" : "Extraer temas", + "Extracts topics from a text and outputs them separated by commas." : "Extrae los temas de un texto y genera una salida separada por comas. ", + "404" : "404", + "Logged in user must be an admin or sub admin" : "El usuario conectado debe ser un administrador o un subadministrador", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Enter the database username and name for %s" : "Introduzca el usuario y el nombre para la base de datos %s", + "Enter the database username for %s" : "Introduzca el usuario de la base de datos %s", + "MySQL username and/or password not valid" : "Usuario y/o contraseña de MySQL inválidos", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "Username is invalid because files already exist for this user" : "El nombre de usuario es inválido porque ya existen archivos para éste", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "PostgreSQL >= 9 required." : "Se requiere PostgreSQL >= 9.", + "Please upgrade your database version." : "Por favor, actualice la versión de la base de datos.", + "Your data directory is readable by other users." : "Su directorio de datos puede ser leído por otros usuarios.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_NI.js b/lib/l10n/es_NI.js index 0a969595b2e..8df3dacbd87 100644 --- a/lib/l10n/es_NI.js +++ b/lib/l10n/es_NI.js @@ -67,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -86,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -136,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -157,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,8 +154,19 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_NI.json b/lib/l10n/es_NI.json index d3bb152cf38..7a0e25fd27d 100644 --- a/lib/l10n/es_NI.json +++ b/lib/l10n/es_NI.json @@ -65,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -84,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -134,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -155,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,8 +152,19 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_PA.js b/lib/l10n/es_PA.js index d8fa9ad67d6..46b49c9264c 100644 --- a/lib/l10n/es_PA.js +++ b/lib/l10n/es_PA.js @@ -67,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -86,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -136,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -157,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,8 +154,19 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_PA.json b/lib/l10n/es_PA.json index 8083d0164d1..e567180c565 100644 --- a/lib/l10n/es_PA.json +++ b/lib/l10n/es_PA.json @@ -65,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -84,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -134,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -155,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,8 +152,19 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_PE.js b/lib/l10n/es_PE.js index 558959bf2f6..f89ca744266 100644 --- a/lib/l10n/es_PE.js +++ b/lib/l10n/es_PE.js @@ -67,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -86,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -136,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -157,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,8 +154,19 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_PE.json b/lib/l10n/es_PE.json index 20e5f5f30d5..3b1a5baa754 100644 --- a/lib/l10n/es_PE.json +++ b/lib/l10n/es_PE.json @@ -65,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -84,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -134,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -155,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,8 +152,19 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_PR.js b/lib/l10n/es_PR.js index b1639dc9ffc..0878b6449b3 100644 --- a/lib/l10n/es_PR.js +++ b/lib/l10n/es_PR.js @@ -67,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -86,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -136,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -157,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,8 +154,19 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_PR.json b/lib/l10n/es_PR.json index 017cfd67d22..6c0d3869226 100644 --- a/lib/l10n/es_PR.json +++ b/lib/l10n/es_PR.json @@ -65,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -84,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -134,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -155,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,8 +152,19 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_PY.js b/lib/l10n/es_PY.js index 0de414992a7..c508e6e3d48 100644 --- a/lib/l10n/es_PY.js +++ b/lib/l10n/es_PY.js @@ -67,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -86,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -136,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -157,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,8 +154,19 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_PY.json b/lib/l10n/es_PY.json index b2fa427189b..23335f48ff8 100644 --- a/lib/l10n/es_PY.json +++ b/lib/l10n/es_PY.json @@ -65,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -84,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -134,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -155,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,8 +152,19 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_SV.js b/lib/l10n/es_SV.js index e5d0f41c17b..aa2f19a2adb 100644 --- a/lib/l10n/es_SV.js +++ b/lib/l10n/es_SV.js @@ -20,7 +20,6 @@ OC.L10N.register( "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -68,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -87,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -137,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -158,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,9 +153,21 @@ OC.L10N.register( "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_SV.json b/lib/l10n/es_SV.json index 4d8379f16b5..5860fa59cc9 100644 --- a/lib/l10n/es_SV.json +++ b/lib/l10n/es_SV.json @@ -18,7 +18,6 @@ "The library %s is not available." : "La biblioteca %s no está disponible. ", "Server version %s or higher is required." : "Se requiere la versión del servidor %s o superior. ", "Server version %s or lower is required." : "La versión del servidor %s o inferior es requerdia. ", - "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Authentication" : "Autenticación", "Unknown filetype" : "Tipo de archivo desconocido", "Invalid image" : "Imagen inválida", @@ -66,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca de", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -85,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -135,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -156,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,9 +151,21 @@ "Storage connection error. %s" : "Se presentó un error con la conexión al almacenamiento. %s", "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", + "Logged in user must be an admin" : "El usuario firmado debe ser un administrador", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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/es_UY.js b/lib/l10n/es_UY.js index cf73ba599d3..a478a757909 100644 --- a/lib/l10n/es_UY.js +++ b/lib/l10n/es_UY.js @@ -67,17 +67,13 @@ OC.L10N.register( "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -86,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -136,12 +131,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -157,7 +146,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -166,8 +154,19 @@ OC.L10N.register( "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/es_UY.json b/lib/l10n/es_UY.json index b1630748484..81576e082a9 100644 --- a/lib/l10n/es_UY.json +++ b/lib/l10n/es_UY.json @@ -65,17 +65,13 @@ "Address" : "Dirección", "Profile picture" : "Foto de perfil", "About" : "Acerca", - "Unknown user" : "Ususario desconocido", "Additional settings" : "Configuraciones adicionales", "You need to enter details of an existing account." : "Necesitas ingresar los detalles de una cuenta existente.", "Oracle connection could not be established" : "No fue posible establecer la conexión a Oracle", - "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", - "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "OS X de Mac no está soportado y %s no funcionará correctamente en esta plataforma ¡Úsalo bajo tu propio riesgo!", "For the best results, please consider using a GNU/Linux server instead." : "Para mejores resultados, por favor cosidera usar en su lugar un servidor 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." : "Al parecer esta instancia %s está corriendo en un ambiente PHP de 32-bits y el open_basedir ha sido configurado en el archivo php.ini. Esto generará problemas con archivos de más de 4GB de tamaño y es altamente desalentado. ", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor elimina el ajuste open_basedir de tu archivo php.ini o cambia a PHP de 64 bits. ", - "Set an admin username." : "Establecer un Usuario administrador", "Set an admin password." : "Establecer la contraseña del administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "El backend %s que comparte debe implementar la interface OCP\\Share_Backend", "Sharing backend %s not found" : "No fue encontrado el Backend que comparte %s ", @@ -84,7 +80,6 @@ "You are not allowed to share %s" : "No tienes permitido compartir %s", "Cannot increase permissions of %s" : "No se pueden incrementar los permisos de %s", "Expiration date is in the past" : "La fecha de expiración se encuentra en el pasado", - "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", "Click the button below to open it." : "Haz click en el botón inferior para abrirlo. ", "The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe", "Could not find category \"%s\"" : "No fue posible encontrar la categoria \"%s\"", @@ -134,12 +129,6 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Se debe proporcionar una contraseña válida", - "The username is already being used" : "Ese usuario ya está en uso", - "Could not create user" : "No fue posible crear el usuario", - "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", - "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", - "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", - "User disabled" : "Usuario deshabilitado", "Login canceled by app" : "Inicio de sesión cancelado por la aplicación", "a safe home for all your data" : "un lugar seguro para todos tus datos", "File is currently busy, please try again later" : "El archivo se encuentra actualmente en uso, por favor intentalo más tarde. ", @@ -155,7 +144,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Esto ha sido causado probablemente por un acelerador de caché como Zend OPcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "¿Los módulos de PHP han sido instalados, pero se siguen enlistando como faltantes?", "Please ask your server administrator to restart the web server." : "Por favor solicita al administrador reiniciar el servidor web. ", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. ", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asegurate de que exista una archivo llamado \".ocdata\" en la raíz del directorio de datos. ", "Could not obtain lock type %d on \"%s\"." : "No fue posible obtener el tipo de bloqueo %d en \"%s\". ", "Storage unauthorized. %s" : "Almacenamiento no autorizado. %s", @@ -164,8 +152,19 @@ "Storage is temporarily not available" : "El almacenamieto se encuentra temporalmente no disponible", "Storage connection timeout. %s" : "El tiempo de la conexión del almacenamiento se agotó. %s", "Full name" : "Nombre completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Sólo se permiten los siguientes caracteres en el usuario: \"a-z\", \"A-Z\", \"0-9\" y \"_.@-'\"", + "Unknown user" : "Ususario desconocido", + "Oracle username and/or password not valid" : "Usuario y/o contraseña de Oracle inválidos", + "PostgreSQL username and/or password not valid" : "El Usuario y/o Contraseña de PostgreSQL inválido(s)", + "Set an admin username." : "Establecer un Usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Se presento una falla al compartir %s, porque este elemento ya ha sido compartido con el usuario %s", + "The username is already being used" : "Ese usuario ya está en uso", + "Could not create user" : "No fue posible crear el usuario", + "A valid username must be provided" : "Debes proporcionar un nombre de usuario válido", + "Username contains whitespace at the beginning or at the end" : "El usuario contiene un espacio en blanco al inicio o al final", + "Username must not consist of dots only" : "El usuario no debe consistir de solo puntos. ", + "User disabled" : "Usuario deshabilitado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Se requiere de por lo menos libxml2 2.7.0. Actualmente %s está instalado. ", - "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. " + "To fix this issue update your libxml2 version and restart your web server." : "Para corregir este tema, por favor actualiza la versión de su libxml2 y reinicia tu servidor web. ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor cambia los permisos a 0770 para que el directorio no pueda ser enlistado por otros usuarios. " },"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 ab62f94437e..62a607811f8 100644 --- a/lib/l10n/et_EE.js +++ b/lib/l10n/et_EE.js @@ -62,15 +62,11 @@ OC.L10N.register( "Display name" : "Kuvatav nimi", "Organisation" : "Organisatsioon", "Role" : "Roll", - "Unknown user" : "Tundmatu kasutaja", "Additional settings" : "Lisaseaded", "You need to enter details of an existing account." : "Sa pead sisestama olemasoleva konto andmed.", "Oracle connection could not be established" : "Ei suuda luua ühendust Oracle baasiga", - "Oracle username and/or password not valid" : "Oracle kasutajatunnus ja/või parool pole õiged", - "PostgreSQL username and/or password not valid" : "PostgreSQL kasutajatunnus ja/või parool pole õiged", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X ei ole toetatud ja %s ei pruugi korralikult toimida sellel platvormil. Kasuta seda omal vastutusel!", "For the best results, please consider using a GNU/Linux server instead." : "Parema tulemuse saavitamiseks palun kaalu serveris GNU/Linux kasutamist.", - "Set an admin username." : "Määra admin kasutajanimi.", "Set an admin password." : "Määra admini parool.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Jagamise tagarakend %s peab kasutusele võtma OCP\\Share_Backend liidese", "Sharing backend %s not found" : "Jagamise tagarakendit %s ei leitud", @@ -79,7 +75,6 @@ OC.L10N.register( "You are not allowed to share %s" : "Sul pole lubatud %s jagada", "Cannot increase permissions of %s" : "Ei saa %s õigusi suurendada", "Expiration date is in the past" : "Aegumise kuupäev on minevikus", - "Sharing %s failed, because this item is already shared with user %s" : "%s jagamine ebaõnnestus, kuna see üksus on juba jagatud kasutajaga %s", "Click the button below to open it." : "Vajuta allolevat nuppu, et see avada.", "The requested share does not exist anymore" : "Soovitud jagamist enam ei eksisteeri", "Could not find category \"%s\"" : "Ei leia kategooriat \"%s\"", @@ -129,12 +124,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dets.", "A valid password must be provided" : "Sisesta nõuetele vastav parool", - "The username is already being used" : "Kasutajanimi on juba kasutuses", - "Could not create user" : "Ei saanud kasutajat luua", - "A valid username must be provided" : "Sisesta nõuetele vastav kasutajatunnus", - "Username contains whitespace at the beginning or at the end" : "Kasutajanime alguses või lõpus on tühik", - "Username must not consist of dots only" : "Kasutajanimi ei tohi koosneda ainult punktidest", - "User disabled" : "Kasutaja deaktiveeritud", "a safe home for all your data" : "turvaline koht sinu andmetele", "File is currently busy, please try again later" : "Fail on hetkel kasutuses, proovi hiljem uuesti", "Application is not enabled" : "Rakendus pole sisse lülitatud", @@ -147,13 +136,23 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "See on tõenäoliselt põhjustatud puhver/kiirendist nagu Zend OPcache või eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "PHP moodulid on paigaldatud, kuid neid näitatakse endiselt kui puuduolevad?", "Please ask your server administrator to restart the web server." : "Palu oma serveri haldajal veebiserver taaskäivitada.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Palun muuda kataloogi õigused 0770-ks, et kataloogi sisu poleks teistele kasutajatele nähtav", "Your data directory is invalid." : "Sinu andmekataloog on vigane", "Could not obtain lock type %d on \"%s\"." : "Ei suutnud hankida %d tüüpi lukustust \"%s\".", "Storage is temporarily not available" : "Salvestusruum pole ajutiselt kättesaadav", "Full name" : "Täisnimi", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Kasutajanimes on lubatud ainult järgmised sümbolid: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Tundmatu kasutaja", + "Oracle username and/or password not valid" : "Oracle kasutajatunnus ja/või parool pole õiged", + "PostgreSQL username and/or password not valid" : "PostgreSQL kasutajatunnus ja/või parool pole õiged", + "Set an admin username." : "Määra admin kasutajanimi.", + "Sharing %s failed, because this item is already shared with user %s" : "%s jagamine ebaõnnestus, kuna see üksus on juba jagatud kasutajaga %s", + "The username is already being used" : "Kasutajanimi on juba kasutuses", + "Could not create user" : "Ei saanud kasutajat luua", + "A valid username must be provided" : "Sisesta nõuetele vastav kasutajatunnus", + "Username contains whitespace at the beginning or at the end" : "Kasutajanime alguses või lõpus on tühik", + "Username must not consist of dots only" : "Kasutajanimi ei tohi koosneda ainult punktidest", + "User disabled" : "Kasutaja deaktiveeritud", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Vaja on vähemalt libxml2 2.7.0. Hetkel on installitud %s.", - "Please upgrade your database version." : "Palun uuenda oma andmebaasi versioon" + "Please upgrade your database version." : "Palun uuenda oma andmebaasi versioon", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Palun muuda kataloogi õigused 0770-ks, et kataloogi sisu poleks teistele kasutajatele nähtav" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/et_EE.json b/lib/l10n/et_EE.json index 27abedc8f33..996ced49a50 100644 --- a/lib/l10n/et_EE.json +++ b/lib/l10n/et_EE.json @@ -60,15 +60,11 @@ "Display name" : "Kuvatav nimi", "Organisation" : "Organisatsioon", "Role" : "Roll", - "Unknown user" : "Tundmatu kasutaja", "Additional settings" : "Lisaseaded", "You need to enter details of an existing account." : "Sa pead sisestama olemasoleva konto andmed.", "Oracle connection could not be established" : "Ei suuda luua ühendust Oracle baasiga", - "Oracle username and/or password not valid" : "Oracle kasutajatunnus ja/või parool pole õiged", - "PostgreSQL username and/or password not valid" : "PostgreSQL kasutajatunnus ja/või parool pole õiged", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X ei ole toetatud ja %s ei pruugi korralikult toimida sellel platvormil. Kasuta seda omal vastutusel!", "For the best results, please consider using a GNU/Linux server instead." : "Parema tulemuse saavitamiseks palun kaalu serveris GNU/Linux kasutamist.", - "Set an admin username." : "Määra admin kasutajanimi.", "Set an admin password." : "Määra admini parool.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Jagamise tagarakend %s peab kasutusele võtma OCP\\Share_Backend liidese", "Sharing backend %s not found" : "Jagamise tagarakendit %s ei leitud", @@ -77,7 +73,6 @@ "You are not allowed to share %s" : "Sul pole lubatud %s jagada", "Cannot increase permissions of %s" : "Ei saa %s õigusi suurendada", "Expiration date is in the past" : "Aegumise kuupäev on minevikus", - "Sharing %s failed, because this item is already shared with user %s" : "%s jagamine ebaõnnestus, kuna see üksus on juba jagatud kasutajaga %s", "Click the button below to open it." : "Vajuta allolevat nuppu, et see avada.", "The requested share does not exist anymore" : "Soovitud jagamist enam ei eksisteeri", "Could not find category \"%s\"" : "Ei leia kategooriat \"%s\"", @@ -127,12 +122,6 @@ "Nov." : "Nov.", "Dec." : "Dets.", "A valid password must be provided" : "Sisesta nõuetele vastav parool", - "The username is already being used" : "Kasutajanimi on juba kasutuses", - "Could not create user" : "Ei saanud kasutajat luua", - "A valid username must be provided" : "Sisesta nõuetele vastav kasutajatunnus", - "Username contains whitespace at the beginning or at the end" : "Kasutajanime alguses või lõpus on tühik", - "Username must not consist of dots only" : "Kasutajanimi ei tohi koosneda ainult punktidest", - "User disabled" : "Kasutaja deaktiveeritud", "a safe home for all your data" : "turvaline koht sinu andmetele", "File is currently busy, please try again later" : "Fail on hetkel kasutuses, proovi hiljem uuesti", "Application is not enabled" : "Rakendus pole sisse lülitatud", @@ -145,13 +134,23 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "See on tõenäoliselt põhjustatud puhver/kiirendist nagu Zend OPcache või eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "PHP moodulid on paigaldatud, kuid neid näitatakse endiselt kui puuduolevad?", "Please ask your server administrator to restart the web server." : "Palu oma serveri haldajal veebiserver taaskäivitada.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Palun muuda kataloogi õigused 0770-ks, et kataloogi sisu poleks teistele kasutajatele nähtav", "Your data directory is invalid." : "Sinu andmekataloog on vigane", "Could not obtain lock type %d on \"%s\"." : "Ei suutnud hankida %d tüüpi lukustust \"%s\".", "Storage is temporarily not available" : "Salvestusruum pole ajutiselt kättesaadav", "Full name" : "Täisnimi", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Kasutajanimes on lubatud ainult järgmised sümbolid: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Tundmatu kasutaja", + "Oracle username and/or password not valid" : "Oracle kasutajatunnus ja/või parool pole õiged", + "PostgreSQL username and/or password not valid" : "PostgreSQL kasutajatunnus ja/või parool pole õiged", + "Set an admin username." : "Määra admin kasutajanimi.", + "Sharing %s failed, because this item is already shared with user %s" : "%s jagamine ebaõnnestus, kuna see üksus on juba jagatud kasutajaga %s", + "The username is already being used" : "Kasutajanimi on juba kasutuses", + "Could not create user" : "Ei saanud kasutajat luua", + "A valid username must be provided" : "Sisesta nõuetele vastav kasutajatunnus", + "Username contains whitespace at the beginning or at the end" : "Kasutajanime alguses või lõpus on tühik", + "Username must not consist of dots only" : "Kasutajanimi ei tohi koosneda ainult punktidest", + "User disabled" : "Kasutaja deaktiveeritud", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Vaja on vähemalt libxml2 2.7.0. Hetkel on installitud %s.", - "Please upgrade your database version." : "Palun uuenda oma andmebaasi versioon" + "Please upgrade your database version." : "Palun uuenda oma andmebaasi versioon", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Palun muuda kataloogi õigused 0770-ks, et kataloogi sisu poleks teistele kasutajatele nähtav" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/eu.js b/lib/l10n/eu.js index 4ce0073319d..9ce8c445b63 100644 --- a/lib/l10n/eu.js +++ b/lib/l10n/eu.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "%1$s aplikazioa ez dago edo zerbitzari honekiko bertsio bateraezina du. Mesedez egiaztatu aplikazioen karpeta.", "Sample configuration detected" : "Adibide-ezarpena detektatua", "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" : "Adibide-ezarpena kopiatu dela detektatu da. Honek zure instalazioa apur dezake eta ez da onartzen. Irakurri dokumentazioa config.php fitxategia aldatu aurretik.", - "404" : "404", "The page could not be found on the server." : "Orria ez da zerbitzarian aurkitu.", "%s email verification" : "%sposta elektronikoaren egiaztapena", "Email verification" : "Posta elektronikoaren egiaztapena", @@ -37,9 +36,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Hurrengo plataformak onartzen dira: %s", "Server version %s or higher is required." : "Zerbitzariaren %s bertsioa edo berriagoa behar da.", "Server version %s or lower is required." : "Zerbitzariaren %s bertsioa edo zaharragoa behar da.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Saioa hasitako erabiltzailea administratzailea, azpi-administratzailea edo baimen berezi bat duena izan behar da ezarpen hau aldatzeko.", - "Logged in user must be an admin or sub admin" : "Saioa hasitako erabiltzailea administratzaile edo azpi-administratzailea izan behar du", - "Logged in user must be an admin" : "Saioa hasitako erabiltzailea administratzailea izan behar da", "Wiping of device %s has started" : "%s gailuaren garbiketa hasi da", "Wiping of device »%s« has started" : "»%s« gailuaren garbiketa hasi da", "»%s« started remote wipe" : "»%s«(e)k urruneko garbiketa hasi du", @@ -118,22 +114,15 @@ OC.L10N.register( "Headline" : "Izenburua", "Organisation" : "Erakundea", "Role" : "Zeregina", - "Unknown user" : "Erabiltzaile ezezaguna", "Additional settings" : "Ezarpen gehiago", - "Enter the database username and name for %s" : "%s sartu datu-basearen izena eta erabiltzaile-izena", - "Enter the database username for %s" : "Sartu %s(r)en datu-base erabiltzaile-izena", "Enter the database name for %s" : "Sartu %s(r)en datu-base izena", "You cannot use dots in the database name %s" : "Ezin duzu punturik erabili %s datu-base izenean", - "MySQL username and/or password not valid" : "MySQL erabiltzaile-izen edota pasahitza baliogabea", "You need to enter details of an existing account." : "Existitzen den kontu baten xehetasunak sartu behar dituzu.", "Oracle connection could not be established" : "Ezin da Oracle konexioa sortu", - "Oracle username and/or password not valid" : "Oracle erabiltzaile edo/eta pasahitza ez dira baliozkoak.", - "PostgreSQL username and/or password not valid" : "PostgreSQL erabiltzailea edo/eta pasahitza ez dira baliozkoak.", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X ez da onartzen eta %s gaizki ibiliko da plataforma honetan. Erabiltzekotan, zure ardurapean.", "For the best results, please consider using a GNU/Linux server instead." : "Emaitza hobeak izateko, mesedez kontsideratu GNU/Linux zerbitzari bat erabiltzea.", "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." : "Badirudi %s instantzia hau 32 biteko PHP ingurune bat exekutatzen ari dela eta open_basedir aldagaia php.ini fitxategian konfiguratu dela. Honek arazoak sortuko ditu 4 GB baino gehiagoko fitxategiekin eta ez da batere gomendagarria.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Mesedez kendu open_basedir ezarpena zure php.ini-tik edo aldatu 64-biteko PHPra.", - "Set an admin username." : "Ezarri administraziorako erabiltzaile izena.", "Set an admin password." : "Ezarri administraziorako pasahitza.", "Cannot create or write into the data directory %s" : "Ezin da sortu edo idatzi %s datu-direktorioan ", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "%s partekatze motorrak OCP\\Share_Backend interfazea inplementatu behar du ", @@ -151,11 +140,11 @@ OC.L10N.register( "Expiration date is in the past" : "Iraungitze-data iraganean dago", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Ezin da iraungitze-data etorkizunean %n egun baino gehiagora jarri","Ezin da iraungitze-data etorkizunean %n egun baino gehiagora jarri"], "Sharing is only allowed with group members" : "Taldeko kideekin bakarrik parteka daiteke", - "Sharing %s failed, because this item is already shared with user %s" : "%s partekatzeak huts egin du dagoeneko %serabiltzailearekin partekatuta dagoelako", "%1$s shared »%2$s« with you" : "%1$serabiltzaileak »%2$s« partekatu du zurekin", "%1$s shared »%2$s« with you." : "%1$serabiltzaileak »%2$s« partekatu du zurekin.", "Click the button below to open it." : "Egin klik beheko botoian hura irekitzeko.", "The requested share does not exist anymore" : "Eskatutako partekatzea ez da existitzen dagoeneko", + "The requested share comes from a disabled user" : "Eskatutako partekatzea desgaitutako erabiltzaile batengatik dator", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Ezin izan da erabiltzailea sortu, erabiltzaile muga gainditu delako. Egiaztatu zure jakinarazpenak gehiago jakiteko.", "Could not find category \"%s\"" : "Ezin da \"%s\" kategoria aurkitu", "Sunday" : "Igandea", @@ -204,14 +193,6 @@ OC.L10N.register( "Nov." : "Aza.", "Dec." : "Abe.", "A valid password must be provided" : "Baliozko pasahitza eman behar da", - "The username is already being used" : "Erabiltzaile izena dagoeneko erabilita dago", - "Could not create user" : "Ezin izan da erabiltzailea sortu", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Honako karaktereak bakarrik onartzen dira erabiltzaile izenetan: \"a-z\", \"A-Z\", \"0-9\", zuriuneak eta \"_.@-'\"", - "A valid username must be provided" : "Baliozko erabiltzaile izena eman behar da", - "Username contains whitespace at the beginning or at the end" : "Erabiltzaile-izenak zuriuneren bat du hasieran edo amaieran", - "Username must not consist of dots only" : "Erabiltzaile-izena ezin da puntuz osatuta soilik egon", - "Username is invalid because files already exist for this user" : "Erabiltzaile-izena ez da baliozkoa erabiltzaile honentzako fitxategiak dagoeneko existitzen direlako", - "User disabled" : "Erabiltzaile desgaituta", "Login canceled by app" : "Aplikazioak saioa bertan behera utzi du", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "\"%1$s\" aplikazioa ezin da instalatu, menpekotasun hauek betetzen ez direlako:%2$s", "a safe home for all your data" : "zure datu guztientzako toki segurua", @@ -244,8 +225,6 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Mesedez eskatu zerbitzariaren administratzaileari web zerbitzaria berrabiarazteko.", "The required %s config variable is not configured in the config.php file." : "Beharrezko %s config aldagaia ez dago konfiguratuta config.php fitxategian.", "Please ask your server administrator to check the Nextcloud configuration." : "Mesedez, eskatu zure zerbitzari administratzaileari Nextclouden konfigurazioa egiaztatzeko.", - "Your data directory is readable by other users." : "Zure datuen karpeta beste erabiltzaileek irakur dezakete.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Aldatu baimenak 0770ra beste erabiltzaileek karpetan sartu ezin izateko.", "Your data directory must be an absolute path." : "Zure datuen karpeta bide-izen absolutua izan behar da.", "Check the value of \"datadirectory\" in your configuration." : "Egiaztatu \"datadirectory\"-ren balioa zure konfigurazioan.", "Your data directory is invalid." : "Zure datuen karpeta baliogabea da.", @@ -262,6 +241,7 @@ OC.L10N.register( "Storage is temporarily not available" : "Biltegia ez dago erabilgarri aldi baterako", "Storage connection timeout. %s" : "Biltegiratze-konexioa denboraz kanpo geratu da. %s", "Free prompt" : "Gonbita librea", + "Runs an arbitrary prompt through the language model." : "Hizkuntza ereduaren zehar esaldi arbitrario bat exekutatzen du.", "Generate headline" : "Sortu izenburua", "Generates a possible headline for a text." : "Testu baten izenburu posiblea sortzen du.", "Summarize" : "Laburtu", @@ -269,12 +249,32 @@ OC.L10N.register( "Extract topics" : "Atera gaiak", "Extracts topics from a text and outputs them separated by commas." : "Gaiak ateratzen ditu testu batetik eta komaz banatuta erakusten ditu.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "%1$s aplikazioaren fitxategiak ez dira behar bezala ordezkatu. Ziurtatu zerbitzariarekin bateragarria den bertsioa dela.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Saioa hasitako erabiltzailea administratzailea, azpi-administratzailea edo baimen berezi bat duena izan behar da ezarpen hau aldatzeko.", + "Logged in user must be an admin or sub admin" : "Saioa hasitako erabiltzailea administratzaile edo azpi-administratzailea izan behar du", + "Logged in user must be an admin" : "Saioa hasitako erabiltzailea administratzailea izan behar da", "Full name" : "Izen osoa", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Ezin izan da erabiltzailea sortu, erabiltzaile muga gainditu delako. Egiaztatu zure jakinarazpenak gehiago jakiteko.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Erabiltzaile-izenean karaktere hauek soilik erabil daitezke: \"a-z\", \"A-Z\", \"0-9\", eta \"_.@-'\"", + "Unknown user" : "Erabiltzaile ezezaguna", + "Enter the database username and name for %s" : "%s sartu datu-basearen izena eta erabiltzaile-izena", + "Enter the database username for %s" : "Sartu %s(r)en datu-base erabiltzaile-izena", + "MySQL username and/or password not valid" : "MySQL erabiltzaile-izen edota pasahitza baliogabea", + "Oracle username and/or password not valid" : "Oracle erabiltzaile edo/eta pasahitza ez dira baliozkoak.", + "PostgreSQL username and/or password not valid" : "PostgreSQL erabiltzailea edo/eta pasahitza ez dira baliozkoak.", + "Set an admin username." : "Ezarri administraziorako erabiltzaile izena.", + "Sharing %s failed, because this item is already shared with user %s" : "%s partekatzeak huts egin du dagoeneko %serabiltzailearekin partekatuta dagoelako", + "The username is already being used" : "Erabiltzaile izena dagoeneko erabilita dago", + "Could not create user" : "Ezin izan da erabiltzailea sortu", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Honako karaktereak bakarrik onartzen dira erabiltzaile izenetan: \"a-z\", \"A-Z\", \"0-9\", zuriuneak eta \"_.@-'\"", + "A valid username must be provided" : "Baliozko erabiltzaile izena eman behar da", + "Username contains whitespace at the beginning or at the end" : "Erabiltzaile-izenak zuriuneren bat du hasieran edo amaieran", + "Username must not consist of dots only" : "Erabiltzaile-izena ezin da puntuz osatuta soilik egon", + "Username is invalid because files already exist for this user" : "Erabiltzaile-izena ez da baliozkoa erabiltzaile honentzako fitxategiak dagoeneko existitzen direlako", + "User disabled" : "Erabiltzaile desgaituta", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 bertsioa edo berriagoa behar da. Orain %s dago instalatuta.", "To fix this issue update your libxml2 version and restart your web server." : "Arazo hori konpontzeko, eguneratu zure libxml2 bertsioa eta berrabiarazi web zerbitzaria.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 behar da", - "Please upgrade your database version." : "Mesedez eguneratu zure datu-basearen bertsioa." + "Please upgrade your database version." : "Mesedez eguneratu zure datu-basearen bertsioa.", + "Your data directory is readable by other users." : "Zure datuen karpeta beste erabiltzaileek irakur dezakete.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Aldatu baimenak 0770ra beste erabiltzaileek karpetan sartu ezin izateko." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/eu.json b/lib/l10n/eu.json index bbe9bb708bb..3e767bd2bc6 100644 --- a/lib/l10n/eu.json +++ b/lib/l10n/eu.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "%1$s aplikazioa ez dago edo zerbitzari honekiko bertsio bateraezina du. Mesedez egiaztatu aplikazioen karpeta.", "Sample configuration detected" : "Adibide-ezarpena detektatua", "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" : "Adibide-ezarpena kopiatu dela detektatu da. Honek zure instalazioa apur dezake eta ez da onartzen. Irakurri dokumentazioa config.php fitxategia aldatu aurretik.", - "404" : "404", "The page could not be found on the server." : "Orria ez da zerbitzarian aurkitu.", "%s email verification" : "%sposta elektronikoaren egiaztapena", "Email verification" : "Posta elektronikoaren egiaztapena", @@ -35,9 +34,6 @@ "The following platforms are supported: %s" : "Hurrengo plataformak onartzen dira: %s", "Server version %s or higher is required." : "Zerbitzariaren %s bertsioa edo berriagoa behar da.", "Server version %s or lower is required." : "Zerbitzariaren %s bertsioa edo zaharragoa behar da.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Saioa hasitako erabiltzailea administratzailea, azpi-administratzailea edo baimen berezi bat duena izan behar da ezarpen hau aldatzeko.", - "Logged in user must be an admin or sub admin" : "Saioa hasitako erabiltzailea administratzaile edo azpi-administratzailea izan behar du", - "Logged in user must be an admin" : "Saioa hasitako erabiltzailea administratzailea izan behar da", "Wiping of device %s has started" : "%s gailuaren garbiketa hasi da", "Wiping of device »%s« has started" : "»%s« gailuaren garbiketa hasi da", "»%s« started remote wipe" : "»%s«(e)k urruneko garbiketa hasi du", @@ -116,22 +112,15 @@ "Headline" : "Izenburua", "Organisation" : "Erakundea", "Role" : "Zeregina", - "Unknown user" : "Erabiltzaile ezezaguna", "Additional settings" : "Ezarpen gehiago", - "Enter the database username and name for %s" : "%s sartu datu-basearen izena eta erabiltzaile-izena", - "Enter the database username for %s" : "Sartu %s(r)en datu-base erabiltzaile-izena", "Enter the database name for %s" : "Sartu %s(r)en datu-base izena", "You cannot use dots in the database name %s" : "Ezin duzu punturik erabili %s datu-base izenean", - "MySQL username and/or password not valid" : "MySQL erabiltzaile-izen edota pasahitza baliogabea", "You need to enter details of an existing account." : "Existitzen den kontu baten xehetasunak sartu behar dituzu.", "Oracle connection could not be established" : "Ezin da Oracle konexioa sortu", - "Oracle username and/or password not valid" : "Oracle erabiltzaile edo/eta pasahitza ez dira baliozkoak.", - "PostgreSQL username and/or password not valid" : "PostgreSQL erabiltzailea edo/eta pasahitza ez dira baliozkoak.", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X ez da onartzen eta %s gaizki ibiliko da plataforma honetan. Erabiltzekotan, zure ardurapean.", "For the best results, please consider using a GNU/Linux server instead." : "Emaitza hobeak izateko, mesedez kontsideratu GNU/Linux zerbitzari bat erabiltzea.", "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." : "Badirudi %s instantzia hau 32 biteko PHP ingurune bat exekutatzen ari dela eta open_basedir aldagaia php.ini fitxategian konfiguratu dela. Honek arazoak sortuko ditu 4 GB baino gehiagoko fitxategiekin eta ez da batere gomendagarria.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Mesedez kendu open_basedir ezarpena zure php.ini-tik edo aldatu 64-biteko PHPra.", - "Set an admin username." : "Ezarri administraziorako erabiltzaile izena.", "Set an admin password." : "Ezarri administraziorako pasahitza.", "Cannot create or write into the data directory %s" : "Ezin da sortu edo idatzi %s datu-direktorioan ", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "%s partekatze motorrak OCP\\Share_Backend interfazea inplementatu behar du ", @@ -149,11 +138,11 @@ "Expiration date is in the past" : "Iraungitze-data iraganean dago", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Ezin da iraungitze-data etorkizunean %n egun baino gehiagora jarri","Ezin da iraungitze-data etorkizunean %n egun baino gehiagora jarri"], "Sharing is only allowed with group members" : "Taldeko kideekin bakarrik parteka daiteke", - "Sharing %s failed, because this item is already shared with user %s" : "%s partekatzeak huts egin du dagoeneko %serabiltzailearekin partekatuta dagoelako", "%1$s shared »%2$s« with you" : "%1$serabiltzaileak »%2$s« partekatu du zurekin", "%1$s shared »%2$s« with you." : "%1$serabiltzaileak »%2$s« partekatu du zurekin.", "Click the button below to open it." : "Egin klik beheko botoian hura irekitzeko.", "The requested share does not exist anymore" : "Eskatutako partekatzea ez da existitzen dagoeneko", + "The requested share comes from a disabled user" : "Eskatutako partekatzea desgaitutako erabiltzaile batengatik dator", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Ezin izan da erabiltzailea sortu, erabiltzaile muga gainditu delako. Egiaztatu zure jakinarazpenak gehiago jakiteko.", "Could not find category \"%s\"" : "Ezin da \"%s\" kategoria aurkitu", "Sunday" : "Igandea", @@ -202,14 +191,6 @@ "Nov." : "Aza.", "Dec." : "Abe.", "A valid password must be provided" : "Baliozko pasahitza eman behar da", - "The username is already being used" : "Erabiltzaile izena dagoeneko erabilita dago", - "Could not create user" : "Ezin izan da erabiltzailea sortu", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Honako karaktereak bakarrik onartzen dira erabiltzaile izenetan: \"a-z\", \"A-Z\", \"0-9\", zuriuneak eta \"_.@-'\"", - "A valid username must be provided" : "Baliozko erabiltzaile izena eman behar da", - "Username contains whitespace at the beginning or at the end" : "Erabiltzaile-izenak zuriuneren bat du hasieran edo amaieran", - "Username must not consist of dots only" : "Erabiltzaile-izena ezin da puntuz osatuta soilik egon", - "Username is invalid because files already exist for this user" : "Erabiltzaile-izena ez da baliozkoa erabiltzaile honentzako fitxategiak dagoeneko existitzen direlako", - "User disabled" : "Erabiltzaile desgaituta", "Login canceled by app" : "Aplikazioak saioa bertan behera utzi du", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "\"%1$s\" aplikazioa ezin da instalatu, menpekotasun hauek betetzen ez direlako:%2$s", "a safe home for all your data" : "zure datu guztientzako toki segurua", @@ -242,8 +223,6 @@ "Please ask your server administrator to restart the web server." : "Mesedez eskatu zerbitzariaren administratzaileari web zerbitzaria berrabiarazteko.", "The required %s config variable is not configured in the config.php file." : "Beharrezko %s config aldagaia ez dago konfiguratuta config.php fitxategian.", "Please ask your server administrator to check the Nextcloud configuration." : "Mesedez, eskatu zure zerbitzari administratzaileari Nextclouden konfigurazioa egiaztatzeko.", - "Your data directory is readable by other users." : "Zure datuen karpeta beste erabiltzaileek irakur dezakete.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Aldatu baimenak 0770ra beste erabiltzaileek karpetan sartu ezin izateko.", "Your data directory must be an absolute path." : "Zure datuen karpeta bide-izen absolutua izan behar da.", "Check the value of \"datadirectory\" in your configuration." : "Egiaztatu \"datadirectory\"-ren balioa zure konfigurazioan.", "Your data directory is invalid." : "Zure datuen karpeta baliogabea da.", @@ -260,6 +239,7 @@ "Storage is temporarily not available" : "Biltegia ez dago erabilgarri aldi baterako", "Storage connection timeout. %s" : "Biltegiratze-konexioa denboraz kanpo geratu da. %s", "Free prompt" : "Gonbita librea", + "Runs an arbitrary prompt through the language model." : "Hizkuntza ereduaren zehar esaldi arbitrario bat exekutatzen du.", "Generate headline" : "Sortu izenburua", "Generates a possible headline for a text." : "Testu baten izenburu posiblea sortzen du.", "Summarize" : "Laburtu", @@ -267,12 +247,32 @@ "Extract topics" : "Atera gaiak", "Extracts topics from a text and outputs them separated by commas." : "Gaiak ateratzen ditu testu batetik eta komaz banatuta erakusten ditu.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "%1$s aplikazioaren fitxategiak ez dira behar bezala ordezkatu. Ziurtatu zerbitzariarekin bateragarria den bertsioa dela.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Saioa hasitako erabiltzailea administratzailea, azpi-administratzailea edo baimen berezi bat duena izan behar da ezarpen hau aldatzeko.", + "Logged in user must be an admin or sub admin" : "Saioa hasitako erabiltzailea administratzaile edo azpi-administratzailea izan behar du", + "Logged in user must be an admin" : "Saioa hasitako erabiltzailea administratzailea izan behar da", "Full name" : "Izen osoa", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Ezin izan da erabiltzailea sortu, erabiltzaile muga gainditu delako. Egiaztatu zure jakinarazpenak gehiago jakiteko.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Erabiltzaile-izenean karaktere hauek soilik erabil daitezke: \"a-z\", \"A-Z\", \"0-9\", eta \"_.@-'\"", + "Unknown user" : "Erabiltzaile ezezaguna", + "Enter the database username and name for %s" : "%s sartu datu-basearen izena eta erabiltzaile-izena", + "Enter the database username for %s" : "Sartu %s(r)en datu-base erabiltzaile-izena", + "MySQL username and/or password not valid" : "MySQL erabiltzaile-izen edota pasahitza baliogabea", + "Oracle username and/or password not valid" : "Oracle erabiltzaile edo/eta pasahitza ez dira baliozkoak.", + "PostgreSQL username and/or password not valid" : "PostgreSQL erabiltzailea edo/eta pasahitza ez dira baliozkoak.", + "Set an admin username." : "Ezarri administraziorako erabiltzaile izena.", + "Sharing %s failed, because this item is already shared with user %s" : "%s partekatzeak huts egin du dagoeneko %serabiltzailearekin partekatuta dagoelako", + "The username is already being used" : "Erabiltzaile izena dagoeneko erabilita dago", + "Could not create user" : "Ezin izan da erabiltzailea sortu", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Honako karaktereak bakarrik onartzen dira erabiltzaile izenetan: \"a-z\", \"A-Z\", \"0-9\", zuriuneak eta \"_.@-'\"", + "A valid username must be provided" : "Baliozko erabiltzaile izena eman behar da", + "Username contains whitespace at the beginning or at the end" : "Erabiltzaile-izenak zuriuneren bat du hasieran edo amaieran", + "Username must not consist of dots only" : "Erabiltzaile-izena ezin da puntuz osatuta soilik egon", + "Username is invalid because files already exist for this user" : "Erabiltzaile-izena ez da baliozkoa erabiltzaile honentzako fitxategiak dagoeneko existitzen direlako", + "User disabled" : "Erabiltzaile desgaituta", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 bertsioa edo berriagoa behar da. Orain %s dago instalatuta.", "To fix this issue update your libxml2 version and restart your web server." : "Arazo hori konpontzeko, eguneratu zure libxml2 bertsioa eta berrabiarazi web zerbitzaria.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 behar da", - "Please upgrade your database version." : "Mesedez eguneratu zure datu-basearen bertsioa." + "Please upgrade your database version." : "Mesedez eguneratu zure datu-basearen bertsioa.", + "Your data directory is readable by other users." : "Zure datuen karpeta beste erabiltzaileek irakur dezakete.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Aldatu baimenak 0770ra beste erabiltzaileek karpetan sartu ezin izateko." },"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 6c69b85d691..81029756700 100644 --- a/lib/l10n/fa.js +++ b/lib/l10n/fa.js @@ -8,7 +8,6 @@ OC.L10N.register( "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.", "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 ، اسناد را بخوانید", - "404" : "۴۰۴", "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", @@ -37,9 +36,6 @@ 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 یا پایینتر.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub admin or gotten special right to access this setting", - "Logged in user must be an admin or sub admin" : "ورود به سیستم کاربر باید یک مدیر یا مدیر فرعی باشد", - "Logged in user must be an admin" : "ورود به سیستم کاربر باید مدیر سایت باشد", "Wiping of device %s has started" : "پاک کردن دستگاه%s شروع شده است", "Wiping of device »%s« has started" : "پاک کردن دستگاه%s شروع شده است", "»%s« started remote wipe" : "%sپاک کردن از راه دور", @@ -57,7 +53,7 @@ OC.L10N.register( "Invalid image" : "عکس نامعتبر", "Avatar image is not square" : "تصویر آواتار مربع نیست", "Files" : "پوشهها", - "View profile" : "مشاهده پروفایل", + "View profile" : "مشاهدهٔ نمایه", "Local time: %s" : "Local time: %s", "today" : "امروز", "tomorrow" : "فردا", @@ -118,22 +114,15 @@ OC.L10N.register( "Headline" : "عنوان", "Organisation" : "سازمان", "Role" : "نقش", - "Unknown user" : "کاربر نامعلوم", "Additional settings" : "تنظیمات اضافی", - "Enter the database username and name for %s" : "ورود نام و نام کاربری پایگاه داده برای %s", - "Enter the database username for %s" : "ورود نام کاربری پایگاه داده برای %s", "Enter the database name for %s" : "ورود نام پایگاه داده برای %s", "You cannot use dots in the database name %s" : "نمیتوانید در در نام پایگاه دادهٔ %s از نقطه استفاده کنید", - "MySQL username and/or password not valid" : "نام کاربری یا گذرواژهٔ مایسکول معتبر نیست", "You need to enter details of an existing account." : "لازم است جزییات یک حساب موحود را وارد کنید.", "Oracle connection could not be established" : "ارتباط اراکل نمیتواند برقرار باشد.", - "Oracle username and/or password not valid" : "نام کاربری و / یا رمزعبور اراکل معتبر نیست.", - "PostgreSQL username 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! " : "مکاواس ۱۰ پشتیبانی نشده و %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 بیتی تغییر دهید.", - "Set an admin username." : "یک نام کاربری برای مدیر تنظیم نمایید.", "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را پیاده سازی کند", @@ -151,7 +140,6 @@ OC.L10N.register( "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", - "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", "%1$s shared »%2$s« with you" : "%1$s به اشتراک گذاشته » %2$s« با شما", "%1$s shared »%2$s« with you." : "%1$s به اشتراک گذاشته » %2$s« با شما", "Click the button below to open it." : "برای باز کردن آن روی دکمه زیر کلیک کنید.", @@ -204,14 +192,6 @@ OC.L10N.register( "Nov." : "نو.", "Dec." : "دس.", "A valid password must be provided" : "رمز عبور صحیح باید وارد شود", - "The username is already being used" : "نامکاربری قبلا استفاده شده است", - "Could not create user" : "نتواسنت کاربر را ایجاد کند", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", - "A valid username must be provided" : "نام کاربری صحیح باید وارد شود", - "Username contains whitespace at the beginning or at the end" : "نام کاربری دارای فضای سفید در ابتدا یا انتهای آن است", - "Username must not consist of dots only" : "نام کاربری نباید فقط از نقاط تشکیل شده باشد", - "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", - "User 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" : "خانهای امن برای تمامی دادههایتان", @@ -244,8 +224,6 @@ OC.L10N.register( "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 is readable by other users." : "Your data directory is readable by other users.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "لطفاً مجوزها را به 0770 تغییر دهید تا فهرست توسط سایر کاربران فهرست نشود.", "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.", @@ -270,12 +248,32 @@ OC.L10N.register( "Extract topics" : "Extract topics", "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "فایل های برنامه %1$sبه درستی تعویض نشد. اطمینان حاصل کنید که این یک نسخه سازگار با سرور است.", + "404" : "۴۰۴", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub admin or gotten special right to access this setting", + "Logged in user must be an admin or sub admin" : "ورود به سیستم کاربر باید یک مدیر یا مدیر فرعی باشد", + "Logged in user must be an admin" : "ورود به سیستم کاربر باید مدیر سایت باشد", "Full name" : "نام کامل", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "The user limit has been reached and the user was not created. Check your notifications to learn more.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "تنها نویسهها زیر در نام کاربری مجازند: \"a-z\" ، \"A-Z\" ، \"0-9\" و \"_. @ - '\"", + "Unknown user" : "کاربر نامعلوم", + "Enter the database username and name for %s" : "ورود نام و نام کاربری پایگاه داده برای %s", + "Enter the database username for %s" : "ورود نام کاربری پایگاه داده برای %s", + "MySQL username and/or password not valid" : "نام کاربری یا گذرواژهٔ مایسکول معتبر نیست", + "Oracle username and/or password not valid" : "نام کاربری و / یا رمزعبور اراکل معتبر نیست.", + "PostgreSQL username and/or password not valid" : "PostgreSQL نام کاربری و / یا رمزعبور معتبر نیست.", + "Set an admin username." : "یک نام کاربری برای مدیر تنظیم نمایید.", + "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", + "The username is already being used" : "نامکاربری قبلا استفاده شده است", + "Could not create user" : "نتواسنت کاربر را ایجاد کند", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", + "A valid username must be provided" : "نام کاربری صحیح باید وارد شود", + "Username contains whitespace at the beginning or at the end" : "نام کاربری دارای فضای سفید در ابتدا یا انتهای آن است", + "Username must not consist of dots only" : "نام کاربری نباید فقط از نقاط تشکیل شده باشد", + "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", + "User disabled" : "کاربر از کار افتاده", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 حداقل مورد نیاز است. در حال حاضر %sنصب شده است", "To fix this issue update your libxml2 version and restart your web server." : "برای رفع این مشکل نسخه libxml2 خود را به روز کنید و سرور وب خود را مجدداً راه اندازی کنید.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 required.", - "Please upgrade your database version." : "Please upgrade your database version." + "Please upgrade your database version." : "Please upgrade your database version.", + "Your data directory is readable by other users." : "Your data directory is readable by other users.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "لطفاً مجوزها را به 0770 تغییر دهید تا فهرست توسط سایر کاربران فهرست نشود." }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/fa.json b/lib/l10n/fa.json index a5024351f34..f519eb24ed5 100644 --- a/lib/l10n/fa.json +++ b/lib/l10n/fa.json @@ -6,7 +6,6 @@ "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.", "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 ، اسناد را بخوانید", - "404" : "۴۰۴", "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", @@ -35,9 +34,6 @@ "The following platforms are supported: %s" : "بنسازههای زیر پشتیبانی میشوند: %s", "Server version %s or higher is required." : "نیاز به کارساز با نگارش %s یا بالاتر.", "Server version %s or lower is required." : "نیاز به کارساز با نگارش %s یا پایینتر.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub admin or gotten special right to access this setting", - "Logged in user must be an admin or sub admin" : "ورود به سیستم کاربر باید یک مدیر یا مدیر فرعی باشد", - "Logged in user must be an admin" : "ورود به سیستم کاربر باید مدیر سایت باشد", "Wiping of device %s has started" : "پاک کردن دستگاه%s شروع شده است", "Wiping of device »%s« has started" : "پاک کردن دستگاه%s شروع شده است", "»%s« started remote wipe" : "%sپاک کردن از راه دور", @@ -55,7 +51,7 @@ "Invalid image" : "عکس نامعتبر", "Avatar image is not square" : "تصویر آواتار مربع نیست", "Files" : "پوشهها", - "View profile" : "مشاهده پروفایل", + "View profile" : "مشاهدهٔ نمایه", "Local time: %s" : "Local time: %s", "today" : "امروز", "tomorrow" : "فردا", @@ -116,22 +112,15 @@ "Headline" : "عنوان", "Organisation" : "سازمان", "Role" : "نقش", - "Unknown user" : "کاربر نامعلوم", "Additional settings" : "تنظیمات اضافی", - "Enter the database username and name for %s" : "ورود نام و نام کاربری پایگاه داده برای %s", - "Enter the database username for %s" : "ورود نام کاربری پایگاه داده برای %s", "Enter the database name for %s" : "ورود نام پایگاه داده برای %s", "You cannot use dots in the database name %s" : "نمیتوانید در در نام پایگاه دادهٔ %s از نقطه استفاده کنید", - "MySQL username and/or password not valid" : "نام کاربری یا گذرواژهٔ مایسکول معتبر نیست", "You need to enter details of an existing account." : "لازم است جزییات یک حساب موحود را وارد کنید.", "Oracle connection could not be established" : "ارتباط اراکل نمیتواند برقرار باشد.", - "Oracle username and/or password not valid" : "نام کاربری و / یا رمزعبور اراکل معتبر نیست.", - "PostgreSQL username 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! " : "مکاواس ۱۰ پشتیبانی نشده و %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 بیتی تغییر دهید.", - "Set an admin username." : "یک نام کاربری برای مدیر تنظیم نمایید.", "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را پیاده سازی کند", @@ -149,7 +138,6 @@ "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", - "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", "%1$s shared »%2$s« with you" : "%1$s به اشتراک گذاشته » %2$s« با شما", "%1$s shared »%2$s« with you." : "%1$s به اشتراک گذاشته » %2$s« با شما", "Click the button below to open it." : "برای باز کردن آن روی دکمه زیر کلیک کنید.", @@ -202,14 +190,6 @@ "Nov." : "نو.", "Dec." : "دس.", "A valid password must be provided" : "رمز عبور صحیح باید وارد شود", - "The username is already being used" : "نامکاربری قبلا استفاده شده است", - "Could not create user" : "نتواسنت کاربر را ایجاد کند", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", - "A valid username must be provided" : "نام کاربری صحیح باید وارد شود", - "Username contains whitespace at the beginning or at the end" : "نام کاربری دارای فضای سفید در ابتدا یا انتهای آن است", - "Username must not consist of dots only" : "نام کاربری نباید فقط از نقاط تشکیل شده باشد", - "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", - "User 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" : "خانهای امن برای تمامی دادههایتان", @@ -242,8 +222,6 @@ "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 is readable by other users." : "Your data directory is readable by other users.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "لطفاً مجوزها را به 0770 تغییر دهید تا فهرست توسط سایر کاربران فهرست نشود.", "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.", @@ -268,12 +246,32 @@ "Extract topics" : "Extract topics", "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "فایل های برنامه %1$sبه درستی تعویض نشد. اطمینان حاصل کنید که این یک نسخه سازگار با سرور است.", + "404" : "۴۰۴", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub admin or gotten special right to access this setting", + "Logged in user must be an admin or sub admin" : "ورود به سیستم کاربر باید یک مدیر یا مدیر فرعی باشد", + "Logged in user must be an admin" : "ورود به سیستم کاربر باید مدیر سایت باشد", "Full name" : "نام کامل", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "The user limit has been reached and the user was not created. Check your notifications to learn more.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "تنها نویسهها زیر در نام کاربری مجازند: \"a-z\" ، \"A-Z\" ، \"0-9\" و \"_. @ - '\"", + "Unknown user" : "کاربر نامعلوم", + "Enter the database username and name for %s" : "ورود نام و نام کاربری پایگاه داده برای %s", + "Enter the database username for %s" : "ورود نام کاربری پایگاه داده برای %s", + "MySQL username and/or password not valid" : "نام کاربری یا گذرواژهٔ مایسکول معتبر نیست", + "Oracle username and/or password not valid" : "نام کاربری و / یا رمزعبور اراکل معتبر نیست.", + "PostgreSQL username and/or password not valid" : "PostgreSQL نام کاربری و / یا رمزعبور معتبر نیست.", + "Set an admin username." : "یک نام کاربری برای مدیر تنظیم نمایید.", + "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", + "The username is already being used" : "نامکاربری قبلا استفاده شده است", + "Could not create user" : "نتواسنت کاربر را ایجاد کند", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", + "A valid username must be provided" : "نام کاربری صحیح باید وارد شود", + "Username contains whitespace at the beginning or at the end" : "نام کاربری دارای فضای سفید در ابتدا یا انتهای آن است", + "Username must not consist of dots only" : "نام کاربری نباید فقط از نقاط تشکیل شده باشد", + "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", + "User disabled" : "کاربر از کار افتاده", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 حداقل مورد نیاز است. در حال حاضر %sنصب شده است", "To fix this issue update your libxml2 version and restart your web server." : "برای رفع این مشکل نسخه libxml2 خود را به روز کنید و سرور وب خود را مجدداً راه اندازی کنید.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 required.", - "Please upgrade your database version." : "Please upgrade your database version." + "Please upgrade your database version." : "Please upgrade your database version.", + "Your data directory is readable by other users." : "Your data directory is readable by other users.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "لطفاً مجوزها را به 0770 تغییر دهید تا فهرست توسط سایر کاربران فهرست نشود." },"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 7eb441edd14..8253908ab8f 100644 --- a/lib/l10n/fi.js +++ b/lib/l10n/fi.js @@ -6,7 +6,6 @@ OC.L10N.register( "See %s" : "Katso %s", "Sample configuration detected" : "Esimerkkimääritykset havaittu", "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" : "On havaittu, että esimerkkimäärityksen on kopioitu. Se voi rikkoa asennuksesi, eikä sitä tueta. Lue ohjeet ennen kuin muutat config.php tiedostoa.", - "404" : "404", "The page could not be found on the server." : "Sivua ei löytynyt palvelimelta.", "Email verification" : "Sähköpostin vahvistus", "Click the following button to confirm your email." : "Napsauta seuraavaa painiketta vahvistaaksesi sähköpostiosoitteesi.", @@ -27,7 +26,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Seuraavat alustat ovat tuettuja: %s", "Server version %s or higher is required." : "Palvelinversio %s tai sitä uudempi vaaditaan.", "Server version %s or lower is required." : "Palvelinversio %s tai alhaisempi vaaditaan.", - "Logged in user must be an admin" : "Sisäänkirjautuneen käyttäjän tulee olla ylläpitäjä", "Wiping of device %s has started" : "Laitteen %s tyhjennys aloitettiin", "Wiping of device »%s« has started" : "Laitteen »%s« tyhjennys aloitettiin", "»%s« started remote wipe" : "»%s« aloitti etätyhjennyksen", @@ -103,18 +101,13 @@ OC.L10N.register( "Headline" : "Otsikko", "Organisation" : "Organisaatio", "Role" : "Rooli", - "Unknown user" : "Tuntematon käyttäjä", "Additional settings" : "Lisäasetukset", - "MySQL username and/or password not valid" : "MySQL-käyttäjätunnus ja/tai -salasana on väärin", "You need to enter details of an existing account." : "Anna olemassa olevan tilin tiedot.", "Oracle connection could not be established" : "Oracle-yhteyttä ei voitu muodostaa", - "Oracle username and/or password not valid" : "Oraclen käyttäjätunnus ja/tai salasana on väärin", - "PostgreSQL username and/or password not valid" : "PostgreSQL:n käyttäjätunnus ja/tai salasana on väärin", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X ei ole tuettu, joten %s ei toimi kunnolla tällä alustalla. Käytä omalla vastuulla!", "For the best results, please consider using a GNU/Linux server instead." : "Käytä parhaan lopputuloksen saamiseksi GNU/Linux-palvelinta.", "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." : "Vaikuttaa siltä, että tämä %s-instanssi toimii 32-bittisessä PHP-ympäristössä ja open_basedir-asetus on määritetty php.ini-tiedostossa. Tämä johtaa ongelmiin yli 4 gigatavun tiedostojen kanssa, eikä siksi ole suositeltavaa.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Poista open_basedir-asetus php.ini-tiedostosta tai vaihda 64-bittiseen PHP:hen.", - "Set an admin username." : "Aseta ylläpitäjän käyttäjätunnus.", "Set an admin password." : "Aseta ylläpitäjän salasana.", "Sharing backend %s not found" : "Jakamisen taustaosaa %s ei löytynyt", "Sharing backend for %s not found" : "Jakamisen taustaosaa kohteelle %s ei löytynyt", @@ -130,7 +123,6 @@ OC.L10N.register( "Expiration date is in the past" : "Vanhenemispäivä on menneisyydessä", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Vanhenemispäivän voi asettaa korkeintaan %n päivään tulevaisuuteen","Vanhenemispäivän voi asettaa korkeintaan %n päivään tulevaisuuteen"], "Sharing is only allowed with group members" : "Jakaminen on sallittu vain ryhmäjäsenten kesken", - "Sharing %s failed, because this item is already shared with user %s" : "Kohteen %s jakaminen epäonnistui, koska kohde on jo jaettu käyttäjän %s kanssa", "%1$s shared »%2$s« with you" : "%1$s jakoi kohteen »%2$s« kanssasi", "%1$s shared »%2$s« with you." : "%1$s jakoi kohteen »%2$s« kanssasi.", "Click the button below to open it." : "Napsauta alla olevaa painiketta avataksesi sen.", @@ -183,14 +175,6 @@ OC.L10N.register( "Nov." : "Marras", "Dec." : "Joulu", "A valid password must be provided" : "Anna kelvollinen salasana", - "The username is already being used" : "Käyttäjätunnus on jo käytössä", - "Could not create user" : "Ei voitu luoda käyttäjää", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\", välilyönnit ja \"_.@-'\"", - "A valid username must be provided" : "Anna kelvollinen käyttäjätunnus", - "Username contains whitespace at the beginning or at the end" : "Käyttäjätunnus sisältää tyhjätilaa joko alussa tai lopussa", - "Username must not consist of dots only" : "Käyttäjänimi ei voi koostua vain pisteistä", - "Username is invalid because files already exist for this user" : "Käyttäjänimi on virheellinen koska tiedostoja on olemassa tälle käyttäjälle", - "User disabled" : "Käyttäjä poistettu käytöstä", "Login canceled by app" : "Kirjautuminen peruttiin sovelluksen toimesta", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Sovellusta \"%1$s\" ei voi asentaa, koska seuraavat riippuvuudet eivät täyty: %2$s", "a safe home for all your data" : "turvallinen koti kaikille tiedostoillesi", @@ -215,7 +199,6 @@ OC.L10N.register( "PHP modules have been installed, but they are still listed as missing?" : "PHP-moduulit on asennettu, mutta ovatko ne vieläkin listattu puuttuviksi?", "Please ask your server administrator to restart the web server." : "Pyydä palvelimen ylläpitäjää käynnistämään web-palvelin uudelleen.", "Please ask your server administrator to check the Nextcloud configuration." : "Pyydä palvelimen ylläpitäjää tarkastamaan Nextcloudin määritykset.", - "Your data directory is readable by other users." : "Datahakemistosi on muiden käyttäjien luettavissa.", "Your data directory must be an absolute path." : "Datahakemiston tulee olla absoluuttinen polku.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Varmista että datahakemiston juuressa on tiedosto nimeltä \".ocdata\".", "Action \"%s\" not supported or implemented." : "Toiminto \"%s\" ei ole tuettu tai sitä ei ole toteutettu.", @@ -226,12 +209,27 @@ OC.L10N.register( "Storage is temporarily not available" : "Tallennustila on tilapäisesti pois käytöstä", "Storage connection timeout. %s" : "Tallennustilan yhteyden aikakatkaisu. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Sovelluksen %1$s tiedostoja ei korvattu oikein Varmista, että sen versio on yhteensopiva palvelimen kanssa.", + "404" : "404", + "Logged in user must be an admin" : "Sisäänkirjautuneen käyttäjän tulee olla ylläpitäjä", "Full name" : "Koko nimi", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Käyttäjää ei luotu, koska käyttäjäraja on tullut täyteen. Tarkista ilmoitukset saadaksesi lisätietoja.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\" ja \"_.@-'\"", + "Unknown user" : "Tuntematon käyttäjä", + "MySQL username and/or password not valid" : "MySQL-käyttäjätunnus ja/tai -salasana on väärin", + "Oracle username and/or password not valid" : "Oraclen käyttäjätunnus ja/tai salasana on väärin", + "PostgreSQL username and/or password not valid" : "PostgreSQL:n käyttäjätunnus ja/tai salasana on väärin", + "Set an admin username." : "Aseta ylläpitäjän käyttäjätunnus.", + "Sharing %s failed, because this item is already shared with user %s" : "Kohteen %s jakaminen epäonnistui, koska kohde on jo jaettu käyttäjän %s kanssa", + "The username is already being used" : "Käyttäjätunnus on jo käytössä", + "Could not create user" : "Ei voitu luoda käyttäjää", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\", välilyönnit ja \"_.@-'\"", + "A valid username must be provided" : "Anna kelvollinen käyttäjätunnus", + "Username contains whitespace at the beginning or at the end" : "Käyttäjätunnus sisältää tyhjätilaa joko alussa tai lopussa", + "Username must not consist of dots only" : "Käyttäjänimi ei voi koostua vain pisteistä", + "Username is invalid because files already exist for this user" : "Käyttäjänimi on virheellinen koska tiedostoja on olemassa tälle käyttäjälle", + "User disabled" : "Käyttäjä poistettu käytöstä", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Vähintään libxml2 2.7.0 vaaditaan. %s on asennettu.", "To fix this issue update your libxml2 version and restart your web server." : "Päivitä libxml2:n versio ja käynnistä http-palvelin uudelleen.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 vaaditaan.", - "Please upgrade your database version." : "Päivitä tietokannan versio." + "Please upgrade your database version." : "Päivitä tietokannan versio.", + "Your data directory is readable by other users." : "Datahakemistosi on muiden käyttäjien luettavissa." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/fi.json b/lib/l10n/fi.json index 3ec59a0eff9..0dd4ef0ee8e 100644 --- a/lib/l10n/fi.json +++ b/lib/l10n/fi.json @@ -4,7 +4,6 @@ "See %s" : "Katso %s", "Sample configuration detected" : "Esimerkkimääritykset havaittu", "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" : "On havaittu, että esimerkkimäärityksen on kopioitu. Se voi rikkoa asennuksesi, eikä sitä tueta. Lue ohjeet ennen kuin muutat config.php tiedostoa.", - "404" : "404", "The page could not be found on the server." : "Sivua ei löytynyt palvelimelta.", "Email verification" : "Sähköpostin vahvistus", "Click the following button to confirm your email." : "Napsauta seuraavaa painiketta vahvistaaksesi sähköpostiosoitteesi.", @@ -25,7 +24,6 @@ "The following platforms are supported: %s" : "Seuraavat alustat ovat tuettuja: %s", "Server version %s or higher is required." : "Palvelinversio %s tai sitä uudempi vaaditaan.", "Server version %s or lower is required." : "Palvelinversio %s tai alhaisempi vaaditaan.", - "Logged in user must be an admin" : "Sisäänkirjautuneen käyttäjän tulee olla ylläpitäjä", "Wiping of device %s has started" : "Laitteen %s tyhjennys aloitettiin", "Wiping of device »%s« has started" : "Laitteen »%s« tyhjennys aloitettiin", "»%s« started remote wipe" : "»%s« aloitti etätyhjennyksen", @@ -101,18 +99,13 @@ "Headline" : "Otsikko", "Organisation" : "Organisaatio", "Role" : "Rooli", - "Unknown user" : "Tuntematon käyttäjä", "Additional settings" : "Lisäasetukset", - "MySQL username and/or password not valid" : "MySQL-käyttäjätunnus ja/tai -salasana on väärin", "You need to enter details of an existing account." : "Anna olemassa olevan tilin tiedot.", "Oracle connection could not be established" : "Oracle-yhteyttä ei voitu muodostaa", - "Oracle username and/or password not valid" : "Oraclen käyttäjätunnus ja/tai salasana on väärin", - "PostgreSQL username and/or password not valid" : "PostgreSQL:n käyttäjätunnus ja/tai salasana on väärin", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X ei ole tuettu, joten %s ei toimi kunnolla tällä alustalla. Käytä omalla vastuulla!", "For the best results, please consider using a GNU/Linux server instead." : "Käytä parhaan lopputuloksen saamiseksi GNU/Linux-palvelinta.", "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." : "Vaikuttaa siltä, että tämä %s-instanssi toimii 32-bittisessä PHP-ympäristössä ja open_basedir-asetus on määritetty php.ini-tiedostossa. Tämä johtaa ongelmiin yli 4 gigatavun tiedostojen kanssa, eikä siksi ole suositeltavaa.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Poista open_basedir-asetus php.ini-tiedostosta tai vaihda 64-bittiseen PHP:hen.", - "Set an admin username." : "Aseta ylläpitäjän käyttäjätunnus.", "Set an admin password." : "Aseta ylläpitäjän salasana.", "Sharing backend %s not found" : "Jakamisen taustaosaa %s ei löytynyt", "Sharing backend for %s not found" : "Jakamisen taustaosaa kohteelle %s ei löytynyt", @@ -128,7 +121,6 @@ "Expiration date is in the past" : "Vanhenemispäivä on menneisyydessä", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Vanhenemispäivän voi asettaa korkeintaan %n päivään tulevaisuuteen","Vanhenemispäivän voi asettaa korkeintaan %n päivään tulevaisuuteen"], "Sharing is only allowed with group members" : "Jakaminen on sallittu vain ryhmäjäsenten kesken", - "Sharing %s failed, because this item is already shared with user %s" : "Kohteen %s jakaminen epäonnistui, koska kohde on jo jaettu käyttäjän %s kanssa", "%1$s shared »%2$s« with you" : "%1$s jakoi kohteen »%2$s« kanssasi", "%1$s shared »%2$s« with you." : "%1$s jakoi kohteen »%2$s« kanssasi.", "Click the button below to open it." : "Napsauta alla olevaa painiketta avataksesi sen.", @@ -181,14 +173,6 @@ "Nov." : "Marras", "Dec." : "Joulu", "A valid password must be provided" : "Anna kelvollinen salasana", - "The username is already being used" : "Käyttäjätunnus on jo käytössä", - "Could not create user" : "Ei voitu luoda käyttäjää", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\", välilyönnit ja \"_.@-'\"", - "A valid username must be provided" : "Anna kelvollinen käyttäjätunnus", - "Username contains whitespace at the beginning or at the end" : "Käyttäjätunnus sisältää tyhjätilaa joko alussa tai lopussa", - "Username must not consist of dots only" : "Käyttäjänimi ei voi koostua vain pisteistä", - "Username is invalid because files already exist for this user" : "Käyttäjänimi on virheellinen koska tiedostoja on olemassa tälle käyttäjälle", - "User disabled" : "Käyttäjä poistettu käytöstä", "Login canceled by app" : "Kirjautuminen peruttiin sovelluksen toimesta", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Sovellusta \"%1$s\" ei voi asentaa, koska seuraavat riippuvuudet eivät täyty: %2$s", "a safe home for all your data" : "turvallinen koti kaikille tiedostoillesi", @@ -213,7 +197,6 @@ "PHP modules have been installed, but they are still listed as missing?" : "PHP-moduulit on asennettu, mutta ovatko ne vieläkin listattu puuttuviksi?", "Please ask your server administrator to restart the web server." : "Pyydä palvelimen ylläpitäjää käynnistämään web-palvelin uudelleen.", "Please ask your server administrator to check the Nextcloud configuration." : "Pyydä palvelimen ylläpitäjää tarkastamaan Nextcloudin määritykset.", - "Your data directory is readable by other users." : "Datahakemistosi on muiden käyttäjien luettavissa.", "Your data directory must be an absolute path." : "Datahakemiston tulee olla absoluuttinen polku.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Varmista että datahakemiston juuressa on tiedosto nimeltä \".ocdata\".", "Action \"%s\" not supported or implemented." : "Toiminto \"%s\" ei ole tuettu tai sitä ei ole toteutettu.", @@ -224,12 +207,27 @@ "Storage is temporarily not available" : "Tallennustila on tilapäisesti pois käytöstä", "Storage connection timeout. %s" : "Tallennustilan yhteyden aikakatkaisu. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Sovelluksen %1$s tiedostoja ei korvattu oikein Varmista, että sen versio on yhteensopiva palvelimen kanssa.", + "404" : "404", + "Logged in user must be an admin" : "Sisäänkirjautuneen käyttäjän tulee olla ylläpitäjä", "Full name" : "Koko nimi", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Käyttäjää ei luotu, koska käyttäjäraja on tullut täyteen. Tarkista ilmoitukset saadaksesi lisätietoja.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\" ja \"_.@-'\"", + "Unknown user" : "Tuntematon käyttäjä", + "MySQL username and/or password not valid" : "MySQL-käyttäjätunnus ja/tai -salasana on väärin", + "Oracle username and/or password not valid" : "Oraclen käyttäjätunnus ja/tai salasana on väärin", + "PostgreSQL username and/or password not valid" : "PostgreSQL:n käyttäjätunnus ja/tai salasana on väärin", + "Set an admin username." : "Aseta ylläpitäjän käyttäjätunnus.", + "Sharing %s failed, because this item is already shared with user %s" : "Kohteen %s jakaminen epäonnistui, koska kohde on jo jaettu käyttäjän %s kanssa", + "The username is already being used" : "Käyttäjätunnus on jo käytössä", + "Could not create user" : "Ei voitu luoda käyttäjää", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Vain seuraavat merkit ovat sallittuja käyttäjätunnuksessa: \"a-z\", \"A-Z\", \"0-9\", välilyönnit ja \"_.@-'\"", + "A valid username must be provided" : "Anna kelvollinen käyttäjätunnus", + "Username contains whitespace at the beginning or at the end" : "Käyttäjätunnus sisältää tyhjätilaa joko alussa tai lopussa", + "Username must not consist of dots only" : "Käyttäjänimi ei voi koostua vain pisteistä", + "Username is invalid because files already exist for this user" : "Käyttäjänimi on virheellinen koska tiedostoja on olemassa tälle käyttäjälle", + "User disabled" : "Käyttäjä poistettu käytöstä", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Vähintään libxml2 2.7.0 vaaditaan. %s on asennettu.", "To fix this issue update your libxml2 version and restart your web server." : "Päivitä libxml2:n versio ja käynnistä http-palvelin uudelleen.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 vaaditaan.", - "Please upgrade your database version." : "Päivitä tietokannan versio." + "Please upgrade your database version." : "Päivitä tietokannan versio.", + "Your data directory is readable by other users." : "Datahakemistosi on muiden käyttäjien luettavissa." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/fr.js b/lib/l10n/fr.js index 412c4c86c53..11cac1289af 100644 --- a/lib/l10n/fr.js +++ b/lib/l10n/fr.js @@ -3,12 +3,11 @@ OC.L10N.register( { "Cannot write into \"config\" directory!" : "Impossible d’écrire dans le répertoire « config » !", "This can usually be fixed by giving the web server write access to the config directory." : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire de configuration.", - "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Ou, si vous préférez conserver le fichier config.php en lecture seule, définissez l'option \"config_is_read_only\" sur true.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Ou, si vous préférez conserver le fichier config.php en lecture seule, définissez l'option « config_is_read_only » sur true.", "See %s" : "Voir %s", "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "L'application %1$s n'est pas présente ou n'est pas compatible avec cette version du serveur. Veuillez vérifier le répertoire des applications.", "Sample configuration detected" : "Configuration d'exemple détectée", "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" : "Il a été détecté que la configuration donnée à titre d'exemple a été copiée. Cela peut rendre votre installation inopérante et n'est pas pris en charge. Veuillez lire la documentation avant d'effectuer des modifications dans config.php", - "404" : "404", "The page could not be found on the server." : "La page n'a pas pu être trouvée sur le serveur.", "%s email verification" : "Vérification de l'e-mail %s", "Email verification" : "Vérification de l'e-mail", @@ -22,7 +21,7 @@ OC.L10N.register( "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s et %5$s", "Education Edition" : "Édition pour l'éducation ", "Enterprise bundle" : "Pack pour entreprise", - "Groupware bundle" : "Pack pour travail collaboratif", + "Groupware bundle" : "Pack Groupware", "Hub bundle" : "Pack Nextcloud Hub", "Social sharing bundle" : "Pack pour partage social", "PHP %s or higher is required." : "PHP %s ou supérieur est requis.", @@ -37,9 +36,9 @@ OC.L10N.register( "The following platforms are supported: %s" : "Les plateformes suivantes sont prises en charge : %s", "Server version %s or higher is required." : "Un serveur de version %s ou supérieure est requis.", "Server version %s or lower is required." : "Un serveur de version %s ou inférieure est requis.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'utilisateur connecté doit être un administrateur, un sous-administrateur ou se voir accorder des droits spéciaux pour accéder à ce réglage", - "Logged in user must be an admin or sub admin" : "L'utilisateur connecté doit être administrateur ou sous-administrateur", - "Logged in user must be an admin" : "L'utilisateur connecté doit être un administrateur", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Le compte connecté doit être un administrateur, un sous-administrateur ou se voir accorder des droits spéciaux pour accéder à ce réglage", + "Logged in account must be an admin or sub admin" : "Le compte connecté doit être administrateur ou sous-administrateur", + "Logged in account must be an admin" : "Le compte connecté doit être un administrateur", "Wiping of device %s has started" : "L'effaçage de l'appareil %s a démarré", "Wiping of device »%s« has started" : "L'effaçage de l'appareil « %s » a démarré", "»%s« started remote wipe" : "« %s » a démarré l'effaçage distant", @@ -54,8 +53,8 @@ OC.L10N.register( "The remote wipe on %s has finished" : "Le nettoyage à distance de %s est terminé", "Authentication" : "Authentification", "Unknown filetype" : "Type de fichier inconnu", - "Invalid image" : "Image non valable", - "Avatar image is not square" : "L'image d'avatar n'est pas carré", + "Invalid image" : "Image invalide", + "Avatar image is not square" : "L'image d'avatar n'est pas carrée", "Files" : "Fichiers", "View profile" : "Voir le profil", "Local time: %s" : "Heure locale : %s", @@ -85,12 +84,12 @@ OC.L10N.register( "Failed to create file from template" : "Impossible de créer le fichier à partir du modèle", "Templates" : "Modèles", "File name is a reserved word" : "Ce nom de fichier est un mot réservé", - "File name contains at least one invalid character" : "Le nom de fichier contient un (des) caractère(s) non valide(s)", + "File name contains at least one invalid character" : "Le nom de fichier contient au moins un caractère invalide", "File name is too long" : "Nom de fichier trop long", "Dot files are not allowed" : "Le nom de fichier ne peut pas commencer par un point", - "Empty filename is not allowed" : "Le nom de fichier ne peut pas être vide", - "App \"%s\" cannot be installed because appinfo file cannot be read." : "L'application \"%s\" ne peut pas être installée car le fichier appinfo ne peut pas être lu.", - "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "L'application \"%s\" ne peut être installée car elle n'est pas compatible avec cette version du serveur", + "Empty filename is not allowed" : "Le nom de fichier n'est pas autorisé", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "L'application « %s » ne peut pas être installée car le fichier appinfo ne peut pas être lu.", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "L'application « %s » ne peut être installée car elle n'est pas compatible avec cette version du serveur.", "__language_name__" : "Français", "This is an automatically sent email, please do not reply." : "Ceci est un e-mail envoyé automatiquement, veuillez ne pas y répondre.", "Help" : "Aide", @@ -118,22 +117,22 @@ OC.L10N.register( "Headline" : "Titre", "Organisation" : "Organisme", "Role" : "Fonction", - "Unknown user" : "Utilisateur inconnu", + "Unknown account" : "Compte inconnu", "Additional settings" : "Paramètres supplémentaires", - "Enter the database username and name for %s" : "Entrez le nom d'utilisateur et le nom de la base de données pour %s", - "Enter the database username for %s" : "Entrez le nom d'utilisateur de la base de données pour %s", + "Enter the database Login and name for %s" : "Saisissez l'identifiant et le nom de la base de données pour %s", + "Enter the database Login for %s" : "Saisissez l'identifiant de la base de données pour %s", "Enter the database name for %s" : "Entrez le nom de la base de données pour %s", "You cannot use dots in the database name %s" : "Vous ne pouvez pas utiliser de points dans le nom de la base de données %s", - "MySQL username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base MySQL non valide(s)", + "MySQL Login and/or password not valid" : "Identifiant et/ou mot de passe MySQL invalide", "You need to enter details of an existing account." : "Vous devez indiquer les détails d'un compte existant.", "Oracle connection could not be established" : "La connexion Oracle ne peut être établie", - "Oracle username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base Oracle non valide(s)", - "PostgreSQL username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base PostgreSQL non valide(s)", + "Oracle Login and/or password not valid" : "Identifiant et/ou mot de passe Oracle invalide", + "PostgreSQL Login and/or password not valid" : "Identifiant et/ou mot de passe PostgreSQL invalide", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X n'est pas pris en charge et %s ne fonctionnera pas correctement sur cette plate-forme. Son utilisation est à vos risques et périls !", "For the best results, please consider using a GNU/Linux server instead." : "Pour obtenir les meilleurs résultats, vous devriez utiliser un serveur 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." : "Il semble que cette instance %s fonctionne sur un environnement PHP 32-bit et open_basedir a été configuré dans php.ini. Cela engendre des problèmes avec les fichiers de taille supérieure à 4 Go et est donc fortement déconseillé.", - "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Veuillez supprimer la configuration open_basedir de votre php.ini ou utiliser une version PHP 64-bit.", - "Set an admin username." : "Spécifiez un nom d'utilisateur pour l'administrateur.", + "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." : "Il semble que cette instance %s fonctionne sur un environnement PHP 32 bits et open_basedir a été configuré dans php.ini. Cela engendre des problèmes avec les fichiers de taille supérieure à 4 Go et est donc fortement déconseillé.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Veuillez retirer la configuration open_basedir de votre php.ini ou utiliser une version PHP 64-bit.", + "Set an admin Login." : "Définissez un identifiant administrateur.", "Set an admin password." : "Spécifiez un mot de passe pour l'administrateur.", "Cannot create or write into the data directory %s" : "Impossible de créer ou d'écrire dans le répertoire des données %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Le service de partage %s doit implémenter l'interface OCP\\Share_Backend", @@ -149,15 +148,16 @@ OC.L10N.register( "Files cannot be shared with delete permissions" : "Les fichiers ne peuvent pas être partagés avec les autorisations de suppression", "Files cannot be shared with create permissions" : "Les fichiers ne peuvent pas être partagés avec les autorisations de création", "Expiration date is in the past" : "La date d'expiration est dans le passé", - "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Impossible de définir la date d'expiration à dans plus de %s jour","Impossible de définir la date d'expiration à dans plus de %s jours","Impossible de définir la date d'expiration à dans plus de %s jours"], + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Impossible de définir la date d'expiration à dans plus de %n jour","Impossible de définir la date d'expiration à dans plus de %n jours","Impossible de définir la date d'expiration à dans plus de %n jours"], "Sharing is only allowed with group members" : "Le partage n'est que possible qu'avec les membres du groupe", - "Sharing %s failed, because this item is already shared with user %s" : "Impossible de partager %s car il est déjà partagé avec l'utilisateur %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Impossible de partager %s car il est déjà partagé avec le compte %s", "%1$s shared »%2$s« with you" : "%1$s a partagé « %2$s » avec vous", "%1$s shared »%2$s« with you." : "%1$s a partagé « %2$s » avec vous.", "Click the button below to open it." : "Cliquez sur le bouton ci-dessous pour l'ouvrir", "The requested share does not exist anymore" : "Le partage demandé n'existe plus", + "The requested share comes from a disabled user" : "Le partage demandé provient d'un utilisateur désactivé", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "L'utilisateur n'a pas été créé car la limite du nombre d'utilisateurs a été atteinte. Consultez vos notifications pour en savoir plus.", - "Could not find category \"%s\"" : "Impossible de trouver la catégorie \"%s\"", + "Could not find category \"%s\"" : "Impossible de trouver la catégorie « %s »", "Sunday" : "Dimanche", "Monday" : "Lundi", "Tuesday" : "Mardi", @@ -204,16 +204,16 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Déc.", "A valid password must be provided" : "Un mot de passe valide doit être saisi", - "The username is already being used" : "Ce nom d'utilisateur est déjà utilisé", - "Could not create user" : "Impossible de créer l'utilisateur", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", espaces et \"_.@-'\"", - "A valid username must be provided" : "Un nom d'utilisateur valide doit être saisi", - "Username contains whitespace at the beginning or at the end" : "Le nom d'utilisateur contient des espaces au début ou à la fin", - "Username must not consist of dots only" : "Le nom d'utilisateur ne doit pas être composé uniquement de points", - "Username is invalid because files already exist for this user" : "Ce nom d'utilisateur n'est pas valide car des fichiers existent déjà pour cet utilisateur", - "User disabled" : "Utilisateur désactivé", - "Login canceled by app" : "L'authentification a été annulé par l'application", - "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "L'application \"%1$s\" ne peut pas être installée à cause des dépendances suivantes non satisfaites : %2$s", + "The Login is already being used" : "L'identifiant est déjà utilisé", + "Could not create account" : "Impossible de créer le compte", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un identifiant : \"a-z\", \"A-Z\", \"0-9\", espaces et \"_.@-'\"", + "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", + "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", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "L'application « %1$s » ne peut pas être installée à cause des dépendances suivantes non satisfaites : %2$s", "a safe home for all your data" : "un lieu sûr pour toutes vos données", "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", @@ -221,10 +221,10 @@ OC.L10N.register( "Authentication error" : "Erreur d'authentification", "Token expired. Please reload page." : "La session a expiré. Veuillez recharger la page.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Aucun pilote de base de données n’est installé (sqlite, mysql ou postgresql).", - "Cannot write into \"config\" directory." : "Impossible d’écrire dans le répertoire \"config\".", - "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire \"config\". Voir %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" : "Ou, si vous préférez conserver le fichier config.php en lecture seule, définissez l'option \"config_is_read_only\" sur true. Voir %s", - "Cannot write into \"apps\" directory." : "Impossible d'écrire dans le répertoire \"apps\".", + "Cannot write into \"config\" directory." : "Impossible d’écrire dans le répertoire « config ».", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire « config ». Voir %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" : "Ou, si vous préférez conserver le fichier config.php en lecture seule, définissez l'option « config_is_read_only » sur true. Voir %s", + "Cannot write into \"apps\" directory." : "Impossible d'écrire dans le répertoire « 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." : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire des applications ou en désactivant le magasin d'applications dans le fichier de configuration.", "Cannot create \"data\" directory." : "Impossible de créer le dossier \"data\".", "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire racine. Voir %s", @@ -234,7 +234,7 @@ OC.L10N.register( "Please install one of these locales on your system and restart your web server." : "Veuillez installer l'un de ces paramètres régionaux sur votre système et redémarrer votre serveur web.", "PHP module %s not installed." : "Le module PHP %s n’est pas installé.", "Please ask your server administrator to install the module." : "Veuillez demander à votre administrateur d’installer le module.", - "PHP setting \"%s\" is not set to \"%s\"." : "Le paramètre PHP \"%s\" n'est pas \"%s\".", + "PHP setting \"%s\" is not set to \"%s\"." : "Le paramètre PHP « %s » n'est pas « %s ».", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ajuster ce paramètre dans php.ini fera fonctionner Nextcould à nouveau", "<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 défini à <code>%s</code> alors que la valeur <code>0</code> est attendue.", "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Pour corriger ce problème définissez <code>mbstring.func_overload</code> à <code>0</code> dans votre php.ini.", @@ -244,8 +244,8 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Veuillez demander à votre administrateur serveur de redémarrer le serveur web.", "The required %s config variable is not configured in the config.php file." : "La valeur de configuration requise %s n'est pas configurée dans votre fichier config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Veuillez demander à votre administrateur serveur de vérifier la configuration de Nextcloud.", - "Your data directory is readable by other users." : "Votre répertoire est lisible par d'autres utilisateurs.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu ne puisse pas être listé par les autres utilisateurs.", + "Your data directory is readable by other people." : "Votre répertoire de données est lisible par d'autres personnes.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu ne puisse pas être listé par les autres personnes.", "Your data directory must be an absolute path." : "Le chemin de votre répertoire doit être un chemin absolu.", "Check the value of \"datadirectory\" in your configuration." : "Verifiez la valeur de \"datadirectory\" dans votre configuration.", "Your data directory is invalid." : "Votre répertoire des données n'est pas valide.", @@ -255,19 +255,47 @@ OC.L10N.register( "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Paramètres manquants pour compléter la requête. Paramètres manquants : \"%s\"", "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "L'identifiant \"%1$s\" est déjà utilisé par l'instance de Cloud Fédéré \"%2$s\"", "Cloud Federation Provider with ID: \"%s\" does not exist." : "L'instance de Cloud Fédéré dont l'identifiant est \"%s\" n'existe pas.", - "Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur \"%s\".", + "Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur « %s ».", "Storage unauthorized. %s" : "Espace de stockage non autorisé. %s", "Storage incomplete configuration. %s" : "Configuration de l'espace de stockage incomplète. %s", "Storage connection error. %s" : "Erreur de connexion à l'espace stockage. %s", "Storage is temporarily not available" : "Le support de stockage est temporairement indisponible", "Storage connection timeout. %s" : "Le délai d'attente pour la connexion à l'espace de stockage a été dépassé. %s", + "Free prompt" : "Prompt", + "Runs an arbitrary prompt through the language model." : "Exécute une commande arbitraire via le modèle de langage.", + "Generate headline" : "Générer un titre", + "Generates a possible headline for a text." : "Génère un titre possible pour un texte.", + "Summarize" : "Résumer", + "Summarizes text by reducing its length without losing key information." : "Résume un texte en réduisant sa longueur sans perdre d'informations essentielles.", + "Extract topics" : "Extraire des thèmes", + "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.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Les fichiers de l'application %1$s n'ont pas été remplacés correctement. Veuillez vérifier que c'est une version compatible avec le serveur.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'utilisateur connecté doit être un administrateur, un sous-administrateur ou se voir accorder des droits spéciaux pour accéder à ce réglage", + "Logged in user must be an admin or sub admin" : "L'utilisateur connecté doit être administrateur ou sous-administrateur", + "Logged in user must be an admin" : "L'utilisateur connecté doit être un administrateur", "Full name" : "Nom complet", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "La limite d'utilisateurs à été atteinte et cet utilisateur n'a pas été créé. Consultez vos notifications pour en savoir plus.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", \"_@-\" et \".\" (le point)", + "Unknown user" : "Utilisateur inconnu", + "Enter the database username and name for %s" : "Entrez le nom d'utilisateur et le nom de la base de données pour %s", + "Enter the database username for %s" : "Entrez le nom d'utilisateur de la base de données pour %s", + "MySQL username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base MySQL non valide(s)", + "Oracle username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base Oracle non valide(s)", + "PostgreSQL username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base PostgreSQL non valide(s)", + "Set an admin username." : "Spécifiez un nom d'utilisateur pour l'administrateur.", + "Sharing %s failed, because this item is already shared with user %s" : "Impossible de partager %s car il est déjà partagé avec l'utilisateur %s", + "The username is already being used" : "Ce nom d'utilisateur est déjà utilisé", + "Could not create user" : "Impossible de créer l'utilisateur", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", espaces et \"_.@-'\"", + "A valid username must be provided" : "Un nom d'utilisateur valide doit être saisi", + "Username contains whitespace at the beginning or at the end" : "Le nom d'utilisateur contient des espaces au début ou à la fin", + "Username must not consist of dots only" : "Le nom d'utilisateur ne doit pas être composé uniquement de points", + "Username is invalid because files already exist for this user" : "Ce nom d'utilisateur n'est pas valide car des fichiers existent déjà pour cet utilisateur", + "User disabled" : "Utilisateur désactivé", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 au moins est requis. Actuellement %s est installé.", "To fix this issue update your libxml2 version and restart your web server." : "Pour régler ce problème, mettez à jour votre version de libxml2 et redémarrez votre serveur web.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 requis.", - "Please upgrade your database version." : "Veuillez mettre à jour votre gestionnaire de base de données." + "Please upgrade your database version." : "Veuillez mettre à jour votre gestionnaire de base de données.", + "Your data directory is readable by other users." : "Votre répertoire est lisible par d'autres utilisateurs.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu ne puisse pas être listé par les autres utilisateurs." }, "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 6d75989d48e..512f87baf42 100644 --- a/lib/l10n/fr.json +++ b/lib/l10n/fr.json @@ -1,12 +1,11 @@ { "translations": { "Cannot write into \"config\" directory!" : "Impossible d’écrire dans le répertoire « config » !", "This can usually be fixed by giving the web server write access to the config directory." : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire de configuration.", - "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Ou, si vous préférez conserver le fichier config.php en lecture seule, définissez l'option \"config_is_read_only\" sur true.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Ou, si vous préférez conserver le fichier config.php en lecture seule, définissez l'option « config_is_read_only » sur true.", "See %s" : "Voir %s", "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "L'application %1$s n'est pas présente ou n'est pas compatible avec cette version du serveur. Veuillez vérifier le répertoire des applications.", "Sample configuration detected" : "Configuration d'exemple détectée", "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" : "Il a été détecté que la configuration donnée à titre d'exemple a été copiée. Cela peut rendre votre installation inopérante et n'est pas pris en charge. Veuillez lire la documentation avant d'effectuer des modifications dans config.php", - "404" : "404", "The page could not be found on the server." : "La page n'a pas pu être trouvée sur le serveur.", "%s email verification" : "Vérification de l'e-mail %s", "Email verification" : "Vérification de l'e-mail", @@ -20,7 +19,7 @@ "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s et %5$s", "Education Edition" : "Édition pour l'éducation ", "Enterprise bundle" : "Pack pour entreprise", - "Groupware bundle" : "Pack pour travail collaboratif", + "Groupware bundle" : "Pack Groupware", "Hub bundle" : "Pack Nextcloud Hub", "Social sharing bundle" : "Pack pour partage social", "PHP %s or higher is required." : "PHP %s ou supérieur est requis.", @@ -35,9 +34,9 @@ "The following platforms are supported: %s" : "Les plateformes suivantes sont prises en charge : %s", "Server version %s or higher is required." : "Un serveur de version %s ou supérieure est requis.", "Server version %s or lower is required." : "Un serveur de version %s ou inférieure est requis.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'utilisateur connecté doit être un administrateur, un sous-administrateur ou se voir accorder des droits spéciaux pour accéder à ce réglage", - "Logged in user must be an admin or sub admin" : "L'utilisateur connecté doit être administrateur ou sous-administrateur", - "Logged in user must be an admin" : "L'utilisateur connecté doit être un administrateur", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Le compte connecté doit être un administrateur, un sous-administrateur ou se voir accorder des droits spéciaux pour accéder à ce réglage", + "Logged in account must be an admin or sub admin" : "Le compte connecté doit être administrateur ou sous-administrateur", + "Logged in account must be an admin" : "Le compte connecté doit être un administrateur", "Wiping of device %s has started" : "L'effaçage de l'appareil %s a démarré", "Wiping of device »%s« has started" : "L'effaçage de l'appareil « %s » a démarré", "»%s« started remote wipe" : "« %s » a démarré l'effaçage distant", @@ -52,8 +51,8 @@ "The remote wipe on %s has finished" : "Le nettoyage à distance de %s est terminé", "Authentication" : "Authentification", "Unknown filetype" : "Type de fichier inconnu", - "Invalid image" : "Image non valable", - "Avatar image is not square" : "L'image d'avatar n'est pas carré", + "Invalid image" : "Image invalide", + "Avatar image is not square" : "L'image d'avatar n'est pas carrée", "Files" : "Fichiers", "View profile" : "Voir le profil", "Local time: %s" : "Heure locale : %s", @@ -83,12 +82,12 @@ "Failed to create file from template" : "Impossible de créer le fichier à partir du modèle", "Templates" : "Modèles", "File name is a reserved word" : "Ce nom de fichier est un mot réservé", - "File name contains at least one invalid character" : "Le nom de fichier contient un (des) caractère(s) non valide(s)", + "File name contains at least one invalid character" : "Le nom de fichier contient au moins un caractère invalide", "File name is too long" : "Nom de fichier trop long", "Dot files are not allowed" : "Le nom de fichier ne peut pas commencer par un point", - "Empty filename is not allowed" : "Le nom de fichier ne peut pas être vide", - "App \"%s\" cannot be installed because appinfo file cannot be read." : "L'application \"%s\" ne peut pas être installée car le fichier appinfo ne peut pas être lu.", - "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "L'application \"%s\" ne peut être installée car elle n'est pas compatible avec cette version du serveur", + "Empty filename is not allowed" : "Le nom de fichier n'est pas autorisé", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "L'application « %s » ne peut pas être installée car le fichier appinfo ne peut pas être lu.", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "L'application « %s » ne peut être installée car elle n'est pas compatible avec cette version du serveur.", "__language_name__" : "Français", "This is an automatically sent email, please do not reply." : "Ceci est un e-mail envoyé automatiquement, veuillez ne pas y répondre.", "Help" : "Aide", @@ -116,22 +115,22 @@ "Headline" : "Titre", "Organisation" : "Organisme", "Role" : "Fonction", - "Unknown user" : "Utilisateur inconnu", + "Unknown account" : "Compte inconnu", "Additional settings" : "Paramètres supplémentaires", - "Enter the database username and name for %s" : "Entrez le nom d'utilisateur et le nom de la base de données pour %s", - "Enter the database username for %s" : "Entrez le nom d'utilisateur de la base de données pour %s", + "Enter the database Login and name for %s" : "Saisissez l'identifiant et le nom de la base de données pour %s", + "Enter the database Login for %s" : "Saisissez l'identifiant de la base de données pour %s", "Enter the database name for %s" : "Entrez le nom de la base de données pour %s", "You cannot use dots in the database name %s" : "Vous ne pouvez pas utiliser de points dans le nom de la base de données %s", - "MySQL username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base MySQL non valide(s)", + "MySQL Login and/or password not valid" : "Identifiant et/ou mot de passe MySQL invalide", "You need to enter details of an existing account." : "Vous devez indiquer les détails d'un compte existant.", "Oracle connection could not be established" : "La connexion Oracle ne peut être établie", - "Oracle username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base Oracle non valide(s)", - "PostgreSQL username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base PostgreSQL non valide(s)", + "Oracle Login and/or password not valid" : "Identifiant et/ou mot de passe Oracle invalide", + "PostgreSQL Login and/or password not valid" : "Identifiant et/ou mot de passe PostgreSQL invalide", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X n'est pas pris en charge et %s ne fonctionnera pas correctement sur cette plate-forme. Son utilisation est à vos risques et périls !", "For the best results, please consider using a GNU/Linux server instead." : "Pour obtenir les meilleurs résultats, vous devriez utiliser un serveur 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." : "Il semble que cette instance %s fonctionne sur un environnement PHP 32-bit et open_basedir a été configuré dans php.ini. Cela engendre des problèmes avec les fichiers de taille supérieure à 4 Go et est donc fortement déconseillé.", - "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Veuillez supprimer la configuration open_basedir de votre php.ini ou utiliser une version PHP 64-bit.", - "Set an admin username." : "Spécifiez un nom d'utilisateur pour l'administrateur.", + "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." : "Il semble que cette instance %s fonctionne sur un environnement PHP 32 bits et open_basedir a été configuré dans php.ini. Cela engendre des problèmes avec les fichiers de taille supérieure à 4 Go et est donc fortement déconseillé.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Veuillez retirer la configuration open_basedir de votre php.ini ou utiliser une version PHP 64-bit.", + "Set an admin Login." : "Définissez un identifiant administrateur.", "Set an admin password." : "Spécifiez un mot de passe pour l'administrateur.", "Cannot create or write into the data directory %s" : "Impossible de créer ou d'écrire dans le répertoire des données %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Le service de partage %s doit implémenter l'interface OCP\\Share_Backend", @@ -147,15 +146,16 @@ "Files cannot be shared with delete permissions" : "Les fichiers ne peuvent pas être partagés avec les autorisations de suppression", "Files cannot be shared with create permissions" : "Les fichiers ne peuvent pas être partagés avec les autorisations de création", "Expiration date is in the past" : "La date d'expiration est dans le passé", - "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Impossible de définir la date d'expiration à dans plus de %s jour","Impossible de définir la date d'expiration à dans plus de %s jours","Impossible de définir la date d'expiration à dans plus de %s jours"], + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Impossible de définir la date d'expiration à dans plus de %n jour","Impossible de définir la date d'expiration à dans plus de %n jours","Impossible de définir la date d'expiration à dans plus de %n jours"], "Sharing is only allowed with group members" : "Le partage n'est que possible qu'avec les membres du groupe", - "Sharing %s failed, because this item is already shared with user %s" : "Impossible de partager %s car il est déjà partagé avec l'utilisateur %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Impossible de partager %s car il est déjà partagé avec le compte %s", "%1$s shared »%2$s« with you" : "%1$s a partagé « %2$s » avec vous", "%1$s shared »%2$s« with you." : "%1$s a partagé « %2$s » avec vous.", "Click the button below to open it." : "Cliquez sur le bouton ci-dessous pour l'ouvrir", "The requested share does not exist anymore" : "Le partage demandé n'existe plus", + "The requested share comes from a disabled user" : "Le partage demandé provient d'un utilisateur désactivé", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "L'utilisateur n'a pas été créé car la limite du nombre d'utilisateurs a été atteinte. Consultez vos notifications pour en savoir plus.", - "Could not find category \"%s\"" : "Impossible de trouver la catégorie \"%s\"", + "Could not find category \"%s\"" : "Impossible de trouver la catégorie « %s »", "Sunday" : "Dimanche", "Monday" : "Lundi", "Tuesday" : "Mardi", @@ -202,16 +202,16 @@ "Nov." : "Nov.", "Dec." : "Déc.", "A valid password must be provided" : "Un mot de passe valide doit être saisi", - "The username is already being used" : "Ce nom d'utilisateur est déjà utilisé", - "Could not create user" : "Impossible de créer l'utilisateur", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", espaces et \"_.@-'\"", - "A valid username must be provided" : "Un nom d'utilisateur valide doit être saisi", - "Username contains whitespace at the beginning or at the end" : "Le nom d'utilisateur contient des espaces au début ou à la fin", - "Username must not consist of dots only" : "Le nom d'utilisateur ne doit pas être composé uniquement de points", - "Username is invalid because files already exist for this user" : "Ce nom d'utilisateur n'est pas valide car des fichiers existent déjà pour cet utilisateur", - "User disabled" : "Utilisateur désactivé", - "Login canceled by app" : "L'authentification a été annulé par l'application", - "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "L'application \"%1$s\" ne peut pas être installée à cause des dépendances suivantes non satisfaites : %2$s", + "The Login is already being used" : "L'identifiant est déjà utilisé", + "Could not create account" : "Impossible de créer le compte", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un identifiant : \"a-z\", \"A-Z\", \"0-9\", espaces et \"_.@-'\"", + "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", + "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", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "L'application « %1$s » ne peut pas être installée à cause des dépendances suivantes non satisfaites : %2$s", "a safe home for all your data" : "un lieu sûr pour toutes vos données", "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", @@ -219,10 +219,10 @@ "Authentication error" : "Erreur d'authentification", "Token expired. Please reload page." : "La session a expiré. Veuillez recharger la page.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Aucun pilote de base de données n’est installé (sqlite, mysql ou postgresql).", - "Cannot write into \"config\" directory." : "Impossible d’écrire dans le répertoire \"config\".", - "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire \"config\". Voir %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" : "Ou, si vous préférez conserver le fichier config.php en lecture seule, définissez l'option \"config_is_read_only\" sur true. Voir %s", - "Cannot write into \"apps\" directory." : "Impossible d'écrire dans le répertoire \"apps\".", + "Cannot write into \"config\" directory." : "Impossible d’écrire dans le répertoire « config ».", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire « config ». Voir %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" : "Ou, si vous préférez conserver le fichier config.php en lecture seule, définissez l'option « config_is_read_only » sur true. Voir %s", + "Cannot write into \"apps\" directory." : "Impossible d'écrire dans le répertoire « 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." : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire des applications ou en désactivant le magasin d'applications dans le fichier de configuration.", "Cannot create \"data\" directory." : "Impossible de créer le dossier \"data\".", "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Ce problème est généralement résolu en donnant au serveur web un accès en écriture au répertoire racine. Voir %s", @@ -232,7 +232,7 @@ "Please install one of these locales on your system and restart your web server." : "Veuillez installer l'un de ces paramètres régionaux sur votre système et redémarrer votre serveur web.", "PHP module %s not installed." : "Le module PHP %s n’est pas installé.", "Please ask your server administrator to install the module." : "Veuillez demander à votre administrateur d’installer le module.", - "PHP setting \"%s\" is not set to \"%s\"." : "Le paramètre PHP \"%s\" n'est pas \"%s\".", + "PHP setting \"%s\" is not set to \"%s\"." : "Le paramètre PHP « %s » n'est pas « %s ».", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ajuster ce paramètre dans php.ini fera fonctionner Nextcould à nouveau", "<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 défini à <code>%s</code> alors que la valeur <code>0</code> est attendue.", "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Pour corriger ce problème définissez <code>mbstring.func_overload</code> à <code>0</code> dans votre php.ini.", @@ -242,8 +242,8 @@ "Please ask your server administrator to restart the web server." : "Veuillez demander à votre administrateur serveur de redémarrer le serveur web.", "The required %s config variable is not configured in the config.php file." : "La valeur de configuration requise %s n'est pas configurée dans votre fichier config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Veuillez demander à votre administrateur serveur de vérifier la configuration de Nextcloud.", - "Your data directory is readable by other users." : "Votre répertoire est lisible par d'autres utilisateurs.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu ne puisse pas être listé par les autres utilisateurs.", + "Your data directory is readable by other people." : "Votre répertoire de données est lisible par d'autres personnes.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu ne puisse pas être listé par les autres personnes.", "Your data directory must be an absolute path." : "Le chemin de votre répertoire doit être un chemin absolu.", "Check the value of \"datadirectory\" in your configuration." : "Verifiez la valeur de \"datadirectory\" dans votre configuration.", "Your data directory is invalid." : "Votre répertoire des données n'est pas valide.", @@ -253,19 +253,47 @@ "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Paramètres manquants pour compléter la requête. Paramètres manquants : \"%s\"", "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "L'identifiant \"%1$s\" est déjà utilisé par l'instance de Cloud Fédéré \"%2$s\"", "Cloud Federation Provider with ID: \"%s\" does not exist." : "L'instance de Cloud Fédéré dont l'identifiant est \"%s\" n'existe pas.", - "Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur \"%s\".", + "Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur « %s ».", "Storage unauthorized. %s" : "Espace de stockage non autorisé. %s", "Storage incomplete configuration. %s" : "Configuration de l'espace de stockage incomplète. %s", "Storage connection error. %s" : "Erreur de connexion à l'espace stockage. %s", "Storage is temporarily not available" : "Le support de stockage est temporairement indisponible", "Storage connection timeout. %s" : "Le délai d'attente pour la connexion à l'espace de stockage a été dépassé. %s", + "Free prompt" : "Prompt", + "Runs an arbitrary prompt through the language model." : "Exécute une commande arbitraire via le modèle de langage.", + "Generate headline" : "Générer un titre", + "Generates a possible headline for a text." : "Génère un titre possible pour un texte.", + "Summarize" : "Résumer", + "Summarizes text by reducing its length without losing key information." : "Résume un texte en réduisant sa longueur sans perdre d'informations essentielles.", + "Extract topics" : "Extraire des thèmes", + "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.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Les fichiers de l'application %1$s n'ont pas été remplacés correctement. Veuillez vérifier que c'est une version compatible avec le serveur.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'utilisateur connecté doit être un administrateur, un sous-administrateur ou se voir accorder des droits spéciaux pour accéder à ce réglage", + "Logged in user must be an admin or sub admin" : "L'utilisateur connecté doit être administrateur ou sous-administrateur", + "Logged in user must be an admin" : "L'utilisateur connecté doit être un administrateur", "Full name" : "Nom complet", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "La limite d'utilisateurs à été atteinte et cet utilisateur n'a pas été créé. Consultez vos notifications pour en savoir plus.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", \"_@-\" et \".\" (le point)", + "Unknown user" : "Utilisateur inconnu", + "Enter the database username and name for %s" : "Entrez le nom d'utilisateur et le nom de la base de données pour %s", + "Enter the database username for %s" : "Entrez le nom d'utilisateur de la base de données pour %s", + "MySQL username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base MySQL non valide(s)", + "Oracle username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base Oracle non valide(s)", + "PostgreSQL username and/or password not valid" : "Nom d'utilisateur et/ou mot de passe de la base PostgreSQL non valide(s)", + "Set an admin username." : "Spécifiez un nom d'utilisateur pour l'administrateur.", + "Sharing %s failed, because this item is already shared with user %s" : "Impossible de partager %s car il est déjà partagé avec l'utilisateur %s", + "The username is already being used" : "Ce nom d'utilisateur est déjà utilisé", + "Could not create user" : "Impossible de créer l'utilisateur", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Seuls les caractères suivants sont autorisés dans un nom d'utilisateur : \"a-z\", \"A-Z\", \"0-9\", espaces et \"_.@-'\"", + "A valid username must be provided" : "Un nom d'utilisateur valide doit être saisi", + "Username contains whitespace at the beginning or at the end" : "Le nom d'utilisateur contient des espaces au début ou à la fin", + "Username must not consist of dots only" : "Le nom d'utilisateur ne doit pas être composé uniquement de points", + "Username is invalid because files already exist for this user" : "Ce nom d'utilisateur n'est pas valide car des fichiers existent déjà pour cet utilisateur", + "User disabled" : "Utilisateur désactivé", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 au moins est requis. Actuellement %s est installé.", "To fix this issue update your libxml2 version and restart your web server." : "Pour régler ce problème, mettez à jour votre version de libxml2 et redémarrez votre serveur web.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 requis.", - "Please upgrade your database version." : "Veuillez mettre à jour votre gestionnaire de base de données." + "Please upgrade your database version." : "Veuillez mettre à jour votre gestionnaire de base de données.", + "Your data directory is readable by other users." : "Votre répertoire est lisible par d'autres utilisateurs.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Veuillez changer les permissions du répertoire en mode 0770 afin que son contenu ne puisse pas être listé par les autres utilisateurs." },"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/gl.js b/lib/l10n/gl.js index 46440e27bcc..c8d507882f6 100644 --- a/lib/l10n/gl.js +++ b/lib/l10n/gl.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "A aplicación %1$s non está presente ou ten unha versión non compatíbel con este servidor. Comprobe o directorio de aplicacións.", "Sample configuration detected" : "Detectouse a configuración de exemplo", "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" : "Detectouse que foi copiada a configuración de exemplo. Isto pode rachar a súa instalación e non é compatíbel. Lea a documentación antes de facer cambios en config.php", - "404" : "404", "The page could not be found on the server." : "Non foi posíbel atopar a páxina no servidor.", "%s email verification" : "Verificación do correo-e %s", "Email verification" : "Verificación do correo-e", @@ -25,21 +24,18 @@ OC.L10N.register( "Groupware bundle" : "Paquete de software colaborativo", "Hub bundle" : "Paquete de concentradores", "Social sharing bundle" : "Paquete para compartir en redes sociais", - "PHP %s or higher is required." : "Precisase PHP %s ou superior.", - "PHP with a version lower than %s is required." : "Precisase PHP cunha versión inferior a %s.", - "%sbit or higher PHP required." : "Precisase PHP para %sbits ou superior.", + "PHP %s or higher is required." : "Precísase de PHP %s ou superior.", + "PHP with a version lower than %s is required." : "Precísase de PHP cunha versión inferior a %s.", + "%sbit or higher PHP required." : "Precísase de PHP para %s bits ou superior.", "The following architectures are supported: %s" : "Admítense as seguintes arquitecturas: %s", "The following databases are supported: %s" : "Admítense as seguintes bases de datos: %s", "The command line tool %s could not be found" : "Non foi posíbel atopar a ferramenta de liña de ordes %s", "The library %s is not available." : "Non está dispoñíbel a biblioteca %s.", - "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Precisase a biblioteca %1$s cunha versión superior a %2$s - dispoñíbel a versión %3$s.", - "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Precisase a biblioteca %1$s cunha versión inferior a %2$s - dispoñíbel a versión %3$s.", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Precísase da biblioteca %1$s cunha versión superior a %2$s - dispoñíbel a versión %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Precísase da biblioteca %1$s cunha versión inferior a %2$s - dispoñíbel a versión %3$s.", "The following platforms are supported: %s" : "Admítense as seguintes plataformas: %s", - "Server version %s or higher is required." : "Precisase a versión %s ou superior do servidor.", - "Server version %s or lower is required." : "Precisase a versión %s ou inferior do servidor.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "O usuario que accede debe ser un administrador, un subadministrador ou ter un dereito especial para acceder a esta configuración", - "Logged in user must be an admin or sub admin" : "O usuario autenticado debe ser un administrador ou subadministrador", - "Logged in user must be an admin" : "O usuario conectado debe ser un administrador", + "Server version %s or higher is required." : "Precísase da versión %s ou superior do servidor.", + "Server version %s or lower is required." : "Precísase da versión %s ou inferior do servidor.", "Wiping of device %s has started" : "Iniciouse a limpeza do dispositivo %s", "Wiping of device »%s« has started" : "Iniciouse a limpeza do dispositivo «%s»", "»%s« started remote wipe" : "«%s» iniciou a limpeza remota", @@ -63,19 +59,19 @@ OC.L10N.register( "tomorrow" : "mañá", "yesterday" : "onte", "_in %n day_::_in %n days_" : ["en %n día","en %n días"], - "_%n day ago_::_%n days ago_" : ["hai %n día","hai %n días"], + "_%n day ago_::_%n days ago_" : ["Hai %n día","Hai %n días"], "next month" : "o vindeiro mes", "last month" : "o mes pasado", "_in %n month_::_in %n months_" : ["en %n mes","en %n meses"], - "_%n month ago_::_%n months ago_" : ["hai %n mes","hai %n meses"], + "_%n month ago_::_%n months ago_" : ["Hai %n mes","Hai %n meses"], "next year" : "o vindeiro ano", "last year" : "o ano pasado", "_in %n year_::_in %n years_" : ["en %n ano","en %n anos"], - "_%n year ago_::_%n years ago_" : ["hai %n ano","hai %n anos"], + "_%n year ago_::_%n years ago_" : ["Hai %n ano","Hai %n anos"], "_in %n hour_::_in %n hours_" : ["en %n hora","en %n horas"], - "_%n hour ago_::_%n hours ago_" : ["hai %n hora","hai %n horas"], + "_%n hour ago_::_%n hours ago_" : ["Hai %n hora","Hai %n horas"], "_in %n minute_::_in %n minutes_" : ["en %n minuto","en %n minutos"], - "_%n minute ago_::_%n minutes ago_" : ["hai %n minuto","hai %n minutos"], + "_%n minute ago_::_%n minutes ago_" : ["Hai %n minuto","Hai %n minutos"], "in a few seconds" : "en poucos segundos", "seconds ago" : "segundos atrás", "Empty file" : "Ficheiro baleiro", @@ -118,22 +114,15 @@ OC.L10N.register( "Headline" : "Titular", "Organisation" : "Organización", "Role" : "Cargo", - "Unknown user" : "Usuario descoñecido", "Additional settings" : "Axustes adicionais", - "Enter the database username and name for %s" : "Introduza o nome de usuario da ase de datos e o nome para %s", - "Enter the database username for %s" : "Introduza o nome de usuario da base de datos para %s", "Enter the database name for %s" : "Introduza o nome da base de datos para %s", "You cannot use dots in the database name %s" : "Non pode usar puntos no nome da base de datos %s", - "MySQL username and/or password not valid" : "Nome de usuario e/ou contrasinal de MySQL incorrecto", "You need to enter details of an existing account." : "Debe introducir os detalles dunha conta existente.", "Oracle connection could not be established" : "Non foi posíbel estabelecer a conexión con Oracle", - "Oracle username and/or password not valid" : "O nome de usuario e/ou contrasinal de Oracle é incorrecto", - "PostgreSQL username and/or password not valid" : "Nome de usuario e/ou contrasinal de PostgreSQL incorrecto", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X non é compatíbel e %s non funcionará correctamente nesta plataforma. Utilíceo baixo a súa responsabilidade!", "For the best results, please consider using a GNU/Linux server instead." : "Para obter mellores resultados, considere o emprego dun servidor GNU/Linux no seu canto.", "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." : "Semella que esta instancia de %s está a funcionar nun contorno PHP de 32 bisst e o open_basedir foi configurado no php.ini. Isto provocará problemas con ficheiros maiores de 4 GB e está absolutamente desaconsellado.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Retire o axuste de open_basedir no php.ini ou cambie a PHP de 64 bits.", - "Set an admin username." : "Estabeleza un nome de usuario administrador", "Set an admin password." : "Estabeleza un contrasinal de administrador", "Cannot create or write into the data directory %s" : "Non é posíbel crear ou escribir no directorio de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "A infraestrutura de compartición %s ten que implementar a interface OCP\\Share_Backend", @@ -151,7 +140,6 @@ OC.L10N.register( "Expiration date is in the past" : "Xa pasou a data de caducidade", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Non é posíbel estabelecer a data de caducidade máis alo de %n día no futuro","Non é posíbel estabelecer a data de caducidade máis alo de %n días no futuro"], "Sharing is only allowed with group members" : "Só se permite compartir cos membros do grupo", - "Sharing %s failed, because this item is already shared with user %s" : "Fallou a compartición de %s por mor de que este elemento xa foi compartido co usuario %s", "%1$s shared »%2$s« with you" : "%1$s compartiu «%2$s» con Vde.", "%1$s shared »%2$s« with you." : "%1$s compartiu «%2$s» con Vde.", "Click the button below to open it." : "Prema no botón de embaixo para abrilo.", @@ -205,17 +193,9 @@ OC.L10N.register( "Nov." : "nov.", "Dec." : "dec.", "A valid password must be provided" : "Debe fornecer un contrasinal", - "The username is already being used" : "Este nome de usuario xa está a ser usado", - "Could not create user" : "Non foi posíbel crear o usuario", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Só se permiten os seguintes caracteres nun nome de usuario: «a-z», «A-Z», «0-9», espazos e «_.@-'»", - "A valid username must be provided" : "Debe fornecer un nome de usuario correcto", - "Username contains whitespace at the beginning or at the end" : "O nome de usuario contén un espazo en branco no inicio ou no final", - "Username must not consist of dots only" : "O nome de usuario non debe consistir só de puntos", - "Username is invalid because files already exist for this user" : "O nome de usuario non é válido porque xa existen ficheiros para este usuario", - "User disabled" : "Usuario desactivado", "Login canceled by app" : "Acceso cancelado pola aplicación", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Non é posíbel instalar a aplicación «%1$s» por mor de non cumprirse as dependencias: %2$s", - "a safe home for all your data" : "un lugar seguro para todos os seus datos", + "a safe home for all your data" : "un acubillo seguro para todos os seus datos", "File is currently busy, please try again later" : "O ficheiro está ocupado neste momento, ténteo máis adiante.", "Cannot download file" : "Non é posíbel descargar o ficheiro", "Application is not enabled" : "A aplicación non está activada", @@ -243,10 +223,8 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isto probabelmente se debe unha caché/acelerador como Zend OPcache ou eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Instaláronse os módulos de PHP, mais aínda aparecen listados como perdidos?", "Please ask your server administrator to restart the web server." : "Pídalle á administración do seu servidor que reinicie o servidor web.", - "The required %s config variable is not configured in the config.php file." : "Precísase a variábel de configuración %s e non está configurada no ficheiro config.php.", + "The required %s config variable is not configured in the config.php file." : "Precísase da variábel de configuración %s e non está configurada no ficheiro config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Pídalle á administración do seu servidor que verifique a configuración de Nextcloud.", - "Your data directory is readable by other users." : "Outros usuarios poden leer o seu directorio de datos.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Cambie os permisos a 0770 para que o directorio non poida ser listado por outros usuarios.", "Your data directory must be an absolute path." : "O seu directorio de datos debe ser unha ruta absoluta.", "Check the value of \"datadirectory\" in your configuration." : "Comprobe o valor de «datadirectory» na súa configuración-", "Your data directory is invalid." : "O seu directorio de datos non é válido.", @@ -271,12 +249,32 @@ OC.L10N.register( "Extract topics" : "Extraer temas", "Extracts topics from a text and outputs them separated by commas." : "Extrae temas dun texto e amósaos separados por comas.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Os ficheiros da aplicación %1$s non foron substituídos correctamente. Asegúrese que é unha versión compatíbel co servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "O usuario que accede debe ser un administrador, un subadministrador ou ter un dereito especial para acceder a esta configuración", + "Logged in user must be an admin or sub admin" : "O usuario autenticado debe ser un administrador ou subadministrador", + "Logged in user must be an admin" : "O usuario conectado debe ser un administrador", "Full name" : "Nome completo", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Acadouse o límite de usuarios e non se creou o usuario. Consulte as súas notificacións para obter máis información.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Só os seguintes caracteres están permitidos nos nomes de usuario: «a-z», «A-Z», «0-9» e «_.@-'»", - "libxml2 2.7.0 is at least required. Currently %s is installed." : "Precisase, cando menos, libxml2 2.7.0. Actualmente esta instalado %s.", + "Unknown user" : "Usuario descoñecido", + "Enter the database username and name for %s" : "Introduza o nome de usuario da ase de datos e o nome para %s", + "Enter the database username for %s" : "Introduza o nome de usuario da base de datos para %s", + "MySQL username and/or password not valid" : "Nome de usuario e/ou contrasinal de MySQL incorrecto", + "Oracle username and/or password not valid" : "O nome de usuario e/ou contrasinal de Oracle é incorrecto", + "PostgreSQL username and/or password not valid" : "Nome de usuario e/ou contrasinal de PostgreSQL incorrecto", + "Set an admin username." : "Estabeleza un nome de usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Fallou a compartición de %s por mor de que este elemento xa foi compartido co usuario %s", + "The username is already being used" : "Este nome de usuario xa está a ser usado", + "Could not create user" : "Non foi posíbel crear o usuario", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Só se permiten os seguintes caracteres nun nome de usuario: «a-z», «A-Z», «0-9», espazos e «_.@-'»", + "A valid username must be provided" : "Debe fornecer un nome de usuario correcto", + "Username contains whitespace at the beginning or at the end" : "O nome de usuario contén un espazo en branco no inicio ou no final", + "Username must not consist of dots only" : "O nome de usuario non debe consistir só de puntos", + "Username is invalid because files already exist for this user" : "O nome de usuario non é válido porque xa existen ficheiros para este usuario", + "User disabled" : "Usuario desactivado", + "libxml2 2.7.0 is at least required. Currently %s is installed." : "Precísase, cando menos, de libxml2 2.7.0. Actualmente esta instalado %s.", "To fix this issue update your libxml2 version and restart your web server." : "Para arranxar esta incidencia, actualice a versión de libxml2 e reinicie o servidor web. ", - "PostgreSQL >= 9 required." : "Precisase PostgreSQL >= 9.", - "Please upgrade your database version." : "Anove a versión da súa base de datos" + "PostgreSQL >= 9 required." : "Precísase de PostgreSQL >= 9.", + "Please upgrade your database version." : "Anove a versión da súa base de datos", + "Your data directory is readable by other users." : "Outros usuarios poden leer o seu directorio de datos.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Cambie os permisos a 0770 para que o directorio non poida ser listado por outros usuarios." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/gl.json b/lib/l10n/gl.json index 982199d4f7c..b6a5c0c4c42 100644 --- a/lib/l10n/gl.json +++ b/lib/l10n/gl.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "A aplicación %1$s non está presente ou ten unha versión non compatíbel con este servidor. Comprobe o directorio de aplicacións.", "Sample configuration detected" : "Detectouse a configuración de exemplo", "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" : "Detectouse que foi copiada a configuración de exemplo. Isto pode rachar a súa instalación e non é compatíbel. Lea a documentación antes de facer cambios en config.php", - "404" : "404", "The page could not be found on the server." : "Non foi posíbel atopar a páxina no servidor.", "%s email verification" : "Verificación do correo-e %s", "Email verification" : "Verificación do correo-e", @@ -23,21 +22,18 @@ "Groupware bundle" : "Paquete de software colaborativo", "Hub bundle" : "Paquete de concentradores", "Social sharing bundle" : "Paquete para compartir en redes sociais", - "PHP %s or higher is required." : "Precisase PHP %s ou superior.", - "PHP with a version lower than %s is required." : "Precisase PHP cunha versión inferior a %s.", - "%sbit or higher PHP required." : "Precisase PHP para %sbits ou superior.", + "PHP %s or higher is required." : "Precísase de PHP %s ou superior.", + "PHP with a version lower than %s is required." : "Precísase de PHP cunha versión inferior a %s.", + "%sbit or higher PHP required." : "Precísase de PHP para %s bits ou superior.", "The following architectures are supported: %s" : "Admítense as seguintes arquitecturas: %s", "The following databases are supported: %s" : "Admítense as seguintes bases de datos: %s", "The command line tool %s could not be found" : "Non foi posíbel atopar a ferramenta de liña de ordes %s", "The library %s is not available." : "Non está dispoñíbel a biblioteca %s.", - "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Precisase a biblioteca %1$s cunha versión superior a %2$s - dispoñíbel a versión %3$s.", - "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Precisase a biblioteca %1$s cunha versión inferior a %2$s - dispoñíbel a versión %3$s.", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Precísase da biblioteca %1$s cunha versión superior a %2$s - dispoñíbel a versión %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Precísase da biblioteca %1$s cunha versión inferior a %2$s - dispoñíbel a versión %3$s.", "The following platforms are supported: %s" : "Admítense as seguintes plataformas: %s", - "Server version %s or higher is required." : "Precisase a versión %s ou superior do servidor.", - "Server version %s or lower is required." : "Precisase a versión %s ou inferior do servidor.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "O usuario que accede debe ser un administrador, un subadministrador ou ter un dereito especial para acceder a esta configuración", - "Logged in user must be an admin or sub admin" : "O usuario autenticado debe ser un administrador ou subadministrador", - "Logged in user must be an admin" : "O usuario conectado debe ser un administrador", + "Server version %s or higher is required." : "Precísase da versión %s ou superior do servidor.", + "Server version %s or lower is required." : "Precísase da versión %s ou inferior do servidor.", "Wiping of device %s has started" : "Iniciouse a limpeza do dispositivo %s", "Wiping of device »%s« has started" : "Iniciouse a limpeza do dispositivo «%s»", "»%s« started remote wipe" : "«%s» iniciou a limpeza remota", @@ -61,19 +57,19 @@ "tomorrow" : "mañá", "yesterday" : "onte", "_in %n day_::_in %n days_" : ["en %n día","en %n días"], - "_%n day ago_::_%n days ago_" : ["hai %n día","hai %n días"], + "_%n day ago_::_%n days ago_" : ["Hai %n día","Hai %n días"], "next month" : "o vindeiro mes", "last month" : "o mes pasado", "_in %n month_::_in %n months_" : ["en %n mes","en %n meses"], - "_%n month ago_::_%n months ago_" : ["hai %n mes","hai %n meses"], + "_%n month ago_::_%n months ago_" : ["Hai %n mes","Hai %n meses"], "next year" : "o vindeiro ano", "last year" : "o ano pasado", "_in %n year_::_in %n years_" : ["en %n ano","en %n anos"], - "_%n year ago_::_%n years ago_" : ["hai %n ano","hai %n anos"], + "_%n year ago_::_%n years ago_" : ["Hai %n ano","Hai %n anos"], "_in %n hour_::_in %n hours_" : ["en %n hora","en %n horas"], - "_%n hour ago_::_%n hours ago_" : ["hai %n hora","hai %n horas"], + "_%n hour ago_::_%n hours ago_" : ["Hai %n hora","Hai %n horas"], "_in %n minute_::_in %n minutes_" : ["en %n minuto","en %n minutos"], - "_%n minute ago_::_%n minutes ago_" : ["hai %n minuto","hai %n minutos"], + "_%n minute ago_::_%n minutes ago_" : ["Hai %n minuto","Hai %n minutos"], "in a few seconds" : "en poucos segundos", "seconds ago" : "segundos atrás", "Empty file" : "Ficheiro baleiro", @@ -116,22 +112,15 @@ "Headline" : "Titular", "Organisation" : "Organización", "Role" : "Cargo", - "Unknown user" : "Usuario descoñecido", "Additional settings" : "Axustes adicionais", - "Enter the database username and name for %s" : "Introduza o nome de usuario da ase de datos e o nome para %s", - "Enter the database username for %s" : "Introduza o nome de usuario da base de datos para %s", "Enter the database name for %s" : "Introduza o nome da base de datos para %s", "You cannot use dots in the database name %s" : "Non pode usar puntos no nome da base de datos %s", - "MySQL username and/or password not valid" : "Nome de usuario e/ou contrasinal de MySQL incorrecto", "You need to enter details of an existing account." : "Debe introducir os detalles dunha conta existente.", "Oracle connection could not be established" : "Non foi posíbel estabelecer a conexión con Oracle", - "Oracle username and/or password not valid" : "O nome de usuario e/ou contrasinal de Oracle é incorrecto", - "PostgreSQL username and/or password not valid" : "Nome de usuario e/ou contrasinal de PostgreSQL incorrecto", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X non é compatíbel e %s non funcionará correctamente nesta plataforma. Utilíceo baixo a súa responsabilidade!", "For the best results, please consider using a GNU/Linux server instead." : "Para obter mellores resultados, considere o emprego dun servidor GNU/Linux no seu canto.", "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." : "Semella que esta instancia de %s está a funcionar nun contorno PHP de 32 bisst e o open_basedir foi configurado no php.ini. Isto provocará problemas con ficheiros maiores de 4 GB e está absolutamente desaconsellado.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Retire o axuste de open_basedir no php.ini ou cambie a PHP de 64 bits.", - "Set an admin username." : "Estabeleza un nome de usuario administrador", "Set an admin password." : "Estabeleza un contrasinal de administrador", "Cannot create or write into the data directory %s" : "Non é posíbel crear ou escribir no directorio de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "A infraestrutura de compartición %s ten que implementar a interface OCP\\Share_Backend", @@ -149,7 +138,6 @@ "Expiration date is in the past" : "Xa pasou a data de caducidade", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Non é posíbel estabelecer a data de caducidade máis alo de %n día no futuro","Non é posíbel estabelecer a data de caducidade máis alo de %n días no futuro"], "Sharing is only allowed with group members" : "Só se permite compartir cos membros do grupo", - "Sharing %s failed, because this item is already shared with user %s" : "Fallou a compartición de %s por mor de que este elemento xa foi compartido co usuario %s", "%1$s shared »%2$s« with you" : "%1$s compartiu «%2$s» con Vde.", "%1$s shared »%2$s« with you." : "%1$s compartiu «%2$s» con Vde.", "Click the button below to open it." : "Prema no botón de embaixo para abrilo.", @@ -203,17 +191,9 @@ "Nov." : "nov.", "Dec." : "dec.", "A valid password must be provided" : "Debe fornecer un contrasinal", - "The username is already being used" : "Este nome de usuario xa está a ser usado", - "Could not create user" : "Non foi posíbel crear o usuario", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Só se permiten os seguintes caracteres nun nome de usuario: «a-z», «A-Z», «0-9», espazos e «_.@-'»", - "A valid username must be provided" : "Debe fornecer un nome de usuario correcto", - "Username contains whitespace at the beginning or at the end" : "O nome de usuario contén un espazo en branco no inicio ou no final", - "Username must not consist of dots only" : "O nome de usuario non debe consistir só de puntos", - "Username is invalid because files already exist for this user" : "O nome de usuario non é válido porque xa existen ficheiros para este usuario", - "User disabled" : "Usuario desactivado", "Login canceled by app" : "Acceso cancelado pola aplicación", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Non é posíbel instalar a aplicación «%1$s» por mor de non cumprirse as dependencias: %2$s", - "a safe home for all your data" : "un lugar seguro para todos os seus datos", + "a safe home for all your data" : "un acubillo seguro para todos os seus datos", "File is currently busy, please try again later" : "O ficheiro está ocupado neste momento, ténteo máis adiante.", "Cannot download file" : "Non é posíbel descargar o ficheiro", "Application is not enabled" : "A aplicación non está activada", @@ -241,10 +221,8 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isto probabelmente se debe unha caché/acelerador como Zend OPcache ou eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Instaláronse os módulos de PHP, mais aínda aparecen listados como perdidos?", "Please ask your server administrator to restart the web server." : "Pídalle á administración do seu servidor que reinicie o servidor web.", - "The required %s config variable is not configured in the config.php file." : "Precísase a variábel de configuración %s e non está configurada no ficheiro config.php.", + "The required %s config variable is not configured in the config.php file." : "Precísase da variábel de configuración %s e non está configurada no ficheiro config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Pídalle á administración do seu servidor que verifique a configuración de Nextcloud.", - "Your data directory is readable by other users." : "Outros usuarios poden leer o seu directorio de datos.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Cambie os permisos a 0770 para que o directorio non poida ser listado por outros usuarios.", "Your data directory must be an absolute path." : "O seu directorio de datos debe ser unha ruta absoluta.", "Check the value of \"datadirectory\" in your configuration." : "Comprobe o valor de «datadirectory» na súa configuración-", "Your data directory is invalid." : "O seu directorio de datos non é válido.", @@ -269,12 +247,32 @@ "Extract topics" : "Extraer temas", "Extracts topics from a text and outputs them separated by commas." : "Extrae temas dun texto e amósaos separados por comas.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Os ficheiros da aplicación %1$s non foron substituídos correctamente. Asegúrese que é unha versión compatíbel co servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "O usuario que accede debe ser un administrador, un subadministrador ou ter un dereito especial para acceder a esta configuración", + "Logged in user must be an admin or sub admin" : "O usuario autenticado debe ser un administrador ou subadministrador", + "Logged in user must be an admin" : "O usuario conectado debe ser un administrador", "Full name" : "Nome completo", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Acadouse o límite de usuarios e non se creou o usuario. Consulte as súas notificacións para obter máis información.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Só os seguintes caracteres están permitidos nos nomes de usuario: «a-z», «A-Z», «0-9» e «_.@-'»", - "libxml2 2.7.0 is at least required. Currently %s is installed." : "Precisase, cando menos, libxml2 2.7.0. Actualmente esta instalado %s.", + "Unknown user" : "Usuario descoñecido", + "Enter the database username and name for %s" : "Introduza o nome de usuario da ase de datos e o nome para %s", + "Enter the database username for %s" : "Introduza o nome de usuario da base de datos para %s", + "MySQL username and/or password not valid" : "Nome de usuario e/ou contrasinal de MySQL incorrecto", + "Oracle username and/or password not valid" : "O nome de usuario e/ou contrasinal de Oracle é incorrecto", + "PostgreSQL username and/or password not valid" : "Nome de usuario e/ou contrasinal de PostgreSQL incorrecto", + "Set an admin username." : "Estabeleza un nome de usuario administrador", + "Sharing %s failed, because this item is already shared with user %s" : "Fallou a compartición de %s por mor de que este elemento xa foi compartido co usuario %s", + "The username is already being used" : "Este nome de usuario xa está a ser usado", + "Could not create user" : "Non foi posíbel crear o usuario", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Só se permiten os seguintes caracteres nun nome de usuario: «a-z», «A-Z», «0-9», espazos e «_.@-'»", + "A valid username must be provided" : "Debe fornecer un nome de usuario correcto", + "Username contains whitespace at the beginning or at the end" : "O nome de usuario contén un espazo en branco no inicio ou no final", + "Username must not consist of dots only" : "O nome de usuario non debe consistir só de puntos", + "Username is invalid because files already exist for this user" : "O nome de usuario non é válido porque xa existen ficheiros para este usuario", + "User disabled" : "Usuario desactivado", + "libxml2 2.7.0 is at least required. Currently %s is installed." : "Precísase, cando menos, de libxml2 2.7.0. Actualmente esta instalado %s.", "To fix this issue update your libxml2 version and restart your web server." : "Para arranxar esta incidencia, actualice a versión de libxml2 e reinicie o servidor web. ", - "PostgreSQL >= 9 required." : "Precisase PostgreSQL >= 9.", - "Please upgrade your database version." : "Anove a versión da súa base de datos" + "PostgreSQL >= 9 required." : "Precísase de PostgreSQL >= 9.", + "Please upgrade your database version." : "Anove a versión da súa base de datos", + "Your data directory is readable by other users." : "Outros usuarios poden leer o seu directorio de datos.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Cambie os permisos a 0770 para que o directorio non poida ser listado por outros usuarios." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/he.js b/lib/l10n/he.js index 1d153513026..8e35fcd975b 100644 --- a/lib/l10n/he.js +++ b/lib/l10n/he.js @@ -21,7 +21,6 @@ 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 ומטה.", - "Logged in user must be an admin" : "על המשתמש שנכנס להיות מנהל", "Authentication" : "אימות", "Unknown filetype" : "סוג קובץ לא מוכר", "Invalid image" : "תמונה לא חוקית", @@ -34,14 +33,14 @@ OC.L10N.register( "_%n day ago_::_%n days ago_" : ["לפני %n יום","לפני %n ימים","לפני %n ימים","לפני %n ימים"], "next month" : "בחודש הבא", "last month" : "חודש שעבר", - "_in %n month_::_in %n months_" : ["בעוד חודש","בעוד חודשיים","בעוד %n חודשים","בעוד %n חודשים"], - "_%n month ago_::_%n months ago_" : ["לפני חודש","לפני חודשיים","לפני %n חודשים","לפני %n חודשים"], + "_in %n month_::_in %n months_" : ["בעוד חודש","בעוד חודשיים","בעוד %n חודשים"], + "_%n month ago_::_%n months ago_" : ["לפני חודש","לפני חודשיים","לפני %n חודשים"], "next year" : "בשנה הבאה", "last year" : "שנה שעברה", "_in %n year_::_in %n years_" : ["בעוד שנה","בעוד שנתיים","בעוד %n שנים","בעוד %n שנים"], "_%n year ago_::_%n years ago_" : ["לפני %n שנה","לפני %n שנים","לפני %n שנים","לפני %n שנים"], "_in %n hour_::_in %n hours_" : ["בעוד שעה","בעוד שעתיים","בעוד %n שעות","בעוד %n שעות"], - "_%n hour ago_::_%n hours ago_" : ["לפני שעה","לפני שעתיים","לפני %n שעות","לפני %n שעות"], + "_%n hour ago_::_%n hours ago_" : ["לפני שעה","לפני שעתיים","לפני %n שעות"], "_in %n minute_::_in %n minutes_" : ["בעוד דקה","בעוד 2 דקות","בעוד %n דקות","בעוד %n דקות"], "_%n minute ago_::_%n minutes ago_" : ["לפני דקה","לפני 2 דקות","לפני %n דקות","לפני %n דקות"], "in a few seconds" : "בעוד מספר שניות", @@ -70,18 +69,13 @@ OC.L10N.register( "Address" : "כתובת", "Profile picture" : "תמונת פרופיל", "About" : "על אודות", - "Unknown user" : "משתמש לא ידוע", "Additional settings" : "הגדרות נוספות", - "MySQL username and/or password not valid" : "שם המשתמש ו/או הססמה של MySQL אינם תקינים", "You need to enter details of an existing account." : "עליך להקליד פרטים של חשבון קיים.", "Oracle connection could not be established" : "לא ניתן היה ליצור חיבור Oracle", - "Oracle username and/or password not valid" : "שם משתמש ו/או סיסמת Oracle אינם תקפים", - "PostgreSQL username 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-bit PHP ושה- open_basedir הוגדר בקובץ php.ini. מצב זה יוביל לבעיות עם קבצים הגדולים מ- 4 GB ואינו מומלץ לחלוטין.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "יש להסיר את הגדרת open_basedir מתוך קובץ php.ini או להחליף לסביבת 64-bit PHP.", - "Set an admin username." : "קביעת שם משתמש מנהל", "Set an admin password." : "קביעת סיסמת מנהל", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "צד אחורי לשיתוף %s חייב ליישם את ממשק OCP\\Share_Backend", "Sharing backend %s not found" : "צד אחורי לשיתוף %s לא נמצא", @@ -94,7 +88,6 @@ OC.L10N.register( "You are not allowed to share %s" : "אינך רשאי/ת לשתף %s", "Cannot increase permissions of %s" : "לא ניתן להוסיף על ההרשאות של %s", "Expiration date is in the past" : "תאריך תפוגה הנו בעבר", - "Sharing %s failed, because this item is already shared with user %s" : "השיתוף %s נכשל, כיוון שהפריט כבר משותף עם משתמש %s", "%1$s shared »%2$s« with you" : "%2$s שותף אתך על ידי %1$s", "%1$s shared »%2$s« with you." : "„%2$s” שותף אתך על ידי %1$s.", "Click the button below to open it." : "יש ללחוץ על הכפתור להלן כדי לפתוח אותו.", @@ -146,13 +139,6 @@ OC.L10N.register( "Nov." : "נוב׳", "Dec." : "דצמ׳", "A valid password must be provided" : "יש לספק ססמה תקנית", - "The username is already being used" : "השם משתמש כבר בשימוש", - "Could not create user" : "לא ניתן ליצור משתמש", - "A valid username must be provided" : "יש לספק שם משתמש תקני", - "Username contains whitespace at the beginning or at the end" : "שם המשתמש מכיל רווח בתחילתו או בסופו", - "Username must not consist of dots only" : "שם המשתמש לא יכול להיות מורכב מנקודות בלבד", - "Username is invalid because files already exist for this user" : "שם המשתמש שגוי כיוון שכבר קיימים קבצים למשתמש הזה", - "User disabled" : "משתמש מנוטרל", "Login canceled by app" : "התחברות בוטלה על ידי יישום", "a safe home for all your data" : "בית בטוח עבור כל המידע שלך", "File is currently busy, please try again later" : "הקובץ בשימוש כרגע, יש לנסות שוב מאוחר יותר", @@ -169,7 +155,6 @@ OC.L10N.register( "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." : "יש לבקש ממנהל השרת שלך להפעיל מחדש את שרת האינטרנט.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "יש לשנות את ההרשאות ל- 0770 כך שהתיקייה לא תרשם על ידי משתמשים אחרים.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "נא לוודא שיש קובץ בשם „.ocdata” בבסיס תיקיית הנתונים שלך.", "Action \"%s\" not supported or implemented." : "הפעולה „%s” אינה נתמכת או שאינה מוטמעת.", "Authentication failed, wrong token or provider ID given" : "האימות נכשל, האסימון או מזהה הספק שסופקו שגויים", @@ -181,9 +166,23 @@ OC.L10N.register( "Storage is temporarily not available" : "האחסון אינו זמין כרגע", "Storage connection timeout. %s" : "פסק זמן חיבור אחסון. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "הקבצים של היישומון %1$s לא מוקמו במקום הנכון. נא לוודא שזו גרסה שהשרת תומך בה.", + "Logged in user must be an admin" : "על המשתמש שנכנס להיות מנהל", "Full name" : "שם מלא", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "רק התווים הבאים מאושרים לשם משתמש: \"a-z\", \"A-Z\", \"0-9\", וגם \"_.@-'\"", + "Unknown user" : "משתמש לא ידוע", + "MySQL username and/or password not valid" : "שם המשתמש ו/או הססמה של MySQL אינם תקינים", + "Oracle username and/or password not valid" : "שם משתמש ו/או סיסמת Oracle אינם תקפים", + "PostgreSQL username and/or password not valid" : "שם משתמש ו/או סיסמת PostgreSQL אינם תקפים", + "Set an admin username." : "קביעת שם משתמש מנהל", + "Sharing %s failed, because this item is already shared with user %s" : "השיתוף %s נכשל, כיוון שהפריט כבר משותף עם משתמש %s", + "The username is already being used" : "השם משתמש כבר בשימוש", + "Could not create user" : "לא ניתן ליצור משתמש", + "A valid username must be provided" : "יש לספק שם משתמש תקני", + "Username contains whitespace at the beginning or at the end" : "שם המשתמש מכיל רווח בתחילתו או בסופו", + "Username must not consist of dots only" : "שם המשתמש לא יכול להיות מורכב מנקודות בלבד", + "Username is invalid because files already exist for this user" : "שם המשתמש שגוי כיוון שכבר קיימים קבצים למשתמש הזה", + "User disabled" : "משתמש מנוטרל", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 נדרש לכל הפחות. כרגע %s מותקן.", - "To fix this issue update your libxml2 version and restart your web server." : "לתיקון הבעיה יש לעדכן את גרסת ה- libxml2 שלך ולהפעיל מחדש את שרת האינטרנט שלך." + "To fix this issue update your libxml2 version and restart your web server." : "לתיקון הבעיה יש לעדכן את גרסת ה- libxml2 שלך ולהפעיל מחדש את שרת האינטרנט שלך.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "יש לשנות את ההרשאות ל- 0770 כך שהתיקייה לא תרשם על ידי משתמשים אחרים." }, -"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;"); +"nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;"); diff --git a/lib/l10n/he.json b/lib/l10n/he.json index 2bcce522fcc..b0828f15305 100644 --- a/lib/l10n/he.json +++ b/lib/l10n/he.json @@ -19,7 +19,6 @@ "The following platforms are supported: %s" : "קיימת תמיכה בפלטפורמות הבאות: %s", "Server version %s or higher is required." : "נדרשת גרסה שרת %s ומעלה.", "Server version %s or lower is required." : "נדרשת גרסה שרת %s ומטה.", - "Logged in user must be an admin" : "על המשתמש שנכנס להיות מנהל", "Authentication" : "אימות", "Unknown filetype" : "סוג קובץ לא מוכר", "Invalid image" : "תמונה לא חוקית", @@ -32,14 +31,14 @@ "_%n day ago_::_%n days ago_" : ["לפני %n יום","לפני %n ימים","לפני %n ימים","לפני %n ימים"], "next month" : "בחודש הבא", "last month" : "חודש שעבר", - "_in %n month_::_in %n months_" : ["בעוד חודש","בעוד חודשיים","בעוד %n חודשים","בעוד %n חודשים"], - "_%n month ago_::_%n months ago_" : ["לפני חודש","לפני חודשיים","לפני %n חודשים","לפני %n חודשים"], + "_in %n month_::_in %n months_" : ["בעוד חודש","בעוד חודשיים","בעוד %n חודשים"], + "_%n month ago_::_%n months ago_" : ["לפני חודש","לפני חודשיים","לפני %n חודשים"], "next year" : "בשנה הבאה", "last year" : "שנה שעברה", "_in %n year_::_in %n years_" : ["בעוד שנה","בעוד שנתיים","בעוד %n שנים","בעוד %n שנים"], "_%n year ago_::_%n years ago_" : ["לפני %n שנה","לפני %n שנים","לפני %n שנים","לפני %n שנים"], "_in %n hour_::_in %n hours_" : ["בעוד שעה","בעוד שעתיים","בעוד %n שעות","בעוד %n שעות"], - "_%n hour ago_::_%n hours ago_" : ["לפני שעה","לפני שעתיים","לפני %n שעות","לפני %n שעות"], + "_%n hour ago_::_%n hours ago_" : ["לפני שעה","לפני שעתיים","לפני %n שעות"], "_in %n minute_::_in %n minutes_" : ["בעוד דקה","בעוד 2 דקות","בעוד %n דקות","בעוד %n דקות"], "_%n minute ago_::_%n minutes ago_" : ["לפני דקה","לפני 2 דקות","לפני %n דקות","לפני %n דקות"], "in a few seconds" : "בעוד מספר שניות", @@ -68,18 +67,13 @@ "Address" : "כתובת", "Profile picture" : "תמונת פרופיל", "About" : "על אודות", - "Unknown user" : "משתמש לא ידוע", "Additional settings" : "הגדרות נוספות", - "MySQL username and/or password not valid" : "שם המשתמש ו/או הססמה של MySQL אינם תקינים", "You need to enter details of an existing account." : "עליך להקליד פרטים של חשבון קיים.", "Oracle connection could not be established" : "לא ניתן היה ליצור חיבור Oracle", - "Oracle username and/or password not valid" : "שם משתמש ו/או סיסמת Oracle אינם תקפים", - "PostgreSQL username 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-bit PHP ושה- open_basedir הוגדר בקובץ php.ini. מצב זה יוביל לבעיות עם קבצים הגדולים מ- 4 GB ואינו מומלץ לחלוטין.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "יש להסיר את הגדרת open_basedir מתוך קובץ php.ini או להחליף לסביבת 64-bit PHP.", - "Set an admin username." : "קביעת שם משתמש מנהל", "Set an admin password." : "קביעת סיסמת מנהל", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "צד אחורי לשיתוף %s חייב ליישם את ממשק OCP\\Share_Backend", "Sharing backend %s not found" : "צד אחורי לשיתוף %s לא נמצא", @@ -92,7 +86,6 @@ "You are not allowed to share %s" : "אינך רשאי/ת לשתף %s", "Cannot increase permissions of %s" : "לא ניתן להוסיף על ההרשאות של %s", "Expiration date is in the past" : "תאריך תפוגה הנו בעבר", - "Sharing %s failed, because this item is already shared with user %s" : "השיתוף %s נכשל, כיוון שהפריט כבר משותף עם משתמש %s", "%1$s shared »%2$s« with you" : "%2$s שותף אתך על ידי %1$s", "%1$s shared »%2$s« with you." : "„%2$s” שותף אתך על ידי %1$s.", "Click the button below to open it." : "יש ללחוץ על הכפתור להלן כדי לפתוח אותו.", @@ -144,13 +137,6 @@ "Nov." : "נוב׳", "Dec." : "דצמ׳", "A valid password must be provided" : "יש לספק ססמה תקנית", - "The username is already being used" : "השם משתמש כבר בשימוש", - "Could not create user" : "לא ניתן ליצור משתמש", - "A valid username must be provided" : "יש לספק שם משתמש תקני", - "Username contains whitespace at the beginning or at the end" : "שם המשתמש מכיל רווח בתחילתו או בסופו", - "Username must not consist of dots only" : "שם המשתמש לא יכול להיות מורכב מנקודות בלבד", - "Username is invalid because files already exist for this user" : "שם המשתמש שגוי כיוון שכבר קיימים קבצים למשתמש הזה", - "User disabled" : "משתמש מנוטרל", "Login canceled by app" : "התחברות בוטלה על ידי יישום", "a safe home for all your data" : "בית בטוח עבור כל המידע שלך", "File is currently busy, please try again later" : "הקובץ בשימוש כרגע, יש לנסות שוב מאוחר יותר", @@ -167,7 +153,6 @@ "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." : "יש לבקש ממנהל השרת שלך להפעיל מחדש את שרת האינטרנט.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "יש לשנות את ההרשאות ל- 0770 כך שהתיקייה לא תרשם על ידי משתמשים אחרים.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "נא לוודא שיש קובץ בשם „.ocdata” בבסיס תיקיית הנתונים שלך.", "Action \"%s\" not supported or implemented." : "הפעולה „%s” אינה נתמכת או שאינה מוטמעת.", "Authentication failed, wrong token or provider ID given" : "האימות נכשל, האסימון או מזהה הספק שסופקו שגויים", @@ -179,9 +164,23 @@ "Storage is temporarily not available" : "האחסון אינו זמין כרגע", "Storage connection timeout. %s" : "פסק זמן חיבור אחסון. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "הקבצים של היישומון %1$s לא מוקמו במקום הנכון. נא לוודא שזו גרסה שהשרת תומך בה.", + "Logged in user must be an admin" : "על המשתמש שנכנס להיות מנהל", "Full name" : "שם מלא", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "רק התווים הבאים מאושרים לשם משתמש: \"a-z\", \"A-Z\", \"0-9\", וגם \"_.@-'\"", + "Unknown user" : "משתמש לא ידוע", + "MySQL username and/or password not valid" : "שם המשתמש ו/או הססמה של MySQL אינם תקינים", + "Oracle username and/or password not valid" : "שם משתמש ו/או סיסמת Oracle אינם תקפים", + "PostgreSQL username and/or password not valid" : "שם משתמש ו/או סיסמת PostgreSQL אינם תקפים", + "Set an admin username." : "קביעת שם משתמש מנהל", + "Sharing %s failed, because this item is already shared with user %s" : "השיתוף %s נכשל, כיוון שהפריט כבר משותף עם משתמש %s", + "The username is already being used" : "השם משתמש כבר בשימוש", + "Could not create user" : "לא ניתן ליצור משתמש", + "A valid username must be provided" : "יש לספק שם משתמש תקני", + "Username contains whitespace at the beginning or at the end" : "שם המשתמש מכיל רווח בתחילתו או בסופו", + "Username must not consist of dots only" : "שם המשתמש לא יכול להיות מורכב מנקודות בלבד", + "Username is invalid because files already exist for this user" : "שם המשתמש שגוי כיוון שכבר קיימים קבצים למשתמש הזה", + "User disabled" : "משתמש מנוטרל", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 נדרש לכל הפחות. כרגע %s מותקן.", - "To fix this issue update your libxml2 version and restart your web server." : "לתיקון הבעיה יש לעדכן את גרסת ה- libxml2 שלך ולהפעיל מחדש את שרת האינטרנט שלך." -},"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;" + "To fix this issue update your libxml2 version and restart your web server." : "לתיקון הבעיה יש לעדכן את גרסת ה- libxml2 שלך ולהפעיל מחדש את שרת האינטרנט שלך.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "יש לשנות את ההרשאות ל- 0770 כך שהתיקייה לא תרשם על ידי משתמשים אחרים." +},"pluralForm" :"nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;" }
\ No newline at end of file diff --git a/lib/l10n/hr.js b/lib/l10n/hr.js index 8885c82fb35..f7e6d9c5dd5 100644 --- a/lib/l10n/hr.js +++ b/lib/l10n/hr.js @@ -33,9 +33,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Podržane su sljedeće platforme: %s", "Server version %s or higher is required." : "Inačica poslužitelja treba biti %s ili viša.", "Server version %s or lower is required." : "Potrebna je inačica poslužitelja %s ili niža.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prijavljeni korisnik mora biti administrator, podadministrator ili imati posebna prava za pristupanje ovoj postavci", - "Logged in user must be an admin or sub admin" : "Prijavljeni korisnik mora biti administrator ili podadministrator", - "Logged in user must be an admin" : "Korisnik koji je prijavljen mora biti administrator", "Wiping of device %s has started" : "Počelo je brisanje sadržaja s uređaja %s", "Wiping of device »%s« has started" : "Počelo je brisanje sadržaja s uređaja »%s«", "»%s« started remote wipe" : "»%s« je počeo daljinsko brisanje", @@ -107,18 +104,13 @@ OC.L10N.register( "Headline" : "Naslov", "Organisation" : "Organizacija", "Role" : "Uloga", - "Unknown user" : "Nepoznat korisnik", "Additional settings" : "Dodatne postavke", - "MySQL username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka MySQL", "You need to enter details of an existing account." : "Trebate unijeti informacije o postojećem računu.", "Oracle connection could not be established" : "Nije moguće uspostaviti vezu s bazom podataka Oracle", - "Oracle username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka Oracle", - "PostgreSQL username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka 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 nije podržan i %s na ovoj platformi neće raditi kako treba. Koristite na vlastiti rizik!", "For the best results, please consider using a GNU/Linux server instead." : "Za najbolje rezultate razmotrite mogućnost korištenja poslužitelja 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." : "Čini se da se ova %s instanca izvodi u 32-bitnom PHP okruženju, a open_basedir je konfiguriran u php.ini. To će dovesti do problema s datotekama većim od 4 GB i stoga se ne preporučuje.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Uklonite postavku open_basedir iz datoteke php.ini ili se prebacite na 64-bitni PHP.", - "Set an admin username." : "Postavite korisničko ime administratora.", "Set an admin password." : "Postavite zaporku administratora.", "Cannot create or write into the data directory %s" : "Nije moguće stvoriti ili pisati u direktorij s podacima %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Pozadina za dijeljenje %s mora implementirati sučelje OCP\\Share_Backend", @@ -136,7 +128,6 @@ OC.L10N.register( "Expiration date is in the past" : "Datum isteka je u prošlosti", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Ne može se postaviti datum isteka više od %n dan u budućnosti","Ne može se postaviti datum isteka više od %n dana u budućnosti","Ne može se postaviti datum isteka više od %n dana u budućnosti"], "Sharing is only allowed with group members" : "Dijeljenje je dopušteno samo članovima grupe", - "Sharing %s failed, because this item is already shared with user %s" : "Dijeljenje %s nije uspjelo jer je ova stavka već podijeljena s korisnikom %s", "%1$s shared »%2$s« with you" : "%1$s dijeli »%2$s« s vama", "%1$s shared »%2$s« with you." : "%1$s dijeli »%2$s« s vama.", "Click the button below to open it." : "Kliknite gumb u nastavku za otvaranje.", @@ -188,13 +179,6 @@ OC.L10N.register( "Nov." : "Stu.", "Dec." : "Pro.", "A valid password must be provided" : "Nužno je navesti ispravnu zaporku", - "The username is already being used" : "Korisničko ime se već koristi", - "Could not create user" : "Nije moguće stvoriti korisnika", - "A valid username must be provided" : "Nužno je navesti ispravno korisničko ime", - "Username contains whitespace at the beginning or at the end" : "Korisničko ime sadrži bijeli prostor na početku ili na kraju", - "Username must not consist of dots only" : "Korisničko ime ne smije se sastojati samo od točkica", - "Username is invalid because files already exist for this user" : "Korisničko ime je nevažeće jer već postoje datoteke za ovog korisnika", - "User disabled" : "Korisnik je onemogućen", "Login canceled by app" : "Prijava je otkazana putem aplikacije", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Aplikaciju „%1$s” nije moguće instalirati jer nisu ispunjene sljedeće ovisnosti: %2$s", "a safe home for all your data" : "siguran dom za sve vaše podatke", @@ -212,7 +196,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Uzrok tome je vjerojatno neki ubrzivač predmemoriranja kao što je Zend OPcache ili eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "PHP moduli su instalirani, ali još uvijek su na popisu onih koji nedostaju?", "Please ask your server administrator to restart the web server." : "Molimo zamolite svog administratora poslužitelja da ponovno pokrene web poslužitelj.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Promijenite dozvole na 0770 tako da se tim direktorijem ne mogu služiti drugi korisnici.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Provjerite postoji li datoteka pod nazivom „.ocdata” u korijenu podatkovnog direktorija.", "Action \"%s\" not supported or implemented." : "Radnja „%s” nije podržana ili provedena.", "Authentication failed, wrong token or provider ID given" : "Autentifikacija nije uspjela, dan je pogrešan token ili ID davatelja usluge", @@ -226,9 +209,25 @@ OC.L10N.register( "Storage is temporarily not available" : "Pohrana privremeno nije dostupna", "Storage connection timeout. %s" : "Istek veze pohrane. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Datoteke aplikacije %1$s nisu ispravno zamijenjene. Provjerite je li inačica kompatibilna s poslužiteljem.", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prijavljeni korisnik mora biti administrator, podadministrator ili imati posebna prava za pristupanje ovoj postavci", + "Logged in user must be an admin or sub admin" : "Prijavljeni korisnik mora biti administrator ili podadministrator", + "Logged in user must be an admin" : "Korisnik koji je prijavljen mora biti administrator", "Full name" : "Puno ime", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "U korisničkom imenu dopušteni su samo sljedeći znakovi: „a – z”, „A – Z”, „0 – 9” i „_.@-'”", + "Unknown user" : "Nepoznat korisnik", + "MySQL username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka MySQL", + "Oracle username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka Oracle", + "PostgreSQL username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka PostgreSQL", + "Set an admin username." : "Postavite korisničko ime administratora.", + "Sharing %s failed, because this item is already shared with user %s" : "Dijeljenje %s nije uspjelo jer je ova stavka već podijeljena s korisnikom %s", + "The username is already being used" : "Korisničko ime se već koristi", + "Could not create user" : "Nije moguće stvoriti korisnika", + "A valid username must be provided" : "Nužno je navesti ispravno korisničko ime", + "Username contains whitespace at the beginning or at the end" : "Korisničko ime sadrži bijeli prostor na početku ili na kraju", + "Username must not consist of dots only" : "Korisničko ime ne smije se sastojati samo od točkica", + "Username is invalid because files already exist for this user" : "Korisničko ime je nevažeće jer već postoje datoteke za ovog korisnika", + "User disabled" : "Korisnik je onemogućen", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Potreban je barem Libxml2 2.7.0. Trenutno je instalirana inačica %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Kako biste riješili ovaj problem, ažurirajte svoju inačicu libxml2 i ponovno pokrenite web poslužitelj." + "To fix this issue update your libxml2 version and restart your web server." : "Kako biste riješili ovaj problem, ažurirajte svoju inačicu libxml2 i ponovno pokrenite web poslužitelj.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Promijenite dozvole na 0770 tako da se tim direktorijem ne mogu služiti drugi korisnici." }, "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/hr.json b/lib/l10n/hr.json index 5417bf218ae..2fcd75ece93 100644 --- a/lib/l10n/hr.json +++ b/lib/l10n/hr.json @@ -31,9 +31,6 @@ "The following platforms are supported: %s" : "Podržane su sljedeće platforme: %s", "Server version %s or higher is required." : "Inačica poslužitelja treba biti %s ili viša.", "Server version %s or lower is required." : "Potrebna je inačica poslužitelja %s ili niža.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prijavljeni korisnik mora biti administrator, podadministrator ili imati posebna prava za pristupanje ovoj postavci", - "Logged in user must be an admin or sub admin" : "Prijavljeni korisnik mora biti administrator ili podadministrator", - "Logged in user must be an admin" : "Korisnik koji je prijavljen mora biti administrator", "Wiping of device %s has started" : "Počelo je brisanje sadržaja s uređaja %s", "Wiping of device »%s« has started" : "Počelo je brisanje sadržaja s uređaja »%s«", "»%s« started remote wipe" : "»%s« je počeo daljinsko brisanje", @@ -105,18 +102,13 @@ "Headline" : "Naslov", "Organisation" : "Organizacija", "Role" : "Uloga", - "Unknown user" : "Nepoznat korisnik", "Additional settings" : "Dodatne postavke", - "MySQL username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka MySQL", "You need to enter details of an existing account." : "Trebate unijeti informacije o postojećem računu.", "Oracle connection could not be established" : "Nije moguće uspostaviti vezu s bazom podataka Oracle", - "Oracle username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka Oracle", - "PostgreSQL username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka 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 nije podržan i %s na ovoj platformi neće raditi kako treba. Koristite na vlastiti rizik!", "For the best results, please consider using a GNU/Linux server instead." : "Za najbolje rezultate razmotrite mogućnost korištenja poslužitelja 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." : "Čini se da se ova %s instanca izvodi u 32-bitnom PHP okruženju, a open_basedir je konfiguriran u php.ini. To će dovesti do problema s datotekama većim od 4 GB i stoga se ne preporučuje.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Uklonite postavku open_basedir iz datoteke php.ini ili se prebacite na 64-bitni PHP.", - "Set an admin username." : "Postavite korisničko ime administratora.", "Set an admin password." : "Postavite zaporku administratora.", "Cannot create or write into the data directory %s" : "Nije moguće stvoriti ili pisati u direktorij s podacima %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Pozadina za dijeljenje %s mora implementirati sučelje OCP\\Share_Backend", @@ -134,7 +126,6 @@ "Expiration date is in the past" : "Datum isteka je u prošlosti", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Ne može se postaviti datum isteka više od %n dan u budućnosti","Ne može se postaviti datum isteka više od %n dana u budućnosti","Ne može se postaviti datum isteka više od %n dana u budućnosti"], "Sharing is only allowed with group members" : "Dijeljenje je dopušteno samo članovima grupe", - "Sharing %s failed, because this item is already shared with user %s" : "Dijeljenje %s nije uspjelo jer je ova stavka već podijeljena s korisnikom %s", "%1$s shared »%2$s« with you" : "%1$s dijeli »%2$s« s vama", "%1$s shared »%2$s« with you." : "%1$s dijeli »%2$s« s vama.", "Click the button below to open it." : "Kliknite gumb u nastavku za otvaranje.", @@ -186,13 +177,6 @@ "Nov." : "Stu.", "Dec." : "Pro.", "A valid password must be provided" : "Nužno je navesti ispravnu zaporku", - "The username is already being used" : "Korisničko ime se već koristi", - "Could not create user" : "Nije moguće stvoriti korisnika", - "A valid username must be provided" : "Nužno je navesti ispravno korisničko ime", - "Username contains whitespace at the beginning or at the end" : "Korisničko ime sadrži bijeli prostor na početku ili na kraju", - "Username must not consist of dots only" : "Korisničko ime ne smije se sastojati samo od točkica", - "Username is invalid because files already exist for this user" : "Korisničko ime je nevažeće jer već postoje datoteke za ovog korisnika", - "User disabled" : "Korisnik je onemogućen", "Login canceled by app" : "Prijava je otkazana putem aplikacije", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Aplikaciju „%1$s” nije moguće instalirati jer nisu ispunjene sljedeće ovisnosti: %2$s", "a safe home for all your data" : "siguran dom za sve vaše podatke", @@ -210,7 +194,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Uzrok tome je vjerojatno neki ubrzivač predmemoriranja kao što je Zend OPcache ili eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "PHP moduli su instalirani, ali još uvijek su na popisu onih koji nedostaju?", "Please ask your server administrator to restart the web server." : "Molimo zamolite svog administratora poslužitelja da ponovno pokrene web poslužitelj.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Promijenite dozvole na 0770 tako da se tim direktorijem ne mogu služiti drugi korisnici.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Provjerite postoji li datoteka pod nazivom „.ocdata” u korijenu podatkovnog direktorija.", "Action \"%s\" not supported or implemented." : "Radnja „%s” nije podržana ili provedena.", "Authentication failed, wrong token or provider ID given" : "Autentifikacija nije uspjela, dan je pogrešan token ili ID davatelja usluge", @@ -224,9 +207,25 @@ "Storage is temporarily not available" : "Pohrana privremeno nije dostupna", "Storage connection timeout. %s" : "Istek veze pohrane. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Datoteke aplikacije %1$s nisu ispravno zamijenjene. Provjerite je li inačica kompatibilna s poslužiteljem.", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prijavljeni korisnik mora biti administrator, podadministrator ili imati posebna prava za pristupanje ovoj postavci", + "Logged in user must be an admin or sub admin" : "Prijavljeni korisnik mora biti administrator ili podadministrator", + "Logged in user must be an admin" : "Korisnik koji je prijavljen mora biti administrator", "Full name" : "Puno ime", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "U korisničkom imenu dopušteni su samo sljedeći znakovi: „a – z”, „A – Z”, „0 – 9” i „_.@-'”", + "Unknown user" : "Nepoznat korisnik", + "MySQL username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka MySQL", + "Oracle username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka Oracle", + "PostgreSQL username and/or password not valid" : "Neispravno korisničko ime i/ili zaporka baze podataka PostgreSQL", + "Set an admin username." : "Postavite korisničko ime administratora.", + "Sharing %s failed, because this item is already shared with user %s" : "Dijeljenje %s nije uspjelo jer je ova stavka već podijeljena s korisnikom %s", + "The username is already being used" : "Korisničko ime se već koristi", + "Could not create user" : "Nije moguće stvoriti korisnika", + "A valid username must be provided" : "Nužno je navesti ispravno korisničko ime", + "Username contains whitespace at the beginning or at the end" : "Korisničko ime sadrži bijeli prostor na početku ili na kraju", + "Username must not consist of dots only" : "Korisničko ime ne smije se sastojati samo od točkica", + "Username is invalid because files already exist for this user" : "Korisničko ime je nevažeće jer već postoje datoteke za ovog korisnika", + "User disabled" : "Korisnik je onemogućen", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Potreban je barem Libxml2 2.7.0. Trenutno je instalirana inačica %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Kako biste riješili ovaj problem, ažurirajte svoju inačicu libxml2 i ponovno pokrenite web poslužitelj." + "To fix this issue update your libxml2 version and restart your web server." : "Kako biste riješili ovaj problem, ažurirajte svoju inačicu libxml2 i ponovno pokrenite web poslužitelj.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Promijenite dozvole na 0770 tako da se tim direktorijem ne mogu služiti drugi korisnici." },"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/hu.js b/lib/l10n/hu.js index 54aa8d7f36a..b2fa6353acf 100644 --- a/lib/l10n/hu.js +++ b/lib/l10n/hu.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "A(z) %1$s alkalmazás nincs jelen, vagy a verziója nem kompatibilis ezzel a kiszolgálóval. Ellenőrizze az alkalmazástárat.", "Sample configuration detected" : "Példabeállítások észlelve", "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" : "Úgy tűnik, hogy a példakonfigurációt másolta le. Ez működésképtelenné teheti a telepítést, és nem támogatott. Olvassa el a dokumentációt, mielőtt módosításokat véget a config.php fájlban.", - "404" : "404", "The page could not be found on the server." : "Az oldal nem található a kiszolgálón.", "%s email verification" : "%s e-mail ellenőrzés", "Email verification" : "E-mail ellenőrzés", @@ -37,9 +36,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "A következő platformok támogatottak: %s", "Server version %s or higher is required." : "%s vagy újabb kiszolgálóverzió szükséges.", "Server version %s or lower is required." : "%s vagy régebbi kiszolgálóverzió szükséges.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "A bejelentkezett felhasználónak rendszergazdának vagy alrendszergazdának kell lennie, vagy speciális hozzáféréssel kell rendelkeznie ehhez a beállításhoz", - "Logged in user must be an admin or sub admin" : "A bejelentkezett felhasználónak rendszergazdának vagy alrendszergazgának kell lennie", - "Logged in user must be an admin" : "A bejelentkezett felhasználónak rendszergazdának kell lennie", "Wiping of device %s has started" : "A(z) %s eszköz törlése megkezdődött", "Wiping of device »%s« has started" : "A(z) „%s” eszköz törlése megkezdődött", "»%s« started remote wipe" : "„%s” elindította a távoli törlést", @@ -118,22 +114,15 @@ OC.L10N.register( "Headline" : "Címsor", "Organisation" : "Szervezet", "Role" : "Szerepkör", - "Unknown user" : "Ismeretlen felhasználó", "Additional settings" : "További beállítások", - "Enter the database username and name for %s" : "Adja meg a %s adatbázisának nevét és a hozzá tartozó felhasználónevet", - "Enter the database username for %s" : "Adja meg a %s adatbázisához tartozó felhasználónevet", "Enter the database name for %s" : "Adja meg a %s adatbázisának nevét", "You cannot use dots in the database name %s" : "A(z) %s adatbázisnév nem tartalmazhat pontot", - "MySQL username and/or password not valid" : "A MySQL felhasználónév vagy jelszó érvénytelen", "You need to enter details of an existing account." : "Egy már létező fiók adatait kell megadnia.", "Oracle connection could not be established" : "Az Oracle kapcsolat nem hozható létre", - "Oracle username and/or password not valid" : "Az Oracle felhasználónév vagy jelszó érvénytelen", - "PostgreSQL username and/or password not valid" : "A PostgreSQL felhasználói név vagy jelszó érvénytelen", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "A Mac OS X nem támogatott, és a %s nem lesz teljesen működőképes. Csak saját felelősségre használja.", "For the best results, please consider using a GNU/Linux server instead." : "A legjobb eredmény érdekében érdemes GNU/Linux kiszolgálót használni.", "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." : "Úgy tűnik, hogy ez a %s példány 32 bites PHP környezetben fut, és az open_basedir be lett állítva a php.ini fájlban. Ez 4 GB-nál nagyobb fájlok esetén problémákat okozhat, így erősen ellenjavallott.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Távolítsa el az open_basedir beállítást a php.ini fájlból, vagy váltson 64 bites PHP-ra.", - "Set an admin username." : "Állítson be egy rendszergazdai felhasználónevet.", "Set an admin password." : "Állítson be egy rendszergazdai jelszót.", "Cannot create or write into the data directory %s" : "Nem létre létrehozni vagy beleírni a(z) %s adatkönyvtárba", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "A(z) %s megosztási alrendszernek meg kell valósítania az OCP\\Share_Backend interfészt", @@ -151,11 +140,11 @@ OC.L10N.register( "Expiration date is in the past" : "A lejárati dátum már elmúlt", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Nem állítható be %n napnál távolabbi lejárati dátum","Nem állítható be %n napnál távolabbi lejárati dátum"], "Sharing is only allowed with group members" : "A megosztás csak a csoport tagjaival engedélyezett", - "Sharing %s failed, because this item is already shared with user %s" : "A(z) %s megosztása nem sikerült, mert ez az elem már meg van osztva a(z) %s felhasználóval", "%1$s shared »%2$s« with you" : "%1$s megosztotta Önnel: „%2$s”", "%1$s shared »%2$s« with you." : "%1$s megosztotta Önnel: „%2$s”.", "Click the button below to open it." : "Kattintson a lenti gombra a megnyitáshoz.", "The requested share does not exist anymore" : "A kért megosztás már nem létezik", + "The requested share comes from a disabled user" : "A kért megosztás letiltott felhasználótól származik", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "A felhasználó nem jött létre, mert elérte a felhasználókorlátot. Nézze meg az értesítéseit, hogy többet tudjon meg.", "Could not find category \"%s\"" : "Ez a kategória nem található: \"%s\"", "Sunday" : "Vasárnap", @@ -204,14 +193,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Érvényes jelszót kell megadnia", - "The username is already being used" : "Ez a felhasználónév már foglalt", - "Could not create user" : "Nem sikerült létrehozni a felhasználót", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "A felhasználónévben csak a következő karakterek engedélyezettek: „a-z”, „A-Z”, „0-9”, szóköz és „_.@-'”", - "A valid username must be provided" : "Érvényes felhasználónevet kell megadnia", - "Username contains whitespace at the beginning or at the end" : "A felhasználónév szóközt tartalmaz az elején vagy a végén", - "Username must not consist of dots only" : "A felhasználónév nem állhat csak pontokból", - "Username is invalid because files already exist for this user" : "A felhasználónév érvénytelen, mert már vannak fájlok ehhez a felhasználóhoz", - "User disabled" : "Felhasználó letiltva", "Login canceled by app" : "Bejelentkezés megszakítva az alkalmazás által", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "A(z) „%1$s” alkalmazást nem lehet telepíteni, mert a következő függőségek nem teljesülnek: %2$s", "a safe home for all your data" : "egy biztonságos hely az adataidnak", @@ -244,8 +225,6 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Kérje meg a rendszergazdát, hogy indítsa újra a webkiszolgálót.", "The required %s config variable is not configured in the config.php file." : "A szükséges %s konfigurációs változó nincs beállítva a config.php fájlban.", "Please ask your server administrator to check the Nextcloud configuration." : "Kérje meg a rendszergazdát, hogy ellenőrizze a Nextcloud konfigurációját.", - "Your data directory is readable by other users." : "Az adatkönyvtára más felhasználók által is olvasható.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Módosítsa a könyvtár elérhetőségi engedélybeállítását 0770-re, hogy a tartalmát más felhasználók ne listázhassák.", "Your data directory must be an absolute path." : "Az adatkönyvtárnak abszolút útvonalnak kell lennie", "Check the value of \"datadirectory\" in your configuration." : "Ellenőrizze a „datadirectory” értékét a konfigurációban.", "Your data directory is invalid." : "Az adatkönyvtár érvénytelen.", @@ -261,13 +240,41 @@ OC.L10N.register( "Storage connection error. %s" : "Tároló kapcsolódási hiba. %s", "Storage is temporarily not available" : "A tároló átmenetileg nem érhető el", "Storage connection timeout. %s" : "Időtúllépés a tárolókapcsolatban. %s", + "Free prompt" : "Szabad prompt", + "Runs an arbitrary prompt through the language model." : "Tetszőleges promptot futtat a nyelvi modellen.", + "Generate headline" : "Címsor előállítása", + "Generates a possible headline for a text." : "Egy lehetséges címsort állít elő egy szöveghez.", + "Summarize" : "Összesítés", + "Summarizes text by reducing its length without losing key information." : "Összesíti a szöveget a hosszúság csökkentésével anélkül, hogy a kulcsinformációk elvesznének.", + "Extract topics" : "Témák kinyerése", + "Extracts topics from a text and outputs them separated by commas." : "Kinyeri a témákat a szövegből, és vesszőkkel elválasztva megjeleníti.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "A(z) %1$s alkalmazás fájljait helytelenül cserélték le. Ellenőrizze, hogy a verzió kompatibilis-e a kiszolgálóval.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "A bejelentkezett felhasználónak rendszergazdának vagy alrendszergazdának kell lennie, vagy speciális hozzáféréssel kell rendelkeznie ehhez a beállításhoz", + "Logged in user must be an admin or sub admin" : "A bejelentkezett felhasználónak rendszergazdának vagy alrendszergazgának kell lennie", + "Logged in user must be an admin" : "A bejelentkezett felhasználónak rendszergazdának kell lennie", "Full name" : "Teljes név", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Elérte a felhasználókorlátot, és a felhasználó nem jött létre. Nézze meg az értesítéseit, hogy többet tudjon meg.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "A felhasználónévben csak a következő karakterek engedélyezettek: „a-z”, „A-Z”, „0-9”, és „_.@-'”", + "Unknown user" : "Ismeretlen felhasználó", + "Enter the database username and name for %s" : "Adja meg a %s adatbázisának nevét és a hozzá tartozó felhasználónevet", + "Enter the database username for %s" : "Adja meg a %s adatbázisához tartozó felhasználónevet", + "MySQL username and/or password not valid" : "A MySQL felhasználónév vagy jelszó érvénytelen", + "Oracle username and/or password not valid" : "Az Oracle felhasználónév vagy jelszó érvénytelen", + "PostgreSQL username and/or password not valid" : "A PostgreSQL felhasználói név vagy jelszó érvénytelen", + "Set an admin username." : "Állítson be egy rendszergazdai felhasználónevet.", + "Sharing %s failed, because this item is already shared with user %s" : "A(z) %s megosztása nem sikerült, mert ez az elem már meg van osztva a(z) %s felhasználóval", + "The username is already being used" : "Ez a felhasználónév már foglalt", + "Could not create user" : "Nem sikerült létrehozni a felhasználót", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "A felhasználónévben csak a következő karakterek engedélyezettek: „a-z”, „A-Z”, „0-9”, szóköz és „_.@-'”", + "A valid username must be provided" : "Érvényes felhasználónevet kell megadnia", + "Username contains whitespace at the beginning or at the end" : "A felhasználónév szóközt tartalmaz az elején vagy a végén", + "Username must not consist of dots only" : "A felhasználónév nem állhat csak pontokból", + "Username is invalid because files already exist for this user" : "A felhasználónév érvénytelen, mert már vannak fájlok ehhez a felhasználóhoz", + "User disabled" : "Felhasználó letiltva", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Legalább libxml2 2.7.0 szükséges. Jelenleg telepített: %s.", "To fix this issue update your libxml2 version and restart your web server." : "A probléma javításához frissítse a libxml2 verziót, és indítsa újra a webkiszolgálót.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 szükséges.", - "Please upgrade your database version." : "Frissítse az adatbázis verzióját." + "Please upgrade your database version." : "Frissítse az adatbázis verzióját.", + "Your data directory is readable by other users." : "Az adatkönyvtára más felhasználók által is olvasható.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Módosítsa a könyvtár elérhetőségi engedélybeállítását 0770-re, hogy a tartalmát más felhasználók ne listázhassák." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/hu.json b/lib/l10n/hu.json index 1f4c8021868..1d9e7307756 100644 --- a/lib/l10n/hu.json +++ b/lib/l10n/hu.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "A(z) %1$s alkalmazás nincs jelen, vagy a verziója nem kompatibilis ezzel a kiszolgálóval. Ellenőrizze az alkalmazástárat.", "Sample configuration detected" : "Példabeállítások észlelve", "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" : "Úgy tűnik, hogy a példakonfigurációt másolta le. Ez működésképtelenné teheti a telepítést, és nem támogatott. Olvassa el a dokumentációt, mielőtt módosításokat véget a config.php fájlban.", - "404" : "404", "The page could not be found on the server." : "Az oldal nem található a kiszolgálón.", "%s email verification" : "%s e-mail ellenőrzés", "Email verification" : "E-mail ellenőrzés", @@ -35,9 +34,6 @@ "The following platforms are supported: %s" : "A következő platformok támogatottak: %s", "Server version %s or higher is required." : "%s vagy újabb kiszolgálóverzió szükséges.", "Server version %s or lower is required." : "%s vagy régebbi kiszolgálóverzió szükséges.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "A bejelentkezett felhasználónak rendszergazdának vagy alrendszergazdának kell lennie, vagy speciális hozzáféréssel kell rendelkeznie ehhez a beállításhoz", - "Logged in user must be an admin or sub admin" : "A bejelentkezett felhasználónak rendszergazdának vagy alrendszergazgának kell lennie", - "Logged in user must be an admin" : "A bejelentkezett felhasználónak rendszergazdának kell lennie", "Wiping of device %s has started" : "A(z) %s eszköz törlése megkezdődött", "Wiping of device »%s« has started" : "A(z) „%s” eszköz törlése megkezdődött", "»%s« started remote wipe" : "„%s” elindította a távoli törlést", @@ -116,22 +112,15 @@ "Headline" : "Címsor", "Organisation" : "Szervezet", "Role" : "Szerepkör", - "Unknown user" : "Ismeretlen felhasználó", "Additional settings" : "További beállítások", - "Enter the database username and name for %s" : "Adja meg a %s adatbázisának nevét és a hozzá tartozó felhasználónevet", - "Enter the database username for %s" : "Adja meg a %s adatbázisához tartozó felhasználónevet", "Enter the database name for %s" : "Adja meg a %s adatbázisának nevét", "You cannot use dots in the database name %s" : "A(z) %s adatbázisnév nem tartalmazhat pontot", - "MySQL username and/or password not valid" : "A MySQL felhasználónév vagy jelszó érvénytelen", "You need to enter details of an existing account." : "Egy már létező fiók adatait kell megadnia.", "Oracle connection could not be established" : "Az Oracle kapcsolat nem hozható létre", - "Oracle username and/or password not valid" : "Az Oracle felhasználónév vagy jelszó érvénytelen", - "PostgreSQL username and/or password not valid" : "A PostgreSQL felhasználói név vagy jelszó érvénytelen", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "A Mac OS X nem támogatott, és a %s nem lesz teljesen működőképes. Csak saját felelősségre használja.", "For the best results, please consider using a GNU/Linux server instead." : "A legjobb eredmény érdekében érdemes GNU/Linux kiszolgálót használni.", "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." : "Úgy tűnik, hogy ez a %s példány 32 bites PHP környezetben fut, és az open_basedir be lett állítva a php.ini fájlban. Ez 4 GB-nál nagyobb fájlok esetén problémákat okozhat, így erősen ellenjavallott.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Távolítsa el az open_basedir beállítást a php.ini fájlból, vagy váltson 64 bites PHP-ra.", - "Set an admin username." : "Állítson be egy rendszergazdai felhasználónevet.", "Set an admin password." : "Állítson be egy rendszergazdai jelszót.", "Cannot create or write into the data directory %s" : "Nem létre létrehozni vagy beleírni a(z) %s adatkönyvtárba", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "A(z) %s megosztási alrendszernek meg kell valósítania az OCP\\Share_Backend interfészt", @@ -149,11 +138,11 @@ "Expiration date is in the past" : "A lejárati dátum már elmúlt", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Nem állítható be %n napnál távolabbi lejárati dátum","Nem állítható be %n napnál távolabbi lejárati dátum"], "Sharing is only allowed with group members" : "A megosztás csak a csoport tagjaival engedélyezett", - "Sharing %s failed, because this item is already shared with user %s" : "A(z) %s megosztása nem sikerült, mert ez az elem már meg van osztva a(z) %s felhasználóval", "%1$s shared »%2$s« with you" : "%1$s megosztotta Önnel: „%2$s”", "%1$s shared »%2$s« with you." : "%1$s megosztotta Önnel: „%2$s”.", "Click the button below to open it." : "Kattintson a lenti gombra a megnyitáshoz.", "The requested share does not exist anymore" : "A kért megosztás már nem létezik", + "The requested share comes from a disabled user" : "A kért megosztás letiltott felhasználótól származik", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "A felhasználó nem jött létre, mert elérte a felhasználókorlátot. Nézze meg az értesítéseit, hogy többet tudjon meg.", "Could not find category \"%s\"" : "Ez a kategória nem található: \"%s\"", "Sunday" : "Vasárnap", @@ -202,14 +191,6 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Érvényes jelszót kell megadnia", - "The username is already being used" : "Ez a felhasználónév már foglalt", - "Could not create user" : "Nem sikerült létrehozni a felhasználót", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "A felhasználónévben csak a következő karakterek engedélyezettek: „a-z”, „A-Z”, „0-9”, szóköz és „_.@-'”", - "A valid username must be provided" : "Érvényes felhasználónevet kell megadnia", - "Username contains whitespace at the beginning or at the end" : "A felhasználónév szóközt tartalmaz az elején vagy a végén", - "Username must not consist of dots only" : "A felhasználónév nem állhat csak pontokból", - "Username is invalid because files already exist for this user" : "A felhasználónév érvénytelen, mert már vannak fájlok ehhez a felhasználóhoz", - "User disabled" : "Felhasználó letiltva", "Login canceled by app" : "Bejelentkezés megszakítva az alkalmazás által", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "A(z) „%1$s” alkalmazást nem lehet telepíteni, mert a következő függőségek nem teljesülnek: %2$s", "a safe home for all your data" : "egy biztonságos hely az adataidnak", @@ -242,8 +223,6 @@ "Please ask your server administrator to restart the web server." : "Kérje meg a rendszergazdát, hogy indítsa újra a webkiszolgálót.", "The required %s config variable is not configured in the config.php file." : "A szükséges %s konfigurációs változó nincs beállítva a config.php fájlban.", "Please ask your server administrator to check the Nextcloud configuration." : "Kérje meg a rendszergazdát, hogy ellenőrizze a Nextcloud konfigurációját.", - "Your data directory is readable by other users." : "Az adatkönyvtára más felhasználók által is olvasható.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Módosítsa a könyvtár elérhetőségi engedélybeállítását 0770-re, hogy a tartalmát más felhasználók ne listázhassák.", "Your data directory must be an absolute path." : "Az adatkönyvtárnak abszolút útvonalnak kell lennie", "Check the value of \"datadirectory\" in your configuration." : "Ellenőrizze a „datadirectory” értékét a konfigurációban.", "Your data directory is invalid." : "Az adatkönyvtár érvénytelen.", @@ -259,13 +238,41 @@ "Storage connection error. %s" : "Tároló kapcsolódási hiba. %s", "Storage is temporarily not available" : "A tároló átmenetileg nem érhető el", "Storage connection timeout. %s" : "Időtúllépés a tárolókapcsolatban. %s", + "Free prompt" : "Szabad prompt", + "Runs an arbitrary prompt through the language model." : "Tetszőleges promptot futtat a nyelvi modellen.", + "Generate headline" : "Címsor előállítása", + "Generates a possible headline for a text." : "Egy lehetséges címsort állít elő egy szöveghez.", + "Summarize" : "Összesítés", + "Summarizes text by reducing its length without losing key information." : "Összesíti a szöveget a hosszúság csökkentésével anélkül, hogy a kulcsinformációk elvesznének.", + "Extract topics" : "Témák kinyerése", + "Extracts topics from a text and outputs them separated by commas." : "Kinyeri a témákat a szövegből, és vesszőkkel elválasztva megjeleníti.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "A(z) %1$s alkalmazás fájljait helytelenül cserélték le. Ellenőrizze, hogy a verzió kompatibilis-e a kiszolgálóval.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "A bejelentkezett felhasználónak rendszergazdának vagy alrendszergazdának kell lennie, vagy speciális hozzáféréssel kell rendelkeznie ehhez a beállításhoz", + "Logged in user must be an admin or sub admin" : "A bejelentkezett felhasználónak rendszergazdának vagy alrendszergazgának kell lennie", + "Logged in user must be an admin" : "A bejelentkezett felhasználónak rendszergazdának kell lennie", "Full name" : "Teljes név", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Elérte a felhasználókorlátot, és a felhasználó nem jött létre. Nézze meg az értesítéseit, hogy többet tudjon meg.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "A felhasználónévben csak a következő karakterek engedélyezettek: „a-z”, „A-Z”, „0-9”, és „_.@-'”", + "Unknown user" : "Ismeretlen felhasználó", + "Enter the database username and name for %s" : "Adja meg a %s adatbázisának nevét és a hozzá tartozó felhasználónevet", + "Enter the database username for %s" : "Adja meg a %s adatbázisához tartozó felhasználónevet", + "MySQL username and/or password not valid" : "A MySQL felhasználónév vagy jelszó érvénytelen", + "Oracle username and/or password not valid" : "Az Oracle felhasználónév vagy jelszó érvénytelen", + "PostgreSQL username and/or password not valid" : "A PostgreSQL felhasználói név vagy jelszó érvénytelen", + "Set an admin username." : "Állítson be egy rendszergazdai felhasználónevet.", + "Sharing %s failed, because this item is already shared with user %s" : "A(z) %s megosztása nem sikerült, mert ez az elem már meg van osztva a(z) %s felhasználóval", + "The username is already being used" : "Ez a felhasználónév már foglalt", + "Could not create user" : "Nem sikerült létrehozni a felhasználót", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "A felhasználónévben csak a következő karakterek engedélyezettek: „a-z”, „A-Z”, „0-9”, szóköz és „_.@-'”", + "A valid username must be provided" : "Érvényes felhasználónevet kell megadnia", + "Username contains whitespace at the beginning or at the end" : "A felhasználónév szóközt tartalmaz az elején vagy a végén", + "Username must not consist of dots only" : "A felhasználónév nem állhat csak pontokból", + "Username is invalid because files already exist for this user" : "A felhasználónév érvénytelen, mert már vannak fájlok ehhez a felhasználóhoz", + "User disabled" : "Felhasználó letiltva", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Legalább libxml2 2.7.0 szükséges. Jelenleg telepített: %s.", "To fix this issue update your libxml2 version and restart your web server." : "A probléma javításához frissítse a libxml2 verziót, és indítsa újra a webkiszolgálót.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 szükséges.", - "Please upgrade your database version." : "Frissítse az adatbázis verzióját." + "Please upgrade your database version." : "Frissítse az adatbázis verzióját.", + "Your data directory is readable by other users." : "Az adatkönyvtára más felhasználók által is olvasható.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Módosítsa a könyvtár elérhetőségi engedélybeállítását 0770-re, hogy a tartalmát más felhasználók ne listázhassák." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/ia.js b/lib/l10n/ia.js index 919e67979c6..8081e4f9c28 100644 --- a/lib/l10n/ia.js +++ b/lib/l10n/ia.js @@ -18,7 +18,6 @@ OC.L10N.register( "Address" : "Adresse", "Profile picture" : "Pictura de profilo", "About" : "A proposito", - "Unknown user" : "Usator incognite", "Sunday" : "Dominica", "Monday" : "Lunedi", "Tuesday" : "Martedi", @@ -65,9 +64,10 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Un contrasigno valide debe esser providite", - "A valid username must be provided" : "Un nomine de usator valide debe esser providite", "Authentication error" : "Error in authentication", "Storage is temporarily not available" : "Immagazinage es provisorimente non disponibile", - "Full name" : "Nomine complete" + "Full name" : "Nomine complete", + "Unknown user" : "Usator incognite", + "A valid username must be provided" : "Un nomine de usator valide debe esser providite" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/ia.json b/lib/l10n/ia.json index dd9415eeb9c..659611e7e48 100644 --- a/lib/l10n/ia.json +++ b/lib/l10n/ia.json @@ -16,7 +16,6 @@ "Address" : "Adresse", "Profile picture" : "Pictura de profilo", "About" : "A proposito", - "Unknown user" : "Usator incognite", "Sunday" : "Dominica", "Monday" : "Lunedi", "Tuesday" : "Martedi", @@ -63,9 +62,10 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Un contrasigno valide debe esser providite", - "A valid username must be provided" : "Un nomine de usator valide debe esser providite", "Authentication error" : "Error in authentication", "Storage is temporarily not available" : "Immagazinage es provisorimente non disponibile", - "Full name" : "Nomine complete" + "Full name" : "Nomine complete", + "Unknown user" : "Usator incognite", + "A valid username must be provided" : "Un nomine de usator valide debe esser providite" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/id.js b/lib/l10n/id.js index 22c945924d7..89933895671 100644 --- a/lib/l10n/id.js +++ b/lib/l10n/id.js @@ -51,16 +51,12 @@ OC.L10N.register( "Address" : "Alamat", "Profile picture" : "Foto profil", "About" : "Tentang.", - "Unknown user" : "Pengguna tidak dikenal", "Additional settings" : "Setelan tambahan", "Oracle connection could not be established" : "Koneksi Oracle tidak dapat dibuat", - "Oracle username and/or password not valid" : "Nama pengguna dan/atau kata sandi Oracle tidak sah", - "PostgreSQL username and/or password not valid" : "Nama pengguna dan/atau kata sandi PostgreSQL tidak valid", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X tidak didukung dan %s tidak akan bekerja dengan baik pada platform ini. Gunakan dengan resiko Anda sendiri!", "For the best results, please consider using a GNU/Linux server instead." : "Untuk hasil terbaik, pertimbangkan untuk menggunakan server GNU/Linux sebagai gantinya. ", "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." : "Kelihatannya instansi %s ini berjalan di lingkungan PHP 32-bit dan open_basedir telah dikonfigurasi di php.ini. Hal ini akan menyebabkan masalah dengan berkas lebih dari 4 GB dan sangat tidak disarankan.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Mohon hapus pengaturan open_basedir didalam php.ini atau beralih ke PHP 64-bit.", - "Set an admin username." : "Tetapkan nama pengguna admin.", "Set an admin password." : "Tetapkan kata sandi admin.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Backend berbagi %s harus mengimplementasi antarmuka OCP\\Share_Backend", "Sharing backend %s not found" : "Backend berbagi %s tidak ditemukan", @@ -69,7 +65,6 @@ OC.L10N.register( "You are not allowed to share %s" : "Anda tidak diizinkan untuk membagikan %s", "Cannot increase permissions of %s" : "Tidak dapat menambah izin %s", "Expiration date is in the past" : "Tanggal kedaluwarsa sudah lewat", - "Sharing %s failed, because this item is already shared with user %s" : "Berbagi %s gagal karena item ini sudah dibagikan dengan pengguna %s", "Could not find category \"%s\"" : "Tidak menemukan kategori \"%s\"", "Sunday" : "Minggu", "Monday" : "Senin", @@ -117,10 +112,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Des.", "A valid password must be provided" : "Tuliskan kata sandi yang valid", - "The username is already being used" : "Nama pengguna ini telah digunakan", - "A valid username must be provided" : "Tuliskan nama pengguna yang valid", - "Username contains whitespace at the beginning or at the end" : "Nama pengguna mengandung spasi di depan atau di belakang.", - "User disabled" : "Pengguna dinonaktifkan", "Login canceled by app" : "Log masuk dibatalkan oleh aplikasi", "a safe home for all your data" : "rumah yang aman untuk semua data Anda", "File is currently busy, please try again later" : "Berkas sedang sibuk, mohon coba lagi nanti", @@ -129,14 +120,13 @@ OC.L10N.register( "Token expired. Please reload page." : "Token sudah kedaluwarsa. Silakan muat ulang halaman.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Tidak ada driver (sqlite, mysql, or postgresql) yang terinstal.", "PHP module %s not installed." : "Module PHP %s tidak terinstal.", - "Please ask your server administrator to install the module." : "Mohon tanyakan administrator Anda untuk menginstal module.", + "Please ask your server administrator to install the module." : "Mohon tanyakan administrator Anda untuk menginstal modul.", "PHP setting \"%s\" is not set to \"%s\"." : "Pengaturan PHP \"%s\" tidak diatur ke \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Menyesuaikan pengaturan ini di php.ini akan membuat Nextcloud berjalan kembali", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Tampaknya PHP diatur untuk memotong inline doc blocks. Hal ini akan menyebabkan beberapa aplikasi inti menjadi tidak dapat diakses.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Hal ini kemungkinan disebabkan oleh cache/akselerator seperti Zend OPcache atau eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Modul PHP telah terinstal, tetapi mereka terlihat tidak ada?", "Please ask your server administrator to restart the web server." : "Mohon minta administrator Anda untuk menjalankan ulang server web.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Mohon ubah perizinan menjadi 0770 sehingga direktori tersebut tidak dapat dilihat oleh pengguna lain.", "Could not obtain lock type %d on \"%s\"." : "Tidak bisa memperoleh jenis kunci %d pada \"%s\".", "Storage unauthorized. %s" : "Penyimpanan tidak terotorisasi. %s", "Storage incomplete configuration. %s" : "Konfigurasi penyimpanan tidak terselesaikan. %s", @@ -144,8 +134,17 @@ OC.L10N.register( "Storage is temporarily not available" : "Penyimpanan sementara tidak tersedia", "Storage connection timeout. %s" : "Koneksi penyimpanan waktu-habis. %s", "Full name" : "Nama lengkap", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Hanya karakter ini yang diizinkan dalam nama pengguna: \"a-z\", \"A-Z\", \"0-9\", dan \"_.@-'\"", + "Unknown user" : "Pengguna tidak dikenal", + "Oracle username and/or password not valid" : "Nama pengguna dan/atau kata sandi Oracle tidak sah", + "PostgreSQL username and/or password not valid" : "Nama pengguna dan/atau kata sandi PostgreSQL tidak valid", + "Set an admin username." : "Tetapkan nama pengguna admin.", + "Sharing %s failed, because this item is already shared with user %s" : "Berbagi %s gagal karena item ini sudah dibagikan dengan pengguna %s", + "The username is already being used" : "Nama pengguna ini telah digunakan", + "A valid username must be provided" : "Tuliskan nama pengguna yang valid", + "Username contains whitespace at the beginning or at the end" : "Nama pengguna mengandung spasi di depan atau di belakang.", + "User disabled" : "Pengguna dinonaktifkan", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Setidaknya libxml2 2.7.0 dibutuhkan. Saat ini %s dipasang.", - "To fix this issue update your libxml2 version and restart your web server." : "Untuk mengatasi masalah ini, perbarui versi libxml2 Anda dan mulai-ulang server web Anda." + "To fix this issue update your libxml2 version and restart your web server." : "Untuk mengatasi masalah ini, perbarui versi libxml2 Anda dan mulai-ulang server web Anda.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Mohon ubah perizinan menjadi 0770 sehingga direktori tersebut tidak dapat dilihat oleh pengguna lain." }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/id.json b/lib/l10n/id.json index 0950b536d82..3509081c1a3 100644 --- a/lib/l10n/id.json +++ b/lib/l10n/id.json @@ -49,16 +49,12 @@ "Address" : "Alamat", "Profile picture" : "Foto profil", "About" : "Tentang.", - "Unknown user" : "Pengguna tidak dikenal", "Additional settings" : "Setelan tambahan", "Oracle connection could not be established" : "Koneksi Oracle tidak dapat dibuat", - "Oracle username and/or password not valid" : "Nama pengguna dan/atau kata sandi Oracle tidak sah", - "PostgreSQL username and/or password not valid" : "Nama pengguna dan/atau kata sandi PostgreSQL tidak valid", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X tidak didukung dan %s tidak akan bekerja dengan baik pada platform ini. Gunakan dengan resiko Anda sendiri!", "For the best results, please consider using a GNU/Linux server instead." : "Untuk hasil terbaik, pertimbangkan untuk menggunakan server GNU/Linux sebagai gantinya. ", "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." : "Kelihatannya instansi %s ini berjalan di lingkungan PHP 32-bit dan open_basedir telah dikonfigurasi di php.ini. Hal ini akan menyebabkan masalah dengan berkas lebih dari 4 GB dan sangat tidak disarankan.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Mohon hapus pengaturan open_basedir didalam php.ini atau beralih ke PHP 64-bit.", - "Set an admin username." : "Tetapkan nama pengguna admin.", "Set an admin password." : "Tetapkan kata sandi admin.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Backend berbagi %s harus mengimplementasi antarmuka OCP\\Share_Backend", "Sharing backend %s not found" : "Backend berbagi %s tidak ditemukan", @@ -67,7 +63,6 @@ "You are not allowed to share %s" : "Anda tidak diizinkan untuk membagikan %s", "Cannot increase permissions of %s" : "Tidak dapat menambah izin %s", "Expiration date is in the past" : "Tanggal kedaluwarsa sudah lewat", - "Sharing %s failed, because this item is already shared with user %s" : "Berbagi %s gagal karena item ini sudah dibagikan dengan pengguna %s", "Could not find category \"%s\"" : "Tidak menemukan kategori \"%s\"", "Sunday" : "Minggu", "Monday" : "Senin", @@ -115,10 +110,6 @@ "Nov." : "Nov.", "Dec." : "Des.", "A valid password must be provided" : "Tuliskan kata sandi yang valid", - "The username is already being used" : "Nama pengguna ini telah digunakan", - "A valid username must be provided" : "Tuliskan nama pengguna yang valid", - "Username contains whitespace at the beginning or at the end" : "Nama pengguna mengandung spasi di depan atau di belakang.", - "User disabled" : "Pengguna dinonaktifkan", "Login canceled by app" : "Log masuk dibatalkan oleh aplikasi", "a safe home for all your data" : "rumah yang aman untuk semua data Anda", "File is currently busy, please try again later" : "Berkas sedang sibuk, mohon coba lagi nanti", @@ -127,14 +118,13 @@ "Token expired. Please reload page." : "Token sudah kedaluwarsa. Silakan muat ulang halaman.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Tidak ada driver (sqlite, mysql, or postgresql) yang terinstal.", "PHP module %s not installed." : "Module PHP %s tidak terinstal.", - "Please ask your server administrator to install the module." : "Mohon tanyakan administrator Anda untuk menginstal module.", + "Please ask your server administrator to install the module." : "Mohon tanyakan administrator Anda untuk menginstal modul.", "PHP setting \"%s\" is not set to \"%s\"." : "Pengaturan PHP \"%s\" tidak diatur ke \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Menyesuaikan pengaturan ini di php.ini akan membuat Nextcloud berjalan kembali", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Tampaknya PHP diatur untuk memotong inline doc blocks. Hal ini akan menyebabkan beberapa aplikasi inti menjadi tidak dapat diakses.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Hal ini kemungkinan disebabkan oleh cache/akselerator seperti Zend OPcache atau eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Modul PHP telah terinstal, tetapi mereka terlihat tidak ada?", "Please ask your server administrator to restart the web server." : "Mohon minta administrator Anda untuk menjalankan ulang server web.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Mohon ubah perizinan menjadi 0770 sehingga direktori tersebut tidak dapat dilihat oleh pengguna lain.", "Could not obtain lock type %d on \"%s\"." : "Tidak bisa memperoleh jenis kunci %d pada \"%s\".", "Storage unauthorized. %s" : "Penyimpanan tidak terotorisasi. %s", "Storage incomplete configuration. %s" : "Konfigurasi penyimpanan tidak terselesaikan. %s", @@ -142,8 +132,17 @@ "Storage is temporarily not available" : "Penyimpanan sementara tidak tersedia", "Storage connection timeout. %s" : "Koneksi penyimpanan waktu-habis. %s", "Full name" : "Nama lengkap", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Hanya karakter ini yang diizinkan dalam nama pengguna: \"a-z\", \"A-Z\", \"0-9\", dan \"_.@-'\"", + "Unknown user" : "Pengguna tidak dikenal", + "Oracle username and/or password not valid" : "Nama pengguna dan/atau kata sandi Oracle tidak sah", + "PostgreSQL username and/or password not valid" : "Nama pengguna dan/atau kata sandi PostgreSQL tidak valid", + "Set an admin username." : "Tetapkan nama pengguna admin.", + "Sharing %s failed, because this item is already shared with user %s" : "Berbagi %s gagal karena item ini sudah dibagikan dengan pengguna %s", + "The username is already being used" : "Nama pengguna ini telah digunakan", + "A valid username must be provided" : "Tuliskan nama pengguna yang valid", + "Username contains whitespace at the beginning or at the end" : "Nama pengguna mengandung spasi di depan atau di belakang.", + "User disabled" : "Pengguna dinonaktifkan", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Setidaknya libxml2 2.7.0 dibutuhkan. Saat ini %s dipasang.", - "To fix this issue update your libxml2 version and restart your web server." : "Untuk mengatasi masalah ini, perbarui versi libxml2 Anda dan mulai-ulang server web Anda." + "To fix this issue update your libxml2 version and restart your web server." : "Untuk mengatasi masalah ini, perbarui versi libxml2 Anda dan mulai-ulang server web Anda.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Mohon ubah perizinan menjadi 0770 sehingga direktori tersebut tidak dapat dilihat oleh pengguna lain." },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/is.js b/lib/l10n/is.js index 512e2d5d831..5916e360121 100644 --- a/lib/l10n/is.js +++ b/lib/l10n/is.js @@ -2,9 +2,19 @@ OC.L10N.register( "lib", { "Cannot write into \"config\" directory!" : "Get ekki skrifað í \"config\" möppuna!", + "This can usually be fixed by giving the web server write access to the config directory." : "Þetta er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í stillingamöppuna.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "En ef þú vilt halda config.php skránni einungis til lesanlegri, skaltu setja valkostinn \"config_is_read_only\" á 'true' í henni.", "See %s" : "Skoðaðu %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Forritið %1$s er ekki til staðar eða er af útgáfu sem ekki er samhæfð þessum netþjóni. Endilega skoðaðu í forritamöppuna.", "Sample configuration detected" : "Fann sýnisuppsetningu", "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" : "Komið hefur í ljós að sýniuppsetningin var afrituð. Þetta getur skemmt uppsetninguna og er ekki stutt. Endilega lestu hjálparskjölin áður en þú gerir breytingar á config.php", + "The page could not be found on the server." : "Síðan fannst ekki á netþjóninum.", + "%s email verification" : "Sannvottun tölvupósts fyrir %s", + "Email verification" : "Sannvottun tölvupósts", + "Click the following button to confirm your email." : "Smelltu á eftirfarandi hnapp til að staðfesta tölvupóstfangið þitt.", + "Click the following link to confirm your email." : "Smelltu á eftirfarandi tengil til að staðfesta tölvupóstfangið þitt.", + "Confirm your email" : "Staðfestu tölvupóstfangið þitt", + "Other activities" : "Aðrar athafnir", "%1$s and %2$s" : "%1$s og %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s og %3$s", "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s og %4$s", @@ -12,18 +22,20 @@ OC.L10N.register( "Education Edition" : "Kennsluútgáfa", "Enterprise bundle" : "Fyrirtækjavöndull", "Groupware bundle" : "Hópvinnsluvöndull", + "Hub bundle" : "Tengivöndull", "Social sharing bundle" : "Deilivöndull fyrir samfélagsmiðla", "PHP %s or higher is required." : "Krafist er PHP %s eða hærra.", "PHP with a version lower than %s is required." : "Krafist er PHP útgáfu %s eða lægri.", "%sbit or higher PHP required." : "Krafist er PHP %sbita eða hærra.", + "The following architectures are supported: %s" : "Eftirfarandi tölvukerfi eru studd: %s", + "The following databases are supported: %s" : "Eftirfarandi gagnagrunnar eru studdir: %s", "The command line tool %s could not be found" : "Skipanalínutólið \"%s\" fannst ekki", "The library %s is not available." : "Aðgerðasafnið %s er ekki tiltækt.", "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Krafist er aðgerðasafns %1$s með útgáfu hærri en %2$s - tiltæk útgáfa er %3$s.", "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Krafist er aðgerðasafns %1$s með útgáfu lægri en %2$s - tiltæk útgáfa er %3$s.", + "The following platforms are supported: %s" : "Eftirfarandi stýrikerfi eru studd: %s", "Server version %s or higher is required." : "Krafist er þjóns af útgáfu %s eða hærra.", "Server version %s or lower is required." : "Krafist er þjóns af útgáfu %s eða lægri.", - "Logged in user must be an admin or sub admin" : "Innskráður notandi verður að vera kerfisstjóri eða undirstjórnandi", - "Logged in user must be an admin" : "Innskráður notandi verður að vera stjórnandi", "Wiping of device %s has started" : "Útþurrkun af tækinu %s er byrjuð", "Wiping of device »%s« has started" : "Útþurrkun af tækinu »%s« er byrjuð", "»%s« started remote wipe" : "»%s« byrjaði fjartengda útþurrkun", @@ -41,6 +53,8 @@ OC.L10N.register( "Invalid image" : "Ógild mynd", "Avatar image is not square" : "Auðkennismynd er ekki ferningslaga", "Files" : "Skrár", + "View profile" : "Skoða notandasnið", + "Local time: %s" : "Staðartími: %s", "today" : "í dag", "tomorrow" : "á morgun", "yesterday" : "í gær", @@ -60,8 +74,11 @@ OC.L10N.register( "_%n minute ago_::_%n minutes ago_" : ["fyrir %n mínútu síðan","fyrir %n mínútum síðan"], "in a few seconds" : "eftir örfáar sekúndur", "seconds ago" : "sekúndum síðan", + "Empty file" : "Tóm skrá", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Eining með auðkenni: %s er ekki til. Virkjaðu hana í forritastillingum eða hafðu samband við kerfisstjóra.", "File already exists" : "Skrá er þegar til", + "Invalid path" : "Ógild slóð", + "Failed to create file from template" : "Mistókst að búa til skrá út frá sniðmáti", "Templates" : "Sniðmát", "File name is a reserved word" : "Skráarheiti er þegar frátekið orð", "File name contains at least one invalid character" : "Skráarheitið inniheldur að minnsta kosti einn ógildan staf", @@ -73,31 +90,41 @@ OC.L10N.register( "__language_name__" : "Íslenska", "This is an automatically sent email, please do not reply." : "Þetta er sjálfvirk tölvupóstsending, ekki svara þessu.", "Help" : "Hjálp", + "Appearance and accessibility" : "Útlit og aðgengi", "Apps" : "Forrit", + "Personal settings" : "Persónulegar stillingar", + "Administration settings" : "Stillingar stjórnunar", "Settings" : "Stillingar", "Log out" : "Skrá út", "Users" : "Notendur", "Email" : "Tölvupóstur", + "Mail %s" : "Póstur %s", + "Fediverse" : "Skýjasamband", + "View %s on the fediverse" : "Skoða %s á skýjasambandi (fediverse)", "Phone" : "Sími", + "Call %s" : "Hringja í %s", "Twitter" : "Twitter", + "View %s on Twitter" : "Skoða %s á Twitter", "Website" : "Vefsvæði", + "Visit %s" : "Heimsækja %s", "Address" : "Vistfang", "Profile picture" : "Einkennismynd", "About" : "Um hugbúnaðinn", + "Display name" : "Birtingarnafn", "Headline" : "Fyrirsögn", + "Organisation" : "Stofnun/Félag/Fyrirtæki", "Role" : "Role", - "Unknown user" : "Óþekktur notandi", "Additional settings" : "Valfrjálsar stillingar", + "Enter the database name for %s" : "Settu inn nafn á gagnagrunni fyrir %s", + "You cannot use dots in the database name %s" : "Þú mátt ekki nota punkta í gagnagrunnsheitinu %s", "You need to enter details of an existing account." : "Þú verður að setja inn auðkenni fyrirliggjandi notandaaðgangs.", "Oracle connection could not be established" : "Ekki tókst að koma tengingu á við Oracle", - "Oracle username and/or password not valid" : "Notandanafn eða lykilorð Oracle er ekki gilt", - "PostgreSQL username and/or password not valid" : "Notandanafn eða lykilorð PostgreSQL er ekki gilt", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X er ekki stutt og %s mun ekki vinna eðlilega á þessu stýrikerfi. Notaðu þetta því á þína eigin ábyrgð! ", "For the best results, please consider using a GNU/Linux server instead." : "Fyrir bestu útkomu ættirðu að íhuga að nota GNU/Linux þjón í staðinn.", "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." : "Það lítur út eins og þessi %s uppsetning sé að keyra á 32-bita PHP umhverfi og að open_basedir hafi verið stillt í php.ini. Þetta mun valda vandamálum með skrár stærri en 4 GB og er stranglega mælt gegn því að þetta sé gert.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Fjarlægðu stillinguna open_basedir úr php.ini eða skiptu yfir í 64-bita PHP.", - "Set an admin username." : "Stilltu notandanafn kerfisstjóra.", "Set an admin password." : "Stilltu lykilorð kerfisstjóra.", + "Cannot create or write into the data directory %s" : "Gat ekki búið til eða skrifað í gagnamöppuna %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Deilingarbakendinn %s verður að vera settur upp fyrir viðmótið OCP\\Share_Backend", "Sharing backend %s not found" : "Deilingarbakendinn %s fannst ekki", "Sharing backend for %s not found" : "Deilingarbakendi fyrir %s fannst ekki", @@ -108,12 +135,17 @@ OC.L10N.register( "%1$s via %2$s" : "%1$s með %2$s", "You are not allowed to share %s" : "Þú hefur ekki heimild til að deila %s", "Cannot increase permissions of %s" : "Get ekki aukið aðgangsheimildir %s", + "Files cannot be shared with delete permissions" : "Ekki er hægt að deila skrá með eyða-heimildum", + "Files cannot be shared with create permissions" : "Ekki er hægt að deila skrá með búa-til-heimildum", "Expiration date is in the past" : "Gildistíminn er þegar runninn út", - "Sharing %s failed, because this item is already shared with user %s" : "Deiling %s mistókst, því þessu atriði er þegar deilt með notandanum %s", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Ekki er hægt að setja lokadagsetningu meira en %n dag fram í tímann","Ekki er hægt að setja lokadagsetningu meira en %n daga fram í tímann"], + "Sharing is only allowed with group members" : "Deiling er aðeins leyfð með meðlimum hópsins", "%1$s shared »%2$s« with you" : "%1$s deildi »%2$s« með þér", "%1$s shared »%2$s« with you." : "%1$s deildi »%2$s« með þér.", "Click the button below to open it." : "Smelltu á hnappinn hér fyrir neðan til að opna það.", "The requested share does not exist anymore" : "Umbeðin sameign er ekki lengur til", + "The requested share comes from a disabled user" : "Umbeðin sameign kemur frá notanda sem er óvirkur", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Notandinn var ekki búinn til þar sem takmörkum á fjölda notenda var náð. Skoðaðu tilkynningarnar þínar til að sjá meira.", "Could not find category \"%s\"" : "Fann ekki flokkinn \"%s\"", "Sunday" : "Sunnudagur", "Monday" : "Mánudagur", @@ -161,31 +193,41 @@ OC.L10N.register( "Nov." : "Nóv.", "Dec." : "Des.", "A valid password must be provided" : "Skráðu inn gilt lykilorð", - "The username is already being used" : "Notandanafnið er þegar í notkun", - "Could not create user" : "Gat ekki búið til notanda", - "A valid username must be provided" : "Skráðu inn gilt notandanafn", - "Username contains whitespace at the beginning or at the end" : "Notandanafnið inniheldur orðabil í upphafi eða enda", - "Username must not consist of dots only" : "Notandanafn má ekki einungis samanstanda af punktum", - "Username is invalid because files already exist for this user" : "Notandanafnið er ógilt vegna þess að þegar eru fyrir hendi skrár sem tilheyra þessum notanda", - "User disabled" : "Notandi óvirkur", "Login canceled by app" : "Forrit hætti við innskráningu", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Ekki var hægt að setja upp \"%1$s\" forritið þar sem eftirfarandi kerfiskröfur eru ekki uppfylltar: %2$s", "a safe home for all your data" : "öruggur staður fyrir öll gögnin þín", "File is currently busy, please try again later" : "Skráin er upptekin í augnablikinu, reyndu aftur síðar", + "Cannot download file" : "Get ekki sótt skrá", "Application is not enabled" : "Forrit ekki virkt", "Authentication error" : "Villa við auðkenningu", "Token expired. Please reload page." : "Kenniteikn er útrunnið. Þú ættir að hlaða síðunni aftur inn.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Engir reklar fyrir gagnagrunn eru uppsettir (sqlite, mysql eða postgresql).", + "Cannot write into \"config\" directory." : "Get ekki skrifað í \"config\" möppuna.", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Þetta er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í stillingamöppuna. Skoðaðu %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" : "Eða, ef þú vilt halda config.php skránni aðeins til lestrar, settu valkostinn \"config_is_read_only\" á 'true' í henni. Skoðaðu %s", + "Cannot write into \"apps\" directory." : "Get ekki skrifað í \"apps\" möppuna.", + "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." : "Þetta er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í forritamöppuna eða gera App Store forritabúðina óvirka í stillingaskránni. ", + "Cannot create \"data\" directory." : "Get ekki búið til \"data\" möppu.", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Þetta er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í rótarmöppuna. Skoðaðu %s", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Heimildir er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í rótarmöppuna. Skoðaðu %s.", + "Your data directory is not writable." : "Gagnamappn þín er ekki lesanleg.", + "Setting locale to %s failed." : "Mistókst að setja upp staðfærsluna %s.", + "Please install one of these locales on your system and restart your web server." : "Settu upp eina af þessum staðfærslum og endurræstu vefþjóninn.", "PHP module %s not installed." : "PHP-einingin %s er ekki uppsett.", "Please ask your server administrator to install the module." : "Biddu kerfisstjórann þinn um að setja eininguna upp.", "PHP setting \"%s\" is not set to \"%s\"." : "PHP-stillingin \"%s\" er ekki sett á \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ef þessi stilling er löguð í php.ini mun Nextcloud keyra aftur", + "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> er stillt á <code>%s</code> í stað gildisins \"<code>0</code> eins og vænst var.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Til að laga þetta vandamál ættirðu að setja <code>mbstring.func_overload</code> sem <code>0</code> í php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP virðist vera sett upp to fjarlægja innantextablokkir (inline doc blocks). Þetta mun gera ýmis kjarnaforrit óaðgengileg.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Þessu veldur væntanlega biðminni/hraðall á borð við Zend OPcache eða eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Búið er að setja upp PHP-einingar, en eru þær ennþá taldar upp eins og þær vanti?", "Please ask your server administrator to restart the web server." : "Biddu kerfisstjórann þinn um að endurræsa vefþjóninn.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endilega breyttu heimildunum í 0770 svo að aðrir notendur geti ekki listað upp innihald hennar.", + "The required %s config variable is not configured in the config.php file." : "Nauðsynleg %s stillingabreyta er ekki stillt í config.php file.", + "Please ask your server administrator to check the Nextcloud configuration." : "Biddu kerfisstjórann þinn um að athuga uppsetninguna á Nextcloud.", + "Your data directory must be an absolute path." : "Gagnamappan þín verður að vera með algilda slóð.", + "Check the value of \"datadirectory\" in your configuration." : "Athugaðu gildi \"datadirectory\" í uppsetningunni þinni.", + "Your data directory is invalid." : "Gagnamappan þín er ógild.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Gakktu úr skugga um að til staðar sé skrá með heitinu \".ocdata\" í rót gagnageymslunnar.", "Action \"%s\" not supported or implemented." : "Aðgerðin \"%s\" er ekki studd eða útfærð.", "Authentication failed, wrong token or provider ID given" : "Auðkenning mistókst, uppgefið rangt teikn eða auðkenni þjónustuveitu", @@ -198,10 +240,41 @@ OC.L10N.register( "Storage connection error. %s" : "Villa í tengingu við gagnageymslu. %s", "Storage is temporarily not available" : "Gagnageymsla ekki tiltæk í augnablikinu", "Storage connection timeout. %s" : "Gagnageymsla féll á tíma. %s", + "Free prompt" : "Frjáls kvaðning", + "Runs an arbitrary prompt through the language model." : "Keyrir óreglulega kvaðningu (prompt) í gegnum tungumálslíkanið.", + "Generate headline" : "Útbúa fyrirsögn", + "Generates a possible headline for a text." : "Útbýr mögulega fyrirsögn fyrir texta.", + "Summarize" : "Gera samantekt", + "Summarizes text by reducing its length without losing key information." : "Tekur saman aðalatriði texta með því að stytta hann án þess að tapa mikilvægustu upplýsingum.", + "Extract topics" : "Taka út efnisflokka", + "Extracts topics from a text and outputs them separated by commas." : "Greinir efnisflokka úr texta og aðskilur þá með kommum.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Skrám forritsins %$1s var ekki rétt skipt út. Gakktu úr skugga um að þetta sé útgáfa sem sé samhæfð útgáfu vefþjónsins.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Innskráður notandi verður að vera kerfisstjóri eða undirstjórnandi eða hafa fengið sérstaka aðgangsheimild fyrir þessa stillingu", + "Logged in user must be an admin or sub admin" : "Innskráður notandi verður að vera kerfisstjóri eða undirstjórnandi", + "Logged in user must be an admin" : "Innskráður notandi verður að vera stjórnandi", "Full name" : "Fullt nafn", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Einungis eru leyfilegir eftirfarandi stafir í notandanafni: \"a-z\", \"A-Z\", \"0-9\", og \"_.@-'\"", + "Unknown user" : "Óþekktur notandi", + "Enter the database username and name for %s" : "Settu inn notandanafn og nafn í gagnagrunni fyrir %s", + "Enter the database username for %s" : "Settu inn notandanafn í gagnagrunni fyrir %s", + "MySQL username and/or password not valid" : "Notandanafn eða lykilorð MySQL er ekki gilt", + "Oracle username and/or password not valid" : "Notandanafn eða lykilorð Oracle er ekki gilt", + "PostgreSQL username and/or password not valid" : "Notandanafn eða lykilorð PostgreSQL er ekki gilt", + "Set an admin username." : "Stilltu notandanafn kerfisstjóra.", + "Sharing %s failed, because this item is already shared with user %s" : "Deiling %s mistókst, því þessu atriði er þegar deilt með notandanum %s", + "The username is already being used" : "Notandanafnið er þegar í notkun", + "Could not create user" : "Gat ekki búið til notanda", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Einungis eru leyfilegir eftirfarandi stafir í notandanafni: \"a-z\", \"A-Z\", \"0-9\", bil og \"_.@-'\"", + "A valid username must be provided" : "Skráðu inn gilt notandanafn", + "Username contains whitespace at the beginning or at the end" : "Notandanafnið inniheldur orðabil í upphafi eða enda", + "Username must not consist of dots only" : "Notandanafn má ekki einungis samanstanda af punktum", + "Username is invalid because files already exist for this user" : "Notandanafnið er ógilt vegna þess að þegar eru fyrir hendi skrár sem tilheyra þessum notanda", + "User disabled" : "Notandi óvirkur", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Krafist er libxml2 2.7.0 hið minnsta. Núna er %s uppsett.", - "To fix this issue update your libxml2 version and restart your web server." : "Til að laga þetta vandamál ættirðu að uppfæra útgáfu þína af libxml2 og endurræsa vefþjóninn." + "To fix this issue update your libxml2 version and restart your web server." : "Til að laga þetta vandamál ættirðu að uppfæra útgáfu þína af libxml2 og endurræsa vefþjóninn.", + "PostgreSQL >= 9 required." : "Krefst PostgreSQL >= 9.", + "Please upgrade your database version." : "Uppfærðu útgáfu gagnagrunnsins.", + "Your data directory is readable by other users." : "Gagnamappn þín er lesanleg fyrir aðra notendur.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endilega breyttu heimildunum í 0770 svo að aðrir notendur geti ekki listað upp innihald hennar." }, "nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);"); diff --git a/lib/l10n/is.json b/lib/l10n/is.json index 372efc31675..63e700a12e9 100644 --- a/lib/l10n/is.json +++ b/lib/l10n/is.json @@ -1,8 +1,18 @@ { "translations": { "Cannot write into \"config\" directory!" : "Get ekki skrifað í \"config\" möppuna!", + "This can usually be fixed by giving the web server write access to the config directory." : "Þetta er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í stillingamöppuna.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "En ef þú vilt halda config.php skránni einungis til lesanlegri, skaltu setja valkostinn \"config_is_read_only\" á 'true' í henni.", "See %s" : "Skoðaðu %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Forritið %1$s er ekki til staðar eða er af útgáfu sem ekki er samhæfð þessum netþjóni. Endilega skoðaðu í forritamöppuna.", "Sample configuration detected" : "Fann sýnisuppsetningu", "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" : "Komið hefur í ljós að sýniuppsetningin var afrituð. Þetta getur skemmt uppsetninguna og er ekki stutt. Endilega lestu hjálparskjölin áður en þú gerir breytingar á config.php", + "The page could not be found on the server." : "Síðan fannst ekki á netþjóninum.", + "%s email verification" : "Sannvottun tölvupósts fyrir %s", + "Email verification" : "Sannvottun tölvupósts", + "Click the following button to confirm your email." : "Smelltu á eftirfarandi hnapp til að staðfesta tölvupóstfangið þitt.", + "Click the following link to confirm your email." : "Smelltu á eftirfarandi tengil til að staðfesta tölvupóstfangið þitt.", + "Confirm your email" : "Staðfestu tölvupóstfangið þitt", + "Other activities" : "Aðrar athafnir", "%1$s and %2$s" : "%1$s og %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s og %3$s", "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s og %4$s", @@ -10,18 +20,20 @@ "Education Edition" : "Kennsluútgáfa", "Enterprise bundle" : "Fyrirtækjavöndull", "Groupware bundle" : "Hópvinnsluvöndull", + "Hub bundle" : "Tengivöndull", "Social sharing bundle" : "Deilivöndull fyrir samfélagsmiðla", "PHP %s or higher is required." : "Krafist er PHP %s eða hærra.", "PHP with a version lower than %s is required." : "Krafist er PHP útgáfu %s eða lægri.", "%sbit or higher PHP required." : "Krafist er PHP %sbita eða hærra.", + "The following architectures are supported: %s" : "Eftirfarandi tölvukerfi eru studd: %s", + "The following databases are supported: %s" : "Eftirfarandi gagnagrunnar eru studdir: %s", "The command line tool %s could not be found" : "Skipanalínutólið \"%s\" fannst ekki", "The library %s is not available." : "Aðgerðasafnið %s er ekki tiltækt.", "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Krafist er aðgerðasafns %1$s með útgáfu hærri en %2$s - tiltæk útgáfa er %3$s.", "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Krafist er aðgerðasafns %1$s með útgáfu lægri en %2$s - tiltæk útgáfa er %3$s.", + "The following platforms are supported: %s" : "Eftirfarandi stýrikerfi eru studd: %s", "Server version %s or higher is required." : "Krafist er þjóns af útgáfu %s eða hærra.", "Server version %s or lower is required." : "Krafist er þjóns af útgáfu %s eða lægri.", - "Logged in user must be an admin or sub admin" : "Innskráður notandi verður að vera kerfisstjóri eða undirstjórnandi", - "Logged in user must be an admin" : "Innskráður notandi verður að vera stjórnandi", "Wiping of device %s has started" : "Útþurrkun af tækinu %s er byrjuð", "Wiping of device »%s« has started" : "Útþurrkun af tækinu »%s« er byrjuð", "»%s« started remote wipe" : "»%s« byrjaði fjartengda útþurrkun", @@ -39,6 +51,8 @@ "Invalid image" : "Ógild mynd", "Avatar image is not square" : "Auðkennismynd er ekki ferningslaga", "Files" : "Skrár", + "View profile" : "Skoða notandasnið", + "Local time: %s" : "Staðartími: %s", "today" : "í dag", "tomorrow" : "á morgun", "yesterday" : "í gær", @@ -58,8 +72,11 @@ "_%n minute ago_::_%n minutes ago_" : ["fyrir %n mínútu síðan","fyrir %n mínútum síðan"], "in a few seconds" : "eftir örfáar sekúndur", "seconds ago" : "sekúndum síðan", + "Empty file" : "Tóm skrá", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Eining með auðkenni: %s er ekki til. Virkjaðu hana í forritastillingum eða hafðu samband við kerfisstjóra.", "File already exists" : "Skrá er þegar til", + "Invalid path" : "Ógild slóð", + "Failed to create file from template" : "Mistókst að búa til skrá út frá sniðmáti", "Templates" : "Sniðmát", "File name is a reserved word" : "Skráarheiti er þegar frátekið orð", "File name contains at least one invalid character" : "Skráarheitið inniheldur að minnsta kosti einn ógildan staf", @@ -71,31 +88,41 @@ "__language_name__" : "Íslenska", "This is an automatically sent email, please do not reply." : "Þetta er sjálfvirk tölvupóstsending, ekki svara þessu.", "Help" : "Hjálp", + "Appearance and accessibility" : "Útlit og aðgengi", "Apps" : "Forrit", + "Personal settings" : "Persónulegar stillingar", + "Administration settings" : "Stillingar stjórnunar", "Settings" : "Stillingar", "Log out" : "Skrá út", "Users" : "Notendur", "Email" : "Tölvupóstur", + "Mail %s" : "Póstur %s", + "Fediverse" : "Skýjasamband", + "View %s on the fediverse" : "Skoða %s á skýjasambandi (fediverse)", "Phone" : "Sími", + "Call %s" : "Hringja í %s", "Twitter" : "Twitter", + "View %s on Twitter" : "Skoða %s á Twitter", "Website" : "Vefsvæði", + "Visit %s" : "Heimsækja %s", "Address" : "Vistfang", "Profile picture" : "Einkennismynd", "About" : "Um hugbúnaðinn", + "Display name" : "Birtingarnafn", "Headline" : "Fyrirsögn", + "Organisation" : "Stofnun/Félag/Fyrirtæki", "Role" : "Role", - "Unknown user" : "Óþekktur notandi", "Additional settings" : "Valfrjálsar stillingar", + "Enter the database name for %s" : "Settu inn nafn á gagnagrunni fyrir %s", + "You cannot use dots in the database name %s" : "Þú mátt ekki nota punkta í gagnagrunnsheitinu %s", "You need to enter details of an existing account." : "Þú verður að setja inn auðkenni fyrirliggjandi notandaaðgangs.", "Oracle connection could not be established" : "Ekki tókst að koma tengingu á við Oracle", - "Oracle username and/or password not valid" : "Notandanafn eða lykilorð Oracle er ekki gilt", - "PostgreSQL username and/or password not valid" : "Notandanafn eða lykilorð PostgreSQL er ekki gilt", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X er ekki stutt og %s mun ekki vinna eðlilega á þessu stýrikerfi. Notaðu þetta því á þína eigin ábyrgð! ", "For the best results, please consider using a GNU/Linux server instead." : "Fyrir bestu útkomu ættirðu að íhuga að nota GNU/Linux þjón í staðinn.", "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." : "Það lítur út eins og þessi %s uppsetning sé að keyra á 32-bita PHP umhverfi og að open_basedir hafi verið stillt í php.ini. Þetta mun valda vandamálum með skrár stærri en 4 GB og er stranglega mælt gegn því að þetta sé gert.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Fjarlægðu stillinguna open_basedir úr php.ini eða skiptu yfir í 64-bita PHP.", - "Set an admin username." : "Stilltu notandanafn kerfisstjóra.", "Set an admin password." : "Stilltu lykilorð kerfisstjóra.", + "Cannot create or write into the data directory %s" : "Gat ekki búið til eða skrifað í gagnamöppuna %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Deilingarbakendinn %s verður að vera settur upp fyrir viðmótið OCP\\Share_Backend", "Sharing backend %s not found" : "Deilingarbakendinn %s fannst ekki", "Sharing backend for %s not found" : "Deilingarbakendi fyrir %s fannst ekki", @@ -106,12 +133,17 @@ "%1$s via %2$s" : "%1$s með %2$s", "You are not allowed to share %s" : "Þú hefur ekki heimild til að deila %s", "Cannot increase permissions of %s" : "Get ekki aukið aðgangsheimildir %s", + "Files cannot be shared with delete permissions" : "Ekki er hægt að deila skrá með eyða-heimildum", + "Files cannot be shared with create permissions" : "Ekki er hægt að deila skrá með búa-til-heimildum", "Expiration date is in the past" : "Gildistíminn er þegar runninn út", - "Sharing %s failed, because this item is already shared with user %s" : "Deiling %s mistókst, því þessu atriði er þegar deilt með notandanum %s", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Ekki er hægt að setja lokadagsetningu meira en %n dag fram í tímann","Ekki er hægt að setja lokadagsetningu meira en %n daga fram í tímann"], + "Sharing is only allowed with group members" : "Deiling er aðeins leyfð með meðlimum hópsins", "%1$s shared »%2$s« with you" : "%1$s deildi »%2$s« með þér", "%1$s shared »%2$s« with you." : "%1$s deildi »%2$s« með þér.", "Click the button below to open it." : "Smelltu á hnappinn hér fyrir neðan til að opna það.", "The requested share does not exist anymore" : "Umbeðin sameign er ekki lengur til", + "The requested share comes from a disabled user" : "Umbeðin sameign kemur frá notanda sem er óvirkur", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Notandinn var ekki búinn til þar sem takmörkum á fjölda notenda var náð. Skoðaðu tilkynningarnar þínar til að sjá meira.", "Could not find category \"%s\"" : "Fann ekki flokkinn \"%s\"", "Sunday" : "Sunnudagur", "Monday" : "Mánudagur", @@ -159,31 +191,41 @@ "Nov." : "Nóv.", "Dec." : "Des.", "A valid password must be provided" : "Skráðu inn gilt lykilorð", - "The username is already being used" : "Notandanafnið er þegar í notkun", - "Could not create user" : "Gat ekki búið til notanda", - "A valid username must be provided" : "Skráðu inn gilt notandanafn", - "Username contains whitespace at the beginning or at the end" : "Notandanafnið inniheldur orðabil í upphafi eða enda", - "Username must not consist of dots only" : "Notandanafn má ekki einungis samanstanda af punktum", - "Username is invalid because files already exist for this user" : "Notandanafnið er ógilt vegna þess að þegar eru fyrir hendi skrár sem tilheyra þessum notanda", - "User disabled" : "Notandi óvirkur", "Login canceled by app" : "Forrit hætti við innskráningu", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Ekki var hægt að setja upp \"%1$s\" forritið þar sem eftirfarandi kerfiskröfur eru ekki uppfylltar: %2$s", "a safe home for all your data" : "öruggur staður fyrir öll gögnin þín", "File is currently busy, please try again later" : "Skráin er upptekin í augnablikinu, reyndu aftur síðar", + "Cannot download file" : "Get ekki sótt skrá", "Application is not enabled" : "Forrit ekki virkt", "Authentication error" : "Villa við auðkenningu", "Token expired. Please reload page." : "Kenniteikn er útrunnið. Þú ættir að hlaða síðunni aftur inn.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Engir reklar fyrir gagnagrunn eru uppsettir (sqlite, mysql eða postgresql).", + "Cannot write into \"config\" directory." : "Get ekki skrifað í \"config\" möppuna.", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Þetta er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í stillingamöppuna. Skoðaðu %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" : "Eða, ef þú vilt halda config.php skránni aðeins til lestrar, settu valkostinn \"config_is_read_only\" á 'true' í henni. Skoðaðu %s", + "Cannot write into \"apps\" directory." : "Get ekki skrifað í \"apps\" möppuna.", + "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." : "Þetta er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í forritamöppuna eða gera App Store forritabúðina óvirka í stillingaskránni. ", + "Cannot create \"data\" directory." : "Get ekki búið til \"data\" möppu.", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Þetta er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í rótarmöppuna. Skoðaðu %s", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Heimildir er venjulega hægt að laga með því að gefa vefþjóninum skrifréttindi í rótarmöppuna. Skoðaðu %s.", + "Your data directory is not writable." : "Gagnamappn þín er ekki lesanleg.", + "Setting locale to %s failed." : "Mistókst að setja upp staðfærsluna %s.", + "Please install one of these locales on your system and restart your web server." : "Settu upp eina af þessum staðfærslum og endurræstu vefþjóninn.", "PHP module %s not installed." : "PHP-einingin %s er ekki uppsett.", "Please ask your server administrator to install the module." : "Biddu kerfisstjórann þinn um að setja eininguna upp.", "PHP setting \"%s\" is not set to \"%s\"." : "PHP-stillingin \"%s\" er ekki sett á \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ef þessi stilling er löguð í php.ini mun Nextcloud keyra aftur", + "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> er stillt á <code>%s</code> í stað gildisins \"<code>0</code> eins og vænst var.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Til að laga þetta vandamál ættirðu að setja <code>mbstring.func_overload</code> sem <code>0</code> í php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP virðist vera sett upp to fjarlægja innantextablokkir (inline doc blocks). Þetta mun gera ýmis kjarnaforrit óaðgengileg.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Þessu veldur væntanlega biðminni/hraðall á borð við Zend OPcache eða eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Búið er að setja upp PHP-einingar, en eru þær ennþá taldar upp eins og þær vanti?", "Please ask your server administrator to restart the web server." : "Biddu kerfisstjórann þinn um að endurræsa vefþjóninn.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endilega breyttu heimildunum í 0770 svo að aðrir notendur geti ekki listað upp innihald hennar.", + "The required %s config variable is not configured in the config.php file." : "Nauðsynleg %s stillingabreyta er ekki stillt í config.php file.", + "Please ask your server administrator to check the Nextcloud configuration." : "Biddu kerfisstjórann þinn um að athuga uppsetninguna á Nextcloud.", + "Your data directory must be an absolute path." : "Gagnamappan þín verður að vera með algilda slóð.", + "Check the value of \"datadirectory\" in your configuration." : "Athugaðu gildi \"datadirectory\" í uppsetningunni þinni.", + "Your data directory is invalid." : "Gagnamappan þín er ógild.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Gakktu úr skugga um að til staðar sé skrá með heitinu \".ocdata\" í rót gagnageymslunnar.", "Action \"%s\" not supported or implemented." : "Aðgerðin \"%s\" er ekki studd eða útfærð.", "Authentication failed, wrong token or provider ID given" : "Auðkenning mistókst, uppgefið rangt teikn eða auðkenni þjónustuveitu", @@ -196,10 +238,41 @@ "Storage connection error. %s" : "Villa í tengingu við gagnageymslu. %s", "Storage is temporarily not available" : "Gagnageymsla ekki tiltæk í augnablikinu", "Storage connection timeout. %s" : "Gagnageymsla féll á tíma. %s", + "Free prompt" : "Frjáls kvaðning", + "Runs an arbitrary prompt through the language model." : "Keyrir óreglulega kvaðningu (prompt) í gegnum tungumálslíkanið.", + "Generate headline" : "Útbúa fyrirsögn", + "Generates a possible headline for a text." : "Útbýr mögulega fyrirsögn fyrir texta.", + "Summarize" : "Gera samantekt", + "Summarizes text by reducing its length without losing key information." : "Tekur saman aðalatriði texta með því að stytta hann án þess að tapa mikilvægustu upplýsingum.", + "Extract topics" : "Taka út efnisflokka", + "Extracts topics from a text and outputs them separated by commas." : "Greinir efnisflokka úr texta og aðskilur þá með kommum.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Skrám forritsins %$1s var ekki rétt skipt út. Gakktu úr skugga um að þetta sé útgáfa sem sé samhæfð útgáfu vefþjónsins.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Innskráður notandi verður að vera kerfisstjóri eða undirstjórnandi eða hafa fengið sérstaka aðgangsheimild fyrir þessa stillingu", + "Logged in user must be an admin or sub admin" : "Innskráður notandi verður að vera kerfisstjóri eða undirstjórnandi", + "Logged in user must be an admin" : "Innskráður notandi verður að vera stjórnandi", "Full name" : "Fullt nafn", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Einungis eru leyfilegir eftirfarandi stafir í notandanafni: \"a-z\", \"A-Z\", \"0-9\", og \"_.@-'\"", + "Unknown user" : "Óþekktur notandi", + "Enter the database username and name for %s" : "Settu inn notandanafn og nafn í gagnagrunni fyrir %s", + "Enter the database username for %s" : "Settu inn notandanafn í gagnagrunni fyrir %s", + "MySQL username and/or password not valid" : "Notandanafn eða lykilorð MySQL er ekki gilt", + "Oracle username and/or password not valid" : "Notandanafn eða lykilorð Oracle er ekki gilt", + "PostgreSQL username and/or password not valid" : "Notandanafn eða lykilorð PostgreSQL er ekki gilt", + "Set an admin username." : "Stilltu notandanafn kerfisstjóra.", + "Sharing %s failed, because this item is already shared with user %s" : "Deiling %s mistókst, því þessu atriði er þegar deilt með notandanum %s", + "The username is already being used" : "Notandanafnið er þegar í notkun", + "Could not create user" : "Gat ekki búið til notanda", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Einungis eru leyfilegir eftirfarandi stafir í notandanafni: \"a-z\", \"A-Z\", \"0-9\", bil og \"_.@-'\"", + "A valid username must be provided" : "Skráðu inn gilt notandanafn", + "Username contains whitespace at the beginning or at the end" : "Notandanafnið inniheldur orðabil í upphafi eða enda", + "Username must not consist of dots only" : "Notandanafn má ekki einungis samanstanda af punktum", + "Username is invalid because files already exist for this user" : "Notandanafnið er ógilt vegna þess að þegar eru fyrir hendi skrár sem tilheyra þessum notanda", + "User disabled" : "Notandi óvirkur", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Krafist er libxml2 2.7.0 hið minnsta. Núna er %s uppsett.", - "To fix this issue update your libxml2 version and restart your web server." : "Til að laga þetta vandamál ættirðu að uppfæra útgáfu þína af libxml2 og endurræsa vefþjóninn." + "To fix this issue update your libxml2 version and restart your web server." : "Til að laga þetta vandamál ættirðu að uppfæra útgáfu þína af libxml2 og endurræsa vefþjóninn.", + "PostgreSQL >= 9 required." : "Krefst PostgreSQL >= 9.", + "Please upgrade your database version." : "Uppfærðu útgáfu gagnagrunnsins.", + "Your data directory is readable by other users." : "Gagnamappn þín er lesanleg fyrir aðra notendur.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endilega breyttu heimildunum í 0770 svo að aðrir notendur geti ekki listað upp innihald hennar." },"pluralForm" :"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);" }
\ No newline at end of file diff --git a/lib/l10n/it.js b/lib/l10n/it.js index 52cf1721362..76b76b91f77 100644 --- a/lib/l10n/it.js +++ b/lib/l10n/it.js @@ -5,15 +5,14 @@ OC.L10N.register( "This can usually be fixed by giving the web server write access to the config directory." : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella config.", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Ma, se preferisci mantenere il file config.php in sola lettura, imposta l'opzione \"config_is_read_only\" a true.", "See %s" : "Vedi %s", - "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "L'applicazione %1$s non è presente o ha una versione non compatibile con questo server. Controlla l'elenco delle app.", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "L'applicazione %1$s non è presente o ha una versione non compatibile con questo server. Controlla l'elenco delle applicazioni.", "Sample configuration detected" : "Configurazione di esempio rilevata", "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" : "È stato rilevato che la configurazione di esempio è stata copiata. Ciò può compromettere la tua installazione e non è supportato. Leggi la documentazione prima di modificare il file config.php", - "404" : "404", "The page could not be found on the server." : "Impossibile trovare la pagina sul server.", "%s email verification" : "Verifica email di %s", "Email verification" : "Verifica email", - "Click the following button to confirm your email." : "Clicca il pulsante seguente per confermare la tua email.", - "Click the following link to confirm your email." : "Clicca il collegamento seguente per confermare la tua email.", + "Click the following button to confirm your email." : "Fai clic sul pulsante seguente per confermare la tua email.", + "Click the following link to confirm your email." : "Fai clic sul collegamento seguente per confermare la tua email.", "Confirm your email" : "Conferma la tua email", "Other activities" : "Altre attività", "%1$s and %2$s" : "%1$s e %2$s", @@ -37,9 +36,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Le seguenti piattaforme sono supportate: %s", "Server version %s or higher is required." : "È richiesta la versione %s o successiva.", "Server version %s or lower is required." : "È richiesta la versione %s o precedente.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'utente connesso deve essere un admin, un sub admin o avere il permesso di accedere a questa impostazione", - "Logged in user must be an admin or sub admin" : "L'utente che ha eseguito l'accesso deve essere un amministratore o sub-amministratore", - "Logged in user must be an admin" : "L'utente che ha eseguito l'accesso deve essere un amministratore ", "Wiping of device %s has started" : "La cancellazione del dispositivo %s è iniziata", "Wiping of device »%s« has started" : "La cancellazione del dispositivo «%s» è iniziata", "»%s« started remote wipe" : "«%s» ha iniziato la cancellazione remota", @@ -118,22 +114,15 @@ OC.L10N.register( "Headline" : "Titolo", "Organisation" : "Organizzazione", "Role" : "Ruolo", - "Unknown user" : "Utente sconosciuto", "Additional settings" : "Impostazioni aggiuntive", - "Enter the database username and name for %s" : "Inserisci il nome utente del database e il nome per %s", - "Enter the database username for %s" : "Inserisci il nome utente del database per %s", "Enter the database name for %s" : "Inserisci il nome del database per %s", "You cannot use dots in the database name %s" : "Non puoi usare punti nel nome del database %s", - "MySQL username and/or password not valid" : "Nome utente e/o password di MySQL non validi", "You need to enter details of an existing account." : "Devi inserire i dettagli di un account esistente.", "Oracle connection could not be established" : "La connessione a Oracle non può essere stabilita", - "Oracle username and/or password not valid" : "Nome utente e/o password di Oracle non validi", - "PostgreSQL username and/or password not valid" : "Nome utente e/o password di PostgreSQL non validi", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X non è supportato e %s non funzionerà correttamente su questa piattaforma. Usalo a tuo rischio!", "For the best results, please consider using a GNU/Linux server instead." : "Per avere il risultato migliore, prendi in considerazione l'utilizzo di un server 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." : "Sembra che questa istanza di %s sia in esecuzione in un ambiente PHP a 32 bit e che open_basedir sia stata configurata in php.ini. Ciò comporterà problemi con i file più grandi di 4 GB ed è altamente sconsigliato.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Rimuovi l'impostazione di open_basedir nel tuo php.ini o passa alla versione a 64 bit di PHP.", - "Set an admin username." : "Imposta un nome utente di amministrazione.", "Set an admin password." : "Imposta una password di amministrazione.", "Cannot create or write into the data directory %s" : "Impossibile creare o scrivere nella cartella dei dati %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Il motore di condivisione %s deve implementare l'interfaccia OCP\\Share_Backend", @@ -151,7 +140,6 @@ OC.L10N.register( "Expiration date is in the past" : "La data di scadenza è nel passato", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Impossibile impostare la data di scadenza a più di %n giorni nel futuro","Impossibile impostare la data di scadenza a più di %n giorni nel futuro","Impossibile impostare la data di scadenza a più di %n giorni nel futuro"], "Sharing is only allowed with group members" : "La condivisione è consentita solo con i membri del gruppo", - "Sharing %s failed, because this item is already shared with user %s" : "Condivisione di %s non riuscita, poiché l'oggetto è già condiviso con l'utente %s", "%1$s shared »%2$s« with you" : "%1$s ha condiviso «%2$s» con te", "%1$s shared »%2$s« with you." : "%1$s ha condiviso «%2$s» con te.", "Click the button below to open it." : "Fai clic sul pulsante sotto per aprirlo.", @@ -205,20 +193,12 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Deve essere fornita una password valida", - "The username is already being used" : "Il nome utente è già utilizzato", - "Could not create user" : "Impossibile creare l'utente", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo i seguenti caratteri sono consentiti in un nome utente: \"a-z\", \"A-Z\", \"0-9\", spazi e \"_.@-'\"", - "A valid username must be provided" : "Deve essere fornito un nome utente valido", - "Username contains whitespace at the beginning or at the end" : "Il nome utente contiene spazi all'inizio o alla fine", - "Username must not consist of dots only" : "Il nome utente non può consistere di soli punti", - "Username is invalid because files already exist for this user" : "Il nome utente non è valido poiché esiste già per questo utente", - "User disabled" : "Utente disabilitato", "Login canceled by app" : "Accesso annullato dall'applicazione", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "L'applicazione \"%1$s\" non può essere installata poiché le seguenti dipendenze non sono soddisfatte: %2$s", "a safe home for all your data" : "un posto sicuro per tutti i tuoi dati", "File is currently busy, please try again later" : "Il file è attualmente occupato, riprova più tardi", "Cannot download file" : "Impossibile scaricare il file", - "Application is not enabled" : "L'applicazione non è abilitata", + "Application is not enabled" : "L'applicazione non è abilitata", "Authentication error" : "Errore di autenticazione", "Token expired. Please reload page." : "Token scaduto. Ricarica la pagina.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Nessun driver di database (sqlite, mysql o postgresql) installato", @@ -226,7 +206,7 @@ OC.L10N.register( "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella config. Vedi %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" : "O, se preferisci mantenere il file config.php in sola lettura, imposta l'opzione \"config_is_read_only\" a true. Vedi %s", "Cannot write into \"apps\" directory." : "Impossibile scrivere nella cartella \"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." : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella apps o disattivando il negozio delle applicazioni nel file di configurazione.", + "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." : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella delle applicazioni o disattivando il negozio delle applicazioni nel file di configurazione.", "Cannot create \"data\" directory." : "Impossibile creare la cartella \"data\".", "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella radice. Vedi %s", "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "I permessi possono essere corretti di solito fornendo al server web accesso in scrittura alla cartella radice. Vedi %s.", @@ -245,8 +225,6 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Chiedi all'amministratore di riavviare il server web.", "The required %s config variable is not configured in the config.php file." : "La variabile %s necessaria non è configurata nel file config.php .", "Please ask your server administrator to check the Nextcloud configuration." : "Chiedi all'amministratore del server di controllare la configurazione di Nextcloud.", - "Your data directory is readable by other users." : "La cartella dei dati è leggibile dagli altri utenti.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Modifica i permessi in 0770 in modo tale che la cartella non sia leggibile dagli altri utenti.", "Your data directory must be an absolute path." : "La cartella dei dati deve essere un percorso assoluto.", "Check the value of \"datadirectory\" in your configuration." : "Controlla il valore di \"datadirectory\" nella tua configurazione.", "Your data directory is invalid." : "La cartella dei dati non è valida.", @@ -271,12 +249,32 @@ OC.L10N.register( "Extract topics" : "Estrai argomenti", "Extracts topics from a text and outputs them separated by commas." : "Estrae gli argomenti da un testo e li elenca separati da virgole.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "I file dell'applicazione %1$s non sono stati sostituiti correttamente. Assicurati che sia una versione compatibile con il server.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'utente connesso deve essere un admin, un sub admin o avere il permesso di accedere a questa impostazione", + "Logged in user must be an admin or sub admin" : "L'utente che ha eseguito l'accesso deve essere un amministratore o sub-amministratore", + "Logged in user must be an admin" : "L'utente che ha eseguito l'accesso deve essere un amministratore ", "Full name" : "Nome completo", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "È stato raggiunto il limite di utenti e l'utente non è stato creato. Controlla le notifiche per maggiori informazioni.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Solo i seguenti caratteri sono consentiti in un nome utente: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"", + "Unknown user" : "Utente sconosciuto", + "Enter the database username and name for %s" : "Inserisci il nome utente del database e il nome per %s", + "Enter the database username for %s" : "Inserisci il nome utente del database per %s", + "MySQL username and/or password not valid" : "Nome utente e/o password di MySQL non validi", + "Oracle username and/or password not valid" : "Nome utente e/o password di Oracle non validi", + "PostgreSQL username and/or password not valid" : "Nome utente e/o password di PostgreSQL non validi", + "Set an admin username." : "Imposta un nome utente di amministrazione.", + "Sharing %s failed, because this item is already shared with user %s" : "Condivisione di %s non riuscita, poiché l'oggetto è già condiviso con l'utente %s", + "The username is already being used" : "Il nome utente è già utilizzato", + "Could not create user" : "Impossibile creare l'utente", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo i seguenti caratteri sono consentiti in un nome utente: \"a-z\", \"A-Z\", \"0-9\", spazi e \"_.@-'\"", + "A valid username must be provided" : "Deve essere fornito un nome utente valido", + "Username contains whitespace at the beginning or at the end" : "Il nome utente contiene spazi all'inizio o alla fine", + "Username must not consist of dots only" : "Il nome utente non può consistere di soli punti", + "Username is invalid because files already exist for this user" : "Il nome utente non è valido poiché esiste già per questo utente", + "User disabled" : "Utente disabilitato", "libxml2 2.7.0 is at least required. Currently %s is installed." : "È richiesta almeno la versione 2.7.0 di libxml2. Quella attualmente installata è la %s.", "To fix this issue update your libxml2 version and restart your web server." : "Per risolvere questo problema, aggiorna la tua versione di libxml2 e riavvia il server web.", "PostgreSQL >= 9 required." : "Richiesto PostgreSQL >= 9.", - "Please upgrade your database version." : "Aggiorna la versione del tuo database." + "Please upgrade your database version." : "Aggiorna la versione del tuo database.", + "Your data directory is readable by other users." : "La cartella dei dati è leggibile dagli altri utenti.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Modifica i permessi in 0770 in modo tale che la cartella non sia leggibile dagli altri utenti." }, "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/it.json b/lib/l10n/it.json index 8fb450a83fd..36a179fe913 100644 --- a/lib/l10n/it.json +++ b/lib/l10n/it.json @@ -3,15 +3,14 @@ "This can usually be fixed by giving the web server write access to the config directory." : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella config.", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Ma, se preferisci mantenere il file config.php in sola lettura, imposta l'opzione \"config_is_read_only\" a true.", "See %s" : "Vedi %s", - "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "L'applicazione %1$s non è presente o ha una versione non compatibile con questo server. Controlla l'elenco delle app.", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "L'applicazione %1$s non è presente o ha una versione non compatibile con questo server. Controlla l'elenco delle applicazioni.", "Sample configuration detected" : "Configurazione di esempio rilevata", "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" : "È stato rilevato che la configurazione di esempio è stata copiata. Ciò può compromettere la tua installazione e non è supportato. Leggi la documentazione prima di modificare il file config.php", - "404" : "404", "The page could not be found on the server." : "Impossibile trovare la pagina sul server.", "%s email verification" : "Verifica email di %s", "Email verification" : "Verifica email", - "Click the following button to confirm your email." : "Clicca il pulsante seguente per confermare la tua email.", - "Click the following link to confirm your email." : "Clicca il collegamento seguente per confermare la tua email.", + "Click the following button to confirm your email." : "Fai clic sul pulsante seguente per confermare la tua email.", + "Click the following link to confirm your email." : "Fai clic sul collegamento seguente per confermare la tua email.", "Confirm your email" : "Conferma la tua email", "Other activities" : "Altre attività", "%1$s and %2$s" : "%1$s e %2$s", @@ -35,9 +34,6 @@ "The following platforms are supported: %s" : "Le seguenti piattaforme sono supportate: %s", "Server version %s or higher is required." : "È richiesta la versione %s o successiva.", "Server version %s or lower is required." : "È richiesta la versione %s o precedente.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'utente connesso deve essere un admin, un sub admin o avere il permesso di accedere a questa impostazione", - "Logged in user must be an admin or sub admin" : "L'utente che ha eseguito l'accesso deve essere un amministratore o sub-amministratore", - "Logged in user must be an admin" : "L'utente che ha eseguito l'accesso deve essere un amministratore ", "Wiping of device %s has started" : "La cancellazione del dispositivo %s è iniziata", "Wiping of device »%s« has started" : "La cancellazione del dispositivo «%s» è iniziata", "»%s« started remote wipe" : "«%s» ha iniziato la cancellazione remota", @@ -116,22 +112,15 @@ "Headline" : "Titolo", "Organisation" : "Organizzazione", "Role" : "Ruolo", - "Unknown user" : "Utente sconosciuto", "Additional settings" : "Impostazioni aggiuntive", - "Enter the database username and name for %s" : "Inserisci il nome utente del database e il nome per %s", - "Enter the database username for %s" : "Inserisci il nome utente del database per %s", "Enter the database name for %s" : "Inserisci il nome del database per %s", "You cannot use dots in the database name %s" : "Non puoi usare punti nel nome del database %s", - "MySQL username and/or password not valid" : "Nome utente e/o password di MySQL non validi", "You need to enter details of an existing account." : "Devi inserire i dettagli di un account esistente.", "Oracle connection could not be established" : "La connessione a Oracle non può essere stabilita", - "Oracle username and/or password not valid" : "Nome utente e/o password di Oracle non validi", - "PostgreSQL username and/or password not valid" : "Nome utente e/o password di PostgreSQL non validi", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X non è supportato e %s non funzionerà correttamente su questa piattaforma. Usalo a tuo rischio!", "For the best results, please consider using a GNU/Linux server instead." : "Per avere il risultato migliore, prendi in considerazione l'utilizzo di un server 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." : "Sembra che questa istanza di %s sia in esecuzione in un ambiente PHP a 32 bit e che open_basedir sia stata configurata in php.ini. Ciò comporterà problemi con i file più grandi di 4 GB ed è altamente sconsigliato.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Rimuovi l'impostazione di open_basedir nel tuo php.ini o passa alla versione a 64 bit di PHP.", - "Set an admin username." : "Imposta un nome utente di amministrazione.", "Set an admin password." : "Imposta una password di amministrazione.", "Cannot create or write into the data directory %s" : "Impossibile creare o scrivere nella cartella dei dati %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Il motore di condivisione %s deve implementare l'interfaccia OCP\\Share_Backend", @@ -149,7 +138,6 @@ "Expiration date is in the past" : "La data di scadenza è nel passato", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Impossibile impostare la data di scadenza a più di %n giorni nel futuro","Impossibile impostare la data di scadenza a più di %n giorni nel futuro","Impossibile impostare la data di scadenza a più di %n giorni nel futuro"], "Sharing is only allowed with group members" : "La condivisione è consentita solo con i membri del gruppo", - "Sharing %s failed, because this item is already shared with user %s" : "Condivisione di %s non riuscita, poiché l'oggetto è già condiviso con l'utente %s", "%1$s shared »%2$s« with you" : "%1$s ha condiviso «%2$s» con te", "%1$s shared »%2$s« with you." : "%1$s ha condiviso «%2$s» con te.", "Click the button below to open it." : "Fai clic sul pulsante sotto per aprirlo.", @@ -203,20 +191,12 @@ "Nov." : "Nov.", "Dec." : "Dic.", "A valid password must be provided" : "Deve essere fornita una password valida", - "The username is already being used" : "Il nome utente è già utilizzato", - "Could not create user" : "Impossibile creare l'utente", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo i seguenti caratteri sono consentiti in un nome utente: \"a-z\", \"A-Z\", \"0-9\", spazi e \"_.@-'\"", - "A valid username must be provided" : "Deve essere fornito un nome utente valido", - "Username contains whitespace at the beginning or at the end" : "Il nome utente contiene spazi all'inizio o alla fine", - "Username must not consist of dots only" : "Il nome utente non può consistere di soli punti", - "Username is invalid because files already exist for this user" : "Il nome utente non è valido poiché esiste già per questo utente", - "User disabled" : "Utente disabilitato", "Login canceled by app" : "Accesso annullato dall'applicazione", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "L'applicazione \"%1$s\" non può essere installata poiché le seguenti dipendenze non sono soddisfatte: %2$s", "a safe home for all your data" : "un posto sicuro per tutti i tuoi dati", "File is currently busy, please try again later" : "Il file è attualmente occupato, riprova più tardi", "Cannot download file" : "Impossibile scaricare il file", - "Application is not enabled" : "L'applicazione non è abilitata", + "Application is not enabled" : "L'applicazione non è abilitata", "Authentication error" : "Errore di autenticazione", "Token expired. Please reload page." : "Token scaduto. Ricarica la pagina.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Nessun driver di database (sqlite, mysql o postgresql) installato", @@ -224,7 +204,7 @@ "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella config. Vedi %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" : "O, se preferisci mantenere il file config.php in sola lettura, imposta l'opzione \"config_is_read_only\" a true. Vedi %s", "Cannot write into \"apps\" directory." : "Impossibile scrivere nella cartella \"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." : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella apps o disattivando il negozio delle applicazioni nel file di configurazione.", + "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." : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella delle applicazioni o disattivando il negozio delle applicazioni nel file di configurazione.", "Cannot create \"data\" directory." : "Impossibile creare la cartella \"data\".", "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Ciò può essere corretto di solito fornendo al server web accesso in scrittura alla cartella radice. Vedi %s", "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "I permessi possono essere corretti di solito fornendo al server web accesso in scrittura alla cartella radice. Vedi %s.", @@ -243,8 +223,6 @@ "Please ask your server administrator to restart the web server." : "Chiedi all'amministratore di riavviare il server web.", "The required %s config variable is not configured in the config.php file." : "La variabile %s necessaria non è configurata nel file config.php .", "Please ask your server administrator to check the Nextcloud configuration." : "Chiedi all'amministratore del server di controllare la configurazione di Nextcloud.", - "Your data directory is readable by other users." : "La cartella dei dati è leggibile dagli altri utenti.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Modifica i permessi in 0770 in modo tale che la cartella non sia leggibile dagli altri utenti.", "Your data directory must be an absolute path." : "La cartella dei dati deve essere un percorso assoluto.", "Check the value of \"datadirectory\" in your configuration." : "Controlla il valore di \"datadirectory\" nella tua configurazione.", "Your data directory is invalid." : "La cartella dei dati non è valida.", @@ -269,12 +247,32 @@ "Extract topics" : "Estrai argomenti", "Extracts topics from a text and outputs them separated by commas." : "Estrae gli argomenti da un testo e li elenca separati da virgole.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "I file dell'applicazione %1$s non sono stati sostituiti correttamente. Assicurati che sia una versione compatibile con il server.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "L'utente connesso deve essere un admin, un sub admin o avere il permesso di accedere a questa impostazione", + "Logged in user must be an admin or sub admin" : "L'utente che ha eseguito l'accesso deve essere un amministratore o sub-amministratore", + "Logged in user must be an admin" : "L'utente che ha eseguito l'accesso deve essere un amministratore ", "Full name" : "Nome completo", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "È stato raggiunto il limite di utenti e l'utente non è stato creato. Controlla le notifiche per maggiori informazioni.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Solo i seguenti caratteri sono consentiti in un nome utente: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"", + "Unknown user" : "Utente sconosciuto", + "Enter the database username and name for %s" : "Inserisci il nome utente del database e il nome per %s", + "Enter the database username for %s" : "Inserisci il nome utente del database per %s", + "MySQL username and/or password not valid" : "Nome utente e/o password di MySQL non validi", + "Oracle username and/or password not valid" : "Nome utente e/o password di Oracle non validi", + "PostgreSQL username and/or password not valid" : "Nome utente e/o password di PostgreSQL non validi", + "Set an admin username." : "Imposta un nome utente di amministrazione.", + "Sharing %s failed, because this item is already shared with user %s" : "Condivisione di %s non riuscita, poiché l'oggetto è già condiviso con l'utente %s", + "The username is already being used" : "Il nome utente è già utilizzato", + "Could not create user" : "Impossibile creare l'utente", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Solo i seguenti caratteri sono consentiti in un nome utente: \"a-z\", \"A-Z\", \"0-9\", spazi e \"_.@-'\"", + "A valid username must be provided" : "Deve essere fornito un nome utente valido", + "Username contains whitespace at the beginning or at the end" : "Il nome utente contiene spazi all'inizio o alla fine", + "Username must not consist of dots only" : "Il nome utente non può consistere di soli punti", + "Username is invalid because files already exist for this user" : "Il nome utente non è valido poiché esiste già per questo utente", + "User disabled" : "Utente disabilitato", "libxml2 2.7.0 is at least required. Currently %s is installed." : "È richiesta almeno la versione 2.7.0 di libxml2. Quella attualmente installata è la %s.", "To fix this issue update your libxml2 version and restart your web server." : "Per risolvere questo problema, aggiorna la tua versione di libxml2 e riavvia il server web.", "PostgreSQL >= 9 required." : "Richiesto PostgreSQL >= 9.", - "Please upgrade your database version." : "Aggiorna la versione del tuo database." + "Please upgrade your database version." : "Aggiorna la versione del tuo database.", + "Your data directory is readable by other users." : "La cartella dei dati è leggibile dagli altri utenti.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Modifica i permessi in 0770 in modo tale che la cartella non sia leggibile dagli altri utenti." },"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/ja.js b/lib/l10n/ja.js index a58519f02ca..8e4a517d267 100644 --- a/lib/l10n/ja.js +++ b/lib/l10n/ja.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "アプリケーション%1$sが存在しないか、このサーバと互換性のないバージョンがあります。apps ディレクトリを確認してください。", "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を変更する前にドキュメントを確認してください。", - "404" : "404", "The page could not be found on the server." : "ページがサーバー上に見つかりませんでした。", "%s email verification" : "%sメールによる確認", "Email verification" : "メールによる確認", @@ -37,9 +36,9 @@ 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 よりも低いバージョンが必要です。", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "この設定にアクセスするには、ログインしたユーザーが管理者、サブ管理者、または特別な権利が必要です。", - "Logged in user must be an admin or sub admin" : "ログインユーザーは管理者またはサブ管理者である必要があります", - "Logged in user must be an admin" : "ログインユーザーは管理者である必要があります", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "この設定にアクセスするには、ログインしたアカウントが管理者、サブ管理者、または特別な権利を持っている必要があります。", + "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«がリモートワイプを開始しました", @@ -118,22 +117,21 @@ OC.L10N.register( "Headline" : "見出し", "Organisation" : "組織", "Role" : "ロール", - "Unknown user" : "不明なユーザー", + "Unknown account" : "不明なアカウント", "Additional settings" : "追加設定", - "Enter the database username and name for %s" : "%sのデータベース名とユーザー名を入力してください", - "Enter the database username for %s" : "%sのデータベースのユーザー名を指定してください", + "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 username and/or password not valid" : "MySQLのユーザー名またはパスワードが有効ではありません", + "MySQL Login and/or password not valid" : "MySQLのログイン名またはパスワードが有効ではありません", "You need to enter details of an existing account." : "既存のアカウントの詳細を入力してください。", "Oracle connection could not be established" : "Oracleへの接続が確立できませんでした。", - "Oracle username and/or password not valid" : "Oracleのユーザー名またはパスワードが有効ではありません", - "PostgreSQL username and/or password not valid" : "PostgreSQLのユーザー名またはパスワードが有効ではありません", + "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 では、サポートされていません。このOSでは、%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 は、32bit PHP 環境で動作しており、php.ini に open_basedir が設定されているようです。4GB以上のファイルで問題が発生するため、この設定を利用しないことをお勧めします。", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "php.ini から open_basedir 設定を削除するか、64bit PHPに切り替えてください。", - "Set an admin username." : "管理者のユーザー名を設定", "Set an admin password." : "管理者のパスワードを設定", "Cannot create or write into the data directory %s" : " データディレクトリ%sに作成、書き込みができません", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "%s のバックエンドの共有には、OCP\\Share_Backend インターフェースを実装しなければなりません。", @@ -151,11 +149,12 @@ OC.L10N.register( "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_" : ["%n 日以上先の有効期限は設定できません "], "Sharing is only allowed with group members" : "共有はグループメンバーにのみ許可されます", - "Sharing %s failed, because this item is already shared with user %s" : "このアイテム%sはすでにユーザー%sと共有されているため、共有に失敗しました", + "Sharing %s failed, because this item is already shared with the account %s" : "このアイテム %s はすでにアカウント %s と共有されているため、共有に失敗しました", "%1$s shared »%2$s« with you" : "%1$s は »%2$s« をあなたと共有しました", "%1$s shared »%2$s« with you." : "%1$sが あなたと »%2$s« を共有しました。", "Click the button below to open it." : "開くには下のボタンをクリック", "The requested share does not exist anymore" : "この共有はもう存在しません。", + "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\" が見つかりませんでした", "Sunday" : "日曜日", @@ -204,14 +203,14 @@ OC.L10N.register( "Nov." : "11月", "Dec." : "12月", "A valid password must be provided" : "有効なパスワードを指定する必要があります", - "The username is already being used" : "このユーザー名はすでに使われています", - "Could not create user" : "ユーザーを作成できませんでした", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "ユーザー名で利用できる文字列: \"a-z\", \"A-Z\", \"0-9\", スペース, \"_.@-\"", - "A valid username must be provided" : "有効なユーザー名を指定する必要があります", - "Username contains whitespace at the beginning or at the end" : "ユーザー名の最初か最後に空白が含まれています", - "Username must not consist of dots only" : "ユーザー名に、ドットのみはつけられません", - "Username is invalid because files already exist for this user" : "このユーザーのファイルが既に存在するため、このユーザー名は使用できません", - "User disabled" : "ユーザーは無効です", + "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" : "ログイン名はドットのみで構成されてはいけません", + "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" : "すべてのデータを安全に保管します", @@ -244,8 +243,8 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "サーバー管理者にWebサーバーを再起動するよう依頼してください。", "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 users." : "データディレクトリは他のユーザーからも読み取ることができます", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "ディレクトリが他のユーザーから見えないように、パーミッションを 0770 に変更してください。", + "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." : "データディレクトリが無効です", @@ -261,7 +260,7 @@ OC.L10N.register( "Storage connection error. %s" : "ストレージへの接続エラー。 %s", "Storage is temporarily not available" : "ストレージは一時的に利用できません", "Storage connection timeout. %s" : "ストレージへの接続がタイムアウト。 %s", - "Free prompt" : "無料プロンプト", + "Free prompt" : "任意のプロンプト", "Runs an arbitrary prompt through the language model." : "言語モデルを通じて任意のプロンプトを実行", "Generate headline" : "見出しの生成", "Generates a possible headline for a text." : "テキストの見出しの候補を生成", @@ -270,12 +269,32 @@ OC.L10N.register( "Extract topics" : "トピックの抽出", "Extracts topics from a text and outputs them separated by commas." : "テキストからトピックを抽出し、カンマ区切りで出力します。", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "アプリ %1$s のファイルが正しく置き換えられませんでした。サーバーと互換性のあるバージョンであることを確認してください。", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "この設定にアクセスするには、ログインしたユーザーが管理者、サブ管理者、または特別な権利が必要です。", + "Logged in user must be an admin or sub admin" : "ログインユーザーは管理者またはサブ管理者である必要があります", + "Logged in user must be an admin" : "ログインユーザーは管理者である必要があります", "Full name" : "フルネーム", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "ユーザー制限に達したため、ユーザーは作成されませんでした。詳細については、通知を確認してください。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列: \"a-z\", \"A-Z\", \"0-9\", \"_.@-\"", + "Unknown user" : "不明なユーザー", + "Enter the database username and name for %s" : "%sのデータベース名とユーザー名を入力してください", + "Enter the database username for %s" : "%sのデータベースのユーザー名を指定してください", + "MySQL username and/or password not valid" : "MySQLのユーザー名またはパスワードが有効ではありません", + "Oracle username and/or password not valid" : "Oracleのユーザー名またはパスワードが有効ではありません", + "PostgreSQL username and/or password not valid" : "PostgreSQLのユーザー名またはパスワードが有効ではありません", + "Set an admin username." : "管理者のユーザー名を設定", + "Sharing %s failed, because this item is already shared with user %s" : "このアイテム%sはすでにユーザー%sと共有されているため、共有に失敗しました", + "The username is already being used" : "このユーザー名はすでに使われています", + "Could not create user" : "ユーザーを作成できませんでした", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "ユーザー名で利用できる文字列: \"a-z\", \"A-Z\", \"0-9\", スペース, \"_.@-\"", + "A valid username must be provided" : "有効なユーザー名を指定する必要があります", + "Username contains whitespace at the beginning or at the end" : "ユーザー名の最初か最後に空白が含まれています", + "Username must not consist of dots only" : "ユーザー名に、ドットのみはつけられません", + "Username is invalid because files already exist for this user" : "このユーザーのファイルが既に存在するため、このユーザー名は使用できません", + "User disabled" : "ユーザーは無効です", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 バージョン 2.7.0 が最低必要です。現在 %s がインストールされています。", "To fix this issue update your libxml2 version and restart your web server." : "この問題を解決するには、libxml2 を更新して、Webサーバーを再起動してください。", "PostgreSQL >= 9 required." : "PostgreSQL 9以上が必要です", - "Please upgrade your database version." : "新しいバージョンのデータベースにアップグレードしてください。" + "Please upgrade your database version." : "新しいバージョンのデータベースにアップグレードしてください。", + "Your data directory is readable by other users." : "データディレクトリは他のユーザーからも読み取ることができます", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "ディレクトリが他のユーザーから見えないように、パーミッションを 0770 に変更してください。" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/ja.json b/lib/l10n/ja.json index f45d9b5e93f..90ca67b7e61 100644 --- a/lib/l10n/ja.json +++ b/lib/l10n/ja.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "アプリケーション%1$sが存在しないか、このサーバと互換性のないバージョンがあります。apps ディレクトリを確認してください。", "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を変更する前にドキュメントを確認してください。", - "404" : "404", "The page could not be found on the server." : "ページがサーバー上に見つかりませんでした。", "%s email verification" : "%sメールによる確認", "Email verification" : "メールによる確認", @@ -35,9 +34,9 @@ "The following platforms are supported: %s" : "次のプラットフォームをサポートしています: %s", "Server version %s or higher is required." : "サーバーの %s よりも高いバージョンが必要です。", "Server version %s or lower is required." : "サーバーの %s よりも低いバージョンが必要です。", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "この設定にアクセスするには、ログインしたユーザーが管理者、サブ管理者、または特別な権利が必要です。", - "Logged in user must be an admin or sub admin" : "ログインユーザーは管理者またはサブ管理者である必要があります", - "Logged in user must be an admin" : "ログインユーザーは管理者である必要があります", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "この設定にアクセスするには、ログインしたアカウントが管理者、サブ管理者、または特別な権利を持っている必要があります。", + "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«がリモートワイプを開始しました", @@ -116,22 +115,21 @@ "Headline" : "見出し", "Organisation" : "組織", "Role" : "ロール", - "Unknown user" : "不明なユーザー", + "Unknown account" : "不明なアカウント", "Additional settings" : "追加設定", - "Enter the database username and name for %s" : "%sのデータベース名とユーザー名を入力してください", - "Enter the database username for %s" : "%sのデータベースのユーザー名を指定してください", + "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 username and/or password not valid" : "MySQLのユーザー名またはパスワードが有効ではありません", + "MySQL Login and/or password not valid" : "MySQLのログイン名またはパスワードが有効ではありません", "You need to enter details of an existing account." : "既存のアカウントの詳細を入力してください。", "Oracle connection could not be established" : "Oracleへの接続が確立できませんでした。", - "Oracle username and/or password not valid" : "Oracleのユーザー名またはパスワードが有効ではありません", - "PostgreSQL username and/or password not valid" : "PostgreSQLのユーザー名またはパスワードが有効ではありません", + "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 では、サポートされていません。このOSでは、%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 は、32bit PHP 環境で動作しており、php.ini に open_basedir が設定されているようです。4GB以上のファイルで問題が発生するため、この設定を利用しないことをお勧めします。", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "php.ini から open_basedir 設定を削除するか、64bit PHPに切り替えてください。", - "Set an admin username." : "管理者のユーザー名を設定", "Set an admin password." : "管理者のパスワードを設定", "Cannot create or write into the data directory %s" : " データディレクトリ%sに作成、書き込みができません", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "%s のバックエンドの共有には、OCP\\Share_Backend インターフェースを実装しなければなりません。", @@ -149,11 +147,12 @@ "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_" : ["%n 日以上先の有効期限は設定できません "], "Sharing is only allowed with group members" : "共有はグループメンバーにのみ許可されます", - "Sharing %s failed, because this item is already shared with user %s" : "このアイテム%sはすでにユーザー%sと共有されているため、共有に失敗しました", + "Sharing %s failed, because this item is already shared with the account %s" : "このアイテム %s はすでにアカウント %s と共有されているため、共有に失敗しました", "%1$s shared »%2$s« with you" : "%1$s は »%2$s« をあなたと共有しました", "%1$s shared »%2$s« with you." : "%1$sが あなたと »%2$s« を共有しました。", "Click the button below to open it." : "開くには下のボタンをクリック", "The requested share does not exist anymore" : "この共有はもう存在しません。", + "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\" が見つかりませんでした", "Sunday" : "日曜日", @@ -202,14 +201,14 @@ "Nov." : "11月", "Dec." : "12月", "A valid password must be provided" : "有効なパスワードを指定する必要があります", - "The username is already being used" : "このユーザー名はすでに使われています", - "Could not create user" : "ユーザーを作成できませんでした", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "ユーザー名で利用できる文字列: \"a-z\", \"A-Z\", \"0-9\", スペース, \"_.@-\"", - "A valid username must be provided" : "有効なユーザー名を指定する必要があります", - "Username contains whitespace at the beginning or at the end" : "ユーザー名の最初か最後に空白が含まれています", - "Username must not consist of dots only" : "ユーザー名に、ドットのみはつけられません", - "Username is invalid because files already exist for this user" : "このユーザーのファイルが既に存在するため、このユーザー名は使用できません", - "User disabled" : "ユーザーは無効です", + "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" : "ログイン名はドットのみで構成されてはいけません", + "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" : "すべてのデータを安全に保管します", @@ -242,8 +241,8 @@ "Please ask your server administrator to restart the web server." : "サーバー管理者にWebサーバーを再起動するよう依頼してください。", "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 users." : "データディレクトリは他のユーザーからも読み取ることができます", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "ディレクトリが他のユーザーから見えないように、パーミッションを 0770 に変更してください。", + "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." : "データディレクトリが無効です", @@ -259,7 +258,7 @@ "Storage connection error. %s" : "ストレージへの接続エラー。 %s", "Storage is temporarily not available" : "ストレージは一時的に利用できません", "Storage connection timeout. %s" : "ストレージへの接続がタイムアウト。 %s", - "Free prompt" : "無料プロンプト", + "Free prompt" : "任意のプロンプト", "Runs an arbitrary prompt through the language model." : "言語モデルを通じて任意のプロンプトを実行", "Generate headline" : "見出しの生成", "Generates a possible headline for a text." : "テキストの見出しの候補を生成", @@ -268,12 +267,32 @@ "Extract topics" : "トピックの抽出", "Extracts topics from a text and outputs them separated by commas." : "テキストからトピックを抽出し、カンマ区切りで出力します。", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "アプリ %1$s のファイルが正しく置き換えられませんでした。サーバーと互換性のあるバージョンであることを確認してください。", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "この設定にアクセスするには、ログインしたユーザーが管理者、サブ管理者、または特別な権利が必要です。", + "Logged in user must be an admin or sub admin" : "ログインユーザーは管理者またはサブ管理者である必要があります", + "Logged in user must be an admin" : "ログインユーザーは管理者である必要があります", "Full name" : "フルネーム", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "ユーザー制限に達したため、ユーザーは作成されませんでした。詳細については、通知を確認してください。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列: \"a-z\", \"A-Z\", \"0-9\", \"_.@-\"", + "Unknown user" : "不明なユーザー", + "Enter the database username and name for %s" : "%sのデータベース名とユーザー名を入力してください", + "Enter the database username for %s" : "%sのデータベースのユーザー名を指定してください", + "MySQL username and/or password not valid" : "MySQLのユーザー名またはパスワードが有効ではありません", + "Oracle username and/or password not valid" : "Oracleのユーザー名またはパスワードが有効ではありません", + "PostgreSQL username and/or password not valid" : "PostgreSQLのユーザー名またはパスワードが有効ではありません", + "Set an admin username." : "管理者のユーザー名を設定", + "Sharing %s failed, because this item is already shared with user %s" : "このアイテム%sはすでにユーザー%sと共有されているため、共有に失敗しました", + "The username is already being used" : "このユーザー名はすでに使われています", + "Could not create user" : "ユーザーを作成できませんでした", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "ユーザー名で利用できる文字列: \"a-z\", \"A-Z\", \"0-9\", スペース, \"_.@-\"", + "A valid username must be provided" : "有効なユーザー名を指定する必要があります", + "Username contains whitespace at the beginning or at the end" : "ユーザー名の最初か最後に空白が含まれています", + "Username must not consist of dots only" : "ユーザー名に、ドットのみはつけられません", + "Username is invalid because files already exist for this user" : "このユーザーのファイルが既に存在するため、このユーザー名は使用できません", + "User disabled" : "ユーザーは無効です", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 バージョン 2.7.0 が最低必要です。現在 %s がインストールされています。", "To fix this issue update your libxml2 version and restart your web server." : "この問題を解決するには、libxml2 を更新して、Webサーバーを再起動してください。", "PostgreSQL >= 9 required." : "PostgreSQL 9以上が必要です", - "Please upgrade your database version." : "新しいバージョンのデータベースにアップグレードしてください。" + "Please upgrade your database version." : "新しいバージョンのデータベースにアップグレードしてください。", + "Your data directory is readable by other users." : "データディレクトリは他のユーザーからも読み取ることができます", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "ディレクトリが他のユーザーから見えないように、パーミッションを 0770 に変更してください。" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/ka.js b/lib/l10n/ka.js index 044dbf40d14..b297dc6d58e 100644 --- a/lib/l10n/ka.js +++ b/lib/l10n/ka.js @@ -1,7 +1,280 @@ OC.L10N.register( "lib", { + "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." : "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.", + "See %s" : "See %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.", + "Sample configuration detected" : "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" : "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", + "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", + "Other activities" : "Other activities", + "%1$s and %2$s" : "%1$s and %2$s", + "%1$s, %2$s and %3$s" : "%1$s, %2$s and %3$s", + "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s and %4$s", + "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s and %5$s", + "Education Edition" : "Education Edition", + "Enterprise bundle" : "Enterprise bundle", + "Groupware bundle" : "Groupware bundle", + "Hub bundle" : "Hub bundle", + "Social sharing bundle" : "Social sharing bundle", + "PHP %s or higher is required." : "PHP %s or higher is required.", + "PHP with a version lower than %s is required." : "PHP with a version lower than %s is required.", + "%sbit or higher PHP required." : "%sbit or higher PHP required.", + "The following architectures are supported: %s" : "The following architectures are supported: %s", + "The following databases are supported: %s" : "The following databases are supported: %s", + "The command line tool %s could not be found" : "The command line tool %s could not be found", + "The library %s is not available." : "The library %s is not available.", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Library %1$s with a version higher than %2$s is required - available version %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Library %1$s with a version lower than %2$s is required - available version %3$s.", + "The following platforms are supported: %s" : "The following platforms are supported: %s", + "Server version %s or higher is required." : "Server version %s or higher is required.", + "Server version %s or lower is required." : "Server version %s or lower is required.", + "Wiping of device %s has started" : "Wiping of device %s has started", + "Wiping of device »%s« has started" : "Wiping of device »%s« has started", + "»%s« started remote wipe" : "»%s« started remote wipe", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished", + "Wiping of device %s has finished" : "Wiping of device %s has finished", + "Wiping of device »%s« has finished" : "Wiping of device »%s« has finished", + "»%s« finished remote wipe" : "»%s« finished remote wipe", + "Device or application »%s« has finished the remote wipe process." : "Device or application »%s« has finished the remote wipe process.", + "Remote wipe started" : "Remote wipe started", + "A remote wipe was started on device %s" : "A remote wipe was started on device %s", + "Remote wipe finished" : "Remote wipe finished", + "The remote wipe on %s has finished" : "The remote wipe on %s has finished", + "Authentication" : "Authentication", + "Unknown filetype" : "Unknown filetype", + "Invalid image" : "Invalid image", + "Avatar image is not square" : "Avatar image is not square", "Files" : "ფაილები", - "__language_name__" : "ქართული ენა" + "View profile" : "View profile", + "Local time: %s" : "Local time: %s", + "today" : "today", + "tomorrow" : "tomorrow", + "yesterday" : "yesterday", + "_in %n day_::_in %n days_" : ["in %n day","in %n days"], + "_%n day ago_::_%n days ago_" : ["%n day ago","%n days ago"], + "next month" : "next month", + "last month" : "last month", + "_in %n month_::_in %n months_" : ["in %n month","in %n months"], + "_%n month ago_::_%n months ago_" : ["%n month ago","%n months ago"], + "next year" : "next year", + "last year" : "last year", + "_in %n year_::_in %n years_" : ["in %n year","in %n years"], + "_%n year ago_::_%n years ago_" : ["%n year ago","%n years ago"], + "_in %n hour_::_in %n hours_" : ["in %n hour","in %n hours"], + "_%n hour ago_::_%n hours ago_" : ["%n hour ago","%n hours ago"], + "_in %n minute_::_in %n minutes_" : ["in %n minute","in %n minutes"], + "_%n minute ago_::_%n minutes ago_" : ["%n minute ago","%n minutes ago"], + "in a few seconds" : "in a few seconds", + "seconds ago" : "seconds ago", + "Empty file" : "Empty file", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator.", + "File already exists" : "File already exists", + "Invalid path" : "Invalid path", + "Failed to create file from template" : "Failed to create file from template", + "Templates" : "Templates", + "File name is a reserved word" : "File name is a reserved word", + "File name contains at least one invalid character" : "File name contains at least one invalid character", + "File name is too long" : "File name is too long", + "Dot files are not allowed" : "Dot files are not allowed", + "Empty filename is not allowed" : "Empty filename is not allowed", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "App \"%s\" cannot be installed because appinfo file cannot be read.", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "App \"%s\" cannot be installed because it is not compatible with this version of the server.", + "__language_name__" : "ქართული ენა", + "This is an automatically sent email, please do not reply." : "This is an automatically sent email, please do not reply.", + "Help" : "Help", + "Appearance and accessibility" : "Appearance and accessibility", + "Apps" : "Apps", + "Personal settings" : "Personal settings", + "Administration settings" : "Administration settings", + "Settings" : "Settings", + "Log out" : "Log out", + "Users" : "Users", + "Email" : "Email", + "Mail %s" : "Mail %s", + "Fediverse" : "Fediverse", + "View %s on the fediverse" : "View %s on the fediverse", + "Phone" : "Phone", + "Call %s" : "Call %s", + "Twitter" : "Twitter", + "View %s on Twitter" : "View %s on Twitter", + "Website" : "Website", + "Visit %s" : "Visit %s", + "Address" : "Address", + "Profile picture" : "Profile picture", + "About" : "About", + "Display name" : "Display name", + "Headline" : "Headline", + "Organisation" : "Organisation", + "Role" : "Role", + "Additional settings" : "Additional settings", + "Enter the database name for %s" : "Enter the database name for %s", + "You cannot use dots in the database name %s" : "You cannot use dots in the database name %s", + "You need to enter details of an existing account." : "You need to enter details of an existing account.", + "Oracle connection could not be established" : "Oracle connection could not be established", + "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! ", + "For the best results, please consider using a GNU/Linux server instead." : "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." : "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.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP.", + "Set an admin password." : "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" : "Sharing backend %s must implement the interface OCP\\Share_Backend", + "Sharing backend %s not found" : "Sharing backend %s not found", + "Sharing backend for %s not found" : "Sharing backend for %s not found", + "%1$s shared »%2$s« with you and wants to add:" : "%1$s shared »%2$s« with you and wants to add:", + "%1$s shared »%2$s« with you and wants to add" : "%1$s shared »%2$s« with you and wants to add", + "»%s« added a note to a file shared with you" : "»%s« added a note to a file shared with you", + "Open »%s«" : "Open »%s«", + "%1$s via %2$s" : "%1$s via %2$s", + "You are not allowed to share %s" : "You are not allowed to share %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", + "Expiration date is in the past" : "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", + "%1$s shared »%2$s« with you" : "%1$s shared »%2$s« with you", + "%1$s shared »%2$s« with you." : "%1$s shared »%2$s« with you.", + "Click the button below to open it." : "Click the button below to open it.", + "The requested share does not exist anymore" : "The requested share does not exist anymore", + "The requested share comes from a disabled user" : "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." : "The user was not created because the user limit has been reached. Check your notifications to learn more.", + "Could not find category \"%s\"" : "Could not find category \"%s\"", + "Sunday" : "Sunday", + "Monday" : "Monday", + "Tuesday" : "Tuesday", + "Wednesday" : "Wednesday", + "Thursday" : "Thursday", + "Friday" : "Friday", + "Saturday" : "Saturday", + "Sun." : "Sun.", + "Mon." : "Mon.", + "Tue." : "Tue.", + "Wed." : "Wed.", + "Thu." : "Thu.", + "Fri." : "Fri.", + "Sat." : "Sat.", + "Su" : "Su", + "Mo" : "Mo", + "Tu" : "Tu", + "We" : "We", + "Th" : "Th", + "Fr" : "Fr", + "Sa" : "Sa", + "January" : "January", + "February" : "February", + "March" : "March", + "April" : "April", + "May" : "May", + "June" : "June", + "July" : "July", + "August" : "August", + "September" : "September", + "October" : "October", + "November" : "November", + "December" : "December", + "Jan." : "Jan.", + "Feb." : "Feb.", + "Mar." : "Mar.", + "Apr." : "Apr.", + "May." : "May.", + "Jun." : "Jun.", + "Jul." : "Jul.", + "Aug." : "Aug.", + "Sep." : "Sep.", + "Oct." : "Oct.", + "Nov." : "Nov.", + "Dec." : "Dec.", + "A valid password must be provided" : "A valid password must be provided", + "Login canceled by app" : "Login canceled by app", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s", + "a safe home for all your data" : "a safe home for all your data", + "File is currently busy, please try again later" : "File is currently busy, please try again later", + "Cannot download file" : "Cannot download file", + "Application is not enabled" : "Application is not enabled", + "Authentication error" : "Authentication error", + "Token expired. Please reload page." : "Token expired. Please reload page.", + "No database drivers (sqlite, mysql, or postgresql) installed." : "No database drivers (sqlite, mysql, or postgresql) installed.", + "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" : "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %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.", + "PHP module %s not installed." : "PHP module %s not installed.", + "Please ask your server administrator to install the module." : "Please ask your server administrator to install the module.", + "PHP setting \"%s\" is not set to \"%s\"." : "PHP setting \"%s\" is not set to \"%s\".", + "Adjusting this setting in php.ini will make Nextcloud run again" : "Adjusting this setting in php.ini will make Nextcloud run again", + "<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 is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.", + "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.", + "PHP modules have been installed, but they are still listed as missing?" : "PHP modules have been installed, but they are still listed as missing?", + "Please ask your server administrator to restart the web server." : "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.", + "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Ensure there is a file called \".ocdata\" in the root of the data directory.", + "Action \"%s\" not supported or implemented." : "Action \"%s\" not supported or implemented.", + "Authentication failed, wrong token or provider ID given" : "Authentication failed, wrong token or provider ID given", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Parameters missing in order to complete the request. Missing Parameters: \"%s\"", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "ID \"%1$s\" already used by cloud federation provider \"%2$s\"", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "Cloud Federation Provider with ID: \"%s\" does not exist.", + "Could not obtain lock type %d on \"%s\"." : "Could not obtain lock type %d on \"%s\".", + "Storage unauthorized. %s" : "Storage unauthorized. %s", + "Storage incomplete configuration. %s" : "Storage incomplete configuration. %s", + "Storage connection error. %s" : "Storage connection error. %s", + "Storage is temporarily not available" : "Storage is temporarily not available", + "Storage connection timeout. %s" : "Storage connection timeout. %s", + "Free prompt" : "Free prompt", + "Runs an arbitrary prompt through the language model." : "Runs an arbitrary prompt through the language model.", + "Generate headline" : "Generate headline", + "Generates a possible headline for a text." : "Generates a possible headline for a text.", + "Summarize" : "Summarize", + "Summarizes text by reducing its length without losing key information." : "Summarizes text by reducing its length without losing key information.", + "Extract topics" : "Extract topics", + "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub admin or gotten special right to access this setting", + "Logged in user must be an admin or sub admin" : "Logged in user must be an admin or sub admin", + "Logged in user must be an admin" : "Logged in user must be an admin", + "Full name" : "Full name", + "Unknown user" : "Unknown user", + "Enter the database username and name for %s" : "Enter the database username and name for %s", + "Enter the database username for %s" : "Enter the database username for %s", + "MySQL username and/or password not valid" : "MySQL username and/or password not valid", + "Oracle username and/or password not valid" : "Oracle username and/or password not valid", + "PostgreSQL username and/or password not valid" : "PostgreSQL username and/or password not valid", + "Set an admin username." : "Set an admin username.", + "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", + "The username is already being used" : "The username is already being used", + "Could not create user" : "Could not create user", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", + "A valid username must be provided" : "A valid username must be provided", + "Username contains whitespace at the beginning or at the end" : "Username contains whitespace at the beginning or at the end", + "Username must not consist of dots only" : "Username must not consist of dots only", + "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", + "User disabled" : "User disabled", + "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 is at least required. Currently %s is installed.", + "To fix this issue update your libxml2 version and restart your web server." : "To fix this issue update your libxml2 version and restart your web server.", + "PostgreSQL >= 9 required." : "PostgreSQL >= 9 required.", + "Please upgrade your database version." : "Please upgrade your database version.", + "Your data directory is readable by other users." : "Your data directory is readable by other users.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Please change the permissions to 0770 so that the directory cannot be listed by other users." }, "nplurals=2; plural=(n!=1);"); diff --git a/lib/l10n/ka.json b/lib/l10n/ka.json index deb9b82e1d4..2d1619a4d32 100644 --- a/lib/l10n/ka.json +++ b/lib/l10n/ka.json @@ -1,5 +1,278 @@ { "translations": { + "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." : "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.", + "See %s" : "See %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.", + "Sample configuration detected" : "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" : "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", + "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", + "Other activities" : "Other activities", + "%1$s and %2$s" : "%1$s and %2$s", + "%1$s, %2$s and %3$s" : "%1$s, %2$s and %3$s", + "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s and %4$s", + "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s and %5$s", + "Education Edition" : "Education Edition", + "Enterprise bundle" : "Enterprise bundle", + "Groupware bundle" : "Groupware bundle", + "Hub bundle" : "Hub bundle", + "Social sharing bundle" : "Social sharing bundle", + "PHP %s or higher is required." : "PHP %s or higher is required.", + "PHP with a version lower than %s is required." : "PHP with a version lower than %s is required.", + "%sbit or higher PHP required." : "%sbit or higher PHP required.", + "The following architectures are supported: %s" : "The following architectures are supported: %s", + "The following databases are supported: %s" : "The following databases are supported: %s", + "The command line tool %s could not be found" : "The command line tool %s could not be found", + "The library %s is not available." : "The library %s is not available.", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Library %1$s with a version higher than %2$s is required - available version %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Library %1$s with a version lower than %2$s is required - available version %3$s.", + "The following platforms are supported: %s" : "The following platforms are supported: %s", + "Server version %s or higher is required." : "Server version %s or higher is required.", + "Server version %s or lower is required." : "Server version %s or lower is required.", + "Wiping of device %s has started" : "Wiping of device %s has started", + "Wiping of device »%s« has started" : "Wiping of device »%s« has started", + "»%s« started remote wipe" : "»%s« started remote wipe", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished", + "Wiping of device %s has finished" : "Wiping of device %s has finished", + "Wiping of device »%s« has finished" : "Wiping of device »%s« has finished", + "»%s« finished remote wipe" : "»%s« finished remote wipe", + "Device or application »%s« has finished the remote wipe process." : "Device or application »%s« has finished the remote wipe process.", + "Remote wipe started" : "Remote wipe started", + "A remote wipe was started on device %s" : "A remote wipe was started on device %s", + "Remote wipe finished" : "Remote wipe finished", + "The remote wipe on %s has finished" : "The remote wipe on %s has finished", + "Authentication" : "Authentication", + "Unknown filetype" : "Unknown filetype", + "Invalid image" : "Invalid image", + "Avatar image is not square" : "Avatar image is not square", "Files" : "ფაილები", - "__language_name__" : "ქართული ენა" + "View profile" : "View profile", + "Local time: %s" : "Local time: %s", + "today" : "today", + "tomorrow" : "tomorrow", + "yesterday" : "yesterday", + "_in %n day_::_in %n days_" : ["in %n day","in %n days"], + "_%n day ago_::_%n days ago_" : ["%n day ago","%n days ago"], + "next month" : "next month", + "last month" : "last month", + "_in %n month_::_in %n months_" : ["in %n month","in %n months"], + "_%n month ago_::_%n months ago_" : ["%n month ago","%n months ago"], + "next year" : "next year", + "last year" : "last year", + "_in %n year_::_in %n years_" : ["in %n year","in %n years"], + "_%n year ago_::_%n years ago_" : ["%n year ago","%n years ago"], + "_in %n hour_::_in %n hours_" : ["in %n hour","in %n hours"], + "_%n hour ago_::_%n hours ago_" : ["%n hour ago","%n hours ago"], + "_in %n minute_::_in %n minutes_" : ["in %n minute","in %n minutes"], + "_%n minute ago_::_%n minutes ago_" : ["%n minute ago","%n minutes ago"], + "in a few seconds" : "in a few seconds", + "seconds ago" : "seconds ago", + "Empty file" : "Empty file", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator.", + "File already exists" : "File already exists", + "Invalid path" : "Invalid path", + "Failed to create file from template" : "Failed to create file from template", + "Templates" : "Templates", + "File name is a reserved word" : "File name is a reserved word", + "File name contains at least one invalid character" : "File name contains at least one invalid character", + "File name is too long" : "File name is too long", + "Dot files are not allowed" : "Dot files are not allowed", + "Empty filename is not allowed" : "Empty filename is not allowed", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "App \"%s\" cannot be installed because appinfo file cannot be read.", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "App \"%s\" cannot be installed because it is not compatible with this version of the server.", + "__language_name__" : "ქართული ენა", + "This is an automatically sent email, please do not reply." : "This is an automatically sent email, please do not reply.", + "Help" : "Help", + "Appearance and accessibility" : "Appearance and accessibility", + "Apps" : "Apps", + "Personal settings" : "Personal settings", + "Administration settings" : "Administration settings", + "Settings" : "Settings", + "Log out" : "Log out", + "Users" : "Users", + "Email" : "Email", + "Mail %s" : "Mail %s", + "Fediverse" : "Fediverse", + "View %s on the fediverse" : "View %s on the fediverse", + "Phone" : "Phone", + "Call %s" : "Call %s", + "Twitter" : "Twitter", + "View %s on Twitter" : "View %s on Twitter", + "Website" : "Website", + "Visit %s" : "Visit %s", + "Address" : "Address", + "Profile picture" : "Profile picture", + "About" : "About", + "Display name" : "Display name", + "Headline" : "Headline", + "Organisation" : "Organisation", + "Role" : "Role", + "Additional settings" : "Additional settings", + "Enter the database name for %s" : "Enter the database name for %s", + "You cannot use dots in the database name %s" : "You cannot use dots in the database name %s", + "You need to enter details of an existing account." : "You need to enter details of an existing account.", + "Oracle connection could not be established" : "Oracle connection could not be established", + "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! ", + "For the best results, please consider using a GNU/Linux server instead." : "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." : "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.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP.", + "Set an admin password." : "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" : "Sharing backend %s must implement the interface OCP\\Share_Backend", + "Sharing backend %s not found" : "Sharing backend %s not found", + "Sharing backend for %s not found" : "Sharing backend for %s not found", + "%1$s shared »%2$s« with you and wants to add:" : "%1$s shared »%2$s« with you and wants to add:", + "%1$s shared »%2$s« with you and wants to add" : "%1$s shared »%2$s« with you and wants to add", + "»%s« added a note to a file shared with you" : "»%s« added a note to a file shared with you", + "Open »%s«" : "Open »%s«", + "%1$s via %2$s" : "%1$s via %2$s", + "You are not allowed to share %s" : "You are not allowed to share %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", + "Expiration date is in the past" : "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", + "%1$s shared »%2$s« with you" : "%1$s shared »%2$s« with you", + "%1$s shared »%2$s« with you." : "%1$s shared »%2$s« with you.", + "Click the button below to open it." : "Click the button below to open it.", + "The requested share does not exist anymore" : "The requested share does not exist anymore", + "The requested share comes from a disabled user" : "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." : "The user was not created because the user limit has been reached. Check your notifications to learn more.", + "Could not find category \"%s\"" : "Could not find category \"%s\"", + "Sunday" : "Sunday", + "Monday" : "Monday", + "Tuesday" : "Tuesday", + "Wednesday" : "Wednesday", + "Thursday" : "Thursday", + "Friday" : "Friday", + "Saturday" : "Saturday", + "Sun." : "Sun.", + "Mon." : "Mon.", + "Tue." : "Tue.", + "Wed." : "Wed.", + "Thu." : "Thu.", + "Fri." : "Fri.", + "Sat." : "Sat.", + "Su" : "Su", + "Mo" : "Mo", + "Tu" : "Tu", + "We" : "We", + "Th" : "Th", + "Fr" : "Fr", + "Sa" : "Sa", + "January" : "January", + "February" : "February", + "March" : "March", + "April" : "April", + "May" : "May", + "June" : "June", + "July" : "July", + "August" : "August", + "September" : "September", + "October" : "October", + "November" : "November", + "December" : "December", + "Jan." : "Jan.", + "Feb." : "Feb.", + "Mar." : "Mar.", + "Apr." : "Apr.", + "May." : "May.", + "Jun." : "Jun.", + "Jul." : "Jul.", + "Aug." : "Aug.", + "Sep." : "Sep.", + "Oct." : "Oct.", + "Nov." : "Nov.", + "Dec." : "Dec.", + "A valid password must be provided" : "A valid password must be provided", + "Login canceled by app" : "Login canceled by app", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s", + "a safe home for all your data" : "a safe home for all your data", + "File is currently busy, please try again later" : "File is currently busy, please try again later", + "Cannot download file" : "Cannot download file", + "Application is not enabled" : "Application is not enabled", + "Authentication error" : "Authentication error", + "Token expired. Please reload page." : "Token expired. Please reload page.", + "No database drivers (sqlite, mysql, or postgresql) installed." : "No database drivers (sqlite, mysql, or postgresql) installed.", + "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" : "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %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.", + "PHP module %s not installed." : "PHP module %s not installed.", + "Please ask your server administrator to install the module." : "Please ask your server administrator to install the module.", + "PHP setting \"%s\" is not set to \"%s\"." : "PHP setting \"%s\" is not set to \"%s\".", + "Adjusting this setting in php.ini will make Nextcloud run again" : "Adjusting this setting in php.ini will make Nextcloud run again", + "<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 is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.", + "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.", + "PHP modules have been installed, but they are still listed as missing?" : "PHP modules have been installed, but they are still listed as missing?", + "Please ask your server administrator to restart the web server." : "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.", + "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Ensure there is a file called \".ocdata\" in the root of the data directory.", + "Action \"%s\" not supported or implemented." : "Action \"%s\" not supported or implemented.", + "Authentication failed, wrong token or provider ID given" : "Authentication failed, wrong token or provider ID given", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Parameters missing in order to complete the request. Missing Parameters: \"%s\"", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "ID \"%1$s\" already used by cloud federation provider \"%2$s\"", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "Cloud Federation Provider with ID: \"%s\" does not exist.", + "Could not obtain lock type %d on \"%s\"." : "Could not obtain lock type %d on \"%s\".", + "Storage unauthorized. %s" : "Storage unauthorized. %s", + "Storage incomplete configuration. %s" : "Storage incomplete configuration. %s", + "Storage connection error. %s" : "Storage connection error. %s", + "Storage is temporarily not available" : "Storage is temporarily not available", + "Storage connection timeout. %s" : "Storage connection timeout. %s", + "Free prompt" : "Free prompt", + "Runs an arbitrary prompt through the language model." : "Runs an arbitrary prompt through the language model.", + "Generate headline" : "Generate headline", + "Generates a possible headline for a text." : "Generates a possible headline for a text.", + "Summarize" : "Summarize", + "Summarizes text by reducing its length without losing key information." : "Summarizes text by reducing its length without losing key information.", + "Extract topics" : "Extract topics", + "Extracts topics from a text and outputs them separated by commas." : "Extracts topics from a text and outputs them separated by commas.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Logged in user must be an admin, a sub admin or gotten special right to access this setting", + "Logged in user must be an admin or sub admin" : "Logged in user must be an admin or sub admin", + "Logged in user must be an admin" : "Logged in user must be an admin", + "Full name" : "Full name", + "Unknown user" : "Unknown user", + "Enter the database username and name for %s" : "Enter the database username and name for %s", + "Enter the database username for %s" : "Enter the database username for %s", + "MySQL username and/or password not valid" : "MySQL username and/or password not valid", + "Oracle username and/or password not valid" : "Oracle username and/or password not valid", + "PostgreSQL username and/or password not valid" : "PostgreSQL username and/or password not valid", + "Set an admin username." : "Set an admin username.", + "Sharing %s failed, because this item is already shared with user %s" : "Sharing %s failed, because this item is already shared with user %s", + "The username is already being used" : "The username is already being used", + "Could not create user" : "Could not create user", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"", + "A valid username must be provided" : "A valid username must be provided", + "Username contains whitespace at the beginning or at the end" : "Username contains whitespace at the beginning or at the end", + "Username must not consist of dots only" : "Username must not consist of dots only", + "Username is invalid because files already exist for this user" : "Username is invalid because files already exist for this user", + "User disabled" : "User disabled", + "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 is at least required. Currently %s is installed.", + "To fix this issue update your libxml2 version and restart your web server." : "To fix this issue update your libxml2 version and restart your web server.", + "PostgreSQL >= 9 required." : "PostgreSQL >= 9 required.", + "Please upgrade your database version." : "Please upgrade your database version.", + "Your data directory is readable by other users." : "Your data directory is readable by other users.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Please change the permissions to 0770 so that the directory cannot be listed by other users." },"pluralForm" :"nplurals=2; plural=(n!=1);" }
\ No newline at end of file diff --git a/lib/l10n/ka_GE.js b/lib/l10n/ka_GE.js index a06bae10006..527bf682514 100644 --- a/lib/l10n/ka_GE.js +++ b/lib/l10n/ka_GE.js @@ -20,7 +20,6 @@ OC.L10N.register( "The library %s is not available." : "ბიბლიოთეკა %s ვერ იქნა ნაპოვნი.", "Server version %s or higher is required." : "საჭიროა სერვერი ვერსიით %s ან მეტი.", "Server version %s or lower is required." : "საჭიროა სერვერი ვერსიით %s ან ნაკლები.", - "Logged in user must be an admin" : "ავტორიზირებული მომხმარებელი უნდა იყოს ადმინისტრატორი", "Authentication" : "აუტენტიფიკაცია", "Unknown filetype" : "ამოუცნობი ფაილის ტიპი", "Invalid image" : "არასწორი სურათი", @@ -68,17 +67,13 @@ OC.L10N.register( "Address" : "მისამართი", "Profile picture" : "პროფილის სურათი", "About" : "შესახებ", - "Unknown user" : "ამოუცნობი მომხმარებელი", "Additional settings" : "დამატებითი პარამეტრები", "You need to enter details of an existing account." : "საჭიროა შეიყვანოთ არსებული ანგარიშის დეტალები.", "Oracle connection could not be established" : "Oracle კავშირი ვერ დამყარდა", - "Oracle username and/or password not valid" : "Oracle მომხმარებლის სახელი და/ან პაროლი არ არის სწორი", - "PostgreSQL username 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 გარემოზე და 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-დან ან გადახვიდეთ 64-ბიტიან PHP-ზე.", - "Set an admin username." : "დააყენეთ ადმინისტრატორის სახელი.", "Set an admin password." : "დააყენეთ ადმინისტრატორის პაროლი.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "გაზიარების ბექენდმა %s-მ მოქმედებაში უნდა მოიყვანოს ინტეფეისი OCP\\Share_Backend", "Sharing backend %s not found" : "გაზიარების ბექენდი %s ვერ იქნა ნაპოვნი", @@ -87,7 +82,6 @@ OC.L10N.register( "You are not allowed to share %s" : "თქვენ არ გაქვთ უფლება გააზიაროთ %s", "Cannot increase permissions of %s" : "%s-ის უფლებების გაზრდა ვერ ხერხდება", "Expiration date is in the past" : "ვადის ამოწურვის თარიღი წარსულშია", - "Sharing %s failed, because this item is already shared with user %s" : "%s-ის გაზიარება არ მოხერხდა, რადგან ობიექტი მომხმარებელ %s-თან უკვე გაზიარებულია", "Click the button below to open it." : "გასახსნელად დააჭირეთ ქვემოთ მყოფ ღილაკს.", "The requested share does not exist anymore" : "მოთხოვნილი გაზიარება მეტი აღარ არსებობს", "Could not find category \"%s\"" : "\"%s\" კატეგორიის მოძებნა ვერ მოხერხდა", @@ -137,12 +131,6 @@ OC.L10N.register( "Nov." : "ნოე.", "Dec." : "დეკ.", "A valid password must be provided" : "უნდა მიუთითოთ სწორი პაროლი", - "The username is already being used" : "ესეთი მომხმარებლის სახელი უკვე არსებობს", - "Could not create user" : "მომხმარებლის შექმნა ვერ მოხერხდა", - "A valid username must be provided" : "უნდა მიუთითოთ არსებული მომხმარებლის სახელი", - "Username contains whitespace at the beginning or at the end" : "მომხმარებლის სახელი დასაწყისსში ან დასასრულში მოიცავს სიცარიელეს", - "Username must not consist of dots only" : "მომხმარებლის სახელი ვერ იქნება შემდგარი მხოლოდ წერტილებისგან", - "User disabled" : "მომხმარებელი გათიშულია", "Login canceled by app" : "აპლიკაციამ ლოგინი უარყო", "a safe home for all your data" : "უსაფრთხო სახლი მთელი თქვენი მონაცემებისათვის", "File is currently busy, please try again later" : "ფაილი ამჟამად დაკავებულია, გთხოვთ მოგვიანებით სცადოთ ახლიდან", @@ -158,7 +146,6 @@ OC.L10N.register( "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." : "გთხოვთ სთხოვოთ თქვენს სერვერის ადმინისტრატორს გადატვირთოს ვებ-სერვერი.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "გთხოვთ შეცვალოთ უფლებები 0770-ზე, რათა დირექტორია სხვა მომხმარებლების მიერ აღარ იყოს კითხვადი.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "დარწმუნდით რომ ფაილი სახელად \".ocdata\" მონაცემების დირექტორიის საწყისშია.", "Could not obtain lock type %d on \"%s\"." : "ჩაკეთვის ტიპის %d მოძიება \"%s\"-ზე ვერ მოხერხდა.", "Storage unauthorized. %s" : "საცავი არაავტორიზირებულია. %s", @@ -166,9 +153,21 @@ OC.L10N.register( "Storage connection error. %s" : "საცავის კავშირის შეცდომა. %s", "Storage is temporarily not available" : "საცავი დროებით ხელმიუწვდომელია", "Storage connection timeout. %s" : "საცავის კავშირის დროის ამოწურვა. %s", + "Logged in user must be an admin" : "ავტორიზირებული მომხმარებელი უნდა იყოს ადმინისტრატორი", "Full name" : "სრული სახელი", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "მომხმარებლის სახელში დაშვებულია მხოლოდ შემდეგი ნიშნები: \"a-z\", \"A-Z\", \"0-9\", და \"_.@-'\"", + "Unknown user" : "ამოუცნობი მომხმარებელი", + "Oracle username and/or password not valid" : "Oracle მომხმარებლის სახელი და/ან პაროლი არ არის სწორი", + "PostgreSQL username and/or password not valid" : "PostgreSQL მომხმარებლის სახელი და/ან პაროლი არ არის სწორი", + "Set an admin username." : "დააყენეთ ადმინისტრატორის სახელი.", + "Sharing %s failed, because this item is already shared with user %s" : "%s-ის გაზიარება არ მოხერხდა, რადგან ობიექტი მომხმარებელ %s-თან უკვე გაზიარებულია", + "The username is already being used" : "ესეთი მომხმარებლის სახელი უკვე არსებობს", + "Could not create user" : "მომხმარებლის შექმნა ვერ მოხერხდა", + "A valid username must be provided" : "უნდა მიუთითოთ არსებული მომხმარებლის სახელი", + "Username contains whitespace at the beginning or at the end" : "მომხმარებლის სახელი დასაწყისსში ან დასასრულში მოიცავს სიცარიელეს", + "Username must not consist of dots only" : "მომხმარებლის სახელი ვერ იქნება შემდგარი მხოლოდ წერტილებისგან", + "User disabled" : "მომხმარებელი გათიშულია", "libxml2 2.7.0 is at least required. Currently %s is installed." : "საჭიროა libxml2 ვერსიით 2.7.0 ან მეტი. ახლა დაყენებულია %s.", - "To fix this issue update your libxml2 version and restart your web server." : "ამ პრობლემის მოსაგვარებლად განაახლეთ libxml2 ვერსია და გადატვირთეთ თქვენი ვებ-სერვერი." + "To fix this issue update your libxml2 version and restart your web server." : "ამ პრობლემის მოსაგვარებლად განაახლეთ libxml2 ვერსია და გადატვირთეთ თქვენი ვებ-სერვერი.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "გთხოვთ შეცვალოთ უფლებები 0770-ზე, რათა დირექტორია სხვა მომხმარებლების მიერ აღარ იყოს კითხვადი." }, "nplurals=2; plural=(n!=1);"); diff --git a/lib/l10n/ka_GE.json b/lib/l10n/ka_GE.json index 4ffc6bfd2ef..c4b6c963bd4 100644 --- a/lib/l10n/ka_GE.json +++ b/lib/l10n/ka_GE.json @@ -18,7 +18,6 @@ "The library %s is not available." : "ბიბლიოთეკა %s ვერ იქნა ნაპოვნი.", "Server version %s or higher is required." : "საჭიროა სერვერი ვერსიით %s ან მეტი.", "Server version %s or lower is required." : "საჭიროა სერვერი ვერსიით %s ან ნაკლები.", - "Logged in user must be an admin" : "ავტორიზირებული მომხმარებელი უნდა იყოს ადმინისტრატორი", "Authentication" : "აუტენტიფიკაცია", "Unknown filetype" : "ამოუცნობი ფაილის ტიპი", "Invalid image" : "არასწორი სურათი", @@ -66,17 +65,13 @@ "Address" : "მისამართი", "Profile picture" : "პროფილის სურათი", "About" : "შესახებ", - "Unknown user" : "ამოუცნობი მომხმარებელი", "Additional settings" : "დამატებითი პარამეტრები", "You need to enter details of an existing account." : "საჭიროა შეიყვანოთ არსებული ანგარიშის დეტალები.", "Oracle connection could not be established" : "Oracle კავშირი ვერ დამყარდა", - "Oracle username and/or password not valid" : "Oracle მომხმარებლის სახელი და/ან პაროლი არ არის სწორი", - "PostgreSQL username 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 გარემოზე და 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-დან ან გადახვიდეთ 64-ბიტიან PHP-ზე.", - "Set an admin username." : "დააყენეთ ადმინისტრატორის სახელი.", "Set an admin password." : "დააყენეთ ადმინისტრატორის პაროლი.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "გაზიარების ბექენდმა %s-მ მოქმედებაში უნდა მოიყვანოს ინტეფეისი OCP\\Share_Backend", "Sharing backend %s not found" : "გაზიარების ბექენდი %s ვერ იქნა ნაპოვნი", @@ -85,7 +80,6 @@ "You are not allowed to share %s" : "თქვენ არ გაქვთ უფლება გააზიაროთ %s", "Cannot increase permissions of %s" : "%s-ის უფლებების გაზრდა ვერ ხერხდება", "Expiration date is in the past" : "ვადის ამოწურვის თარიღი წარსულშია", - "Sharing %s failed, because this item is already shared with user %s" : "%s-ის გაზიარება არ მოხერხდა, რადგან ობიექტი მომხმარებელ %s-თან უკვე გაზიარებულია", "Click the button below to open it." : "გასახსნელად დააჭირეთ ქვემოთ მყოფ ღილაკს.", "The requested share does not exist anymore" : "მოთხოვნილი გაზიარება მეტი აღარ არსებობს", "Could not find category \"%s\"" : "\"%s\" კატეგორიის მოძებნა ვერ მოხერხდა", @@ -135,12 +129,6 @@ "Nov." : "ნოე.", "Dec." : "დეკ.", "A valid password must be provided" : "უნდა მიუთითოთ სწორი პაროლი", - "The username is already being used" : "ესეთი მომხმარებლის სახელი უკვე არსებობს", - "Could not create user" : "მომხმარებლის შექმნა ვერ მოხერხდა", - "A valid username must be provided" : "უნდა მიუთითოთ არსებული მომხმარებლის სახელი", - "Username contains whitespace at the beginning or at the end" : "მომხმარებლის სახელი დასაწყისსში ან დასასრულში მოიცავს სიცარიელეს", - "Username must not consist of dots only" : "მომხმარებლის სახელი ვერ იქნება შემდგარი მხოლოდ წერტილებისგან", - "User disabled" : "მომხმარებელი გათიშულია", "Login canceled by app" : "აპლიკაციამ ლოგინი უარყო", "a safe home for all your data" : "უსაფრთხო სახლი მთელი თქვენი მონაცემებისათვის", "File is currently busy, please try again later" : "ფაილი ამჟამად დაკავებულია, გთხოვთ მოგვიანებით სცადოთ ახლიდან", @@ -156,7 +144,6 @@ "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." : "გთხოვთ სთხოვოთ თქვენს სერვერის ადმინისტრატორს გადატვირთოს ვებ-სერვერი.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "გთხოვთ შეცვალოთ უფლებები 0770-ზე, რათა დირექტორია სხვა მომხმარებლების მიერ აღარ იყოს კითხვადი.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "დარწმუნდით რომ ფაილი სახელად \".ocdata\" მონაცემების დირექტორიის საწყისშია.", "Could not obtain lock type %d on \"%s\"." : "ჩაკეთვის ტიპის %d მოძიება \"%s\"-ზე ვერ მოხერხდა.", "Storage unauthorized. %s" : "საცავი არაავტორიზირებულია. %s", @@ -164,9 +151,21 @@ "Storage connection error. %s" : "საცავის კავშირის შეცდომა. %s", "Storage is temporarily not available" : "საცავი დროებით ხელმიუწვდომელია", "Storage connection timeout. %s" : "საცავის კავშირის დროის ამოწურვა. %s", + "Logged in user must be an admin" : "ავტორიზირებული მომხმარებელი უნდა იყოს ადმინისტრატორი", "Full name" : "სრული სახელი", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "მომხმარებლის სახელში დაშვებულია მხოლოდ შემდეგი ნიშნები: \"a-z\", \"A-Z\", \"0-9\", და \"_.@-'\"", + "Unknown user" : "ამოუცნობი მომხმარებელი", + "Oracle username and/or password not valid" : "Oracle მომხმარებლის სახელი და/ან პაროლი არ არის სწორი", + "PostgreSQL username and/or password not valid" : "PostgreSQL მომხმარებლის სახელი და/ან პაროლი არ არის სწორი", + "Set an admin username." : "დააყენეთ ადმინისტრატორის სახელი.", + "Sharing %s failed, because this item is already shared with user %s" : "%s-ის გაზიარება არ მოხერხდა, რადგან ობიექტი მომხმარებელ %s-თან უკვე გაზიარებულია", + "The username is already being used" : "ესეთი მომხმარებლის სახელი უკვე არსებობს", + "Could not create user" : "მომხმარებლის შექმნა ვერ მოხერხდა", + "A valid username must be provided" : "უნდა მიუთითოთ არსებული მომხმარებლის სახელი", + "Username contains whitespace at the beginning or at the end" : "მომხმარებლის სახელი დასაწყისსში ან დასასრულში მოიცავს სიცარიელეს", + "Username must not consist of dots only" : "მომხმარებლის სახელი ვერ იქნება შემდგარი მხოლოდ წერტილებისგან", + "User disabled" : "მომხმარებელი გათიშულია", "libxml2 2.7.0 is at least required. Currently %s is installed." : "საჭიროა libxml2 ვერსიით 2.7.0 ან მეტი. ახლა დაყენებულია %s.", - "To fix this issue update your libxml2 version and restart your web server." : "ამ პრობლემის მოსაგვარებლად განაახლეთ libxml2 ვერსია და გადატვირთეთ თქვენი ვებ-სერვერი." + "To fix this issue update your libxml2 version and restart your web server." : "ამ პრობლემის მოსაგვარებლად განაახლეთ libxml2 ვერსია და გადატვირთეთ თქვენი ვებ-სერვერი.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "გთხოვთ შეცვალოთ უფლებები 0770-ზე, რათა დირექტორია სხვა მომხმარებლების მიერ აღარ იყოს კითხვადი." },"pluralForm" :"nplurals=2; plural=(n!=1);" }
\ No newline at end of file diff --git a/lib/l10n/km.js b/lib/l10n/km.js index f7216ea9301..e74fbe82cc4 100644 --- a/lib/l10n/km.js +++ b/lib/l10n/km.js @@ -22,10 +22,7 @@ OC.L10N.register( "Address" : "អាសយដ្ឋាន", "Profile picture" : "រូបភាពប្រវត្តិរូប", "About" : "អំពី", - "Unknown user" : "មិនស្គាល់អ្នកប្រើប្រាស់", "Oracle connection could not be established" : "មិនអាចបង្កើតការតភ្ជាប់ Oracle", - "PostgreSQL username and/or password not valid" : "ឈ្មោះអ្នកប្រើ និង/ឬ ពាក្យសម្ងាត់ PostgreSQL គឺមិនត្រូវទេ", - "Set an admin username." : "កំណត់ឈ្មោះអ្នកគ្រប់គ្រង។", "Set an admin password." : "កំណត់ពាក្យសម្ងាត់អ្នកគ្រប់គ្រង។", "Could not find category \"%s\"" : "រកមិនឃើញចំណាត់ក្រុម \"%s\"", "Sunday" : "ថ្ងៃអាទិត្យ", @@ -67,8 +64,11 @@ OC.L10N.register( "Nov." : "វិច្ឆិកា", "Dec." : "ធ្នូ", "A valid password must be provided" : "ត្រូវផ្ដល់ពាក្យសម្ងាត់ឲ្យបានត្រឹមត្រូវ", - "A valid username must be provided" : "ត្រូវផ្ដល់ឈ្មោះអ្នកប្រើឲ្យបានត្រឹមត្រូវ", "Application is not enabled" : "មិនបានបើកកម្មវិធី", - "Authentication error" : "កំហុសការផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ" + "Authentication error" : "កំហុសការផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ", + "Unknown user" : "មិនស្គាល់អ្នកប្រើប្រាស់", + "PostgreSQL username and/or password not valid" : "ឈ្មោះអ្នកប្រើ និង/ឬ ពាក្យសម្ងាត់ PostgreSQL គឺមិនត្រូវទេ", + "Set an admin username." : "កំណត់ឈ្មោះអ្នកគ្រប់គ្រង។", + "A valid username must be provided" : "ត្រូវផ្ដល់ឈ្មោះអ្នកប្រើឲ្យបានត្រឹមត្រូវ" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/km.json b/lib/l10n/km.json index cb0d114d2a7..692fd4048de 100644 --- a/lib/l10n/km.json +++ b/lib/l10n/km.json @@ -20,10 +20,7 @@ "Address" : "អាសយដ្ឋាន", "Profile picture" : "រូបភាពប្រវត្តិរូប", "About" : "អំពី", - "Unknown user" : "មិនស្គាល់អ្នកប្រើប្រាស់", "Oracle connection could not be established" : "មិនអាចបង្កើតការតភ្ជាប់ Oracle", - "PostgreSQL username and/or password not valid" : "ឈ្មោះអ្នកប្រើ និង/ឬ ពាក្យសម្ងាត់ PostgreSQL គឺមិនត្រូវទេ", - "Set an admin username." : "កំណត់ឈ្មោះអ្នកគ្រប់គ្រង។", "Set an admin password." : "កំណត់ពាក្យសម្ងាត់អ្នកគ្រប់គ្រង។", "Could not find category \"%s\"" : "រកមិនឃើញចំណាត់ក្រុម \"%s\"", "Sunday" : "ថ្ងៃអាទិត្យ", @@ -65,8 +62,11 @@ "Nov." : "វិច្ឆិកា", "Dec." : "ធ្នូ", "A valid password must be provided" : "ត្រូវផ្ដល់ពាក្យសម្ងាត់ឲ្យបានត្រឹមត្រូវ", - "A valid username must be provided" : "ត្រូវផ្ដល់ឈ្មោះអ្នកប្រើឲ្យបានត្រឹមត្រូវ", "Application is not enabled" : "មិនបានបើកកម្មវិធី", - "Authentication error" : "កំហុសការផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ" + "Authentication error" : "កំហុសការផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ", + "Unknown user" : "មិនស្គាល់អ្នកប្រើប្រាស់", + "PostgreSQL username and/or password not valid" : "ឈ្មោះអ្នកប្រើ និង/ឬ ពាក្យសម្ងាត់ PostgreSQL គឺមិនត្រូវទេ", + "Set an admin username." : "កំណត់ឈ្មោះអ្នកគ្រប់គ្រង។", + "A valid username must be provided" : "ត្រូវផ្ដល់ឈ្មោះអ្នកប្រើឲ្យបានត្រឹមត្រូវ" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/kn.js b/lib/l10n/kn.js index db63146d03e..a768fa9b0b8 100644 --- a/lib/l10n/kn.js +++ b/lib/l10n/kn.js @@ -32,7 +32,7 @@ OC.L10N.register( "November" : "ನವೆಂಬರ್", "December" : "ಡಿಸೆಂಬರ್", "A valid password must be provided" : "ಸರಿಯಾದ ಬಳಕೆದಾರ ಗುಪ್ತಪದ ಒದಗಿಸಬೇಕಾಗಿದೆ", - "A valid username must be provided" : "ಮಾನ್ಯ ಬಳಕೆದಾರ ಹೆಸರು ಒದಗಿಸಬೇಕಾಗುತ್ತದೆ", - "Authentication error" : "ದೃಢೀಕರಣ ದೋಷ" + "Authentication error" : "ದೃಢೀಕರಣ ದೋಷ", + "A valid username must be provided" : "ಮಾನ್ಯ ಬಳಕೆದಾರ ಹೆಸರು ಒದಗಿಸಬೇಕಾಗುತ್ತದೆ" }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/kn.json b/lib/l10n/kn.json index bf27ad27c2d..502012185f8 100644 --- a/lib/l10n/kn.json +++ b/lib/l10n/kn.json @@ -30,7 +30,7 @@ "November" : "ನವೆಂಬರ್", "December" : "ಡಿಸೆಂಬರ್", "A valid password must be provided" : "ಸರಿಯಾದ ಬಳಕೆದಾರ ಗುಪ್ತಪದ ಒದಗಿಸಬೇಕಾಗಿದೆ", - "A valid username must be provided" : "ಮಾನ್ಯ ಬಳಕೆದಾರ ಹೆಸರು ಒದಗಿಸಬೇಕಾಗುತ್ತದೆ", - "Authentication error" : "ದೃಢೀಕರಣ ದೋಷ" + "Authentication error" : "ದೃಢೀಕರಣ ದೋಷ", + "A valid username must be provided" : "ಮಾನ್ಯ ಬಳಕೆದಾರ ಹೆಸರು ಒದಗಿಸಬೇಕಾಗುತ್ತದೆ" },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/lib/l10n/ko.js b/lib/l10n/ko.js index 00377f3d7e3..f34bea1fb3c 100644 --- a/lib/l10n/ko.js +++ b/lib/l10n/ko.js @@ -2,10 +2,17 @@ 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." : "config 디렉터리에 웹 서버 쓰기 권한을 부여해서 해결할 수 있습니다", + "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." : "애플리케이션 %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." : "페이지를 서버에서 찾을 수 없습니다.", + "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", @@ -14,26 +21,42 @@ OC.L10N.register( "Education Edition" : "교육용 에디션", "Enterprise bundle" : "엔터프라이즈 번들", "Groupware bundle" : "그룹웨어 번들", + "Hub bundle" : "Hub 번들", "Social sharing bundle" : "소셜 공유 번들", "PHP %s or higher is required." : "PHP 버전 %s 이상이 필요합니다.", "PHP with a version lower than %s is required." : "PHP 버전 %s 미만이 필요합니다.", "%sbit or higher PHP required." : "%s비트 이상의 PHP가 필요합니다.", + "The following architectures are supported: %s" : "다음 아키텍쳐를 지원합니다: %s", + "The following databases are supported: %s" : "다음 데이터베이스를 지원합니다: %s", "The command line tool %s could not be found" : "명령행 도구 %s을(를) 찾을 수 없습니다", "The library %s is not available." : "%s 라이브러리를 사용할 수 없습니다.", "Library %1$s with a version higher than %2$s is required - available version %3$s." : "%1$s 라이브러리의 버전 %2$s 이상이 필요합니다. 사용 가능한 버전은 %3$s입니다.", "Library %1$s with a version lower than %2$s is required - available version %3$s." : "%1$s 라이브러리의 버전 %2$s 이상이 필요합니다. 사용 가능한 버전은 %3$s입니다.", + "The following platforms are supported: %s" : "다음 플랫폼을 지원합니다: %s", "Server version %s or higher is required." : "서버 버전 %s 이상이 필요합니다.", "Server version %s or lower is required." : "서버 버전 %s 미만이 필요합니다.", - "Logged in user must be an admin or sub admin" : "로그인한 사용자는 관리자 또는 부 관리자여야 합니다.", - "Logged in user must be an admin" : "로그인한 사용자는 관리자여야 합니다.", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "로그인된 계정이 관리자, 부 관리자, 또는 이 설정에 접근할 수 있는 권한을 부여받은 계정이어야 합니다", + "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에서 시작됨", + "Remote wipe finished" : "원격 제거가 완료됨", + "The remote wipe on %s has finished" : "%s에서의 원격 제거가 완료됨", "Authentication" : "인증", "Unknown filetype" : "알 수 없는 파일 형식", "Invalid image" : "잘못된 사진", "Avatar image is not square" : "아바타 사진이 정사각형이 아님", "Files" : "파일", "View profile" : "프로필 보기", + "Local time: %s" : "현지 시간: %s", "today" : "오늘", "tomorrow" : "내일", "yesterday" : "어제", @@ -56,6 +79,8 @@ OC.L10N.register( "Empty file" : "빈 파일", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "ID: %s인 모듈이 존재하지 않습니다. 앱 설정에서 확인하거나 시스템 관리자에게 연락하십시오.", "File already exists" : "파일이 이미 있습니다.", + "Invalid path" : "잘못된 경로", + "Failed to create file from template" : "템플릿으로 새 파일을 만들 수 없음", "Templates" : "템플릿", "File name is a reserved word" : "파일 이름이 예약된 단어임", "File name contains at least one invalid character" : "파일 이름에 잘못된 글자가 한 자 이상 있음", @@ -75,27 +100,34 @@ OC.L10N.register( "Log out" : "로그아웃", "Users" : "사용자", "Email" : "이메일", + "Mail %s" : "%s에게 메일 보내기", + "Fediverse" : "Fediverse", + "View %s on the fediverse" : "Fediverse에서 %s 보기", "Phone" : "전화 번호", + "Call %s" : "%s에게 전화하기", "Twitter" : "Twitter", + "View %s on Twitter" : "Twitter에서 %s 보기", "Website" : "웹 사이트", + "Visit %s" : "%s 방문하기", "Address" : "주소", "Profile picture" : "프로필 사진", "About" : "정보", + "Display name" : "표시 이름", "Headline" : "표제", "Organisation" : "조직", "Role" : "직책", - "Unknown user" : "알려지지 않은 사용자", + "Unknown account" : "알 수 없는 계정", "Additional settings" : "고급 설정", + "Enter the database name for %s" : "%s에 대한 데이터베이스 이름을 입력하십시오", + "You cannot use dots in the database name %s" : "데이터베이스 이름에 점(.)을 사용할 수 없습니다 %s", "You need to enter details of an existing account." : "존재하는 계정 정보를 입력해야 합니다.", "Oracle connection could not be established" : "Oracle 연결을 수립할 수 없습니다.", - "Oracle username and/or password not valid" : "Oracle 사용자 이름이나 암호가 잘못되었습니다.", - "PostgreSQL username 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이 설정되어 있습니다. 4GB 이상의 파일 처리에 문제가 생길 수 있으므로 추천하지 않습니다.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "php.ini의 open_basedir 설정을 삭제하거나 64비트 PHP로 전환하십시오.", - "Set an admin username." : "관리자의 사용자 이름을 설정합니다.", "Set an admin password." : "관리자의 암호를 설정합니다.", + "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의 공유 백엔드를 찾을 수 없음", @@ -106,10 +138,18 @@ OC.L10N.register( "%1$s via %2$s" : "%1$s(%2$s 경유)", "You are not allowed to share %s" : "%s을(를) 공유할 수 있는 권한이 없습니다", "Cannot increase permissions of %s" : "%s의 권한을 늘릴 수 없습니다.", + "Files cannot be shared with delete permissions" : "파일을 삭제 권한으로 공유할 수 없습니다", + "Files cannot be shared with create permissions" : "파일을 생성 권한으로 공유할 수 없습니다", "Expiration date is in the past" : "만료 날짜가 과거입니다", - "Sharing %s failed, because this item is already shared with user %s" : "%s을(를) 공유할 수 없습니다. 이 항목을 이미 %s 님과 공유하고 있습니다", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["만료 날짜는 최대 %s일까지 설정할 수 있습니다"], + "Sharing is only allowed with group members" : "같은 그룹 사용자에게만 공유할 수 있습니다", + "Sharing %s failed, because this item is already shared with the account %s" : "%s을(를) 공유할 수 없습니다. 이 항목을 이미 %s 계정과 공유하고 있습니다", + "%1$s shared »%2$s« with you" : "%1$s 님이 »%2$s« 항목을 공유했습니다", + "%1$s shared »%2$s« with you." : "%1$s 님이 »%2$s« 항목을 공유했습니다", "Click the button below to open it." : "아래 단추를 눌러서 열 수 있습니다.", "The requested share does not exist anymore" : "요청한 공유가 더 이상 존재하지 않습니다", + "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\"을(를) 찾을 수 없습니다", "Sunday" : "일요일", "Monday" : "월요일", @@ -157,34 +197,48 @@ OC.L10N.register( "Nov." : "11월", "Dec." : "12월", "A valid password must be provided" : "올바른 암호를 입력해야 합니다", - "The username is already being used" : "사용자 이름이 이미 존재합니다", - "Could not create user" : "사용자를 만들 수 없습니다", - "A valid username must be provided" : "올바른 사용자 이름을 입력해야 합니다", - "Username contains whitespace at the beginning or at the end" : "사용자 이름의 시작이나 끝에 공백이 있습니다", - "Username must not consist of dots only" : "사용자 이름에 마침표만 있으면 안 됩니다", - "Username is invalid because files already exist for this user" : "무효한 사용자이름. 이미 존재함", - "User disabled" : "사용자 비활성화됨", + "Could not create account" : "계정을 만들 수 없음", + "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" : "내 모든 데이터의 안전한 저장소", "File is currently busy, please try again later" : "파일이 현재 사용 중, 나중에 다시 시도하십시오", + "Cannot download file" : "파일을 다운로드할 수 없음", "Application is not enabled" : "앱이 활성화되지 않았습니다", "Authentication error" : "인증 오류", "Token expired. Please reload page." : "토큰이 만료되었습니다. 페이지를 새로 고치십시오.", "No database drivers (sqlite, mysql, or postgresql) installed." : "데이터베이스 드라이버(sqlite, mysql, postgresql)가 설치되지 않았습니다.", + "Cannot write into \"config\" directory." : "\"config\" 디렉토리에 기록할 수 없습니다", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "config 디렉터리에 웹 서버의 쓰기 권한을 부여해서 해결할 수 있습니다. %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." : "apps 디렉토리에 웹 서버의 쓰기 권한을 부여하거나 설정 파일에서 앱 스토어를 비활성화하면 해결됩니다.", + "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\"(으)로 설정되어 있지 않습니다.", "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>가 <code>%s</code>(으)로 설정되어 있으나, 올바른 값은 <code>0</code>입니다.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "이 문제를 해결하려면 php.ini 에서 <code>mbstring.func_overload</code>를 <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." : "서버 관리자에게 웹 서버 재시작을 요청하십시오.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "권한을 0770으로 변경하여 다른 사용자가 읽을 수 없도록 하십시오.", + "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 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 \".ocdata\" in the root of the data directory." : "데이터 디렉터리의 최상위 디렉터리에 \".ocdata\" 파일이 있는지 확인하십시오.", "Action \"%s\" not supported or implemented." : "동작 \"%s\"을(를) 지원하지 않거나 사용할 수 없습니다. ", "Authentication failed, wrong token or provider ID given" : "인증이 실패하였습니다. 토큰이나 프로바이더 ID가 틀렸습니다.", "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "요청을 완료하기 위한 매개변수가 누락되었습니다. 누락된 매개변수: \"%s\"", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "ID \"%1$s\"은(는) 클라우드 연합 제공자 \"%2$s\"이(가) 이미 사용 중입니다.", "Cloud Federation Provider with ID: \"%s\" does not exist." : "ID가 \"%s\"인 클라우드 연합 제공자가 없습니다.", "Could not obtain lock type %d on \"%s\"." : "잠금 형식 %d을(를) \"%s\"에 대해 얻을 수 없습니다.", "Storage unauthorized. %s" : "저장소가 인증되지 않았습니다. %s", @@ -192,10 +246,38 @@ OC.L10N.register( "Storage connection error. %s" : "저장소 연결 오류입니다. %s", "Storage is temporarily not available" : "저장소를 임시로 사용할 수 없음", "Storage connection timeout. %s" : "저장소 연결 시간이 초과되었습니다. %s", + "Generate headline" : "헤드라인 생성", + "Generates a possible headline for a text." : "내용에 대한 헤드라인을 생성하십시오.", + "Summarize" : "요약", + "Summarizes text by reducing its length without losing key information." : "중요 정보로 내용을 축약하십시오.", + "Extract topics" : "주제 추출", + "Extracts topics from a text and outputs them separated by commas." : "내용에서 주요 주제를 추출하고 쉼표로 이를 구분하십시오.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "앱 %1$s의 파일이 올바르게 교체되지 않았습니다. 서버와 호환되는 버전인지 확인하십시오.", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "로그인된 사용자가 관리자, 부 관리자, 또는 이 설정에 접근할 수 있는 권한을 부여받은 사용자일 것입니다.", + "Logged in user must be an admin or sub admin" : "로그인한 사용자는 관리자 또는 부 관리자여야 합니다.", + "Logged in user must be an admin" : "로그인한 사용자는 관리자여야 합니다.", "Full name" : "전체 이름", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "다음 문자만 이름에 사용할 수 있습니다: \"a-z\", \"A-Z\", \"0-9\", 및 \"_.@-'\"", + "Unknown user" : "알려지지 않은 사용자", + "Enter the database username and name for %s" : "%s에 대한 데이터베이스 사용자 이름과 이름을 입력하십시오", + "Enter the database username for %s" : "%s에 대한 데이터베이스 사용자 이름을 입력하십시오", + "MySQL username and/or password not valid" : "MySQL 사용자 이름 또는 암호가 잘못되었습니다", + "Oracle username and/or password not valid" : "Oracle 사용자 이름이나 암호가 잘못되었습니다.", + "PostgreSQL username and/or password not valid" : "PostgreSQL 사용자 이름 또는 암호가 잘못되었습니다", + "Set an admin username." : "관리자의 사용자 이름을 설정합니다.", + "Sharing %s failed, because this item is already shared with user %s" : "%s을(를) 공유할 수 없습니다. 이 항목을 이미 %s 님과 공유하고 있습니다", + "The username is already being used" : "사용자 이름이 이미 존재합니다", + "Could not create user" : "사용자를 만들 수 없습니다", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "사용자 이름에는 다음 문자만 사용할 수 있습니다: \"a-z, \"A-Z\", \"0-9\", 공백, \"_.@-'\"", + "A valid username must be provided" : "올바른 사용자 이름을 입력해야 합니다", + "Username contains whitespace at the beginning or at the end" : "사용자 이름의 시작이나 끝에 공백이 있습니다", + "Username must not consist of dots only" : "사용자 이름에 마침표만 있으면 안 됩니다", + "Username is invalid because files already exist for this user" : "무효한 사용자이름. 이미 존재함", + "User disabled" : "사용자 비활성화됨", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 이상이 필요합니다. 현재 버전은 %s입니다.", - "To fix this issue update your libxml2 version and restart your web server." : "이 문제를 해결하려면 libxml2 버전을 업데이트하고 웹 서버를 다시 시작하십시오." + "To fix this issue update your libxml2 version and restart your web server." : "이 문제를 해결하려면 libxml2 버전을 업데이트하고 웹 서버를 다시 시작하십시오.", + "PostgreSQL >= 9 required." : "PostgreSQL 버전 9 이상이 필요합니다", + "Please upgrade your database version." : "데이터베이스 버전을 업그레이드 하십시오", + "Your data directory is readable by other users." : "현재 데이터 디렉토리를 다른 사람이 읽을 수 있습니다.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "권한을 0770으로 변경하여 다른 사용자가 읽을 수 없도록 하십시오." }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/ko.json b/lib/l10n/ko.json index 0fb317916e3..1d39df18a8a 100644 --- a/lib/l10n/ko.json +++ b/lib/l10n/ko.json @@ -1,9 +1,16 @@ { "translations": { "Cannot write into \"config\" directory!" : "\"config\" 디렉터리에 기록할 수 없습니다!", + "This can usually be fixed by giving the web server write access to the config directory." : "config 디렉터리에 웹 서버 쓰기 권한을 부여해서 해결할 수 있습니다", + "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." : "애플리케이션 %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." : "페이지를 서버에서 찾을 수 없습니다.", + "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", @@ -12,26 +19,42 @@ "Education Edition" : "교육용 에디션", "Enterprise bundle" : "엔터프라이즈 번들", "Groupware bundle" : "그룹웨어 번들", + "Hub bundle" : "Hub 번들", "Social sharing bundle" : "소셜 공유 번들", "PHP %s or higher is required." : "PHP 버전 %s 이상이 필요합니다.", "PHP with a version lower than %s is required." : "PHP 버전 %s 미만이 필요합니다.", "%sbit or higher PHP required." : "%s비트 이상의 PHP가 필요합니다.", + "The following architectures are supported: %s" : "다음 아키텍쳐를 지원합니다: %s", + "The following databases are supported: %s" : "다음 데이터베이스를 지원합니다: %s", "The command line tool %s could not be found" : "명령행 도구 %s을(를) 찾을 수 없습니다", "The library %s is not available." : "%s 라이브러리를 사용할 수 없습니다.", "Library %1$s with a version higher than %2$s is required - available version %3$s." : "%1$s 라이브러리의 버전 %2$s 이상이 필요합니다. 사용 가능한 버전은 %3$s입니다.", "Library %1$s with a version lower than %2$s is required - available version %3$s." : "%1$s 라이브러리의 버전 %2$s 이상이 필요합니다. 사용 가능한 버전은 %3$s입니다.", + "The following platforms are supported: %s" : "다음 플랫폼을 지원합니다: %s", "Server version %s or higher is required." : "서버 버전 %s 이상이 필요합니다.", "Server version %s or lower is required." : "서버 버전 %s 미만이 필요합니다.", - "Logged in user must be an admin or sub admin" : "로그인한 사용자는 관리자 또는 부 관리자여야 합니다.", - "Logged in user must be an admin" : "로그인한 사용자는 관리자여야 합니다.", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "로그인된 계정이 관리자, 부 관리자, 또는 이 설정에 접근할 수 있는 권한을 부여받은 계정이어야 합니다", + "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에서 시작됨", + "Remote wipe finished" : "원격 제거가 완료됨", + "The remote wipe on %s has finished" : "%s에서의 원격 제거가 완료됨", "Authentication" : "인증", "Unknown filetype" : "알 수 없는 파일 형식", "Invalid image" : "잘못된 사진", "Avatar image is not square" : "아바타 사진이 정사각형이 아님", "Files" : "파일", "View profile" : "프로필 보기", + "Local time: %s" : "현지 시간: %s", "today" : "오늘", "tomorrow" : "내일", "yesterday" : "어제", @@ -54,6 +77,8 @@ "Empty file" : "빈 파일", "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "ID: %s인 모듈이 존재하지 않습니다. 앱 설정에서 확인하거나 시스템 관리자에게 연락하십시오.", "File already exists" : "파일이 이미 있습니다.", + "Invalid path" : "잘못된 경로", + "Failed to create file from template" : "템플릿으로 새 파일을 만들 수 없음", "Templates" : "템플릿", "File name is a reserved word" : "파일 이름이 예약된 단어임", "File name contains at least one invalid character" : "파일 이름에 잘못된 글자가 한 자 이상 있음", @@ -73,27 +98,34 @@ "Log out" : "로그아웃", "Users" : "사용자", "Email" : "이메일", + "Mail %s" : "%s에게 메일 보내기", + "Fediverse" : "Fediverse", + "View %s on the fediverse" : "Fediverse에서 %s 보기", "Phone" : "전화 번호", + "Call %s" : "%s에게 전화하기", "Twitter" : "Twitter", + "View %s on Twitter" : "Twitter에서 %s 보기", "Website" : "웹 사이트", + "Visit %s" : "%s 방문하기", "Address" : "주소", "Profile picture" : "프로필 사진", "About" : "정보", + "Display name" : "표시 이름", "Headline" : "표제", "Organisation" : "조직", "Role" : "직책", - "Unknown user" : "알려지지 않은 사용자", + "Unknown account" : "알 수 없는 계정", "Additional settings" : "고급 설정", + "Enter the database name for %s" : "%s에 대한 데이터베이스 이름을 입력하십시오", + "You cannot use dots in the database name %s" : "데이터베이스 이름에 점(.)을 사용할 수 없습니다 %s", "You need to enter details of an existing account." : "존재하는 계정 정보를 입력해야 합니다.", "Oracle connection could not be established" : "Oracle 연결을 수립할 수 없습니다.", - "Oracle username and/or password not valid" : "Oracle 사용자 이름이나 암호가 잘못되었습니다.", - "PostgreSQL username 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이 설정되어 있습니다. 4GB 이상의 파일 처리에 문제가 생길 수 있으므로 추천하지 않습니다.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "php.ini의 open_basedir 설정을 삭제하거나 64비트 PHP로 전환하십시오.", - "Set an admin username." : "관리자의 사용자 이름을 설정합니다.", "Set an admin password." : "관리자의 암호를 설정합니다.", + "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의 공유 백엔드를 찾을 수 없음", @@ -104,10 +136,18 @@ "%1$s via %2$s" : "%1$s(%2$s 경유)", "You are not allowed to share %s" : "%s을(를) 공유할 수 있는 권한이 없습니다", "Cannot increase permissions of %s" : "%s의 권한을 늘릴 수 없습니다.", + "Files cannot be shared with delete permissions" : "파일을 삭제 권한으로 공유할 수 없습니다", + "Files cannot be shared with create permissions" : "파일을 생성 권한으로 공유할 수 없습니다", "Expiration date is in the past" : "만료 날짜가 과거입니다", - "Sharing %s failed, because this item is already shared with user %s" : "%s을(를) 공유할 수 없습니다. 이 항목을 이미 %s 님과 공유하고 있습니다", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["만료 날짜는 최대 %s일까지 설정할 수 있습니다"], + "Sharing is only allowed with group members" : "같은 그룹 사용자에게만 공유할 수 있습니다", + "Sharing %s failed, because this item is already shared with the account %s" : "%s을(를) 공유할 수 없습니다. 이 항목을 이미 %s 계정과 공유하고 있습니다", + "%1$s shared »%2$s« with you" : "%1$s 님이 »%2$s« 항목을 공유했습니다", + "%1$s shared »%2$s« with you." : "%1$s 님이 »%2$s« 항목을 공유했습니다", "Click the button below to open it." : "아래 단추를 눌러서 열 수 있습니다.", "The requested share does not exist anymore" : "요청한 공유가 더 이상 존재하지 않습니다", + "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\"을(를) 찾을 수 없습니다", "Sunday" : "일요일", "Monday" : "월요일", @@ -155,34 +195,48 @@ "Nov." : "11월", "Dec." : "12월", "A valid password must be provided" : "올바른 암호를 입력해야 합니다", - "The username is already being used" : "사용자 이름이 이미 존재합니다", - "Could not create user" : "사용자를 만들 수 없습니다", - "A valid username must be provided" : "올바른 사용자 이름을 입력해야 합니다", - "Username contains whitespace at the beginning or at the end" : "사용자 이름의 시작이나 끝에 공백이 있습니다", - "Username must not consist of dots only" : "사용자 이름에 마침표만 있으면 안 됩니다", - "Username is invalid because files already exist for this user" : "무효한 사용자이름. 이미 존재함", - "User disabled" : "사용자 비활성화됨", + "Could not create account" : "계정을 만들 수 없음", + "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" : "내 모든 데이터의 안전한 저장소", "File is currently busy, please try again later" : "파일이 현재 사용 중, 나중에 다시 시도하십시오", + "Cannot download file" : "파일을 다운로드할 수 없음", "Application is not enabled" : "앱이 활성화되지 않았습니다", "Authentication error" : "인증 오류", "Token expired. Please reload page." : "토큰이 만료되었습니다. 페이지를 새로 고치십시오.", "No database drivers (sqlite, mysql, or postgresql) installed." : "데이터베이스 드라이버(sqlite, mysql, postgresql)가 설치되지 않았습니다.", + "Cannot write into \"config\" directory." : "\"config\" 디렉토리에 기록할 수 없습니다", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "config 디렉터리에 웹 서버의 쓰기 권한을 부여해서 해결할 수 있습니다. %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." : "apps 디렉토리에 웹 서버의 쓰기 권한을 부여하거나 설정 파일에서 앱 스토어를 비활성화하면 해결됩니다.", + "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\"(으)로 설정되어 있지 않습니다.", "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>가 <code>%s</code>(으)로 설정되어 있으나, 올바른 값은 <code>0</code>입니다.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "이 문제를 해결하려면 php.ini 에서 <code>mbstring.func_overload</code>를 <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." : "서버 관리자에게 웹 서버 재시작을 요청하십시오.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "권한을 0770으로 변경하여 다른 사용자가 읽을 수 없도록 하십시오.", + "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 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 \".ocdata\" in the root of the data directory." : "데이터 디렉터리의 최상위 디렉터리에 \".ocdata\" 파일이 있는지 확인하십시오.", "Action \"%s\" not supported or implemented." : "동작 \"%s\"을(를) 지원하지 않거나 사용할 수 없습니다. ", "Authentication failed, wrong token or provider ID given" : "인증이 실패하였습니다. 토큰이나 프로바이더 ID가 틀렸습니다.", "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "요청을 완료하기 위한 매개변수가 누락되었습니다. 누락된 매개변수: \"%s\"", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "ID \"%1$s\"은(는) 클라우드 연합 제공자 \"%2$s\"이(가) 이미 사용 중입니다.", "Cloud Federation Provider with ID: \"%s\" does not exist." : "ID가 \"%s\"인 클라우드 연합 제공자가 없습니다.", "Could not obtain lock type %d on \"%s\"." : "잠금 형식 %d을(를) \"%s\"에 대해 얻을 수 없습니다.", "Storage unauthorized. %s" : "저장소가 인증되지 않았습니다. %s", @@ -190,10 +244,38 @@ "Storage connection error. %s" : "저장소 연결 오류입니다. %s", "Storage is temporarily not available" : "저장소를 임시로 사용할 수 없음", "Storage connection timeout. %s" : "저장소 연결 시간이 초과되었습니다. %s", + "Generate headline" : "헤드라인 생성", + "Generates a possible headline for a text." : "내용에 대한 헤드라인을 생성하십시오.", + "Summarize" : "요약", + "Summarizes text by reducing its length without losing key information." : "중요 정보로 내용을 축약하십시오.", + "Extract topics" : "주제 추출", + "Extracts topics from a text and outputs them separated by commas." : "내용에서 주요 주제를 추출하고 쉼표로 이를 구분하십시오.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "앱 %1$s의 파일이 올바르게 교체되지 않았습니다. 서버와 호환되는 버전인지 확인하십시오.", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "로그인된 사용자가 관리자, 부 관리자, 또는 이 설정에 접근할 수 있는 권한을 부여받은 사용자일 것입니다.", + "Logged in user must be an admin or sub admin" : "로그인한 사용자는 관리자 또는 부 관리자여야 합니다.", + "Logged in user must be an admin" : "로그인한 사용자는 관리자여야 합니다.", "Full name" : "전체 이름", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "다음 문자만 이름에 사용할 수 있습니다: \"a-z\", \"A-Z\", \"0-9\", 및 \"_.@-'\"", + "Unknown user" : "알려지지 않은 사용자", + "Enter the database username and name for %s" : "%s에 대한 데이터베이스 사용자 이름과 이름을 입력하십시오", + "Enter the database username for %s" : "%s에 대한 데이터베이스 사용자 이름을 입력하십시오", + "MySQL username and/or password not valid" : "MySQL 사용자 이름 또는 암호가 잘못되었습니다", + "Oracle username and/or password not valid" : "Oracle 사용자 이름이나 암호가 잘못되었습니다.", + "PostgreSQL username and/or password not valid" : "PostgreSQL 사용자 이름 또는 암호가 잘못되었습니다", + "Set an admin username." : "관리자의 사용자 이름을 설정합니다.", + "Sharing %s failed, because this item is already shared with user %s" : "%s을(를) 공유할 수 없습니다. 이 항목을 이미 %s 님과 공유하고 있습니다", + "The username is already being used" : "사용자 이름이 이미 존재합니다", + "Could not create user" : "사용자를 만들 수 없습니다", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "사용자 이름에는 다음 문자만 사용할 수 있습니다: \"a-z, \"A-Z\", \"0-9\", 공백, \"_.@-'\"", + "A valid username must be provided" : "올바른 사용자 이름을 입력해야 합니다", + "Username contains whitespace at the beginning or at the end" : "사용자 이름의 시작이나 끝에 공백이 있습니다", + "Username must not consist of dots only" : "사용자 이름에 마침표만 있으면 안 됩니다", + "Username is invalid because files already exist for this user" : "무효한 사용자이름. 이미 존재함", + "User disabled" : "사용자 비활성화됨", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 이상이 필요합니다. 현재 버전은 %s입니다.", - "To fix this issue update your libxml2 version and restart your web server." : "이 문제를 해결하려면 libxml2 버전을 업데이트하고 웹 서버를 다시 시작하십시오." + "To fix this issue update your libxml2 version and restart your web server." : "이 문제를 해결하려면 libxml2 버전을 업데이트하고 웹 서버를 다시 시작하십시오.", + "PostgreSQL >= 9 required." : "PostgreSQL 버전 9 이상이 필요합니다", + "Please upgrade your database version." : "데이터베이스 버전을 업그레이드 하십시오", + "Your data directory is readable by other users." : "현재 데이터 디렉토리를 다른 사람이 읽을 수 있습니다.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "권한을 0770으로 변경하여 다른 사용자가 읽을 수 없도록 하십시오." },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/lo.js b/lib/l10n/lo.js index d5bd2961de3..63f101c8df5 100644 --- a/lib/l10n/lo.js +++ b/lib/l10n/lo.js @@ -17,7 +17,7 @@ OC.L10N.register( "Address" : "ທີ່ຢູ່", "About" : "ກ່ຽວກັບ", "Role" : "ພາລະບົດບາດ", - "User disabled" : "ປິດຊື່ຜູ້ໃຊ້", - "Full name" : "ຊື່ເຕັມ" + "Full name" : "ຊື່ເຕັມ", + "User disabled" : "ປິດຊື່ຜູ້ໃຊ້" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/lo.json b/lib/l10n/lo.json index 9c060b912e8..9d1715861ba 100644 --- a/lib/l10n/lo.json +++ b/lib/l10n/lo.json @@ -15,7 +15,7 @@ "Address" : "ທີ່ຢູ່", "About" : "ກ່ຽວກັບ", "Role" : "ພາລະບົດບາດ", - "User disabled" : "ປິດຊື່ຜູ້ໃຊ້", - "Full name" : "ຊື່ເຕັມ" + "Full name" : "ຊື່ເຕັມ", + "User disabled" : "ປິດຊື່ຜູ້ໃຊ້" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/lt_LT.js b/lib/l10n/lt_LT.js index 676a5bf51dc..4080a0895aa 100644 --- a/lib/l10n/lt_LT.js +++ b/lib/l10n/lt_LT.js @@ -5,6 +5,7 @@ OC.L10N.register( "See %s" : "Žiūrėkite %s", "Sample configuration detected" : "Aptiktas konfigūracijos pavyzdys", "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" : "Pastebėta, kad nukopijuota pavyzdinė konfigūracija. Tai gali pažeisti jūsų diegimą ir yra nepalaikoma. Prieš atliekant pakeitimus config.php faile, prašome perskaityti dokumentaciją.", + "The page could not be found on the server." : "Šio puslapio nepavyko rasti serveryje.", "Other activities" : "Kitos veiklos", "%1$s and %2$s" : "%1$s ir %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s ir %3$s", @@ -17,7 +18,6 @@ OC.L10N.register( "The library %s is not available." : "Biblioteka %s nėra prieinama.", "Server version %s or higher is required." : "Reikalinga %s arba aukštesnė serverio versija ", "Server version %s or lower is required." : "Reikalinga %s arba žemesnė serverio versija. ", - "Logged in user must be an admin" : "Prisijungęs naudotojas privalo būti administratoriumi", "Wiping of device %s has started" : "Įrenginio %s duomenų ištrynimas pradėtas", "Wiping of device »%s« has started" : "Įrenginio »%s« duomenų ištrynimas pradėtas", "»%s« started remote wipe" : "»%s« pradėjo nuotolinių duomenų ištrynimą", @@ -71,6 +71,7 @@ OC.L10N.register( "Appearance and accessibility" : "Išvaizda ir prieinamumas", "Apps" : "Programėlės", "Personal settings" : "Asmeniniai nustatymai", + "Administration settings" : "Administravimo nustatymai", "Settings" : "Nustatymai", "Log out" : "Atsijungti", "Users" : "Naudotojai", @@ -87,17 +88,12 @@ OC.L10N.register( "Headline" : "Antraštė", "Organisation" : "Organizacija", "Role" : "Vaidmuo", - "Unknown user" : "Nežinomas naudotojas", "Additional settings" : "Papildomi nustatymai", - "MySQL username and/or password not valid" : "Neteisingas MySQL naudotojo vardas ir/arba slaptažodis", "You need to enter details of an existing account." : "Jūs turite suvesti egzistuojančios paskyros duomenis.", "Oracle connection could not be established" : "Nepavyko užmegzti Oracle ryšio", - "Oracle username and/or password not valid" : "Neteisingas Oracle naudotojo vardas ir/arba slaptažodis", - "PostgreSQL username and/or password not valid" : "Neteisingas PostgreSQL naudotojo vardas ir/arba slaptažodis", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X nėra palaikomas, %s neveiks tinkamai šioje platformoje. Naudodami prisiimate visą riziką !", "For the best results, please consider using a GNU/Linux server instead." : "Geriausiems rezultatams, apsvarstykite galimybę, vietoj šio, naudoti GNU/Linux serverį", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Pašalinkite savo php.ini faile open_basedir nustatymą arba persijunkite į 64-bitų PHP.", - "Set an admin username." : "Nustatyti administratoriaus naudotojo vardą.", "Set an admin password." : "Nustatyti administratoriaus slaptažodį.", "%1$s shared »%2$s« with you and wants to add:" : "%1$s pasidalino „%2$s“ su jumis ir parašė pastabą:", "%1$s shared »%2$s« with you and wants to add" : "%1$s pasidalino „%2$s“ su jumis ir parašė pastabą", @@ -107,7 +103,6 @@ OC.L10N.register( "You are not allowed to share %s" : "Jums neleidžiama bendrinti %s", "Cannot increase permissions of %s" : "Negalima pridėti papildomų %s leidimų", "Expiration date is in the past" : "Bendrinimo pabaigos data yra praėjęs laikas", - "Sharing %s failed, because this item is already shared with user %s" : "%s bendrinimas nepavyko, kadangi šis elementas jau yra bendrinamas su naudotoju %s", "%1$s shared »%2$s« with you" : "%1$s pasidalino „%2$s“ su jumis", "%1$s shared »%2$s« with you." : "%1$s pasidalino „%2$s“ su jumis.", "Click the button below to open it." : "Norėdami atverti failą, spustelėkite mygtuką žemiau.", @@ -159,12 +154,6 @@ OC.L10N.register( "Nov." : "Lap.", "Dec." : "Grd.", "A valid password must be provided" : "Slaptažodis turi būti tinkamas", - "The username is already being used" : "Naudotojo vardas jau yra naudojamas", - "Could not create user" : "Nepavyko sukurti naudotojo", - "A valid username must be provided" : "Privalo būti pateiktas tinkamas naudotojo vardas", - "Username contains whitespace at the beginning or at the end" : "Naudotojo varde pradžioje ar pabaigoje yra tarpas", - "Username must not consist of dots only" : "Naudotojo vardas negali būti sudarytas tik iš taškų.", - "User disabled" : "Naudotojas išjungtas", "Login canceled by app" : "Programėlė nutraukė prisijungimo procesą", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Programėlė \"%1$s\" negali būti įdiegta, nes nėra patenkinamos šios priklausomybės: %2$s", "a safe home for all your data" : "saugūs namai visiems jūsų duomenims", @@ -179,7 +168,6 @@ OC.L10N.register( "Adjusting this setting in php.ini will make Nextcloud run again" : "Šių nustatymų pritaikymas php.ini faile, iš naujo paleis Nextcloud", "PHP modules have been installed, but they are still listed as missing?" : "PHP moduliai yra įdiegti, bet jų vis tiek trūksta?", "Please ask your server administrator to restart the web server." : "Kreipkitės į savo sistemos administratorių, kad jis perkrautų žiniatinklio serverį.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Pakeiskite leidimus į 0770, kad šis katalogas negalėtų būti išvardytas kitiems naudotojams.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Įsitikinkite, kad šakniniame duomenų kataloge yra failas, pavadinimu „.ocdata“.", "Action \"%s\" not supported or implemented." : "Veiksmas \"%s\" nepalaikomas ar neįgyvendintas.", "Authentication failed, wrong token or provider ID given" : "Tapatybės nustatymas nepavyko, nurodytas neteisingas prieigos raktas arba teikėjo ID", @@ -189,9 +177,22 @@ OC.L10N.register( "Storage connection error. %s" : "Saugyklos sujungimo ryšio klaida. %s", "Storage is temporarily not available" : "Saugykla yra laikinai neprieinama", "Storage connection timeout. %s" : "Sujungimo su saugykla laikas baigėsi. %s", + "Logged in user must be an admin" : "Prisijungęs naudotojas privalo būti administratoriumi", "Full name" : "Vardas, pavardė", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Naudotojo varde leidžiama naudoti tik šiuos simbolius: „a-z“, „A-Z“, „0-9“, ir „_.@-'“", + "Unknown user" : "Nežinomas naudotojas", + "MySQL username and/or password not valid" : "Neteisingas MySQL naudotojo vardas ir/arba slaptažodis", + "Oracle username and/or password not valid" : "Neteisingas Oracle naudotojo vardas ir/arba slaptažodis", + "PostgreSQL username and/or password not valid" : "Neteisingas PostgreSQL naudotojo vardas ir/arba slaptažodis", + "Set an admin username." : "Nustatyti administratoriaus naudotojo vardą.", + "Sharing %s failed, because this item is already shared with user %s" : "%s bendrinimas nepavyko, kadangi šis elementas jau yra bendrinamas su naudotoju %s", + "The username is already being used" : "Naudotojo vardas jau yra naudojamas", + "Could not create user" : "Nepavyko sukurti naudotojo", + "A valid username must be provided" : "Privalo būti pateiktas tinkamas naudotojo vardas", + "Username contains whitespace at the beginning or at the end" : "Naudotojo varde pradžioje ar pabaigoje yra tarpas", + "Username must not consist of dots only" : "Naudotojo vardas negali būti sudarytas tik iš taškų.", + "User disabled" : "Naudotojas išjungtas", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Reikalinga ne mažesnė nei libxml2 2.7.0 versija. Šiuo metu yra instaliuota %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Atnaujinkite libxml2 versiją ir perkraukite žiniatinklio serverį, kad sutvarkytumėte šią problemą." + "To fix this issue update your libxml2 version and restart your web server." : "Atnaujinkite libxml2 versiją ir perkraukite žiniatinklio serverį, kad sutvarkytumėte šią problemą.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Pakeiskite leidimus į 0770, kad šis katalogas negalėtų būti išvardytas kitiems naudotojams." }, "nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);"); diff --git a/lib/l10n/lt_LT.json b/lib/l10n/lt_LT.json index 0085d5d35fc..ab78ab9bd9f 100644 --- a/lib/l10n/lt_LT.json +++ b/lib/l10n/lt_LT.json @@ -3,6 +3,7 @@ "See %s" : "Žiūrėkite %s", "Sample configuration detected" : "Aptiktas konfigūracijos pavyzdys", "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" : "Pastebėta, kad nukopijuota pavyzdinė konfigūracija. Tai gali pažeisti jūsų diegimą ir yra nepalaikoma. Prieš atliekant pakeitimus config.php faile, prašome perskaityti dokumentaciją.", + "The page could not be found on the server." : "Šio puslapio nepavyko rasti serveryje.", "Other activities" : "Kitos veiklos", "%1$s and %2$s" : "%1$s ir %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s ir %3$s", @@ -15,7 +16,6 @@ "The library %s is not available." : "Biblioteka %s nėra prieinama.", "Server version %s or higher is required." : "Reikalinga %s arba aukštesnė serverio versija ", "Server version %s or lower is required." : "Reikalinga %s arba žemesnė serverio versija. ", - "Logged in user must be an admin" : "Prisijungęs naudotojas privalo būti administratoriumi", "Wiping of device %s has started" : "Įrenginio %s duomenų ištrynimas pradėtas", "Wiping of device »%s« has started" : "Įrenginio »%s« duomenų ištrynimas pradėtas", "»%s« started remote wipe" : "»%s« pradėjo nuotolinių duomenų ištrynimą", @@ -69,6 +69,7 @@ "Appearance and accessibility" : "Išvaizda ir prieinamumas", "Apps" : "Programėlės", "Personal settings" : "Asmeniniai nustatymai", + "Administration settings" : "Administravimo nustatymai", "Settings" : "Nustatymai", "Log out" : "Atsijungti", "Users" : "Naudotojai", @@ -85,17 +86,12 @@ "Headline" : "Antraštė", "Organisation" : "Organizacija", "Role" : "Vaidmuo", - "Unknown user" : "Nežinomas naudotojas", "Additional settings" : "Papildomi nustatymai", - "MySQL username and/or password not valid" : "Neteisingas MySQL naudotojo vardas ir/arba slaptažodis", "You need to enter details of an existing account." : "Jūs turite suvesti egzistuojančios paskyros duomenis.", "Oracle connection could not be established" : "Nepavyko užmegzti Oracle ryšio", - "Oracle username and/or password not valid" : "Neteisingas Oracle naudotojo vardas ir/arba slaptažodis", - "PostgreSQL username and/or password not valid" : "Neteisingas PostgreSQL naudotojo vardas ir/arba slaptažodis", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X nėra palaikomas, %s neveiks tinkamai šioje platformoje. Naudodami prisiimate visą riziką !", "For the best results, please consider using a GNU/Linux server instead." : "Geriausiems rezultatams, apsvarstykite galimybę, vietoj šio, naudoti GNU/Linux serverį", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Pašalinkite savo php.ini faile open_basedir nustatymą arba persijunkite į 64-bitų PHP.", - "Set an admin username." : "Nustatyti administratoriaus naudotojo vardą.", "Set an admin password." : "Nustatyti administratoriaus slaptažodį.", "%1$s shared »%2$s« with you and wants to add:" : "%1$s pasidalino „%2$s“ su jumis ir parašė pastabą:", "%1$s shared »%2$s« with you and wants to add" : "%1$s pasidalino „%2$s“ su jumis ir parašė pastabą", @@ -105,7 +101,6 @@ "You are not allowed to share %s" : "Jums neleidžiama bendrinti %s", "Cannot increase permissions of %s" : "Negalima pridėti papildomų %s leidimų", "Expiration date is in the past" : "Bendrinimo pabaigos data yra praėjęs laikas", - "Sharing %s failed, because this item is already shared with user %s" : "%s bendrinimas nepavyko, kadangi šis elementas jau yra bendrinamas su naudotoju %s", "%1$s shared »%2$s« with you" : "%1$s pasidalino „%2$s“ su jumis", "%1$s shared »%2$s« with you." : "%1$s pasidalino „%2$s“ su jumis.", "Click the button below to open it." : "Norėdami atverti failą, spustelėkite mygtuką žemiau.", @@ -157,12 +152,6 @@ "Nov." : "Lap.", "Dec." : "Grd.", "A valid password must be provided" : "Slaptažodis turi būti tinkamas", - "The username is already being used" : "Naudotojo vardas jau yra naudojamas", - "Could not create user" : "Nepavyko sukurti naudotojo", - "A valid username must be provided" : "Privalo būti pateiktas tinkamas naudotojo vardas", - "Username contains whitespace at the beginning or at the end" : "Naudotojo varde pradžioje ar pabaigoje yra tarpas", - "Username must not consist of dots only" : "Naudotojo vardas negali būti sudarytas tik iš taškų.", - "User disabled" : "Naudotojas išjungtas", "Login canceled by app" : "Programėlė nutraukė prisijungimo procesą", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Programėlė \"%1$s\" negali būti įdiegta, nes nėra patenkinamos šios priklausomybės: %2$s", "a safe home for all your data" : "saugūs namai visiems jūsų duomenims", @@ -177,7 +166,6 @@ "Adjusting this setting in php.ini will make Nextcloud run again" : "Šių nustatymų pritaikymas php.ini faile, iš naujo paleis Nextcloud", "PHP modules have been installed, but they are still listed as missing?" : "PHP moduliai yra įdiegti, bet jų vis tiek trūksta?", "Please ask your server administrator to restart the web server." : "Kreipkitės į savo sistemos administratorių, kad jis perkrautų žiniatinklio serverį.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Pakeiskite leidimus į 0770, kad šis katalogas negalėtų būti išvardytas kitiems naudotojams.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Įsitikinkite, kad šakniniame duomenų kataloge yra failas, pavadinimu „.ocdata“.", "Action \"%s\" not supported or implemented." : "Veiksmas \"%s\" nepalaikomas ar neįgyvendintas.", "Authentication failed, wrong token or provider ID given" : "Tapatybės nustatymas nepavyko, nurodytas neteisingas prieigos raktas arba teikėjo ID", @@ -187,9 +175,22 @@ "Storage connection error. %s" : "Saugyklos sujungimo ryšio klaida. %s", "Storage is temporarily not available" : "Saugykla yra laikinai neprieinama", "Storage connection timeout. %s" : "Sujungimo su saugykla laikas baigėsi. %s", + "Logged in user must be an admin" : "Prisijungęs naudotojas privalo būti administratoriumi", "Full name" : "Vardas, pavardė", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Naudotojo varde leidžiama naudoti tik šiuos simbolius: „a-z“, „A-Z“, „0-9“, ir „_.@-'“", + "Unknown user" : "Nežinomas naudotojas", + "MySQL username and/or password not valid" : "Neteisingas MySQL naudotojo vardas ir/arba slaptažodis", + "Oracle username and/or password not valid" : "Neteisingas Oracle naudotojo vardas ir/arba slaptažodis", + "PostgreSQL username and/or password not valid" : "Neteisingas PostgreSQL naudotojo vardas ir/arba slaptažodis", + "Set an admin username." : "Nustatyti administratoriaus naudotojo vardą.", + "Sharing %s failed, because this item is already shared with user %s" : "%s bendrinimas nepavyko, kadangi šis elementas jau yra bendrinamas su naudotoju %s", + "The username is already being used" : "Naudotojo vardas jau yra naudojamas", + "Could not create user" : "Nepavyko sukurti naudotojo", + "A valid username must be provided" : "Privalo būti pateiktas tinkamas naudotojo vardas", + "Username contains whitespace at the beginning or at the end" : "Naudotojo varde pradžioje ar pabaigoje yra tarpas", + "Username must not consist of dots only" : "Naudotojo vardas negali būti sudarytas tik iš taškų.", + "User disabled" : "Naudotojas išjungtas", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Reikalinga ne mažesnė nei libxml2 2.7.0 versija. Šiuo metu yra instaliuota %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Atnaujinkite libxml2 versiją ir perkraukite žiniatinklio serverį, kad sutvarkytumėte šią problemą." + "To fix this issue update your libxml2 version and restart your web server." : "Atnaujinkite libxml2 versiją ir perkraukite žiniatinklio serverį, kad sutvarkytumėte šią problemą.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Pakeiskite leidimus į 0770, kad šis katalogas negalėtų būti išvardytas kitiems naudotojams." },"pluralForm" :"nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);" }
\ No newline at end of file diff --git a/lib/l10n/lv.js b/lib/l10n/lv.js index a94b81c32bd..1f8b2e3cf21 100644 --- a/lib/l10n/lv.js +++ b/lib/l10n/lv.js @@ -5,7 +5,6 @@ OC.L10N.register( "See %s" : "Skatīt %s", "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", - "404" : "404", "%s email verification" : "%s e-pasta pārbaude", "Email verification" : "E-pasta pārbaude", "Click the following button to confirm your email." : "Noklikšķiniet uz šīs pogas, lai apstiprinātu savu e-pastu.", @@ -57,12 +56,8 @@ OC.L10N.register( "Address" : "Adrese", "Profile picture" : "Profila attēls", "About" : "Par", - "Unknown user" : "Nezināms lietotājs", "Additional settings" : "Papildu iestatījumi", "Oracle connection could not be established" : "Nevar izveidot savienojumu ar Oracle", - "Oracle username and/or password not valid" : "Nav derīga Oracle parole un/vai lietotājvārds", - "PostgreSQL username and/or password not valid" : "Nav derīga PostgreSQL parole un/vai lietotājvārds", - "Set an admin username." : "Iestatiet administratora lietotājvārdu.", "Set an admin password." : "Iestatiet administratora paroli.", "Open »%s«" : "Atvērt »%s«", "You are not allowed to share %s" : "Jums nav atļauts dalīties %s", @@ -113,9 +108,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Jānorāda derīga parole", - "The username is already being used" : "Šāds lietotājvārds jau tiek izmantots", - "A valid username must be provided" : "Jānorāda derīgs lietotājvārds", - "User disabled" : "Lietotājs deaktivizēts", "Login canceled by app" : "Pieteikšanos atcelā lietotne", "a safe home for all your data" : "droša vieta visiem jūsu datiem", "File is currently busy, please try again later" : "Datne pašlaik ir aizņemta. Lūdzu, vēlāk mēģiniet vēlreiz", @@ -132,6 +124,14 @@ OC.L10N.register( "Storage connection error. %s" : "Datu savienojuma kļūda. %s", "Storage is temporarily not available" : "Glabātuve īslaicīgi nav pieejama", "Storage connection timeout. %s" : "Datu savienojuma taimauts. %s", - "Full name" : "Pilns vārds" + "404" : "404", + "Full name" : "Pilns vārds", + "Unknown user" : "Nezināms lietotājs", + "Oracle username and/or password not valid" : "Nav derīga Oracle parole un/vai lietotājvārds", + "PostgreSQL username and/or password not valid" : "Nav derīga PostgreSQL parole un/vai lietotājvārds", + "Set an admin username." : "Iestatiet administratora lietotājvārdu.", + "The username is already being used" : "Šāds lietotājvārds jau tiek izmantots", + "A valid username must be provided" : "Jānorāda derīgs lietotājvārds", + "User disabled" : "Lietotājs deaktivizēts" }, "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"); diff --git a/lib/l10n/lv.json b/lib/l10n/lv.json index 8df04cbdcc1..60439c188dc 100644 --- a/lib/l10n/lv.json +++ b/lib/l10n/lv.json @@ -3,7 +3,6 @@ "See %s" : "Skatīt %s", "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", - "404" : "404", "%s email verification" : "%s e-pasta pārbaude", "Email verification" : "E-pasta pārbaude", "Click the following button to confirm your email." : "Noklikšķiniet uz šīs pogas, lai apstiprinātu savu e-pastu.", @@ -55,12 +54,8 @@ "Address" : "Adrese", "Profile picture" : "Profila attēls", "About" : "Par", - "Unknown user" : "Nezināms lietotājs", "Additional settings" : "Papildu iestatījumi", "Oracle connection could not be established" : "Nevar izveidot savienojumu ar Oracle", - "Oracle username and/or password not valid" : "Nav derīga Oracle parole un/vai lietotājvārds", - "PostgreSQL username and/or password not valid" : "Nav derīga PostgreSQL parole un/vai lietotājvārds", - "Set an admin username." : "Iestatiet administratora lietotājvārdu.", "Set an admin password." : "Iestatiet administratora paroli.", "Open »%s«" : "Atvērt »%s«", "You are not allowed to share %s" : "Jums nav atļauts dalīties %s", @@ -111,9 +106,6 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Jānorāda derīga parole", - "The username is already being used" : "Šāds lietotājvārds jau tiek izmantots", - "A valid username must be provided" : "Jānorāda derīgs lietotājvārds", - "User disabled" : "Lietotājs deaktivizēts", "Login canceled by app" : "Pieteikšanos atcelā lietotne", "a safe home for all your data" : "droša vieta visiem jūsu datiem", "File is currently busy, please try again later" : "Datne pašlaik ir aizņemta. Lūdzu, vēlāk mēģiniet vēlreiz", @@ -130,6 +122,14 @@ "Storage connection error. %s" : "Datu savienojuma kļūda. %s", "Storage is temporarily not available" : "Glabātuve īslaicīgi nav pieejama", "Storage connection timeout. %s" : "Datu savienojuma taimauts. %s", - "Full name" : "Pilns vārds" + "404" : "404", + "Full name" : "Pilns vārds", + "Unknown user" : "Nezināms lietotājs", + "Oracle username and/or password not valid" : "Nav derīga Oracle parole un/vai lietotājvārds", + "PostgreSQL username and/or password not valid" : "Nav derīga PostgreSQL parole un/vai lietotājvārds", + "Set an admin username." : "Iestatiet administratora lietotājvārdu.", + "The username is already being used" : "Šāds lietotājvārds jau tiek izmantots", + "A valid username must be provided" : "Jānorāda derīgs lietotājvārds", + "User disabled" : "Lietotājs deaktivizēts" },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);" }
\ No newline at end of file diff --git a/lib/l10n/mk.js b/lib/l10n/mk.js index bda43400d66..e284b1c7dc2 100644 --- a/lib/l10n/mk.js +++ b/lib/l10n/mk.js @@ -7,7 +7,6 @@ OC.L10N.register( "See %s" : "Види %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", - "404" : "404", "The page could not be found on the server." : "Страницата не е пронајдена на серверот.", "%s email verification" : "%s е-пошта верификација", "Email verification" : "Е-пошта верификација", @@ -36,9 +35,6 @@ 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 или помала на серверот.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Најавените корисници мора да бидат администратори, ко-администратори или да имаат специјални дозволи за да пристапат до овие поставки", - "Logged in user must be an admin or sub admin" : "Најавениот корисник мора да биде администратор или заменик администратор", - "Logged in user must be an admin" : "Најавениот корисник мора да биде администратор", "Wiping of device %s has started" : "Започна бришење на уредот %s", "Wiping of device »%s« has started" : "Започна бришење на уредот »%s«", "»%s« started remote wipe" : "Запошна далечинско бришење на уредот »%s«", @@ -65,8 +61,8 @@ OC.L10N.register( "_%n day ago_::_%n days ago_" : ["пред 1 ден","пред %n дена"], "next month" : "следниот месец", "last month" : "предходниот месец", - "_in %n month_::_in %n months_" : ["за 1 месец","за %n месеца"], - "_%n month ago_::_%n months ago_" : ["пред 1 месец","пред %n месеци"], + "_in %n month_::_in %n months_" : ["за %n месец","за %n месеца"], + "_%n month ago_::_%n months ago_" : ["пред %n месец","пред %n месеци"], "next year" : "следниот месец", "last year" : "предходната година", "_in %n year_::_in %n years_" : ["за 1 година","за %n години"], @@ -117,22 +113,15 @@ OC.L10N.register( "Headline" : "Наслов", "Organisation" : "Организација", "Role" : "Улога", - "Unknown user" : "Непознат корисник", "Additional settings" : "Дополнителни параметри", - "Enter the database username and name for %s" : "Внесете го корисничкото име и името на базата за %s", - "Enter the database username for %s" : "Внесете го корисничкото име на базата за %s", "Enter the database name for %s" : "Внесете го името на базата за %s", "You cannot use dots in the database name %s" : "Не можеш да користиш точки во името на базата %s", - "MySQL username and/or password not valid" : "Погрешно MySQL корисничко име и/или лозинка", "You need to enter details of an existing account." : "Потребно е да внесете детали од постоечката сметка.", "Oracle connection could not be established" : "Oracle врската неможе да се воспостави", - "Oracle username and/or password not valid" : "Oracle корисничкото име и/или лозинката не се валидни", - "PostgreSQL username 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 средина и open_basedir е конфигурано во php.ini. Ова ќе прави проблеми со датотеки поголеми од 4 GB.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Отстранете го параметарот open_basedir од php.ini или преминете на 64-битна PHP средина.", - "Set an admin username." : "Постави администраторско корисничко име", "Set an admin password." : "Постави администраторска лозинка.", "Cannot create or write into the data directory %s" : "Неможете да креирате или да запишувате во папката за податоци %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "За позадинското споделување %s мора се имплементира интерфејсот OCP\\Share_Backend", @@ -150,7 +139,6 @@ OC.L10N.register( "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_" : ["Неможе да се постави рок на траење повеќе од 1 ден","Неможе да се постави рок на траење повеќе од %s дена"], "Sharing is only allowed with group members" : "Споделувањето е овозможено само со членови на групата", - "Sharing %s failed, because this item is already shared with user %s" : "Споделувањето на %s е неуспешно, бидејќи истото веќе е споделено со корисникот %s", "%1$s shared »%2$s« with you" : "%1$s сподели »%2$s« со вас", "%1$s shared »%2$s« with you." : "%1$s сподели »%2$s« со вас.", "Click the button below to open it." : "Кликнете на копчето подолу за да ја отворите.", @@ -203,14 +191,6 @@ OC.L10N.register( "Nov." : "Ное.", "Dec." : "Дек.", "A valid password must be provided" : "Мора да се обезбеди валидна лозинка", - "The username is already being used" : "Корисничкото име е веќе во употреба", - "Could not create user" : "Неможе да се креира корисник", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Само следниве карактери се дозволени во корисничкото име: \"a-z\", \"A-Z\", \"0-9\", празно место и \"_.@-'\"", - "A valid username must be provided" : "Мора да се внесе валидно корисничко име ", - "Username contains whitespace at the beginning or at the end" : "Корисничкото име содржи празно место на почетокот или на крајот", - "Username must not consist of dots only" : "Корисничкото име не смее да се состои само од точки", - "Username is invalid because files already exist for this user" : "Невалидно корисничкото име бидејќи веќе постојат датотеки за овој корисник", - "User 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" : "безбеден дом за сите ваши податоци", @@ -243,8 +223,6 @@ OC.L10N.register( "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." : "Замолете го сервер администраторот да ја провери конфигурацијата.", - "Your data directory is readable by other users." : "Вашата папка со податоци може да се чита и од други корисници.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Поставете дозвола на папката 0770, за да неможе да се чита од други корисници.", "Your data directory must be an absolute path." : "Вашата папка со податоци мора да биде апсолутна патека.", "Check the value of \"datadirectory\" in your configuration." : "Проверете ја вредноста на \"datadirectory\" во вашата конфигурација.", "Your data directory is invalid." : "Вашата папка со податоци не е валидна.", @@ -260,13 +238,34 @@ OC.L10N.register( "Storage connection error. %s" : "Грешка во конекција до складиштето. %s", "Storage is temporarily not available" : "Складиштето моментално не е достапно", "Storage connection timeout. %s" : "Поврзувањето со складиштето не успеа. %s", + "Generate headline" : "Генерирај заглавие", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Датотеките од аоликацијата %1$s не се преклопени коректно. Проверете дали верзијата е компатибилна со серверот.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Најавените корисници мора да бидат администратори, ко-администратори или да имаат специјални дозволи за да пристапат до овие поставки", + "Logged in user must be an admin or sub admin" : "Најавениот корисник мора да биде администратор или заменик администратор", + "Logged in user must be an admin" : "Најавениот корисник мора да биде администратор", "Full name" : "Цело име", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Максималниот број на корисници е достигнат. Проверете ги вашите известувања за да дознаете повеќе.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Само следниве карактери се дозволени во корисничкото име:: \"a-z\", \"A-Z\", \"0-9\", и \"_.@-'\"", + "Unknown user" : "Непознат корисник", + "Enter the database username and name for %s" : "Внесете го корисничкото име и името на базата за %s", + "Enter the database username for %s" : "Внесете го корисничкото име на базата за %s", + "MySQL username and/or password not valid" : "Погрешно MySQL корисничко име и/или лозинка", + "Oracle username and/or password not valid" : "Oracle корисничкото име и/или лозинката не се валидни", + "PostgreSQL username and/or password not valid" : "PostgreSQL корисничкото име и/или лозинка не се валидни", + "Set an admin username." : "Постави администраторско корисничко име", + "Sharing %s failed, because this item is already shared with user %s" : "Споделувањето на %s е неуспешно, бидејќи истото веќе е споделено со корисникот %s", + "The username is already being used" : "Корисничкото име е веќе во употреба", + "Could not create user" : "Неможе да се креира корисник", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Само следниве карактери се дозволени во корисничкото име: \"a-z\", \"A-Z\", \"0-9\", празно место и \"_.@-'\"", + "A valid username must be provided" : "Мора да се внесе валидно корисничко име ", + "Username contains whitespace at the beginning or at the end" : "Корисничкото име содржи празно место на почетокот или на крајот", + "Username must not consist of dots only" : "Корисничкото име не смее да се состои само од точки", + "Username is invalid because files already exist for this user" : "Невалидно корисничкото име бидејќи веќе постојат датотеки за овој корисник", + "User disabled" : "Оневозможен корисник", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Потербна минимална верзија на libxml2 е 2.7.0. Моментална верзија е %s.", "To fix this issue update your libxml2 version and restart your web server." : "За да го поправите овој проблем, ажурирајте ја верзијата на libxml2 и рестартирајте го вашиот веб сервер.", "PostgreSQL >= 9 required." : "Потребно е PostgreSQL >= 9 ", - "Please upgrade your database version." : "Ве молиме надградете ја верзијата на базата со податоци" + "Please upgrade your database version." : "Ве молиме надградете ја верзијата на базата со податоци", + "Your data directory is readable by other users." : "Вашата папка со податоци може да се чита и од други корисници.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Поставете дозвола на папката 0770, за да неможе да се чита од други корисници." }, "nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"); diff --git a/lib/l10n/mk.json b/lib/l10n/mk.json index 3177350622d..46bcf32a604 100644 --- a/lib/l10n/mk.json +++ b/lib/l10n/mk.json @@ -5,7 +5,6 @@ "See %s" : "Види %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", - "404" : "404", "The page could not be found on the server." : "Страницата не е пронајдена на серверот.", "%s email verification" : "%s е-пошта верификација", "Email verification" : "Е-пошта верификација", @@ -34,9 +33,6 @@ "The following platforms are supported: %s" : "Следниве платформи се поддржани: %s", "Server version %s or higher is required." : "Потребна е верзија %s или поголема на серверот.", "Server version %s or lower is required." : "Потербна е верзија %s или помала на серверот.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Најавените корисници мора да бидат администратори, ко-администратори или да имаат специјални дозволи за да пристапат до овие поставки", - "Logged in user must be an admin or sub admin" : "Најавениот корисник мора да биде администратор или заменик администратор", - "Logged in user must be an admin" : "Најавениот корисник мора да биде администратор", "Wiping of device %s has started" : "Започна бришење на уредот %s", "Wiping of device »%s« has started" : "Започна бришење на уредот »%s«", "»%s« started remote wipe" : "Запошна далечинско бришење на уредот »%s«", @@ -63,8 +59,8 @@ "_%n day ago_::_%n days ago_" : ["пред 1 ден","пред %n дена"], "next month" : "следниот месец", "last month" : "предходниот месец", - "_in %n month_::_in %n months_" : ["за 1 месец","за %n месеца"], - "_%n month ago_::_%n months ago_" : ["пред 1 месец","пред %n месеци"], + "_in %n month_::_in %n months_" : ["за %n месец","за %n месеца"], + "_%n month ago_::_%n months ago_" : ["пред %n месец","пред %n месеци"], "next year" : "следниот месец", "last year" : "предходната година", "_in %n year_::_in %n years_" : ["за 1 година","за %n години"], @@ -115,22 +111,15 @@ "Headline" : "Наслов", "Organisation" : "Организација", "Role" : "Улога", - "Unknown user" : "Непознат корисник", "Additional settings" : "Дополнителни параметри", - "Enter the database username and name for %s" : "Внесете го корисничкото име и името на базата за %s", - "Enter the database username for %s" : "Внесете го корисничкото име на базата за %s", "Enter the database name for %s" : "Внесете го името на базата за %s", "You cannot use dots in the database name %s" : "Не можеш да користиш точки во името на базата %s", - "MySQL username and/or password not valid" : "Погрешно MySQL корисничко име и/или лозинка", "You need to enter details of an existing account." : "Потребно е да внесете детали од постоечката сметка.", "Oracle connection could not be established" : "Oracle врската неможе да се воспостави", - "Oracle username and/or password not valid" : "Oracle корисничкото име и/или лозинката не се валидни", - "PostgreSQL username 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 средина и open_basedir е конфигурано во php.ini. Ова ќе прави проблеми со датотеки поголеми од 4 GB.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Отстранете го параметарот open_basedir од php.ini или преминете на 64-битна PHP средина.", - "Set an admin username." : "Постави администраторско корисничко име", "Set an admin password." : "Постави администраторска лозинка.", "Cannot create or write into the data directory %s" : "Неможете да креирате или да запишувате во папката за податоци %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "За позадинското споделување %s мора се имплементира интерфејсот OCP\\Share_Backend", @@ -148,7 +137,6 @@ "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_" : ["Неможе да се постави рок на траење повеќе од 1 ден","Неможе да се постави рок на траење повеќе од %s дена"], "Sharing is only allowed with group members" : "Споделувањето е овозможено само со членови на групата", - "Sharing %s failed, because this item is already shared with user %s" : "Споделувањето на %s е неуспешно, бидејќи истото веќе е споделено со корисникот %s", "%1$s shared »%2$s« with you" : "%1$s сподели »%2$s« со вас", "%1$s shared »%2$s« with you." : "%1$s сподели »%2$s« со вас.", "Click the button below to open it." : "Кликнете на копчето подолу за да ја отворите.", @@ -201,14 +189,6 @@ "Nov." : "Ное.", "Dec." : "Дек.", "A valid password must be provided" : "Мора да се обезбеди валидна лозинка", - "The username is already being used" : "Корисничкото име е веќе во употреба", - "Could not create user" : "Неможе да се креира корисник", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Само следниве карактери се дозволени во корисничкото име: \"a-z\", \"A-Z\", \"0-9\", празно место и \"_.@-'\"", - "A valid username must be provided" : "Мора да се внесе валидно корисничко име ", - "Username contains whitespace at the beginning or at the end" : "Корисничкото име содржи празно место на почетокот или на крајот", - "Username must not consist of dots only" : "Корисничкото име не смее да се состои само од точки", - "Username is invalid because files already exist for this user" : "Невалидно корисничкото име бидејќи веќе постојат датотеки за овој корисник", - "User 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" : "безбеден дом за сите ваши податоци", @@ -241,8 +221,6 @@ "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." : "Замолете го сервер администраторот да ја провери конфигурацијата.", - "Your data directory is readable by other users." : "Вашата папка со податоци може да се чита и од други корисници.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Поставете дозвола на папката 0770, за да неможе да се чита од други корисници.", "Your data directory must be an absolute path." : "Вашата папка со податоци мора да биде апсолутна патека.", "Check the value of \"datadirectory\" in your configuration." : "Проверете ја вредноста на \"datadirectory\" во вашата конфигурација.", "Your data directory is invalid." : "Вашата папка со податоци не е валидна.", @@ -258,13 +236,34 @@ "Storage connection error. %s" : "Грешка во конекција до складиштето. %s", "Storage is temporarily not available" : "Складиштето моментално не е достапно", "Storage connection timeout. %s" : "Поврзувањето со складиштето не успеа. %s", + "Generate headline" : "Генерирај заглавие", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Датотеките од аоликацијата %1$s не се преклопени коректно. Проверете дали верзијата е компатибилна со серверот.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Најавените корисници мора да бидат администратори, ко-администратори или да имаат специјални дозволи за да пристапат до овие поставки", + "Logged in user must be an admin or sub admin" : "Најавениот корисник мора да биде администратор или заменик администратор", + "Logged in user must be an admin" : "Најавениот корисник мора да биде администратор", "Full name" : "Цело име", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Максималниот број на корисници е достигнат. Проверете ги вашите известувања за да дознаете повеќе.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Само следниве карактери се дозволени во корисничкото име:: \"a-z\", \"A-Z\", \"0-9\", и \"_.@-'\"", + "Unknown user" : "Непознат корисник", + "Enter the database username and name for %s" : "Внесете го корисничкото име и името на базата за %s", + "Enter the database username for %s" : "Внесете го корисничкото име на базата за %s", + "MySQL username and/or password not valid" : "Погрешно MySQL корисничко име и/или лозинка", + "Oracle username and/or password not valid" : "Oracle корисничкото име и/или лозинката не се валидни", + "PostgreSQL username and/or password not valid" : "PostgreSQL корисничкото име и/или лозинка не се валидни", + "Set an admin username." : "Постави администраторско корисничко име", + "Sharing %s failed, because this item is already shared with user %s" : "Споделувањето на %s е неуспешно, бидејќи истото веќе е споделено со корисникот %s", + "The username is already being used" : "Корисничкото име е веќе во употреба", + "Could not create user" : "Неможе да се креира корисник", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Само следниве карактери се дозволени во корисничкото име: \"a-z\", \"A-Z\", \"0-9\", празно место и \"_.@-'\"", + "A valid username must be provided" : "Мора да се внесе валидно корисничко име ", + "Username contains whitespace at the beginning or at the end" : "Корисничкото име содржи празно место на почетокот или на крајот", + "Username must not consist of dots only" : "Корисничкото име не смее да се состои само од точки", + "Username is invalid because files already exist for this user" : "Невалидно корисничкото име бидејќи веќе постојат датотеки за овој корисник", + "User disabled" : "Оневозможен корисник", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Потербна минимална верзија на libxml2 е 2.7.0. Моментална верзија е %s.", "To fix this issue update your libxml2 version and restart your web server." : "За да го поправите овој проблем, ажурирајте ја верзијата на libxml2 и рестартирајте го вашиот веб сервер.", "PostgreSQL >= 9 required." : "Потребно е PostgreSQL >= 9 ", - "Please upgrade your database version." : "Ве молиме надградете ја верзијата на базата со податоци" + "Please upgrade your database version." : "Ве молиме надградете ја верзијата на базата со податоци", + "Your data directory is readable by other users." : "Вашата папка со податоци може да се чита и од други корисници.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Поставете дозвола на папката 0770, за да неможе да се чита од други корисници." },"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;" }
\ No newline at end of file diff --git a/lib/l10n/mn.js b/lib/l10n/mn.js index a705374d0ac..61156577126 100644 --- a/lib/l10n/mn.js +++ b/lib/l10n/mn.js @@ -28,7 +28,6 @@ OC.L10N.register( "Address" : "хаяг", "Profile picture" : "Профайл зураг", "About" : "Тухай", - "Unknown user" : "Тодорхойгүй хэрэглэгч", "Open »%s«" : "»%s« нээх", "Sunday" : "ням гариг", "Monday" : "даваа", @@ -42,6 +41,7 @@ OC.L10N.register( "a safe home for all your data" : "Таны өгөгдлүүдийн аюулгүй гэр", "Authentication error" : "Нотолгооны алдаа", "Storage is temporarily not available" : "Хадгалах төхөөрөмж нь түр хугацаанд ашиглах боломжгүй байна", - "Full name" : "бүтэн нэр" + "Full name" : "бүтэн нэр", + "Unknown user" : "Тодорхойгүй хэрэглэгч" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/mn.json b/lib/l10n/mn.json index a684de4999f..e6bde595766 100644 --- a/lib/l10n/mn.json +++ b/lib/l10n/mn.json @@ -26,7 +26,6 @@ "Address" : "хаяг", "Profile picture" : "Профайл зураг", "About" : "Тухай", - "Unknown user" : "Тодорхойгүй хэрэглэгч", "Open »%s«" : "»%s« нээх", "Sunday" : "ням гариг", "Monday" : "даваа", @@ -40,6 +39,7 @@ "a safe home for all your data" : "Таны өгөгдлүүдийн аюулгүй гэр", "Authentication error" : "Нотолгооны алдаа", "Storage is temporarily not available" : "Хадгалах төхөөрөмж нь түр хугацаанд ашиглах боломжгүй байна", - "Full name" : "бүтэн нэр" + "Full name" : "бүтэн нэр", + "Unknown user" : "Тодорхойгүй хэрэглэгч" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/nb.js b/lib/l10n/nb.js index 23651c77213..87b9a9162f4 100644 --- a/lib/l10n/nb.js +++ b/lib/l10n/nb.js @@ -2,10 +2,12 @@ OC.L10N.register( "lib", { "Cannot write into \"config\" directory!" : "Kan ikke skrive til «config»-mappen!", + "This can usually be fixed by giving the web server write access to the config directory." : "Dette kan vanligvis løses ved å gi webserveren skrivetilgang til config-katalogen.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Men hvis du foretrekker å holde config.php filen skrivebeskyttet, angir du alternativet \"config_is_read_only\" til sant i den.", "See %s" : "Se %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Applikasjon %1$s er ikke til stede eller har en ikke-kompatibel versjon med denne serveren. Vennligst undersøk apps-katalogen.", "Sample configuration detected" : "Eksempeloppsett oppdaget", "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" : "Det ble oppdaget at eksempeloppsettet er blitt kopiert. Dette kan ødelegge installasjonen din og støttes ikke. Les dokumentasjonen før du gjør endringer i config.php", - "404" : "404", "The page could not be found on the server." : "Siden ble ikke funnet på serveren.", "%s email verification" : "%s e-postbekreftelse", "Email verification" : "E-postbekreftelse", @@ -20,21 +22,43 @@ OC.L10N.register( "Education Edition" : "Utdanningsversjon", "Enterprise bundle" : "Bedrifts-pakke", "Groupware bundle" : "Gruppevare-pakke", + "Hub bundle" : "Hub-pakke", + "Public sector bundle" : "Pakke for offentlig sektor", "Social sharing bundle" : "Sosialdelings-pakke", "PHP %s or higher is required." : "PHP %s eller nyere kreves.", "PHP with a version lower than %s is required." : "PHP med en versjon lavere enn %s kreves.", "%sbit or higher PHP required." : "%sbit eller høyere PHP kreves", + "The following architectures are supported: %s" : "Følgende arkitekturer støttes: %s.", + "The following databases are supported: %s" : "Følgende databaser støttes: %s.", "The command line tool %s could not be found" : "Kommandolinjeverktøyet %s ble ikke funnet", "The library %s is not available." : "Biblioteket %s er ikke tilgjengelig.", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Bibliotek %1$s med en versjon høyere enn %2$s kreves - tilgjengelig versjon %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Bibliotek %1$s med en versjon lavere enn %2$s kreves - tilgjengelig versjon %3$s.", + "The following platforms are supported: %s" : "Følgende plattformer støttes: %s.", "Server version %s or higher is required." : "Serverversjon %s eller høyere kreves.", "Server version %s or lower is required." : "Serverversjon %s eller lavere kreves.", - "Logged in user must be an admin" : "Innlogget bruker må være administrator", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Innlogget konto må være administrator, underadministrator eller ha fått spesiell rett til å få tilgang til denne innstillingen.", + "Logged in account must be an admin or sub admin" : "Innlogget konto må være administrator eller en underadministrator.", + "Logged in account must be an admin" : "Innlogget konto må være administrator", + "Wiping of device %s has started" : "Sikker sletting av enhet %s er startet", + "Wiping of device »%s« has started" : "Sikker sletting av enhet \"%s\" er startet", + "»%s« started remote wipe" : "\"%s\" startet sikker fjernsletting", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "Enhet eller applikasjon »%s« har startet den eksterne og sikre slettingsprosessen. Du vil motta en ny e-post når prosessen er fullført.", + "Wiping of device %s has finished" : "Sikker sletting av enhet %s er ferdig", + "Wiping of device »%s« has finished" : "Sikker sletting av enhet \"%s\" er ferdig", + "»%s« finished remote wipe" : "\"%s\" fullførte sikker fjernsletting", + "Device or application »%s« has finished the remote wipe process." : "Enhet eller applikasjon \"%s\" er ferdig med den eksterne og sikre slettingsprosessen.", + "Remote wipe started" : "Fjernsletting startet", + "A remote wipe was started on device %s" : "En fjernsletting ble startet på enhet %s", + "Remote wipe finished" : "Fjernsletting ferdig", + "The remote wipe on %s has finished" : "Fjernslettingen på %s er ferdig", "Authentication" : "Autentisering", "Unknown filetype" : "Ukjent filtype", "Invalid image" : "Ugyldig bilde", "Avatar image is not square" : "Avatarbilde er ikke firkantet", "Files" : "Filer", "View profile" : "Vis profil", + "Local time: %s" : "Lokal tid: %s", "today" : "i dag", "tomorrow" : "I morgen", "yesterday" : "i går", @@ -58,6 +82,7 @@ OC.L10N.register( "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Modul med ID: %s finnes ikke. Skru den på i app-innstillingene eller kontakt en administrator.", "File already exists" : "Filen finnes allerede", "Invalid path" : "Ugyldig filbane", + "Failed to create file from template" : "Oppretting av fil fra mal feilet", "Templates" : "Maler", "File name is a reserved word" : "Filnavnet er et reservert ord", "File name contains at least one invalid character" : "Filnavnet inneholder minst ett ulovlig tegn", @@ -78,6 +103,8 @@ OC.L10N.register( "Users" : "Brukere", "Email" : "E-post", "Mail %s" : "E-post til %s", + "Fediverse" : "Fediverse", + "View %s on the fediverse" : "Se %s på fediverse", "Phone" : "Telefon", "Call %s" : "Ring %s", "Twitter" : "Twitter", @@ -87,21 +114,28 @@ OC.L10N.register( "Address" : "Adresse", "Profile picture" : "Profilbilde", "About" : "Om", + "Display name" : "Visningsnavn", "Headline" : "Overskrift", "Organisation" : "Organisasion", "Role" : "Rolle", - "Unknown user" : "Ukjent bruker", + "Unknown account" : "Ukjent konto", "Additional settings" : "Flere innstillinger", + "Enter the database Login and name for %s" : "Skriv inn databasens pålogging og navn for %s", + "Enter the database Login for %s" : "Skriv inn databasens pålogging for %s", + "Enter the database name for %s" : "Skriv inn databasens navn for %s", + "You cannot use dots in the database name %s" : "Du kan ikke bruke punktum i databasenavnet %s", + "MySQL Login and/or password not valid" : "MySQL-pålogging og/eller passord ikke gyldig", "You need to enter details of an existing account." : "Du må legge in detaljene til en eksisterende konto.", "Oracle connection could not be established" : "Klarte ikke å etablere forbindelse til Oracle", - "Oracle username and/or password not valid" : "Oracle-brukernavn og/eller passord er ikke gyldig", - "PostgreSQL username and/or password not valid" : "PostgreSQL-brukernavn og/eller passord er ikke gyldig", + "Oracle Login and/or password not valid" : "Oracle-pålogging og/eller passord ikke gyldig", + "PostgreSQL Login and/or password not valid" : "PostgreSQL-pålogging og/eller passord ikke gyldig", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X støttes ikke og %s vil ikke fungere korrekt på denne plattformen. Bruk på egen risiko!", "For the best results, please consider using a GNU/Linux server instead." : "For beste resultat, vurder å bruke en GNU/Linux-server i stedet.", "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." : "Det ser ut for at %s-instansen kjører i et 32-bit PHP-miljø med open_basedir satt opp i php.ini. Dette vil føre til problemer med filer over 4 GB og frarådes på det sterkeste.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Fjern innstillingen open_basedir i php.ini eller bytt til 64-bit PHP.", - "Set an admin username." : "Sett et admin-brukernavn.", + "Set an admin Login." : "Angi en admin-pålogging.", "Set an admin password." : "Sett et admin-passord.", + "Cannot create or write into the data directory %s" : "Kan ikke opprette eller skrive i datakatalogen %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Delings-server %s må implementere grensesnittet OCP\\Share_Backend", "Sharing backend %s not found" : "Delings-server %s ikke funnet", "Sharing backend for %s not found" : "Delings-server for %s ikke funnet", @@ -112,12 +146,18 @@ OC.L10N.register( "%1$s via %2$s" : "%1$s via %2$s", "You are not allowed to share %s" : "Du har ikke lov til å dele %s", "Cannot increase permissions of %s" : "Kan ikke øke tillatelser for %s", + "Files cannot be shared with delete permissions" : "Filer kan ikke deles med slett-rettigheter", + "Files cannot be shared with create permissions" : "Filer kan ikke deles med opprettingstillatelser", "Expiration date is in the past" : "Utløpsdato er i fortid", - "Sharing %s failed, because this item is already shared with user %s" : "Deling av %s mislyktes, fordi dette elementet allerede er delt med bruker %s", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Kan ikke sette utløpsdato mer enn %n dag i fremtiden","Kan ikke sette utløpsdato mer enn %n dager i fremtiden"], + "Sharing is only allowed with group members" : "Deling er kun tillatt med gruppemedlemmer", + "Sharing %s failed, because this item is already shared with the account %s" : "Deling av %s feilet, fordi dette elementet er allerede delt med kontoen %s", "%1$s shared »%2$s« with you" : "%1$s delte »%2$s« med deg", "%1$s shared »%2$s« with you." : "%1$s delte »%2$s« med deg.", "Click the button below to open it." : "Klikk på knappen nedenfor for å åpne den.", "The requested share does not exist anymore" : "Forespurt ressurs finnes ikke lenger", + "The requested share comes from a disabled user" : "Den forespurte delingen kommer fra en deaktivert bruker", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Brukeren ble ikke opprettet fordi brukergrensen er nådd. Sjekk varslene dine for å finne ut mer.", "Could not find category \"%s\"" : "Kunne ikke finne kategori \"%s\"", "Sunday" : "Søndag", "Monday" : "Mandag", @@ -165,13 +205,16 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Des.", "A valid password must be provided" : "Oppgi et gyldig passord", - "The username is already being used" : "Brukernavnet er allerede i bruk", - "Could not create user" : "Kunne ikke opprette bruker", - "A valid username must be provided" : "Oppgi et gyldig brukernavn", - "Username contains whitespace at the beginning or at the end" : "Brukernavn inneholder blanke på begynnelsen eller slutten", - "Username must not consist of dots only" : "Brukernavn kan ikke bare bestå av punktum", - "User disabled" : "Brukeren er deaktivert", + "The Login is already being used" : "Påloggingen er allerede i bruk", + "Could not create account" : "Kunne ikke opprette konto", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kun følgende tegn er tillatt i en pålogging: \"a-z\", \"A-Z\", \"0-9\", mellomrom og \"_.@-'\"", + "A valid Login must be provided" : "En gyldig pålogging må angis", + "Login contains whitespace at the beginning or at the end" : "Pålogging inneholder mellomrom i begynnelsen eller på slutten", + "Login must not consist of dots only" : "Pålogging kan ikke bare bestå av punktum", + "Login is invalid because files already exist for this user" : "Påloggingen er ugyldig fordi det finnes allerede filer for denne brukeren.", + "Account disabled" : "Konto deaktivert", "Login canceled by app" : "Innlogging avbrutt av app", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "App \"%1$s\" kan ikke installeres fordi følgende avhengigheter ikke er møtt: %2$s.", "a safe home for all your data" : "et sikkert hjem for alle dine data", "File is currently busy, please try again later" : "Filen er opptatt for øyeblikket, prøv igjen senere", "Cannot download file" : "Kan ikke laste ned fil", @@ -179,25 +222,81 @@ OC.L10N.register( "Authentication error" : "Autentikasjonsfeil", "Token expired. Please reload page." : "Symbol utløpt. Last inn siden på nytt.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Ingen databasedrivere (sqlite, mysql, or postgresql) installert.", + "Cannot write into \"config\" directory." : "Kan ikke skrive i \"config\"-katalogen.", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Dette kan vanligvis ordnes ved å gi webserveren skrivetilgang til config-katalogen. Se %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" : "Men hvis du foretrekker å holde config.php filen skrivebeskyttet, angir du alternativet \"config_is_read_only\" til sant i den. Se %s.", + "Cannot write into \"apps\" directory." : "Kan ikke skrive i \"apps\"-katalogen.", + "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." : "Dette kan vanligvis løses ved å gi webserveren skrivetilgang til apps-katalogen eller deaktivere App Store i konfigurasjonsfilen.", + "Cannot create \"data\" directory." : "Kan ikke opprette \"data\"-katalogen.", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Dette kan vanligvis ordnes ved å gi webserveren skrivetilgang til rotkatalogen. Se %s.", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Tillatelser kan vanligvis ordnes ved å gi webserveren skrivetilgang til rotkatalogen. Se %s.", + "Your data directory is not writable." : "Datakatalogen kan ikke skrives til.", + "Setting locale to %s failed." : "Innstilling av nasjonal innstilling til %s feilet.", + "Please install one of these locales on your system and restart your web server." : "Installer en av disse nasjonale innstillingene på systemet ditt, og start webserveren på nytt.", "PHP module %s not installed." : "PHP-modul %s er ikke installert.", "Please ask your server administrator to install the module." : "Be server-administratoren om å installere modulen.", "PHP setting \"%s\" is not set to \"%s\"." : "PHP-innstilling \"%s\" er ikke satt til \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ved å endre denne innstillingen i php.ini gjør at Nextcloud vil kjøre igjen.", + "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> er satt til <code>%s</code> istedenfor den forventede verdien <code>0</code>.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "For å fikse dette problemet sett <code>mbstring.func_overload</code> til <code>0</code> i php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Det ser ut til at at PHP er satt opp til å fjerne innebygde doc-blokker. Dette gjør at flere av kjerneapplikasjonene blir utilgjengelige.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Dette forårsakes sannsynligvis av hurtiglager/akselerator, som f.eks. Zend OPcache eller eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "PHP-moduler har blitt installert, men de listes fortsatt som fraværende?", "Please ask your server administrator to restart the web server." : "Be server-administratoren om å starte webserveren på nytt.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endre tillatelsene til 0770 slik at mappen ikke kan listes av andre brukere.", + "The required %s config variable is not configured in the config.php file." : "Den nødvendige %s konfigurasjonsvariabelen er ikke konfigurert i config.php-filen.", + "Please ask your server administrator to check the Nextcloud configuration." : "Be serveradministratoren din om å sjekke Nextcloud-konfigurasjonen.", + "Your data directory is readable by other people." : "Datakatalogen din er lesbar for andre personer.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Endre tillatelsene til 0770 slik at katalogen ikke kan listes av andre personer.", + "Your data directory must be an absolute path." : "Datakatalogen din må være en absolutt sti.", + "Check the value of \"datadirectory\" in your configuration." : "Sjekk verdien for \"datadirectory\" i konfigurasjonen din.", + "Your data directory is invalid." : "Datakatalogen din er ugyldig.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Forsikre deg om at det finnes ei fil kalt \".ocdata\" på rota av datamappa.", + "Action \"%s\" not supported or implemented." : "Handling \"%s\" ikke støttet eller implementert.", + "Authentication failed, wrong token or provider ID given" : "Autentisering feilet, feil token eller leverandør-ID gitt", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Parametere mangler for å fullføre forespørselen. Manglende parametere: \"%s\".", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "ID \"%1$s\" allerede brukt av cloud federation-leverandør \"%2$s\".", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "Cloud Federation-leverandør med ID: \"%s\" finnes ikke.", "Could not obtain lock type %d on \"%s\"." : "Klarte ikke å låse med type %d på \"%s\".", "Storage unauthorized. %s" : "Lager uautorisert: %s", "Storage incomplete configuration. %s" : "Ikke komplett oppsett for lager. %s", "Storage connection error. %s" : "Tilkoblingsfeil for lager. %s", "Storage is temporarily not available" : "Lagring er midlertidig utilgjengelig", "Storage connection timeout. %s" : "Tidsavbrudd ved tilkobling av lager: %s", + "Free prompt" : "Ledig ledetekst", + "Runs an arbitrary prompt through the language model." : "Kjører en vilkårlig ledetekst gjennom språkmodellen.", + "Generate headline" : "Generer overskrift", + "Generates a possible headline for a text." : "Genererer en mulig overskrift for en tekst.", + "Summarize" : "Oppsummere", + "Summarizes text by reducing its length without losing key information." : "Oppsummerer tekst ved å redusere lengden uten å miste nøkkelinformasjon.", + "Extract topics" : "Trekk ut emner", + "Extracts topics from a text and outputs them separated by commas." : "Trekker ut emner fra en tekst og sender dem ut atskilt med komma.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Filene i appen %1$s ble ikke erstattet på riktig måte. Forsikre deg om at det er en versjon som er kompatibel med serveren.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Innlogget bruker må være administrator, underadministrator eller ha fått spesiell rett til å få tilgang til denne innstillingen.", + "Logged in user must be an admin or sub admin" : "Innlogget bruker må være administrator eller en underadministrator.", + "Logged in user must be an admin" : "Innlogget bruker må være administrator", "Full name" : "Fullt navn", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Bare disse tegnene tillates i et brukernavn: \"a-z\", \"A-Z\", \"0-9\" og \"_.@-'\"", + "Unknown user" : "Ukjent bruker", + "Enter the database username and name for %s" : "Skriv inn databasens brukernavn og navn for %s", + "Enter the database username for %s" : "Skriv inn databasens brukernavn for %s", + "MySQL username and/or password not valid" : "MySQL-brukernavn og/eller passord ikke gyldig", + "Oracle username and/or password not valid" : "Oracle-brukernavn og/eller passord er ikke gyldig", + "PostgreSQL username and/or password not valid" : "PostgreSQL-brukernavn og/eller passord er ikke gyldig", + "Set an admin username." : "Sett et admin-brukernavn.", + "Sharing %s failed, because this item is already shared with user %s" : "Deling av %s mislyktes, fordi dette elementet allerede er delt med bruker %s", + "The username is already being used" : "Brukernavnet er allerede i bruk", + "Could not create user" : "Kunne ikke opprette bruker", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kun følgende tegn er tillatt i et brukernavn: \"a-z\", \"A-Z\", \"0-9\", mellomrom og \"_.@-'\"", + "A valid username must be provided" : "Oppgi et gyldig brukernavn", + "Username contains whitespace at the beginning or at the end" : "Brukernavn inneholder blanke på begynnelsen eller slutten", + "Username must not consist of dots only" : "Brukernavn kan ikke bare bestå av punktum", + "Username is invalid because files already exist for this user" : "Brukernavnet er ugyldig fordi det finnes allerede filer for denne brukeren.", + "User disabled" : "Brukeren er deaktivert", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Krever minst libxml2 2.7.0. Per nå er %s installert.", - "To fix this issue update your libxml2 version and restart your web server." : "For å fikse dette problemet, oppdater din libxml2 versjon og start webserveren på nytt." + "To fix this issue update your libxml2 version and restart your web server." : "For å fikse dette problemet, oppdater din libxml2 versjon og start webserveren på nytt.", + "PostgreSQL >= 9 required." : "PostgreSQL >= 9 kreves.", + "Please upgrade your database version." : "Oppgrader databaseversjonen din.", + "Your data directory is readable by other users." : "Datakatalogen din kan leses av andre brukere.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endre tillatelsene til 0770 slik at mappen ikke kan listes av andre brukere." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/nb.json b/lib/l10n/nb.json index 32b5ae98957..cdf14b5a3db 100644 --- a/lib/l10n/nb.json +++ b/lib/l10n/nb.json @@ -1,9 +1,11 @@ { "translations": { "Cannot write into \"config\" directory!" : "Kan ikke skrive til «config»-mappen!", + "This can usually be fixed by giving the web server write access to the config directory." : "Dette kan vanligvis løses ved å gi webserveren skrivetilgang til config-katalogen.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Men hvis du foretrekker å holde config.php filen skrivebeskyttet, angir du alternativet \"config_is_read_only\" til sant i den.", "See %s" : "Se %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Applikasjon %1$s er ikke til stede eller har en ikke-kompatibel versjon med denne serveren. Vennligst undersøk apps-katalogen.", "Sample configuration detected" : "Eksempeloppsett oppdaget", "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" : "Det ble oppdaget at eksempeloppsettet er blitt kopiert. Dette kan ødelegge installasjonen din og støttes ikke. Les dokumentasjonen før du gjør endringer i config.php", - "404" : "404", "The page could not be found on the server." : "Siden ble ikke funnet på serveren.", "%s email verification" : "%s e-postbekreftelse", "Email verification" : "E-postbekreftelse", @@ -18,21 +20,43 @@ "Education Edition" : "Utdanningsversjon", "Enterprise bundle" : "Bedrifts-pakke", "Groupware bundle" : "Gruppevare-pakke", + "Hub bundle" : "Hub-pakke", + "Public sector bundle" : "Pakke for offentlig sektor", "Social sharing bundle" : "Sosialdelings-pakke", "PHP %s or higher is required." : "PHP %s eller nyere kreves.", "PHP with a version lower than %s is required." : "PHP med en versjon lavere enn %s kreves.", "%sbit or higher PHP required." : "%sbit eller høyere PHP kreves", + "The following architectures are supported: %s" : "Følgende arkitekturer støttes: %s.", + "The following databases are supported: %s" : "Følgende databaser støttes: %s.", "The command line tool %s could not be found" : "Kommandolinjeverktøyet %s ble ikke funnet", "The library %s is not available." : "Biblioteket %s er ikke tilgjengelig.", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Bibliotek %1$s med en versjon høyere enn %2$s kreves - tilgjengelig versjon %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Bibliotek %1$s med en versjon lavere enn %2$s kreves - tilgjengelig versjon %3$s.", + "The following platforms are supported: %s" : "Følgende plattformer støttes: %s.", "Server version %s or higher is required." : "Serverversjon %s eller høyere kreves.", "Server version %s or lower is required." : "Serverversjon %s eller lavere kreves.", - "Logged in user must be an admin" : "Innlogget bruker må være administrator", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Innlogget konto må være administrator, underadministrator eller ha fått spesiell rett til å få tilgang til denne innstillingen.", + "Logged in account must be an admin or sub admin" : "Innlogget konto må være administrator eller en underadministrator.", + "Logged in account must be an admin" : "Innlogget konto må være administrator", + "Wiping of device %s has started" : "Sikker sletting av enhet %s er startet", + "Wiping of device »%s« has started" : "Sikker sletting av enhet \"%s\" er startet", + "»%s« started remote wipe" : "\"%s\" startet sikker fjernsletting", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "Enhet eller applikasjon »%s« har startet den eksterne og sikre slettingsprosessen. Du vil motta en ny e-post når prosessen er fullført.", + "Wiping of device %s has finished" : "Sikker sletting av enhet %s er ferdig", + "Wiping of device »%s« has finished" : "Sikker sletting av enhet \"%s\" er ferdig", + "»%s« finished remote wipe" : "\"%s\" fullførte sikker fjernsletting", + "Device or application »%s« has finished the remote wipe process." : "Enhet eller applikasjon \"%s\" er ferdig med den eksterne og sikre slettingsprosessen.", + "Remote wipe started" : "Fjernsletting startet", + "A remote wipe was started on device %s" : "En fjernsletting ble startet på enhet %s", + "Remote wipe finished" : "Fjernsletting ferdig", + "The remote wipe on %s has finished" : "Fjernslettingen på %s er ferdig", "Authentication" : "Autentisering", "Unknown filetype" : "Ukjent filtype", "Invalid image" : "Ugyldig bilde", "Avatar image is not square" : "Avatarbilde er ikke firkantet", "Files" : "Filer", "View profile" : "Vis profil", + "Local time: %s" : "Lokal tid: %s", "today" : "i dag", "tomorrow" : "I morgen", "yesterday" : "i går", @@ -56,6 +80,7 @@ "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Modul med ID: %s finnes ikke. Skru den på i app-innstillingene eller kontakt en administrator.", "File already exists" : "Filen finnes allerede", "Invalid path" : "Ugyldig filbane", + "Failed to create file from template" : "Oppretting av fil fra mal feilet", "Templates" : "Maler", "File name is a reserved word" : "Filnavnet er et reservert ord", "File name contains at least one invalid character" : "Filnavnet inneholder minst ett ulovlig tegn", @@ -76,6 +101,8 @@ "Users" : "Brukere", "Email" : "E-post", "Mail %s" : "E-post til %s", + "Fediverse" : "Fediverse", + "View %s on the fediverse" : "Se %s på fediverse", "Phone" : "Telefon", "Call %s" : "Ring %s", "Twitter" : "Twitter", @@ -85,21 +112,28 @@ "Address" : "Adresse", "Profile picture" : "Profilbilde", "About" : "Om", + "Display name" : "Visningsnavn", "Headline" : "Overskrift", "Organisation" : "Organisasion", "Role" : "Rolle", - "Unknown user" : "Ukjent bruker", + "Unknown account" : "Ukjent konto", "Additional settings" : "Flere innstillinger", + "Enter the database Login and name for %s" : "Skriv inn databasens pålogging og navn for %s", + "Enter the database Login for %s" : "Skriv inn databasens pålogging for %s", + "Enter the database name for %s" : "Skriv inn databasens navn for %s", + "You cannot use dots in the database name %s" : "Du kan ikke bruke punktum i databasenavnet %s", + "MySQL Login and/or password not valid" : "MySQL-pålogging og/eller passord ikke gyldig", "You need to enter details of an existing account." : "Du må legge in detaljene til en eksisterende konto.", "Oracle connection could not be established" : "Klarte ikke å etablere forbindelse til Oracle", - "Oracle username and/or password not valid" : "Oracle-brukernavn og/eller passord er ikke gyldig", - "PostgreSQL username and/or password not valid" : "PostgreSQL-brukernavn og/eller passord er ikke gyldig", + "Oracle Login and/or password not valid" : "Oracle-pålogging og/eller passord ikke gyldig", + "PostgreSQL Login and/or password not valid" : "PostgreSQL-pålogging og/eller passord ikke gyldig", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X støttes ikke og %s vil ikke fungere korrekt på denne plattformen. Bruk på egen risiko!", "For the best results, please consider using a GNU/Linux server instead." : "For beste resultat, vurder å bruke en GNU/Linux-server i stedet.", "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." : "Det ser ut for at %s-instansen kjører i et 32-bit PHP-miljø med open_basedir satt opp i php.ini. Dette vil føre til problemer med filer over 4 GB og frarådes på det sterkeste.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Fjern innstillingen open_basedir i php.ini eller bytt til 64-bit PHP.", - "Set an admin username." : "Sett et admin-brukernavn.", + "Set an admin Login." : "Angi en admin-pålogging.", "Set an admin password." : "Sett et admin-passord.", + "Cannot create or write into the data directory %s" : "Kan ikke opprette eller skrive i datakatalogen %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Delings-server %s må implementere grensesnittet OCP\\Share_Backend", "Sharing backend %s not found" : "Delings-server %s ikke funnet", "Sharing backend for %s not found" : "Delings-server for %s ikke funnet", @@ -110,12 +144,18 @@ "%1$s via %2$s" : "%1$s via %2$s", "You are not allowed to share %s" : "Du har ikke lov til å dele %s", "Cannot increase permissions of %s" : "Kan ikke øke tillatelser for %s", + "Files cannot be shared with delete permissions" : "Filer kan ikke deles med slett-rettigheter", + "Files cannot be shared with create permissions" : "Filer kan ikke deles med opprettingstillatelser", "Expiration date is in the past" : "Utløpsdato er i fortid", - "Sharing %s failed, because this item is already shared with user %s" : "Deling av %s mislyktes, fordi dette elementet allerede er delt med bruker %s", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Kan ikke sette utløpsdato mer enn %n dag i fremtiden","Kan ikke sette utløpsdato mer enn %n dager i fremtiden"], + "Sharing is only allowed with group members" : "Deling er kun tillatt med gruppemedlemmer", + "Sharing %s failed, because this item is already shared with the account %s" : "Deling av %s feilet, fordi dette elementet er allerede delt med kontoen %s", "%1$s shared »%2$s« with you" : "%1$s delte »%2$s« med deg", "%1$s shared »%2$s« with you." : "%1$s delte »%2$s« med deg.", "Click the button below to open it." : "Klikk på knappen nedenfor for å åpne den.", "The requested share does not exist anymore" : "Forespurt ressurs finnes ikke lenger", + "The requested share comes from a disabled user" : "Den forespurte delingen kommer fra en deaktivert bruker", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Brukeren ble ikke opprettet fordi brukergrensen er nådd. Sjekk varslene dine for å finne ut mer.", "Could not find category \"%s\"" : "Kunne ikke finne kategori \"%s\"", "Sunday" : "Søndag", "Monday" : "Mandag", @@ -163,13 +203,16 @@ "Nov." : "Nov.", "Dec." : "Des.", "A valid password must be provided" : "Oppgi et gyldig passord", - "The username is already being used" : "Brukernavnet er allerede i bruk", - "Could not create user" : "Kunne ikke opprette bruker", - "A valid username must be provided" : "Oppgi et gyldig brukernavn", - "Username contains whitespace at the beginning or at the end" : "Brukernavn inneholder blanke på begynnelsen eller slutten", - "Username must not consist of dots only" : "Brukernavn kan ikke bare bestå av punktum", - "User disabled" : "Brukeren er deaktivert", + "The Login is already being used" : "Påloggingen er allerede i bruk", + "Could not create account" : "Kunne ikke opprette konto", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kun følgende tegn er tillatt i en pålogging: \"a-z\", \"A-Z\", \"0-9\", mellomrom og \"_.@-'\"", + "A valid Login must be provided" : "En gyldig pålogging må angis", + "Login contains whitespace at the beginning or at the end" : "Pålogging inneholder mellomrom i begynnelsen eller på slutten", + "Login must not consist of dots only" : "Pålogging kan ikke bare bestå av punktum", + "Login is invalid because files already exist for this user" : "Påloggingen er ugyldig fordi det finnes allerede filer for denne brukeren.", + "Account disabled" : "Konto deaktivert", "Login canceled by app" : "Innlogging avbrutt av app", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "App \"%1$s\" kan ikke installeres fordi følgende avhengigheter ikke er møtt: %2$s.", "a safe home for all your data" : "et sikkert hjem for alle dine data", "File is currently busy, please try again later" : "Filen er opptatt for øyeblikket, prøv igjen senere", "Cannot download file" : "Kan ikke laste ned fil", @@ -177,25 +220,81 @@ "Authentication error" : "Autentikasjonsfeil", "Token expired. Please reload page." : "Symbol utløpt. Last inn siden på nytt.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Ingen databasedrivere (sqlite, mysql, or postgresql) installert.", + "Cannot write into \"config\" directory." : "Kan ikke skrive i \"config\"-katalogen.", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Dette kan vanligvis ordnes ved å gi webserveren skrivetilgang til config-katalogen. Se %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" : "Men hvis du foretrekker å holde config.php filen skrivebeskyttet, angir du alternativet \"config_is_read_only\" til sant i den. Se %s.", + "Cannot write into \"apps\" directory." : "Kan ikke skrive i \"apps\"-katalogen.", + "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." : "Dette kan vanligvis løses ved å gi webserveren skrivetilgang til apps-katalogen eller deaktivere App Store i konfigurasjonsfilen.", + "Cannot create \"data\" directory." : "Kan ikke opprette \"data\"-katalogen.", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Dette kan vanligvis ordnes ved å gi webserveren skrivetilgang til rotkatalogen. Se %s.", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Tillatelser kan vanligvis ordnes ved å gi webserveren skrivetilgang til rotkatalogen. Se %s.", + "Your data directory is not writable." : "Datakatalogen kan ikke skrives til.", + "Setting locale to %s failed." : "Innstilling av nasjonal innstilling til %s feilet.", + "Please install one of these locales on your system and restart your web server." : "Installer en av disse nasjonale innstillingene på systemet ditt, og start webserveren på nytt.", "PHP module %s not installed." : "PHP-modul %s er ikke installert.", "Please ask your server administrator to install the module." : "Be server-administratoren om å installere modulen.", "PHP setting \"%s\" is not set to \"%s\"." : "PHP-innstilling \"%s\" er ikke satt til \"%s\".", "Adjusting this setting in php.ini will make Nextcloud run again" : "Ved å endre denne innstillingen i php.ini gjør at Nextcloud vil kjøre igjen.", + "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> er satt til <code>%s</code> istedenfor den forventede verdien <code>0</code>.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "For å fikse dette problemet sett <code>mbstring.func_overload</code> til <code>0</code> i php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Det ser ut til at at PHP er satt opp til å fjerne innebygde doc-blokker. Dette gjør at flere av kjerneapplikasjonene blir utilgjengelige.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Dette forårsakes sannsynligvis av hurtiglager/akselerator, som f.eks. Zend OPcache eller eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "PHP-moduler har blitt installert, men de listes fortsatt som fraværende?", "Please ask your server administrator to restart the web server." : "Be server-administratoren om å starte webserveren på nytt.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endre tillatelsene til 0770 slik at mappen ikke kan listes av andre brukere.", + "The required %s config variable is not configured in the config.php file." : "Den nødvendige %s konfigurasjonsvariabelen er ikke konfigurert i config.php-filen.", + "Please ask your server administrator to check the Nextcloud configuration." : "Be serveradministratoren din om å sjekke Nextcloud-konfigurasjonen.", + "Your data directory is readable by other people." : "Datakatalogen din er lesbar for andre personer.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Endre tillatelsene til 0770 slik at katalogen ikke kan listes av andre personer.", + "Your data directory must be an absolute path." : "Datakatalogen din må være en absolutt sti.", + "Check the value of \"datadirectory\" in your configuration." : "Sjekk verdien for \"datadirectory\" i konfigurasjonen din.", + "Your data directory is invalid." : "Datakatalogen din er ugyldig.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Forsikre deg om at det finnes ei fil kalt \".ocdata\" på rota av datamappa.", + "Action \"%s\" not supported or implemented." : "Handling \"%s\" ikke støttet eller implementert.", + "Authentication failed, wrong token or provider ID given" : "Autentisering feilet, feil token eller leverandør-ID gitt", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Parametere mangler for å fullføre forespørselen. Manglende parametere: \"%s\".", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "ID \"%1$s\" allerede brukt av cloud federation-leverandør \"%2$s\".", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "Cloud Federation-leverandør med ID: \"%s\" finnes ikke.", "Could not obtain lock type %d on \"%s\"." : "Klarte ikke å låse med type %d på \"%s\".", "Storage unauthorized. %s" : "Lager uautorisert: %s", "Storage incomplete configuration. %s" : "Ikke komplett oppsett for lager. %s", "Storage connection error. %s" : "Tilkoblingsfeil for lager. %s", "Storage is temporarily not available" : "Lagring er midlertidig utilgjengelig", "Storage connection timeout. %s" : "Tidsavbrudd ved tilkobling av lager: %s", + "Free prompt" : "Ledig ledetekst", + "Runs an arbitrary prompt through the language model." : "Kjører en vilkårlig ledetekst gjennom språkmodellen.", + "Generate headline" : "Generer overskrift", + "Generates a possible headline for a text." : "Genererer en mulig overskrift for en tekst.", + "Summarize" : "Oppsummere", + "Summarizes text by reducing its length without losing key information." : "Oppsummerer tekst ved å redusere lengden uten å miste nøkkelinformasjon.", + "Extract topics" : "Trekk ut emner", + "Extracts topics from a text and outputs them separated by commas." : "Trekker ut emner fra en tekst og sender dem ut atskilt med komma.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Filene i appen %1$s ble ikke erstattet på riktig måte. Forsikre deg om at det er en versjon som er kompatibel med serveren.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Innlogget bruker må være administrator, underadministrator eller ha fått spesiell rett til å få tilgang til denne innstillingen.", + "Logged in user must be an admin or sub admin" : "Innlogget bruker må være administrator eller en underadministrator.", + "Logged in user must be an admin" : "Innlogget bruker må være administrator", "Full name" : "Fullt navn", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Bare disse tegnene tillates i et brukernavn: \"a-z\", \"A-Z\", \"0-9\" og \"_.@-'\"", + "Unknown user" : "Ukjent bruker", + "Enter the database username and name for %s" : "Skriv inn databasens brukernavn og navn for %s", + "Enter the database username for %s" : "Skriv inn databasens brukernavn for %s", + "MySQL username and/or password not valid" : "MySQL-brukernavn og/eller passord ikke gyldig", + "Oracle username and/or password not valid" : "Oracle-brukernavn og/eller passord er ikke gyldig", + "PostgreSQL username and/or password not valid" : "PostgreSQL-brukernavn og/eller passord er ikke gyldig", + "Set an admin username." : "Sett et admin-brukernavn.", + "Sharing %s failed, because this item is already shared with user %s" : "Deling av %s mislyktes, fordi dette elementet allerede er delt med bruker %s", + "The username is already being used" : "Brukernavnet er allerede i bruk", + "Could not create user" : "Kunne ikke opprette bruker", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kun følgende tegn er tillatt i et brukernavn: \"a-z\", \"A-Z\", \"0-9\", mellomrom og \"_.@-'\"", + "A valid username must be provided" : "Oppgi et gyldig brukernavn", + "Username contains whitespace at the beginning or at the end" : "Brukernavn inneholder blanke på begynnelsen eller slutten", + "Username must not consist of dots only" : "Brukernavn kan ikke bare bestå av punktum", + "Username is invalid because files already exist for this user" : "Brukernavnet er ugyldig fordi det finnes allerede filer for denne brukeren.", + "User disabled" : "Brukeren er deaktivert", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Krever minst libxml2 2.7.0. Per nå er %s installert.", - "To fix this issue update your libxml2 version and restart your web server." : "For å fikse dette problemet, oppdater din libxml2 versjon og start webserveren på nytt." + "To fix this issue update your libxml2 version and restart your web server." : "For å fikse dette problemet, oppdater din libxml2 versjon og start webserveren på nytt.", + "PostgreSQL >= 9 required." : "PostgreSQL >= 9 kreves.", + "Please upgrade your database version." : "Oppgrader databaseversjonen din.", + "Your data directory is readable by other users." : "Datakatalogen din kan leses av andre brukere.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Endre tillatelsene til 0770 slik at mappen ikke kan listes av andre brukere." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/nl.js b/lib/l10n/nl.js index 068552cebb0..79912ad4b47 100644 --- a/lib/l10n/nl.js +++ b/lib/l10n/nl.js @@ -35,9 +35,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "De volgende platforms worden ondersteund: %s", "Server version %s or higher is required." : "Serverversie %s of hoger vereist.", "Server version %s or lower is required." : "Serverversie %s of lager vereist.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Ingelogde gebruiken moet beheerder, sub-beheerder of gebruiker met speciale rechten om deze instelling te veranderen zijn", - "Logged in user must be an admin or sub admin" : "Ingelogde gebruiker moet een beheerder of subbeheerder zijn", - "Logged in user must be an admin" : "Ingelogde gebruiker moet een beheerder zijn", "Wiping of device %s has started" : "Leegmaken van toestel %sis gestart", "Wiping of device »%s« has started" : "Leegmaken van toestel \"%s\" is gestart", "»%s« started remote wipe" : "\"%s\" startte leegmaken op afstand", @@ -94,6 +91,7 @@ OC.L10N.register( "Appearance and accessibility" : "Weergave en toegankelijkheid", "Apps" : "Apps", "Personal settings" : "Persoonlijke instellingen", + "Administration settings" : "Beheerder instellingen", "Settings" : "Instellingen", "Log out" : "Uitloggen", "Users" : "Gebruikers", @@ -111,18 +109,13 @@ OC.L10N.register( "Headline" : "Hoofdlijn", "Organisation" : "Organisatie", "Role" : "Rol", - "Unknown user" : "Onbekende gebruiker", "Additional settings" : "Aanvullende instellingen", - "MySQL username and/or password not valid" : "MySQL gebruikersnaam en/of wachtwoord ongeldig", "You need to enter details of an existing account." : "Geef de details van een bestaand account op.", "Oracle connection could not be established" : "Er kon geen verbinding met Oracle worden gemaakt.", - "Oracle username and/or password not valid" : "Oracle gebruikersnaam en/of wachtwoord ongeldig", - "PostgreSQL username and/or password not valid" : "PostgreSQL gebruikersnaam en/of wachtwoord ongeldig", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OSX wordt niet ondersteund en %s zal niet goed werken op dit platform. Gebruik het op eigen risico!", "For the best results, please consider using a GNU/Linux server instead." : "Voor het beste resultaat adviseren wij het gebruik van een GNU/Linux server.", "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." : "Het lijkt erop dat deze %s versie draait in een 32 bits PHP omgeving en dat open_basedir is geconfigureerd in php.ini. Dat zal leiden tot problemen met bestanden groter dan 4 GB en wordt dus sterk afgeraden.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Verwijder de open_basedir instelling in php.ini of schakel over op de 64bit PHP.", - "Set an admin username." : "Stel de gebruikersnaam van de beheerder in.", "Set an admin password." : "Stel een beheerders wachtwoord in.", "Cannot create or write into the data directory %s" : "Kan niets creëren of wegschrijven in de datadirectory %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "De gedeelde achtergrond %s moet de OCP\\Share_Backend interface implementeren", @@ -140,7 +133,6 @@ 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 user %s" : "Delen van %s is mislukt, omdat het object al wordt gedeeld met gebruiker %s", "%1$s shared »%2$s« with you" : "%1$s deelde \"%2$s\" met jou", "%1$s shared »%2$s« with you." : "%1$s deelde \"%2$s\" met jou.", "Click the button below to open it." : "Klik de onderstaande button om te openen.", @@ -192,13 +184,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Er moet een geldig wachtwoord worden opgegeven", - "The username is already being used" : "De gebruikersnaam bestaat al", - "Could not create user" : "Kan gebruiker niet aanmaken.", - "A valid username must be provided" : "Er moet een geldige gebruikersnaam worden opgegeven", - "Username contains whitespace at the beginning or at the end" : "De gebruikersnaam bevat spaties aan het begin of aan het eind", - "Username must not consist of dots only" : "De gebruikersnaam mag niet uit alleen punten bestaan", - "Username is invalid because files already exist for this user" : "Gebruikersnaam is ongeldig omdat er al bestanden voor deze gebruiker bestaan", - "User disabled" : "Gebruiker uitgeschakeld", "Login canceled by app" : "Inloggen geannuleerd door app", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "App \"%1$s\" kan niet worden geïnstalleerd, omdat de volgende afhankelijkheden niet zijn ingevuld: %2$s", "a safe home for all your data" : "een veilige plek voor al je gegevens", @@ -228,8 +213,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Dit wordt vermoedelijk veroorzaakt door een cache/accelerator, zoals Zend OPcache of eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "PHP modules zijn geïnstalleerd, maar ze worden nog steeds als ontbrekend aangegeven?", "Please ask your server administrator to restart the web server." : "Vraag je beheerder de webserver opnieuw te starten.", - "Your data directory is readable by other users." : "Je datamap is leesbaar voor andere gebruikers.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Wijzig de machtiging in 0770 zodat de directory niet door andere gebruikers bekeken kan worden.", "Your data directory must be an absolute path." : "Je datamap moet een absolute bestandslocatie hebben.", "Check the value of \"datadirectory\" in your configuration." : "Controleer de waarde van \"datadirectory\" in je configuratie.", "Your data directory is invalid." : "Je datamap is ongeldig.", @@ -246,11 +229,28 @@ OC.L10N.register( "Storage is temporarily not available" : "Opslag is tijdelijk niet beschikbaar", "Storage connection timeout. %s" : "Opslag verbinding time-out. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "De bestanden van app %1$szijn niet correct vervangen. Zorg ervoor dat de versie compatible is met de server.", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Ingelogde gebruiken moet beheerder, sub-beheerder of gebruiker met speciale rechten om deze instelling te veranderen zijn", + "Logged in user must be an admin or sub admin" : "Ingelogde gebruiker moet een beheerder of subbeheerder zijn", + "Logged in user must be an admin" : "Ingelogde gebruiker moet een beheerder zijn", "Full name" : "Volledige naam", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Alleen de volgende tekens zijn toegestaan in een gebruikersnaam: \"a-z\", \"A-Z\", \"0-9\", en \"_.@-\"", + "Unknown user" : "Onbekende gebruiker", + "MySQL username and/or password not valid" : "MySQL gebruikersnaam en/of wachtwoord ongeldig", + "Oracle username and/or password not valid" : "Oracle gebruikersnaam en/of wachtwoord ongeldig", + "PostgreSQL username and/or password not valid" : "PostgreSQL gebruikersnaam en/of wachtwoord ongeldig", + "Set an admin username." : "Stel de gebruikersnaam van de beheerder in.", + "Sharing %s failed, because this item is already shared with user %s" : "Delen van %s is mislukt, omdat het object al wordt gedeeld met gebruiker %s", + "The username is already being used" : "De gebruikersnaam bestaat al", + "Could not create user" : "Kan gebruiker niet aanmaken.", + "A valid username must be provided" : "Er moet een geldige gebruikersnaam worden opgegeven", + "Username contains whitespace at the beginning or at the end" : "De gebruikersnaam bevat spaties aan het begin of aan het eind", + "Username must not consist of dots only" : "De gebruikersnaam mag niet uit alleen punten bestaan", + "Username is invalid because files already exist for this user" : "Gebruikersnaam is ongeldig omdat er al bestanden voor deze gebruiker bestaan", + "User disabled" : "Gebruiker uitgeschakeld", "libxml2 2.7.0 is at least required. Currently %s is installed." : "De minimale versie van libxml2 versie is 2.7.0. Momenteel is versie%s geïnstalleerd.", "To fix this issue update your libxml2 version and restart your web server." : "Om dit probleem op te lossen, moet je de libxml2 versie bijwerken en je webserver herstarten.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 is vereist.", - "Please upgrade your database version." : "Werk je databaseversie bij." + "Please upgrade your database version." : "Werk je databaseversie bij.", + "Your data directory is readable by other users." : "Je datamap is leesbaar voor andere gebruikers.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Wijzig de machtiging in 0770 zodat de directory niet door andere gebruikers bekeken kan worden." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/nl.json b/lib/l10n/nl.json index a7c9066de3a..d79830ded97 100644 --- a/lib/l10n/nl.json +++ b/lib/l10n/nl.json @@ -33,9 +33,6 @@ "The following platforms are supported: %s" : "De volgende platforms worden ondersteund: %s", "Server version %s or higher is required." : "Serverversie %s of hoger vereist.", "Server version %s or lower is required." : "Serverversie %s of lager vereist.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Ingelogde gebruiken moet beheerder, sub-beheerder of gebruiker met speciale rechten om deze instelling te veranderen zijn", - "Logged in user must be an admin or sub admin" : "Ingelogde gebruiker moet een beheerder of subbeheerder zijn", - "Logged in user must be an admin" : "Ingelogde gebruiker moet een beheerder zijn", "Wiping of device %s has started" : "Leegmaken van toestel %sis gestart", "Wiping of device »%s« has started" : "Leegmaken van toestel \"%s\" is gestart", "»%s« started remote wipe" : "\"%s\" startte leegmaken op afstand", @@ -92,6 +89,7 @@ "Appearance and accessibility" : "Weergave en toegankelijkheid", "Apps" : "Apps", "Personal settings" : "Persoonlijke instellingen", + "Administration settings" : "Beheerder instellingen", "Settings" : "Instellingen", "Log out" : "Uitloggen", "Users" : "Gebruikers", @@ -109,18 +107,13 @@ "Headline" : "Hoofdlijn", "Organisation" : "Organisatie", "Role" : "Rol", - "Unknown user" : "Onbekende gebruiker", "Additional settings" : "Aanvullende instellingen", - "MySQL username and/or password not valid" : "MySQL gebruikersnaam en/of wachtwoord ongeldig", "You need to enter details of an existing account." : "Geef de details van een bestaand account op.", "Oracle connection could not be established" : "Er kon geen verbinding met Oracle worden gemaakt.", - "Oracle username and/or password not valid" : "Oracle gebruikersnaam en/of wachtwoord ongeldig", - "PostgreSQL username and/or password not valid" : "PostgreSQL gebruikersnaam en/of wachtwoord ongeldig", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OSX wordt niet ondersteund en %s zal niet goed werken op dit platform. Gebruik het op eigen risico!", "For the best results, please consider using a GNU/Linux server instead." : "Voor het beste resultaat adviseren wij het gebruik van een GNU/Linux server.", "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." : "Het lijkt erop dat deze %s versie draait in een 32 bits PHP omgeving en dat open_basedir is geconfigureerd in php.ini. Dat zal leiden tot problemen met bestanden groter dan 4 GB en wordt dus sterk afgeraden.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Verwijder de open_basedir instelling in php.ini of schakel over op de 64bit PHP.", - "Set an admin username." : "Stel de gebruikersnaam van de beheerder in.", "Set an admin password." : "Stel een beheerders wachtwoord in.", "Cannot create or write into the data directory %s" : "Kan niets creëren of wegschrijven in de datadirectory %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "De gedeelde achtergrond %s moet de OCP\\Share_Backend interface implementeren", @@ -138,7 +131,6 @@ "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 user %s" : "Delen van %s is mislukt, omdat het object al wordt gedeeld met gebruiker %s", "%1$s shared »%2$s« with you" : "%1$s deelde \"%2$s\" met jou", "%1$s shared »%2$s« with you." : "%1$s deelde \"%2$s\" met jou.", "Click the button below to open it." : "Klik de onderstaande button om te openen.", @@ -190,13 +182,6 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Er moet een geldig wachtwoord worden opgegeven", - "The username is already being used" : "De gebruikersnaam bestaat al", - "Could not create user" : "Kan gebruiker niet aanmaken.", - "A valid username must be provided" : "Er moet een geldige gebruikersnaam worden opgegeven", - "Username contains whitespace at the beginning or at the end" : "De gebruikersnaam bevat spaties aan het begin of aan het eind", - "Username must not consist of dots only" : "De gebruikersnaam mag niet uit alleen punten bestaan", - "Username is invalid because files already exist for this user" : "Gebruikersnaam is ongeldig omdat er al bestanden voor deze gebruiker bestaan", - "User disabled" : "Gebruiker uitgeschakeld", "Login canceled by app" : "Inloggen geannuleerd door app", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "App \"%1$s\" kan niet worden geïnstalleerd, omdat de volgende afhankelijkheden niet zijn ingevuld: %2$s", "a safe home for all your data" : "een veilige plek voor al je gegevens", @@ -226,8 +211,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Dit wordt vermoedelijk veroorzaakt door een cache/accelerator, zoals Zend OPcache of eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "PHP modules zijn geïnstalleerd, maar ze worden nog steeds als ontbrekend aangegeven?", "Please ask your server administrator to restart the web server." : "Vraag je beheerder de webserver opnieuw te starten.", - "Your data directory is readable by other users." : "Je datamap is leesbaar voor andere gebruikers.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Wijzig de machtiging in 0770 zodat de directory niet door andere gebruikers bekeken kan worden.", "Your data directory must be an absolute path." : "Je datamap moet een absolute bestandslocatie hebben.", "Check the value of \"datadirectory\" in your configuration." : "Controleer de waarde van \"datadirectory\" in je configuratie.", "Your data directory is invalid." : "Je datamap is ongeldig.", @@ -244,11 +227,28 @@ "Storage is temporarily not available" : "Opslag is tijdelijk niet beschikbaar", "Storage connection timeout. %s" : "Opslag verbinding time-out. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "De bestanden van app %1$szijn niet correct vervangen. Zorg ervoor dat de versie compatible is met de server.", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Ingelogde gebruiken moet beheerder, sub-beheerder of gebruiker met speciale rechten om deze instelling te veranderen zijn", + "Logged in user must be an admin or sub admin" : "Ingelogde gebruiker moet een beheerder of subbeheerder zijn", + "Logged in user must be an admin" : "Ingelogde gebruiker moet een beheerder zijn", "Full name" : "Volledige naam", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Alleen de volgende tekens zijn toegestaan in een gebruikersnaam: \"a-z\", \"A-Z\", \"0-9\", en \"_.@-\"", + "Unknown user" : "Onbekende gebruiker", + "MySQL username and/or password not valid" : "MySQL gebruikersnaam en/of wachtwoord ongeldig", + "Oracle username and/or password not valid" : "Oracle gebruikersnaam en/of wachtwoord ongeldig", + "PostgreSQL username and/or password not valid" : "PostgreSQL gebruikersnaam en/of wachtwoord ongeldig", + "Set an admin username." : "Stel de gebruikersnaam van de beheerder in.", + "Sharing %s failed, because this item is already shared with user %s" : "Delen van %s is mislukt, omdat het object al wordt gedeeld met gebruiker %s", + "The username is already being used" : "De gebruikersnaam bestaat al", + "Could not create user" : "Kan gebruiker niet aanmaken.", + "A valid username must be provided" : "Er moet een geldige gebruikersnaam worden opgegeven", + "Username contains whitespace at the beginning or at the end" : "De gebruikersnaam bevat spaties aan het begin of aan het eind", + "Username must not consist of dots only" : "De gebruikersnaam mag niet uit alleen punten bestaan", + "Username is invalid because files already exist for this user" : "Gebruikersnaam is ongeldig omdat er al bestanden voor deze gebruiker bestaan", + "User disabled" : "Gebruiker uitgeschakeld", "libxml2 2.7.0 is at least required. Currently %s is installed." : "De minimale versie van libxml2 versie is 2.7.0. Momenteel is versie%s geïnstalleerd.", "To fix this issue update your libxml2 version and restart your web server." : "Om dit probleem op te lossen, moet je de libxml2 versie bijwerken en je webserver herstarten.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 is vereist.", - "Please upgrade your database version." : "Werk je databaseversie bij." + "Please upgrade your database version." : "Werk je databaseversie bij.", + "Your data directory is readable by other users." : "Je datamap is leesbaar voor andere gebruikers.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Wijzig de machtiging in 0770 zodat de directory niet door andere gebruikers bekeken kan worden." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/nn_NO.js b/lib/l10n/nn_NO.js index 03a76a1ea36..5fd93282589 100644 --- a/lib/l10n/nn_NO.js +++ b/lib/l10n/nn_NO.js @@ -27,7 +27,6 @@ OC.L10N.register( "Address" : "Adresse", "Profile picture" : "Profilbilete", "About" : "Om", - "Unknown user" : "Ukjend brukar", "Additional settings" : "Tilleggsinnstillingar", "Set an admin password." : "Vel eit admin-passord.", "Open »%s«" : "Opna »%s«", @@ -77,10 +76,11 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Des.", "A valid password must be provided" : "Du må oppgje eit gyldig passord", - "A valid username must be provided" : "Du må oppgje eit gyldig brukarnamn", - "User disabled" : "Brukar deaktivert", "Login canceled by app" : "Innlogging avbroten av app", "Authentication error" : "Feil i autentisering", - "Full name" : "Fult namn" + "Full name" : "Fult namn", + "Unknown user" : "Ukjend brukar", + "A valid username must be provided" : "Du må oppgje eit gyldig brukarnamn", + "User disabled" : "Brukar deaktivert" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/nn_NO.json b/lib/l10n/nn_NO.json index da77b6f1521..c0f90bf8285 100644 --- a/lib/l10n/nn_NO.json +++ b/lib/l10n/nn_NO.json @@ -25,7 +25,6 @@ "Address" : "Adresse", "Profile picture" : "Profilbilete", "About" : "Om", - "Unknown user" : "Ukjend brukar", "Additional settings" : "Tilleggsinnstillingar", "Set an admin password." : "Vel eit admin-passord.", "Open »%s«" : "Opna »%s«", @@ -75,10 +74,11 @@ "Nov." : "Nov.", "Dec." : "Des.", "A valid password must be provided" : "Du må oppgje eit gyldig passord", - "A valid username must be provided" : "Du må oppgje eit gyldig brukarnamn", - "User disabled" : "Brukar deaktivert", "Login canceled by app" : "Innlogging avbroten av app", "Authentication error" : "Feil i autentisering", - "Full name" : "Fult namn" + "Full name" : "Fult namn", + "Unknown user" : "Ukjend brukar", + "A valid username must be provided" : "Du må oppgje eit gyldig brukarnamn", + "User disabled" : "Brukar deaktivert" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/oc.js b/lib/l10n/oc.js index 98984f9747a..f195727b58e 100644 --- a/lib/l10n/oc.js +++ b/lib/l10n/oc.js @@ -69,10 +69,10 @@ OC.L10N.register( "November" : "Novembre", "December" : "Decembre", "May." : "Mai.", - "User disabled" : "Utilizaire desactivat", "a safe home for all your data" : "un ostal segur per vòstras donadas", "Authentication error" : "Error d’autentificacion", "Storage is temporarily not available" : "Emmagazinatge temporàriament indisponible", - "Full name" : "Nom complèt" + "Full name" : "Nom complèt", + "User disabled" : "Utilizaire desactivat" }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/oc.json b/lib/l10n/oc.json index 53eac3420a8..174eeb6d97e 100644 --- a/lib/l10n/oc.json +++ b/lib/l10n/oc.json @@ -67,10 +67,10 @@ "November" : "Novembre", "December" : "Decembre", "May." : "Mai.", - "User disabled" : "Utilizaire desactivat", "a safe home for all your data" : "un ostal segur per vòstras donadas", "Authentication error" : "Error d’autentificacion", "Storage is temporarily not available" : "Emmagazinatge temporàriament indisponible", - "Full name" : "Nom complèt" + "Full name" : "Nom complèt", + "User disabled" : "Utilizaire desactivat" },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/lib/l10n/pl.js b/lib/l10n/pl.js index 68de01a6171..2be818ae31c 100644 --- a/lib/l10n/pl.js +++ b/lib/l10n/pl.js @@ -5,9 +5,9 @@ OC.L10N.register( "This can usually be fixed by giving the web server write access to the config directory." : "Zwykle można to naprawić, nadając serwerowi WWW dostęp do zapisu do katalogu config.", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Ale jeśli wolisz, aby plik config.php był tylko do odczytu, ustaw w nim opcję \"config_is_read_only\" na true.", "See %s" : "Zobacz %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplikacja %1$s nie jest dostępna lub ma wersję niekompatybilną z tym serwerem. Sprawdź katalog aplikacji.", "Sample configuration detected" : "Wykryto przykładową konfigurację", "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" : "Wykryto, że przykładowa konfiguracja została skopiowana. Może to spowodować przerwanie instalacji, która nie jest wspierana. Przeczytaj dokumentację przed dokonaniem zmian w pliku config.php", - "404" : "404", "The page could not be found on the server." : "Nie znaleziono strony na serwerze.", "%s email verification" : "Weryfikacja adresu e-mail %s", "Email verification" : "Weryfikacja adresu e-mail", @@ -36,9 +36,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Obsługiwane są następujące platformy: %s", "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 user must be an admin, a sub admin or gotten special right to access this setting" : "Zalogowany użytkownik musi być administratorem, subadministratorem lub mieć specjalne uprawnienia dostępu do tego ustawienia", - "Logged in user must be an admin or sub admin" : "Zalogowany użytkownik musi być administratorem lub współadministratorem", - "Logged in user must be an admin" : "Zalogowany użytkownik musi być administratorem", "Wiping of device %s has started" : "Rozpoczęto czyszczenie urządzenia %s", "Wiping of device »%s« has started" : "Rozpoczęto czyszczenie urządzenia »%s«", "»%s« started remote wipe" : "»%s« rozpoczęło zdalne czyszczenie", @@ -113,25 +110,19 @@ OC.L10N.register( "Address" : "Adres", "Profile picture" : "Zdjęcie profilowe", "About" : "Informacje", + "Display name" : "Wyświetlana nazwa", "Headline" : "Nagłówek", "Organisation" : "Organizacja", "Role" : "Rola społeczna", - "Unknown user" : "Nieznany użytkownik", "Additional settings" : "Ustawienia dodatkowe", - "Enter the database username and name for %s" : "Podaj nazwę użytkownika i nazwę bazy danych dla %s", - "Enter the database username for %s" : "Podaj nazwę użytkownika 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 username and/or password not valid" : "Błędna nazwa użytkownika i/lub hasło do bazy danych 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 username and/or password not valid" : "Zła nazwa użytkownika i/lub hasło do bazy danych Oracle", - "PostgreSQL username and/or password not valid" : "Zła nazwa użytkownika i/lub hasło do bazy danych 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 wspierany i %s nie będzie działać poprawnie na tej platformie. Używasz go 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.", - "Set an admin username." : "Ustaw nazwę administratora.", "Set an admin password." : "Ustaw hasło administratora.", "Cannot create or write into the data directory %s" : "Nie można tworzyć ani zapisywać w katalogu %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Zaplecze do udostępniania %s musi implementować interfejs OCP\\Share_Backend", @@ -149,11 +140,11 @@ OC.L10N.register( "Expiration date is in the past" : "Data ważności już minęła", "_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 user %s" : "Udostępnianie %s nie powiodło się, ponieważ element jest już udostępniony użytkownikowi %s", "%1$s shared »%2$s« with you" : "%1$s udostępnił Tobie »%2$s«", "%1$s shared »%2$s« with you." : "%1$s udostępnił Tobie »%2$s«.", "Click the button below to open it." : "Kliknij przycisk poniżej, aby otworzyć.", "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.", "Could not find category \"%s\"" : "Nie można znaleźć kategorii \"%s\"", "Sunday" : "Niedziela", @@ -202,14 +193,6 @@ OC.L10N.register( "Nov." : "Lis.", "Dec." : "Gru.", "A valid password must be provided" : "Należy podać prawidłowe hasło", - "The username is already being used" : "Ta nazwa użytkownika jest już używana", - "Could not create user" : "Nie można utworzyć użytkownika", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "W nazwie użytkownika dozwolone są tylko następujące znaki : \"a-z\", \"A-Z\", \"0-9\", spacje i \"_.@-'\"", - "A valid username must be provided" : "Należy podać prawidłową nazwę użytkownika", - "Username contains whitespace at the beginning or at the end" : "Nazwa użytkownika zawiera spację na początku albo na końcu", - "Username must not consist of dots only" : "Nazwa użytkownika nie może się składać tylko z kropek", - "Username is invalid because files already exist for this user" : "Nazwa użytkownika jest nieprawidłowa, ponieważ pliki już istnieją dla tego użytkownika", - "User disabled" : "Użytkownik zablokowany", "Login canceled by app" : "Logowanie anulowane przez aplikację", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Nie można zainstalować aplikacji \"%1$s\", ponieważ nie są spełnione następujące zależności: %2$s", "a safe home for all your data" : "bezpieczny dom dla wszystkich Twoich danych", @@ -242,8 +225,6 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Poproś administratora serwera o ponowne uruchomienie serwera WWW.", "The required %s config variable is not configured in the config.php file." : "Wymagana zmienna konfiguracyjna %s nie jest skonfigurowana w pliku config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Poproś administratora serwera o sprawdzenie konfiguracji Nextcloud.", - "Your data directory is readable by other users." : "Twój katalog danych jest widoczny dla innych użytkowników.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Zmień uprawnienia na 0770, aby katalog nie był widoczny dla innych użytkowników.", "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.", @@ -259,13 +240,41 @@ 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", + "Free prompt" : "Monit bezpłatny", + "Runs an arbitrary prompt through the language model." : "Uruchamia dowolny monit w modelu języka.", + "Generate headline" : "Wygeneruj nagłówek", + "Generates a possible headline for a text." : "Generuje możliwy nagłówek tekstu.", + "Summarize" : "Podsumuj", + "Summarizes text by reducing its length without losing key information." : "Podsumowuje tekst, zmniejszając jego długość bez utraty kluczowych informacji.", + "Extract topics" : "Wyodrębnij tematy", + "Extracts topics from a text and outputs them separated by commas." : "Wyodrębnia tematy z tekstu i wyświetla je oddzielone przecinkami.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Pliki aplikacji %1$s nie zostały poprawnie zastąpione. Upewnij się, że jest to wersja zgodna z serwerem.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Zalogowany użytkownik musi być administratorem, subadministratorem lub mieć specjalne uprawnienia dostępu do tego ustawienia", + "Logged in user must be an admin or sub admin" : "Zalogowany użytkownik musi być administratorem lub współadministratorem", + "Logged in user must be an admin" : "Zalogowany użytkownik musi być administratorem", "Full name" : "Pełna nazwa", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Osiągnięto limit użytkowników i użytkownik nie został utworzony. Sprawdź swoje powiadomienia, aby dowiedzieć się więcej.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "W nazwie użytkownika dozwolone są tylko następujące znaki : \"a-z\", \"A-Z\", \"0-9\" i \"_.@-'\"", + "Unknown user" : "Nieznany użytkownik", + "Enter the database username and name for %s" : "Podaj nazwę użytkownika i nazwę bazy danych dla %s", + "Enter the database username for %s" : "Podaj nazwę użytkownika bazy danych dla %s", + "MySQL username and/or password not valid" : "Błędna nazwa użytkownika i/lub hasło do bazy danych MySQL", + "Oracle username and/or password not valid" : "Zła nazwa użytkownika i/lub hasło do bazy danych Oracle", + "PostgreSQL username and/or password not valid" : "Zła nazwa użytkownika i/lub hasło do bazy danych PostgreSQL", + "Set an admin username." : "Ustaw nazwę administratora.", + "Sharing %s failed, because this item is already shared with user %s" : "Udostępnianie %s nie powiodło się, ponieważ element jest już udostępniony użytkownikowi %s", + "The username is already being used" : "Ta nazwa użytkownika jest już używana", + "Could not create user" : "Nie można utworzyć użytkownika", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "W nazwie użytkownika dozwolone są tylko następujące znaki : \"a-z\", \"A-Z\", \"0-9\", spacje i \"_.@-'\"", + "A valid username must be provided" : "Należy podać prawidłową nazwę użytkownika", + "Username contains whitespace at the beginning or at the end" : "Nazwa użytkownika zawiera spację na początku albo na końcu", + "Username must not consist of dots only" : "Nazwa użytkownika nie może się składać tylko z kropek", + "Username is invalid because files already exist for this user" : "Nazwa użytkownika jest nieprawidłowa, ponieważ pliki już istnieją dla tego użytkownika", + "User disabled" : "Użytkownik zablokowany", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Wymagana wersja dla libxml2 to przynajmniej 2.7.0. Aktualnie zainstalowana jest %s.", "To fix this issue update your libxml2 version and restart your web server." : "Aby rozwiązać ten problem, zaktualizuj wersję libxml2 i ponownie uruchom serwer WWW.", "PostgreSQL >= 9 required." : "Wymagany PostgreSQL >= 9", - "Please upgrade your database version." : "Zaktualizuj wersję bazy danych." + "Please upgrade your database version." : "Zaktualizuj wersję bazy danych.", + "Your data directory is readable by other users." : "Twój katalog danych jest widoczny dla innych użytkowników.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Zmień uprawnienia na 0770, aby katalog nie był widoczny dla innych użytkowników." }, "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 ea9d21d3b76..333203431e7 100644 --- a/lib/l10n/pl.json +++ b/lib/l10n/pl.json @@ -3,9 +3,9 @@ "This can usually be fixed by giving the web server write access to the config directory." : "Zwykle można to naprawić, nadając serwerowi WWW dostęp do zapisu do katalogu config.", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Ale jeśli wolisz, aby plik config.php był tylko do odczytu, ustaw w nim opcję \"config_is_read_only\" na true.", "See %s" : "Zobacz %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplikacja %1$s nie jest dostępna lub ma wersję niekompatybilną z tym serwerem. Sprawdź katalog aplikacji.", "Sample configuration detected" : "Wykryto przykładową konfigurację", "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" : "Wykryto, że przykładowa konfiguracja została skopiowana. Może to spowodować przerwanie instalacji, która nie jest wspierana. Przeczytaj dokumentację przed dokonaniem zmian w pliku config.php", - "404" : "404", "The page could not be found on the server." : "Nie znaleziono strony na serwerze.", "%s email verification" : "Weryfikacja adresu e-mail %s", "Email verification" : "Weryfikacja adresu e-mail", @@ -34,9 +34,6 @@ "The following platforms are supported: %s" : "Obsługiwane są następujące platformy: %s", "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 user must be an admin, a sub admin or gotten special right to access this setting" : "Zalogowany użytkownik musi być administratorem, subadministratorem lub mieć specjalne uprawnienia dostępu do tego ustawienia", - "Logged in user must be an admin or sub admin" : "Zalogowany użytkownik musi być administratorem lub współadministratorem", - "Logged in user must be an admin" : "Zalogowany użytkownik musi być administratorem", "Wiping of device %s has started" : "Rozpoczęto czyszczenie urządzenia %s", "Wiping of device »%s« has started" : "Rozpoczęto czyszczenie urządzenia »%s«", "»%s« started remote wipe" : "»%s« rozpoczęło zdalne czyszczenie", @@ -111,25 +108,19 @@ "Address" : "Adres", "Profile picture" : "Zdjęcie profilowe", "About" : "Informacje", + "Display name" : "Wyświetlana nazwa", "Headline" : "Nagłówek", "Organisation" : "Organizacja", "Role" : "Rola społeczna", - "Unknown user" : "Nieznany użytkownik", "Additional settings" : "Ustawienia dodatkowe", - "Enter the database username and name for %s" : "Podaj nazwę użytkownika i nazwę bazy danych dla %s", - "Enter the database username for %s" : "Podaj nazwę użytkownika 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 username and/or password not valid" : "Błędna nazwa użytkownika i/lub hasło do bazy danych 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 username and/or password not valid" : "Zła nazwa użytkownika i/lub hasło do bazy danych Oracle", - "PostgreSQL username and/or password not valid" : "Zła nazwa użytkownika i/lub hasło do bazy danych 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 wspierany i %s nie będzie działać poprawnie na tej platformie. Używasz go 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.", - "Set an admin username." : "Ustaw nazwę administratora.", "Set an admin password." : "Ustaw hasło administratora.", "Cannot create or write into the data directory %s" : "Nie można tworzyć ani zapisywać w katalogu %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Zaplecze do udostępniania %s musi implementować interfejs OCP\\Share_Backend", @@ -147,11 +138,11 @@ "Expiration date is in the past" : "Data ważności już minęła", "_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 user %s" : "Udostępnianie %s nie powiodło się, ponieważ element jest już udostępniony użytkownikowi %s", "%1$s shared »%2$s« with you" : "%1$s udostępnił Tobie »%2$s«", "%1$s shared »%2$s« with you." : "%1$s udostępnił Tobie »%2$s«.", "Click the button below to open it." : "Kliknij przycisk poniżej, aby otworzyć.", "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.", "Could not find category \"%s\"" : "Nie można znaleźć kategorii \"%s\"", "Sunday" : "Niedziela", @@ -200,14 +191,6 @@ "Nov." : "Lis.", "Dec." : "Gru.", "A valid password must be provided" : "Należy podać prawidłowe hasło", - "The username is already being used" : "Ta nazwa użytkownika jest już używana", - "Could not create user" : "Nie można utworzyć użytkownika", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "W nazwie użytkownika dozwolone są tylko następujące znaki : \"a-z\", \"A-Z\", \"0-9\", spacje i \"_.@-'\"", - "A valid username must be provided" : "Należy podać prawidłową nazwę użytkownika", - "Username contains whitespace at the beginning or at the end" : "Nazwa użytkownika zawiera spację na początku albo na końcu", - "Username must not consist of dots only" : "Nazwa użytkownika nie może się składać tylko z kropek", - "Username is invalid because files already exist for this user" : "Nazwa użytkownika jest nieprawidłowa, ponieważ pliki już istnieją dla tego użytkownika", - "User disabled" : "Użytkownik zablokowany", "Login canceled by app" : "Logowanie anulowane przez aplikację", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Nie można zainstalować aplikacji \"%1$s\", ponieważ nie są spełnione następujące zależności: %2$s", "a safe home for all your data" : "bezpieczny dom dla wszystkich Twoich danych", @@ -240,8 +223,6 @@ "Please ask your server administrator to restart the web server." : "Poproś administratora serwera o ponowne uruchomienie serwera WWW.", "The required %s config variable is not configured in the config.php file." : "Wymagana zmienna konfiguracyjna %s nie jest skonfigurowana w pliku config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Poproś administratora serwera o sprawdzenie konfiguracji Nextcloud.", - "Your data directory is readable by other users." : "Twój katalog danych jest widoczny dla innych użytkowników.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Zmień uprawnienia na 0770, aby katalog nie był widoczny dla innych użytkowników.", "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.", @@ -257,13 +238,41 @@ "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", + "Free prompt" : "Monit bezpłatny", + "Runs an arbitrary prompt through the language model." : "Uruchamia dowolny monit w modelu języka.", + "Generate headline" : "Wygeneruj nagłówek", + "Generates a possible headline for a text." : "Generuje możliwy nagłówek tekstu.", + "Summarize" : "Podsumuj", + "Summarizes text by reducing its length without losing key information." : "Podsumowuje tekst, zmniejszając jego długość bez utraty kluczowych informacji.", + "Extract topics" : "Wyodrębnij tematy", + "Extracts topics from a text and outputs them separated by commas." : "Wyodrębnia tematy z tekstu i wyświetla je oddzielone przecinkami.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Pliki aplikacji %1$s nie zostały poprawnie zastąpione. Upewnij się, że jest to wersja zgodna z serwerem.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Zalogowany użytkownik musi być administratorem, subadministratorem lub mieć specjalne uprawnienia dostępu do tego ustawienia", + "Logged in user must be an admin or sub admin" : "Zalogowany użytkownik musi być administratorem lub współadministratorem", + "Logged in user must be an admin" : "Zalogowany użytkownik musi być administratorem", "Full name" : "Pełna nazwa", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Osiągnięto limit użytkowników i użytkownik nie został utworzony. Sprawdź swoje powiadomienia, aby dowiedzieć się więcej.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "W nazwie użytkownika dozwolone są tylko następujące znaki : \"a-z\", \"A-Z\", \"0-9\" i \"_.@-'\"", + "Unknown user" : "Nieznany użytkownik", + "Enter the database username and name for %s" : "Podaj nazwę użytkownika i nazwę bazy danych dla %s", + "Enter the database username for %s" : "Podaj nazwę użytkownika bazy danych dla %s", + "MySQL username and/or password not valid" : "Błędna nazwa użytkownika i/lub hasło do bazy danych MySQL", + "Oracle username and/or password not valid" : "Zła nazwa użytkownika i/lub hasło do bazy danych Oracle", + "PostgreSQL username and/or password not valid" : "Zła nazwa użytkownika i/lub hasło do bazy danych PostgreSQL", + "Set an admin username." : "Ustaw nazwę administratora.", + "Sharing %s failed, because this item is already shared with user %s" : "Udostępnianie %s nie powiodło się, ponieważ element jest już udostępniony użytkownikowi %s", + "The username is already being used" : "Ta nazwa użytkownika jest już używana", + "Could not create user" : "Nie można utworzyć użytkownika", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "W nazwie użytkownika dozwolone są tylko następujące znaki : \"a-z\", \"A-Z\", \"0-9\", spacje i \"_.@-'\"", + "A valid username must be provided" : "Należy podać prawidłową nazwę użytkownika", + "Username contains whitespace at the beginning or at the end" : "Nazwa użytkownika zawiera spację na początku albo na końcu", + "Username must not consist of dots only" : "Nazwa użytkownika nie może się składać tylko z kropek", + "Username is invalid because files already exist for this user" : "Nazwa użytkownika jest nieprawidłowa, ponieważ pliki już istnieją dla tego użytkownika", + "User disabled" : "Użytkownik zablokowany", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Wymagana wersja dla libxml2 to przynajmniej 2.7.0. Aktualnie zainstalowana jest %s.", "To fix this issue update your libxml2 version and restart your web server." : "Aby rozwiązać ten problem, zaktualizuj wersję libxml2 i ponownie uruchom serwer WWW.", "PostgreSQL >= 9 required." : "Wymagany PostgreSQL >= 9", - "Please upgrade your database version." : "Zaktualizuj wersję bazy danych." + "Please upgrade your database version." : "Zaktualizuj wersję bazy danych.", + "Your data directory is readable by other users." : "Twój katalog danych jest widoczny dla innych użytkowników.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Zmień uprawnienia na 0770, aby katalog nie był widoczny dla innych użytkowników." },"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 4270e0b3192..3b21a523cce 100644 --- a/lib/l10n/pt_BR.js +++ b/lib/l10n/pt_BR.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplicação %1$s não está presente ou possui uma versão não compatível com este servidor. Verifique o diretório de aplicativos.", "Sample configuration detected" : "Configuração de exemplo detectada", "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" : "Foi detectado que a configuração de exemplo foi copiada. Isso pode terminar sua instalação e não é suportado. Por favor leia a documentação antes de realizar mudanças no config.php", - "404" : "404", "The page could not be found on the server." : "A página não pôde ser encontrada no servidor.", "%s email verification" : "%s e-mail de verificação", "Email verification" : "E-mail de verificação", @@ -24,6 +23,7 @@ OC.L10N.register( "Enterprise bundle" : "Pacote Enterprise", "Groupware bundle" : "Pacote Groupware", "Hub bundle" : "Pacote de hub", + "Public sector bundle" : "Pacote do setor público", "Social sharing bundle" : "Pacote de compartilhamento social", "PHP %s or higher is required." : "PHP %s ou superior é necessário.", "PHP with a version lower than %s is required." : "É necessária uma versão PHP mais antiga que a %s.", @@ -37,9 +37,9 @@ OC.L10N.register( "The following platforms are supported: %s" : "As seguintes plataformas são suportadas: %s", "Server version %s or higher is required." : "É requerido um servidor da versão %s ou superior.", "Server version %s or lower is required." : "É requerido um servidor da versão %s ou abaixo.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "O usuário conectado deve ser um administrador, um subadministrador ou ter direito especial para acessar esta configuração", - "Logged in user must be an admin or sub admin" : "O usuário conectado deve ser um administrador ou subadministrador", - "Logged in user must be an admin" : "O usuário conectado deve ser um administrador", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "A conta conectada deve ser um administrador, um subadministrador ou ter direito especial para acessar esta configuração", + "Logged in account must be an admin or sub admin" : "A conta conectada deve ser de um administrador ou subadministrador", + "Logged in account must be an admin" : "A conta logada deve ser de um administrador", "Wiping of device %s has started" : "Limpeza do dispositivo %s iniciou", "Wiping of device »%s« has started" : "A limpeza do dispositivo »%s« terminou", "»%s« started remote wipe" : "»%s« iniciou a limpeza remota", @@ -118,22 +118,22 @@ OC.L10N.register( "Headline" : "Título ", "Organisation" : "Organização", "Role" : "Função", - "Unknown user" : "Usuário desconhecido", + "Unknown account" : "Conta desconhecida", "Additional settings" : "Configurações adicionais", - "Enter the database username and name for %s" : "Digite o nome de usuário e o nome do banco de dados para %s", - "Enter the database username for %s" : "Digite o nome de usuário do banco de dados para %s", + "Enter the database Login and name for %s" : "Insira o login e o nome do banco de dados para %s", + "Enter the database Login for %s" : "Insira o login do banco de dados para %s", "Enter the database name for %s" : "Digite o nome do banco de dados para %s", "You cannot use dots in the database name %s" : "Você não pode usar pontos no nome do banco de dados %s", - "MySQL username and/or password not valid" : "Nome de usuário e/ou senha do MySQL inválidos", + "MySQL Login and/or password not valid" : "Login e/ou senha do MySQL inválidos", "You need to enter details of an existing account." : "Você necessita entrar detalhes de uma conta existente.", "Oracle connection could not be established" : "Conexão Oracle não pôde ser estabelecida", - "Oracle username and/or password not valid" : "Nome de usuário e/ou senha Oracle inválidos", - "PostgreSQL username and/or password not valid" : "Nome de usuário e/ou senha PostgreSQL inválidos", + "Oracle Login and/or password not valid" : "Login e/ou senha Oracle inválidos", + "PostgreSQL Login and/or password not valid" : "Login e/ou senha do PostgreSQL inválidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X não é suportado e %s não funcionará corretamente nesta plataforma. Use-o por sua conta e risco!", "For the best results, please consider using a GNU/Linux server instead." : "Para obter melhores resultados, por favor considere o uso de um servidor GNU/Linux em seu lugar.", "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." : "Aparentemente a instância %s está rodando em um ambiente PHP de 32 bits e o open_basedir foi configurado no php.ini. Isto pode gerar problemas com arquivos maiores que 4GB e é altamente não recomendável.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor, remova a configuração de open_basedir de seu php.ini ou mude o PHP para 64bit.", - "Set an admin username." : "Defina um nome do usuário administrador.", + "Set an admin Login." : "Defina um login de administrador.", "Set an admin password." : "Defina uma senha para o administrador.", "Cannot create or write into the data directory %s" : "Não foi possível criar ou escrever no diretório de dados %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "A plataforma de compartilhamento %s deve implementar a interface OCP\\Share_Backend", @@ -151,11 +151,12 @@ OC.L10N.register( "Expiration date is in the past" : "Data de expiração está no passado", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Não foi possível definir a data de expiração superior que %n dias no futuro","Não foi possível definir a data de expiração superior que %n dias no futuro","Não foi possível definir a data de expiração superior que %n dias no futuro"], "Sharing is only allowed with group members" : "O compartilhamento só é permitido com membros do grupo ", - "Sharing %s failed, because this item is already shared with user %s" : "Compartilhamento %s falhou, porque este item já está compartilhado com o usuário %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Falha no compartilhamento %s porque este item já está compartilhado com a conta %s", "%1$s shared »%2$s« with you" : "%1$s compartilhou »%2$s« com você", "%1$s shared »%2$s« with you." : "%1$s compartilhou »%2$s« com você.", "Click the button below to open it." : "Clique no botão abaixo para abri-lo.", "The requested share does not exist anymore" : "O compartilhamento solicitado não existe mais", + "The requested share comes from a disabled user" : "O compartilhamento solicitado vem de um usuário desabilitado", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "O usuário não foi criado porque o limite de usuários foi atingido. Confira suas notificações para saber mais.", "Could not find category \"%s\"" : "Impossível localizar a categoria \"%s\"", "Sunday" : "Domingo", @@ -204,14 +205,14 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dez.", "A valid password must be provided" : "Uma senha válida deve ser fornecida", - "The username is already being used" : "Este nome de usuário já está em uso", - "Could not create user" : "Não foi possível criar o usuário", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Apenas os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", espaços e \"_.@-'\"", - "A valid username must be provided" : "Um nome de usuário válido deve ser fornecido", - "Username contains whitespace at the beginning or at the end" : "O nome de usuário contém espaço em branco no início ou no fim", - "Username must not consist of dots only" : "Nome do usuário não pode consistir de pontos somente", - "Username is invalid because files already exist for this user" : "O nome de usuário é inválido porque já exstem arquivos para este usuário", - "User disabled" : "Usuário desativado", + "The Login is already being used" : "O Login já está sendo usado", + "Could not create account" : "Não foi possível criar a conta", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Somente os seguintes caracteres são permitidos em um Login: \"a-z\", \"A-Z\", \"0-9\", espaços e \"_.@-'\"", + "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 em pontos", + "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", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "O aplicativo \"%1$s\" não pode ser instalado devido à estas dependências: %2$s", "a safe home for all your data" : "Um lar seguro para todos os seus dados", @@ -244,8 +245,8 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Por favor peça ao administrador do servidor para reiniciar o servidor web.", "The required %s config variable is not configured in the config.php file." : "A variável %s de configuração necessária não está configurada no arquivo config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Peça ao administrador do servidor para verificar a configuração do Nextcloud.", - "Your data directory is readable by other users." : "Seu diretório de dados pode ser lido por outros usuários.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que o diretório não possa ser lido por outros usuários.", + "Your data directory is readable by other people." : "Seu diretório de dados pode ser lido por outras pessoas.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Altere as permissões para 0770 para que o diretório não possa ser listado por outras pessoas.", "Your data directory must be an absolute path." : "Seu diretório de dados deve ser um caminho absoluto.", "Check the value of \"datadirectory\" in your configuration." : "Verifique o valor de \"datadirectory\" em sua configuração.", "Your data directory is invalid." : "Seu diretório de dados é inválido.", @@ -270,12 +271,32 @@ OC.L10N.register( "Extract topics" : "Extrair tópicos", "Extracts topics from a text and outputs them separated by commas." : "Extrai tópicos de um texto e os gera separados por vírgulas.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Os arquivos do aplicativo %1$s não foram instalados corretamente. Certifique-se que é uma versão compatível com seu servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "O usuário conectado deve ser um administrador, um subadministrador ou ter direito especial para acessar esta configuração", + "Logged in user must be an admin or sub admin" : "O usuário conectado deve ser um administrador ou subadministrador", + "Logged in user must be an admin" : "O usuário conectado deve ser um administrador", "Full name" : "Nome completo ", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "O limite de usuários foi atingido e o usuário não foi criado. Verifique suas notificações para saber mais.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Somente os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"", + "Unknown user" : "Usuário desconhecido", + "Enter the database username and name for %s" : "Digite o nome de usuário e o nome do banco de dados para %s", + "Enter the database username for %s" : "Digite o nome de usuário do banco de dados para %s", + "MySQL username and/or password not valid" : "Nome de usuário e/ou senha do MySQL inválidos", + "Oracle username and/or password not valid" : "Nome de usuário e/ou senha Oracle inválidos", + "PostgreSQL username and/or password not valid" : "Nome de usuário e/ou senha PostgreSQL inválidos", + "Set an admin username." : "Defina um nome do usuário administrador.", + "Sharing %s failed, because this item is already shared with user %s" : "Compartilhamento %s falhou, porque este item já está compartilhado com o usuário %s", + "The username is already being used" : "Este nome de usuário já está em uso", + "Could not create user" : "Não foi possível criar o usuário", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Apenas os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", espaços e \"_.@-'\"", + "A valid username must be provided" : "Um nome de usuário válido deve ser fornecido", + "Username contains whitespace at the beginning or at the end" : "O nome de usuário contém espaço em branco no início ou no fim", + "Username must not consist of dots only" : "Nome do usuário não pode consistir de pontos somente", + "Username is invalid because files already exist for this user" : "O nome de usuário é inválido porque já exstem arquivos para este usuário", + "User disabled" : "Usuário desativado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "A libxml2 2.7.0 é a versão mínima necessária. Atualmente a versão %s está instalada.", "To fix this issue update your libxml2 version and restart your web server." : "Para corrigir este problema, atualize a versão da sua libxml2 e reinicie seu servidor web.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 é necessário.", - "Please upgrade your database version." : "Por favor, atualize a versão do seu banco de dados." + "Please upgrade your database version." : "Por favor, atualize a versão do seu banco de dados.", + "Your data directory is readable by other users." : "Seu diretório de dados pode ser lido por outros usuários.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que o diretório não possa ser lido por outros usuários." }, "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 edb7e705072..0c14c1e32fa 100644 --- a/lib/l10n/pt_BR.json +++ b/lib/l10n/pt_BR.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplicação %1$s não está presente ou possui uma versão não compatível com este servidor. Verifique o diretório de aplicativos.", "Sample configuration detected" : "Configuração de exemplo detectada", "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" : "Foi detectado que a configuração de exemplo foi copiada. Isso pode terminar sua instalação e não é suportado. Por favor leia a documentação antes de realizar mudanças no config.php", - "404" : "404", "The page could not be found on the server." : "A página não pôde ser encontrada no servidor.", "%s email verification" : "%s e-mail de verificação", "Email verification" : "E-mail de verificação", @@ -22,6 +21,7 @@ "Enterprise bundle" : "Pacote Enterprise", "Groupware bundle" : "Pacote Groupware", "Hub bundle" : "Pacote de hub", + "Public sector bundle" : "Pacote do setor público", "Social sharing bundle" : "Pacote de compartilhamento social", "PHP %s or higher is required." : "PHP %s ou superior é necessário.", "PHP with a version lower than %s is required." : "É necessária uma versão PHP mais antiga que a %s.", @@ -35,9 +35,9 @@ "The following platforms are supported: %s" : "As seguintes plataformas são suportadas: %s", "Server version %s or higher is required." : "É requerido um servidor da versão %s ou superior.", "Server version %s or lower is required." : "É requerido um servidor da versão %s ou abaixo.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "O usuário conectado deve ser um administrador, um subadministrador ou ter direito especial para acessar esta configuração", - "Logged in user must be an admin or sub admin" : "O usuário conectado deve ser um administrador ou subadministrador", - "Logged in user must be an admin" : "O usuário conectado deve ser um administrador", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "A conta conectada deve ser um administrador, um subadministrador ou ter direito especial para acessar esta configuração", + "Logged in account must be an admin or sub admin" : "A conta conectada deve ser de um administrador ou subadministrador", + "Logged in account must be an admin" : "A conta logada deve ser de um administrador", "Wiping of device %s has started" : "Limpeza do dispositivo %s iniciou", "Wiping of device »%s« has started" : "A limpeza do dispositivo »%s« terminou", "»%s« started remote wipe" : "»%s« iniciou a limpeza remota", @@ -116,22 +116,22 @@ "Headline" : "Título ", "Organisation" : "Organização", "Role" : "Função", - "Unknown user" : "Usuário desconhecido", + "Unknown account" : "Conta desconhecida", "Additional settings" : "Configurações adicionais", - "Enter the database username and name for %s" : "Digite o nome de usuário e o nome do banco de dados para %s", - "Enter the database username for %s" : "Digite o nome de usuário do banco de dados para %s", + "Enter the database Login and name for %s" : "Insira o login e o nome do banco de dados para %s", + "Enter the database Login for %s" : "Insira o login do banco de dados para %s", "Enter the database name for %s" : "Digite o nome do banco de dados para %s", "You cannot use dots in the database name %s" : "Você não pode usar pontos no nome do banco de dados %s", - "MySQL username and/or password not valid" : "Nome de usuário e/ou senha do MySQL inválidos", + "MySQL Login and/or password not valid" : "Login e/ou senha do MySQL inválidos", "You need to enter details of an existing account." : "Você necessita entrar detalhes de uma conta existente.", "Oracle connection could not be established" : "Conexão Oracle não pôde ser estabelecida", - "Oracle username and/or password not valid" : "Nome de usuário e/ou senha Oracle inválidos", - "PostgreSQL username and/or password not valid" : "Nome de usuário e/ou senha PostgreSQL inválidos", + "Oracle Login and/or password not valid" : "Login e/ou senha Oracle inválidos", + "PostgreSQL Login and/or password not valid" : "Login e/ou senha do PostgreSQL inválidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X não é suportado e %s não funcionará corretamente nesta plataforma. Use-o por sua conta e risco!", "For the best results, please consider using a GNU/Linux server instead." : "Para obter melhores resultados, por favor considere o uso de um servidor GNU/Linux em seu lugar.", "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." : "Aparentemente a instância %s está rodando em um ambiente PHP de 32 bits e o open_basedir foi configurado no php.ini. Isto pode gerar problemas com arquivos maiores que 4GB e é altamente não recomendável.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor, remova a configuração de open_basedir de seu php.ini ou mude o PHP para 64bit.", - "Set an admin username." : "Defina um nome do usuário administrador.", + "Set an admin Login." : "Defina um login de administrador.", "Set an admin password." : "Defina uma senha para o administrador.", "Cannot create or write into the data directory %s" : "Não foi possível criar ou escrever no diretório de dados %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "A plataforma de compartilhamento %s deve implementar a interface OCP\\Share_Backend", @@ -149,11 +149,12 @@ "Expiration date is in the past" : "Data de expiração está no passado", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Não foi possível definir a data de expiração superior que %n dias no futuro","Não foi possível definir a data de expiração superior que %n dias no futuro","Não foi possível definir a data de expiração superior que %n dias no futuro"], "Sharing is only allowed with group members" : "O compartilhamento só é permitido com membros do grupo ", - "Sharing %s failed, because this item is already shared with user %s" : "Compartilhamento %s falhou, porque este item já está compartilhado com o usuário %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Falha no compartilhamento %s porque este item já está compartilhado com a conta %s", "%1$s shared »%2$s« with you" : "%1$s compartilhou »%2$s« com você", "%1$s shared »%2$s« with you." : "%1$s compartilhou »%2$s« com você.", "Click the button below to open it." : "Clique no botão abaixo para abri-lo.", "The requested share does not exist anymore" : "O compartilhamento solicitado não existe mais", + "The requested share comes from a disabled user" : "O compartilhamento solicitado vem de um usuário desabilitado", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "O usuário não foi criado porque o limite de usuários foi atingido. Confira suas notificações para saber mais.", "Could not find category \"%s\"" : "Impossível localizar a categoria \"%s\"", "Sunday" : "Domingo", @@ -202,14 +203,14 @@ "Nov." : "Nov.", "Dec." : "Dez.", "A valid password must be provided" : "Uma senha válida deve ser fornecida", - "The username is already being used" : "Este nome de usuário já está em uso", - "Could not create user" : "Não foi possível criar o usuário", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Apenas os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", espaços e \"_.@-'\"", - "A valid username must be provided" : "Um nome de usuário válido deve ser fornecido", - "Username contains whitespace at the beginning or at the end" : "O nome de usuário contém espaço em branco no início ou no fim", - "Username must not consist of dots only" : "Nome do usuário não pode consistir de pontos somente", - "Username is invalid because files already exist for this user" : "O nome de usuário é inválido porque já exstem arquivos para este usuário", - "User disabled" : "Usuário desativado", + "The Login is already being used" : "O Login já está sendo usado", + "Could not create account" : "Não foi possível criar a conta", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Somente os seguintes caracteres são permitidos em um Login: \"a-z\", \"A-Z\", \"0-9\", espaços e \"_.@-'\"", + "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 em pontos", + "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", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "O aplicativo \"%1$s\" não pode ser instalado devido à estas dependências: %2$s", "a safe home for all your data" : "Um lar seguro para todos os seus dados", @@ -242,8 +243,8 @@ "Please ask your server administrator to restart the web server." : "Por favor peça ao administrador do servidor para reiniciar o servidor web.", "The required %s config variable is not configured in the config.php file." : "A variável %s de configuração necessária não está configurada no arquivo config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Peça ao administrador do servidor para verificar a configuração do Nextcloud.", - "Your data directory is readable by other users." : "Seu diretório de dados pode ser lido por outros usuários.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que o diretório não possa ser lido por outros usuários.", + "Your data directory is readable by other people." : "Seu diretório de dados pode ser lido por outras pessoas.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Altere as permissões para 0770 para que o diretório não possa ser listado por outras pessoas.", "Your data directory must be an absolute path." : "Seu diretório de dados deve ser um caminho absoluto.", "Check the value of \"datadirectory\" in your configuration." : "Verifique o valor de \"datadirectory\" em sua configuração.", "Your data directory is invalid." : "Seu diretório de dados é inválido.", @@ -268,12 +269,32 @@ "Extract topics" : "Extrair tópicos", "Extracts topics from a text and outputs them separated by commas." : "Extrai tópicos de um texto e os gera separados por vírgulas.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Os arquivos do aplicativo %1$s não foram instalados corretamente. Certifique-se que é uma versão compatível com seu servidor.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "O usuário conectado deve ser um administrador, um subadministrador ou ter direito especial para acessar esta configuração", + "Logged in user must be an admin or sub admin" : "O usuário conectado deve ser um administrador ou subadministrador", + "Logged in user must be an admin" : "O usuário conectado deve ser um administrador", "Full name" : "Nome completo ", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "O limite de usuários foi atingido e o usuário não foi criado. Verifique suas notificações para saber mais.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Somente os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"", + "Unknown user" : "Usuário desconhecido", + "Enter the database username and name for %s" : "Digite o nome de usuário e o nome do banco de dados para %s", + "Enter the database username for %s" : "Digite o nome de usuário do banco de dados para %s", + "MySQL username and/or password not valid" : "Nome de usuário e/ou senha do MySQL inválidos", + "Oracle username and/or password not valid" : "Nome de usuário e/ou senha Oracle inválidos", + "PostgreSQL username and/or password not valid" : "Nome de usuário e/ou senha PostgreSQL inválidos", + "Set an admin username." : "Defina um nome do usuário administrador.", + "Sharing %s failed, because this item is already shared with user %s" : "Compartilhamento %s falhou, porque este item já está compartilhado com o usuário %s", + "The username is already being used" : "Este nome de usuário já está em uso", + "Could not create user" : "Não foi possível criar o usuário", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Apenas os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", espaços e \"_.@-'\"", + "A valid username must be provided" : "Um nome de usuário válido deve ser fornecido", + "Username contains whitespace at the beginning or at the end" : "O nome de usuário contém espaço em branco no início ou no fim", + "Username must not consist of dots only" : "Nome do usuário não pode consistir de pontos somente", + "Username is invalid because files already exist for this user" : "O nome de usuário é inválido porque já exstem arquivos para este usuário", + "User disabled" : "Usuário desativado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "A libxml2 2.7.0 é a versão mínima necessária. Atualmente a versão %s está instalada.", "To fix this issue update your libxml2 version and restart your web server." : "Para corrigir este problema, atualize a versão da sua libxml2 e reinicie seu servidor web.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 é necessário.", - "Please upgrade your database version." : "Por favor, atualize a versão do seu banco de dados." + "Please upgrade your database version." : "Por favor, atualize a versão do seu banco de dados.", + "Your data directory is readable by other users." : "Seu diretório de dados pode ser lido por outros usuários.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que o diretório não possa ser lido por outros usuários." },"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 c30c214db40..f46eadf7fa3 100644 --- a/lib/l10n/pt_PT.js +++ b/lib/l10n/pt_PT.js @@ -29,8 +29,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "As seguintes plataformas são suportadas: %s", "Server version %s or higher is required." : "É necessária versão do servidor %s or superior. ", "Server version %s or lower is required." : "É necessária versão do servidor %s or inferior.", - "Logged in user must be an admin or sub admin" : "O utilizador autenticado tem de ser um administrador ou subadministrador", - "Logged in user must be an admin" : "O utilizador autenticado tem de ser um administrador", "Authentication" : "Autenticação", "Unknown filetype" : "Tipo de ficheiro desconhecido", "Invalid image" : "Imagem inválida", @@ -91,17 +89,13 @@ OC.L10N.register( "Headline" : "Título ", "Organisation" : "Organização", "Role" : "Função", - "Unknown user" : "Utilizador desconhecido", "Additional settings" : "Definições adicionais", "You need to enter details of an existing account." : "Precisa de introduzir detalhes de uma conta existente.", "Oracle connection could not be established" : "Não foi possível estabelecer a ligação Oracle", - "Oracle username and/or password not valid" : "Nome de utilizador/palavra-passe do Oracle inválidos", - "PostgreSQL username and/or password not valid" : "Nome de utilizador/password do PostgreSQL inválidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Esta plataforma não suporta o sistema operativo Mac OS X e o %s poderá não funcionar correctamente. Utilize por sua conta e risco.", "For the best results, please consider using a GNU/Linux server instead." : "Para um melhor resultado, utilize antes o servidor 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." : "Parece que a instância %s está a ser executada num ambiente PHP de 32-bits e o open_basedir foi configurado no php.ini. Isto levará a problemas com ficheiros de tamanho superior a 4 GB e é altamente desencorajado.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor, remova a definição open_basedir do seu php.ini ou altere o seu PHP para 64-bits.", - "Set an admin username." : "Definir um nome de utilizador de administrador", "Set an admin password." : "Definia uma palavra-passe de administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Ao partilhar a interface %s deve implementar a interface OCP\\Share_Backend", "Sharing backend %s not found" : "Não foi encontrada a partilha da interface %s", @@ -114,7 +108,6 @@ OC.L10N.register( "You are not allowed to share %s" : "Não está autorizado a partilhar %s", "Cannot increase permissions of %s" : "Não é possível aumentar as permissões de %s", "Expiration date is in the past" : "A data de expiração está no passado", - "Sharing %s failed, because this item is already shared with user %s" : "A partilha de %s falhou, porque este item já está a ser partilhado com o utilizador %s", "%1$s shared »%2$s« with you" : "%1$s partilhado »%2$s« contigo", "%1$s shared »%2$s« with you." : "%1$s partilhado »%2$s« contigo.", "Click the button below to open it." : "Clicar no botão abaixo para abrir.", @@ -166,12 +159,6 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dez.", "A valid password must be provided" : "Deve ser fornecida uma palavra-passe válida", - "The username is already being used" : "O nome de utilizador já está a ser usado", - "Could not create user" : "Não foi possível criar o utilizador", - "A valid username must be provided" : "Um nome de utilizador válido deve ser fornecido", - "Username contains whitespace at the beginning or at the end" : "Nome de utilizador contém espaço em branco no início ou no fim", - "Username must not consist of dots only" : "O utilizador não pode consistir de apenas pontos", - "User disabled" : "Utilizador desativado", "Login canceled by app" : "Sessão cancelada pela app", "a safe home for all your data" : "Um lugar seguro para todos os seus dados", "File is currently busy, please try again later" : "O ficheiro está ocupado, por favor, tente mais tarde", @@ -189,7 +176,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isto é provavelmente causado por uma cache/acelerador como o Zend OPcache or eAcelerador.", "PHP modules have been installed, but they are still listed as missing?" : "Os módulos PHP foram instalados, mas eles ainda estão listados como desaparecidos?", "Please ask your server administrator to restart the web server." : "Pro favor pergunte ao seu administrador do servidor para reiniciar o servidor da internet.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que esse directório não possa ser listado por outros utilizadores.", "Your data directory is invalid." : "A sua diretoria de dados é inválida.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Garanta que existe um ficheiro chamado \".occdata\" na raiz do directório de dados", "Action \"%s\" not supported or implemented." : "Ação \"%s\" não suportada ou implementada.", @@ -199,11 +185,24 @@ OC.L10N.register( "Storage connection error. %s" : "Erro de ligação ao armazenamento. %s", "Storage is temporarily not available" : "Armazenamento temporariamente indisponível", "Storage connection timeout. %s" : "Tempo de ligação ao armazenamento expirou. %s", + "Logged in user must be an admin or sub admin" : "O utilizador autenticado tem de ser um administrador ou subadministrador", + "Logged in user must be an admin" : "O utilizador autenticado tem de ser um administrador", "Full name" : "Nome completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Apenas os seguintes caracteres são permitidos num nome de utilizador: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"", + "Unknown user" : "Utilizador desconhecido", + "Oracle username and/or password not valid" : "Nome de utilizador/palavra-passe do Oracle inválidos", + "PostgreSQL username and/or password not valid" : "Nome de utilizador/password do PostgreSQL inválidos", + "Set an admin username." : "Definir um nome de utilizador de administrador", + "Sharing %s failed, because this item is already shared with user %s" : "A partilha de %s falhou, porque este item já está a ser partilhado com o utilizador %s", + "The username is already being used" : "O nome de utilizador já está a ser usado", + "Could not create user" : "Não foi possível criar o utilizador", + "A valid username must be provided" : "Um nome de utilizador válido deve ser fornecido", + "Username contains whitespace at the beginning or at the end" : "Nome de utilizador contém espaço em branco no início ou no fim", + "Username must not consist of dots only" : "O utilizador não pode consistir de apenas pontos", + "User disabled" : "Utilizador desativado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Necessária pelo menos libxml2 2.7.0. Atualmente %s está instalada.", "To fix this issue update your libxml2 version and restart your web server." : "Para corrigir este problema actualize a versão da libxml2 e reinicie o seu servidor web.", "PostgreSQL >= 9 required." : "Necessário PostgreSQL >= 9", - "Please upgrade your database version." : "Por favor, atualize a sua versão da base de dados" + "Please upgrade your database version." : "Por favor, atualize a sua versão da base de dados", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que esse directório não possa ser listado por outros utilizadores." }, "nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/lib/l10n/pt_PT.json b/lib/l10n/pt_PT.json index a2df26d40e8..7648acae2bf 100644 --- a/lib/l10n/pt_PT.json +++ b/lib/l10n/pt_PT.json @@ -27,8 +27,6 @@ "The following platforms are supported: %s" : "As seguintes plataformas são suportadas: %s", "Server version %s or higher is required." : "É necessária versão do servidor %s or superior. ", "Server version %s or lower is required." : "É necessária versão do servidor %s or inferior.", - "Logged in user must be an admin or sub admin" : "O utilizador autenticado tem de ser um administrador ou subadministrador", - "Logged in user must be an admin" : "O utilizador autenticado tem de ser um administrador", "Authentication" : "Autenticação", "Unknown filetype" : "Tipo de ficheiro desconhecido", "Invalid image" : "Imagem inválida", @@ -89,17 +87,13 @@ "Headline" : "Título ", "Organisation" : "Organização", "Role" : "Função", - "Unknown user" : "Utilizador desconhecido", "Additional settings" : "Definições adicionais", "You need to enter details of an existing account." : "Precisa de introduzir detalhes de uma conta existente.", "Oracle connection could not be established" : "Não foi possível estabelecer a ligação Oracle", - "Oracle username and/or password not valid" : "Nome de utilizador/palavra-passe do Oracle inválidos", - "PostgreSQL username and/or password not valid" : "Nome de utilizador/password do PostgreSQL inválidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Esta plataforma não suporta o sistema operativo Mac OS X e o %s poderá não funcionar correctamente. Utilize por sua conta e risco.", "For the best results, please consider using a GNU/Linux server instead." : "Para um melhor resultado, utilize antes o servidor 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." : "Parece que a instância %s está a ser executada num ambiente PHP de 32-bits e o open_basedir foi configurado no php.ini. Isto levará a problemas com ficheiros de tamanho superior a 4 GB e é altamente desencorajado.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Por favor, remova a definição open_basedir do seu php.ini ou altere o seu PHP para 64-bits.", - "Set an admin username." : "Definir um nome de utilizador de administrador", "Set an admin password." : "Definia uma palavra-passe de administrador.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Ao partilhar a interface %s deve implementar a interface OCP\\Share_Backend", "Sharing backend %s not found" : "Não foi encontrada a partilha da interface %s", @@ -112,7 +106,6 @@ "You are not allowed to share %s" : "Não está autorizado a partilhar %s", "Cannot increase permissions of %s" : "Não é possível aumentar as permissões de %s", "Expiration date is in the past" : "A data de expiração está no passado", - "Sharing %s failed, because this item is already shared with user %s" : "A partilha de %s falhou, porque este item já está a ser partilhado com o utilizador %s", "%1$s shared »%2$s« with you" : "%1$s partilhado »%2$s« contigo", "%1$s shared »%2$s« with you." : "%1$s partilhado »%2$s« contigo.", "Click the button below to open it." : "Clicar no botão abaixo para abrir.", @@ -164,12 +157,6 @@ "Nov." : "Nov.", "Dec." : "Dez.", "A valid password must be provided" : "Deve ser fornecida uma palavra-passe válida", - "The username is already being used" : "O nome de utilizador já está a ser usado", - "Could not create user" : "Não foi possível criar o utilizador", - "A valid username must be provided" : "Um nome de utilizador válido deve ser fornecido", - "Username contains whitespace at the beginning or at the end" : "Nome de utilizador contém espaço em branco no início ou no fim", - "Username must not consist of dots only" : "O utilizador não pode consistir de apenas pontos", - "User disabled" : "Utilizador desativado", "Login canceled by app" : "Sessão cancelada pela app", "a safe home for all your data" : "Um lugar seguro para todos os seus dados", "File is currently busy, please try again later" : "O ficheiro está ocupado, por favor, tente mais tarde", @@ -187,7 +174,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Isto é provavelmente causado por uma cache/acelerador como o Zend OPcache or eAcelerador.", "PHP modules have been installed, but they are still listed as missing?" : "Os módulos PHP foram instalados, mas eles ainda estão listados como desaparecidos?", "Please ask your server administrator to restart the web server." : "Pro favor pergunte ao seu administrador do servidor para reiniciar o servidor da internet.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que esse directório não possa ser listado por outros utilizadores.", "Your data directory is invalid." : "A sua diretoria de dados é inválida.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Garanta que existe um ficheiro chamado \".occdata\" na raiz do directório de dados", "Action \"%s\" not supported or implemented." : "Ação \"%s\" não suportada ou implementada.", @@ -197,11 +183,24 @@ "Storage connection error. %s" : "Erro de ligação ao armazenamento. %s", "Storage is temporarily not available" : "Armazenamento temporariamente indisponível", "Storage connection timeout. %s" : "Tempo de ligação ao armazenamento expirou. %s", + "Logged in user must be an admin or sub admin" : "O utilizador autenticado tem de ser um administrador ou subadministrador", + "Logged in user must be an admin" : "O utilizador autenticado tem de ser um administrador", "Full name" : "Nome completo", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Apenas os seguintes caracteres são permitidos num nome de utilizador: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"", + "Unknown user" : "Utilizador desconhecido", + "Oracle username and/or password not valid" : "Nome de utilizador/palavra-passe do Oracle inválidos", + "PostgreSQL username and/or password not valid" : "Nome de utilizador/password do PostgreSQL inválidos", + "Set an admin username." : "Definir um nome de utilizador de administrador", + "Sharing %s failed, because this item is already shared with user %s" : "A partilha de %s falhou, porque este item já está a ser partilhado com o utilizador %s", + "The username is already being used" : "O nome de utilizador já está a ser usado", + "Could not create user" : "Não foi possível criar o utilizador", + "A valid username must be provided" : "Um nome de utilizador válido deve ser fornecido", + "Username contains whitespace at the beginning or at the end" : "Nome de utilizador contém espaço em branco no início ou no fim", + "Username must not consist of dots only" : "O utilizador não pode consistir de apenas pontos", + "User disabled" : "Utilizador desativado", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Necessária pelo menos libxml2 2.7.0. Atualmente %s está instalada.", "To fix this issue update your libxml2 version and restart your web server." : "Para corrigir este problema actualize a versão da libxml2 e reinicie o seu servidor web.", "PostgreSQL >= 9 required." : "Necessário PostgreSQL >= 9", - "Please upgrade your database version." : "Por favor, atualize a sua versão da base de dados" + "Please upgrade your database version." : "Por favor, atualize a sua versão da base de dados", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Por favor altere as permissões para 0770 para que esse directório não possa ser listado por outros utilizadores." },"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/ro.js b/lib/l10n/ro.js index d08182f5786..ecc02d047ca 100644 --- a/lib/l10n/ro.js +++ b/lib/l10n/ro.js @@ -2,75 +2,148 @@ OC.L10N.register( "lib", { "Cannot write into \"config\" directory!" : "Nu se poate scrie în folderul \"config\"!", + "This can usually be fixed by giving the web server write access to the config directory." : "Aceasta se poate rezolva de obicei dând acces în scriere serverului în directorul configurației.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Dar, dacă preferați să păstrați config.php doar în citire, setați opțiunea \"config_is_read_only\" ca true.", "See %s" : "Vezi %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplicația %1$s nu este prezentă sau are o versiune incompatibilă cu acest server. Verificați directorul aplicațiilor.", "Sample configuration detected" : "A fost detectată o configurație exemplu", "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" : "S-a detectat copierea configurației exemplu. Acest lucru poate duce la oprirea instanței tale și nu este suportat. Te rugăm să citești documentația înainte de a face modificări în fișierul config.php", + "The page could not be found on the server." : "Pagina nu a fost găsită.", + "%s email verification" : "%s verificare email", + "Email verification" : "Verificare email", + "Click the following button to confirm your email." : "Apăsați butonul următor pentru confirmare email.", + "Click the following link to confirm your email." : "Click pe linkul următor pentru confirmare email.", + "Confirm your email" : "Confirmați emailul", "Other activities" : "Alte activități", "%1$s and %2$s" : "%1$s și %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s și %3$s", "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s și %4$s", "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s și %5$s", + "Education Edition" : "Ediția pentru educație", + "Enterprise bundle" : "Pachetul enterprise", + "Groupware bundle" : "Pachetul Groupware", + "Hub bundle" : "Pachetul central", + "Social sharing bundle" : "Pachetul de partajare", "PHP %s or higher is required." : "Versiunea PHP %s sau mai mare este necesară.", "PHP with a version lower than %s is required." : "Este necesară o versiune PHP mai mică decât %s", "%sbit or higher PHP required." : "Este necesar PHP %sbit sau mai mare.", + "The following architectures are supported: %s" : "Sunt suportate următoarele arhitecturi: %s", + "The following databases are supported: %s" : "Sunt suportate următoarele baze de date: %s", "The command line tool %s could not be found" : "Unealta în linie de comandă %s nu a fost găsită", "The library %s is not available." : "Biblioteca %s nu este disponibilă.", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Biblioteca %1$s cu o versiune superioară %2$s este necesară - versiunea disponibilă %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Biblioteca %1$s cu o versiune inferioară %2$s este necesară - versiunea disponibilă %3$s.", + "The following platforms are supported: %s" : "Sunt suportate următoarele platforme: %s", + "Server version %s or higher is required." : "Este necesară versiunea %s a serverului sau superioară.", + "Server version %s or lower is required." : "Este necesară versiunea %s a serverului, sau inferioară.", + "Wiping of device %s has started" : "A început curățarea dispozitivului %s ", + "Wiping of device »%s« has started" : "A început curățarea dispozitivului »%s« ", + "»%s« started remote wipe" : "»%s« a pornit curățarea la distanță", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "Dispozitivul sau aplicația »%s« a inițiat procesul de ștergere la distanță. Veți primi un alt mail când procesul se va finaliza", + "Wiping of device %s has finished" : "Curățarea dispozitivului %s s-a finalizat", + "Wiping of device »%s« has finished" : "Curățarea dispozitivului »%s« s-a finalizat", + "»%s« finished remote wipe" : "»%s« a finalizat curățarea la distanță", + "Device or application »%s« has finished the remote wipe process." : "Dispozitivul sau aplicația »%s« a finalizat procesul de curățare la distanță.", + "Remote wipe started" : "Curățarea la distanță a fost inițiată", + "A remote wipe was started on device %s" : "A fost inițiată o curățare la distanță a dispozitivului %s", + "Remote wipe finished" : "Curățarea la distanță a fost finalizată", + "The remote wipe on %s has finished" : "Curățarea la distanță a %s a fost finalizată", "Authentication" : "Autentificare", "Unknown filetype" : "Tip fișier necunoscut", "Invalid image" : "Imagine invalidă", + "Avatar image is not square" : "Imaginea de avatar nu este pătrată", "Files" : "Fișiere", "View profile" : "Vezi profilul", "Local time: %s" : "Timp local: %s", "today" : "astăzi", "tomorrow" : "mâine", "yesterday" : "ieri", - "_%n day ago_::_%n days ago_" : ["Acum o zi","Acum %n zile","Acum %n zile"], + "_in %n day_::_in %n days_" : ["în %n zi","în %n zile","în %n zile"], + "_%n day ago_::_%n days ago_" : ["%n zi în rumă","Acum %n zile","Acum %n zile"], "next month" : "luna viitoare", "last month" : "ultima lună", + "_in %n month_::_in %n months_" : ["în %n lună","în %n luni","în %n luni"], "_%n month ago_::_%n months ago_" : ["%n lună în urmă","%n luni în urmă","%n luni în urmă"], "next year" : "anul viitor", "last year" : "ultimul an", + "_in %n year_::_in %n years_" : ["în %n an","în %n ani","în %n ani"], "_%n year ago_::_%n years ago_" : ["%n an în urmă","%n ani în urmâ","%n ani în urmâ"], + "_in %n hour_::_in %n hours_" : ["în %n oră","în %n ore","în %n ore"], "_%n hour ago_::_%n hours ago_" : ["%n oră în urmă","%n ore în urmă","%n ore în urmă"], + "_in %n minute_::_in %n minutes_" : ["în %n minut","în %n minute","în %n minute"], + "_%n minute ago_::_%n minutes ago_" : ["%n minut în urmă","%n minute în urmă","%n minute în urmă"], "in a few seconds" : "în câteva secunde", "seconds ago" : "secunde în urmă", + "Empty file" : "Fișier gol", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Modulul cu ID: %s nu există. Activați-l din setările aplicației sau contactați administratorul.", "File already exists" : "Fișierul există deja", + "Invalid path" : "Cale invalidă", + "Failed to create file from template" : "Eroare la crearea fișierului pe baza șablonului", "Templates" : "Șabloane", "File name is a reserved word" : "Numele fișierului este un cuvânt rezervat", "File name contains at least one invalid character" : "Numele fișierului conține cel puțin un caracter invalid", "File name is too long" : "Numele fișierului este prea lung", "Dot files are not allowed" : "Fișierele care încep cu caracterul punct nu sunt permise", "Empty filename is not allowed" : "Nu este permis fișier fără nume", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "Aplicația \"%s\" nu poate fi instalată deoarece fișierul appinfo nu poate fi citit.", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Aplicația \"%s\" nu poate fi instalată deoarece nu este compatibilă cu versiunea serverului.", "__language_name__" : "Română", + "This is an automatically sent email, please do not reply." : "Acesta este un email automat, nu răspundeți.", "Help" : "Ajutor", + "Appearance and accessibility" : "Aspect și accesibilitate", "Apps" : "Aplicații", + "Personal settings" : "Setări personale", + "Administration settings" : "Setări de administrare", "Settings" : "Setări", "Log out" : "Ieșire", "Users" : "Utilizatori", "Email" : "E-mail", + "View %s on the fediverse" : "Vedeți %s pe fediverse", "Phone" : "Telefon", + "Call %s" : "Apel %s", "Twitter" : "Twitter", + "View %s on Twitter" : "Vedeți %s pe X", "Website" : "Site web", + "Visit %s" : "Vizitați %s", "Address" : "Adresă", "Profile picture" : "Imagine de profil", "About" : "Despre", + "Display name" : "Nume afișat", + "Headline" : "Titlu", + "Organisation" : "Organizație", "Role" : "Rol", - "Unknown user" : "Utilizator necunoscut", "Additional settings" : "Setări adiționale", + "Enter the database name for %s" : "Introduceți numele bazei de date pentru %s", + "You cannot use dots in the database name %s" : "Nu puteți folosi puncte în numele bazei de date %s", + "You need to enter details of an existing account." : "Sunt necesare detaliile unui cont existent.", "Oracle connection could not be established" : "Conexiunea Oracle nu a putut fi stabilită", - "Oracle username and/or password not valid" : "Numele de utilizator sau / și parola Oracle nu sunt valide", - "PostgreSQL username and/or password not valid" : "Nume utilizator și/sau parolă PostgreSQL greșită", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X nu este suportat și %s nu va funcționa corect pe această platformă. Continuați pe propriul risc! ", "For the best results, please consider using a GNU/Linux server instead." : "Pentru cele mai bune rezultate, ia în calcul folosirea unui server care rulează un sistem de operare GNU/Linux.", - "Set an admin username." : "Setează un nume de administrator.", + "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." : "Se pare că această instanță a %s rulează o versiune 32-bit a PHP și open_basedir a fost configurat în php.ini. Aceasta va conduce la probleme cu fișierele mai mari de 4 GB și nu este deloc recomandată.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Eliminați setarea open_basedir din php.ini utilizați versiunea 64-bit a PHP.", "Set an admin password." : "Setează o parolă de administrator.", + "Cannot create or write into the data directory %s" : "Nu se poate crea sau scrie în dosarul pentru date %s", + "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Backend-ul de partajare %s trebuie să implementeze interfața OCP\\Share_Backend", + "Sharing backend %s not found" : "Backend-ul de partajare %s nu există", + "Sharing backend for %s not found" : "Backend-ul de partajare pentru %s nu a fost găsit", + "%1$s shared »%2$s« with you and wants to add:" : "%1$s a partajat »%2$s« cu tine și vrea să adauge:", + "%1$s shared »%2$s« with you and wants to add" : "%1$s a partajat »%2$s« cu tine și vrea să adauge", "»%s« added a note to a file shared with you" : "%s« a adaugat un comentariu la un fișier partajat cu tine", "Open »%s«" : "Deschide »%s«", "%1$s via %2$s" : "%1$sprin %2$s", "You are not allowed to share %s" : "Nu există permisiunea de partajare %s", + "Cannot increase permissions of %s" : "Nu se pot extinde permisiunile pentru %s", + "Files cannot be shared with delete permissions" : "Fișierele nu pot fi partajate cu permisiunea de ștergere", + "Files cannot be shared with create permissions" : "Fișierele nu pot fi partajate cu permisiunea de creare", "Expiration date is in the past" : "Data expirării este în trecut", - "Sharing %s failed, because this item is already shared with user %s" : "Partajarea %s a eșuat deoarece acest element este deja partajat cu utilizatorul %s", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Data expirării nu poate fi mai mult de %n zi în viitor","Data expirării nu poate fi mai mult de %n zile în viitor","Data expirării nu poate fi mai mult de %n zile în viitor"], + "Sharing is only allowed with group members" : "Partajarea este permisă doar cu membrii grupului", + "%1$s shared »%2$s« with you" : "%1$s a partajat »%2$s« cu tine", "%1$s shared »%2$s« with you." : "%1$sa partajat »%2$s« cu tine.", "Click the button below to open it." : "Apasă pe butonul de jos pentru a deschide.", + "The requested share does not exist anymore" : "Partajarea solicitată nu mai există", + "The requested share comes from a disabled user" : "Partajarea solicitată provine de la un utilizator dezactivat", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Utilizatorul nu a fost creat deoarece s-a atins limita acestui număr. Verificați notificările pentru a afla mai mult.", "Could not find category \"%s\"" : "Cloud nu a gasit categoria \"%s\"", "Sunday" : "Duminică", "Monday" : "Luni", @@ -118,21 +191,87 @@ OC.L10N.register( "Nov." : "Noi.", "Dec." : "Dec.", "A valid password must be provided" : "Trebuie să furnizaţi o parolă validă", - "The username is already being used" : "Numele de utilizator este deja folosit", - "Could not create user" : "Nu s-a putut crea utilizatorul", - "A valid username must be provided" : "Trebuie să furnizaţi un nume de utilizator valid", - "Username contains whitespace at the beginning or at the end" : "Utilizatorul contine spațiu liber la început sau la sfârșit", - "Username must not consist of dots only" : "Numele utilizatorului nu poate conține numai puncte", - "User disabled" : "Utilizator dezactivat", + "Login canceled by app" : "Autentificare anulată de aplicație", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Aplicația \"%1$s\" nu poate fi instalată deoarece următoarele dependențe nu sunt satisfăcute: %2$s", + "a safe home for all your data" : "o casă sigură pentru toate datele dumneavoastră", + "File is currently busy, please try again later" : "Fișierul este blocat momentan, încercați din nou mai târziu", + "Cannot download file" : "Fișierul nu se poate descărca", "Application is not enabled" : "Aplicația nu este activată", "Authentication error" : "Eroare la autentificare", "Token expired. Please reload page." : "Token expirat. Te rugăm să reîncarci pagina.", + "No database drivers (sqlite, mysql, or postgresql) installed." : "Nu sunt instalate drivere pentru baze de date (sqlite, mysql sau postgresql).", + "Cannot write into \"config\" directory." : "Nu se poate scrie în directorul \"config\".", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Aceasta se poate remedia de obicei prin asigurarea accesului în scriere serverului la directorul configurației. Vedeți %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" : "Sau, dacă preferați să păstrați config.php doar în citire, setați opțiunea \"config_is_read_only\" ca true. Vedeți %s", + "Cannot write into \"apps\" directory." : "Nu se poate scrie în directorul \"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." : "Aceasta se poate remedia permițând serverului web să acceseze directorul aplicațiilor sau dezactivând App Store în fișierul de configurație.", + "Cannot create \"data\" directory." : "Nu se poate crea directorul \"data\".", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Aceasta se remediază de obicei permițând serverului web accesul în scriere în directorul rădăcină. Vedeți %s", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Permisiunile se rezolvă de obicei dând serverului web acces în scriere în directorul rădăcină. Vedeți %s.", + "Your data directory is not writable." : "Directorul data nu are acces în scriere.", + "Setting locale to %s failed." : "Setarea localizării la %s a eșuat.", + "Please install one of these locales on your system and restart your web server." : "Instalați una din aceste localizări pe sistem și reporniți serverul web.", "PHP module %s not installed." : "Modulul PHP %s nu este instalat.", + "Please ask your server administrator to install the module." : "Solicitați administratorului să instaleze modulul.", "PHP setting \"%s\" is not set to \"%s\"." : "Setarea PHP \"%s\" nu este setată la \"%s\".", + "Adjusting this setting in php.ini will make Nextcloud run again" : "Ajustând aceste setări în php.ini va permite ca Nextcloud să funcționeze din nou", + "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> este setată la <code>%s</code> în locul valorii așteptate <code>0</code>.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Pentru a remedia problema setați <code>mbstring.func_overload</code> la <code>0</code> în php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP este aparent configurat pentru a elimina blocurile de documente inline. Acest lucru va face mai multe aplicații de bază inaccesibile.", + "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Aceasta se datorează probabil unui accelerator/cache precum Zend OPcache sau eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Modulele PHP au fost instalate, dar apar ca lipsind?", + "Please ask your server administrator to restart the web server." : "Solicitați administratorului să restarteze serverul web.", + "The required %s config variable is not configured in the config.php file." : "Variabila de configurație %s nu este prezentă în config.php.", + "Please ask your server administrator to check the Nextcloud configuration." : "Solicitați administratorului să verifice configurația Nextcloud. ", + "Your data directory must be an absolute path." : "Directorul de date trebuie să fie o cale absolută.", + "Check the value of \"datadirectory\" in your configuration." : "Verificați valoarea \"datadirectory\" în configurație.", + "Your data directory is invalid." : "Directorul de date este invalid.", + "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asigurați-vă că fișierul \".ocdata\" există în rădăcina directorului de date.", + "Action \"%s\" not supported or implemented." : "Acțiunea \"%s\" nu este suportată sau implementată.", + "Authentication failed, wrong token or provider ID given" : "Autentificare eșuată, token greșit sau ID provider eronat", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Parametri lipsă pentru îndeplinirea solicitării. Parametrii lipsă: \"%s\"", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "ID \"%1$s\" deja folosit de providerul cloud federation \"%2$s\"", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "Providerul Cloud Federation cu ID: \"%s\" nu există.", + "Could not obtain lock type %d on \"%s\"." : "Nu se poate aplica tipul %d de blocare pe \"%s\".", + "Storage unauthorized. %s" : "Spațiu de stocare neautorizat. %s", + "Storage incomplete configuration. %s" : "Configurație incompletă a spațiului de stocare. %s", + "Storage connection error. %s" : "Eroare conexiune cu spațiul de stocare. %s", "Storage is temporarily not available" : "Spațiu de stocare este indisponibil temporar", + "Storage connection timeout. %s" : "Timeout la conexiunea cu spațiul de stocare. %s", + "Free prompt" : "Eliberează prompt-ul", + "Runs an arbitrary prompt through the language model." : "Rulează un prompt arbitrar prin modelul lingvistic.", + "Generate headline" : "Generează titlu", + "Generates a possible headline for a text." : "Generează un posibil titlu pentru text", + "Summarize" : "Rezumă", + "Summarizes text by reducing its length without losing key information." : "Rezumă textul prin reducerea lungimii acestuia, fără a pierde informațiile cheie.", + "Extract topics" : "Extrage subiecte", + "Extracts topics from a text and outputs them separated by commas." : "Extrage subiecte din text și le furnizează separate prin virgulă.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Fișierele aplicației %1$s nu au fost înlocuite corect. Asigurați-vă că versiunea este compatibilă cu cea a serverului. ", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Utilizatorul trebuie să fie administrator, sub-administrator sau să aibă permisiunea specială de a accesa această setare", + "Logged in user must be an admin or sub admin" : "Utilizatorul trebuie să fie administrator sau sub-administrator", + "Logged in user must be an admin" : "Utilizatorul trebuie să fie administrator", "Full name" : "Nume complet", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Numai următoarele caractere sunt permise în numele utilizatorului: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" + "Unknown user" : "Utilizator necunoscut", + "Enter the database username and name for %s" : "Introduceți utilizatorul pentru baza de date și numele pentru %s", + "Enter the database username for %s" : "Introduceți utilizatorul pentru %s", + "MySQL username and/or password not valid" : "Utilizatorul sau/și parola MySQL invalide", + "Oracle username and/or password not valid" : "Numele de utilizator sau / și parola Oracle nu sunt valide", + "PostgreSQL username and/or password not valid" : "Nume utilizator și/sau parolă PostgreSQL greșită", + "Set an admin username." : "Setează un nume de administrator.", + "Sharing %s failed, because this item is already shared with user %s" : "Partajarea %s a eșuat deoarece acest element este deja partajat cu utilizatorul %s", + "The username is already being used" : "Numele de utilizator este deja folosit", + "Could not create user" : "Nu s-a putut crea utilizatorul", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Doar următoarele caractere sunt permise în numele de utilizatori: \"a-z\", \"A-Z\", \"0-9\", spații și \"_.@-'\"", + "A valid username must be provided" : "Trebuie să furnizaţi un nume de utilizator valid", + "Username contains whitespace at the beginning or at the end" : "Utilizatorul contine spațiu liber la început sau la sfârșit", + "Username must not consist of dots only" : "Numele utilizatorului nu poate conține numai puncte", + "Username is invalid because files already exist for this user" : "Numele utilizatorului este invalid deoarece există deja fișiere pentru acesta", + "User disabled" : "Utilizator dezactivat", + "libxml2 2.7.0 is at least required. Currently %s is installed." : "Este necesar libxml2 2.7.0, cel puțin. Acum este instalat %s.", + "To fix this issue update your libxml2 version and restart your web server." : "Pentru remediere actualizați versiunea libxml2 și reporniți serverul web.", + "PostgreSQL >= 9 required." : "Este necesar PostgreSQL >= 9 .", + "Please upgrade your database version." : "Faceți upgrade la versiunea bazei de date.", + "Your data directory is readable by other users." : "Directorul de date este accesibil altor utilizatori.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Setați permisiunea 0770 astfel ca directorul să nu poată fi parcurs de alți utilizatori." }, "nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"); diff --git a/lib/l10n/ro.json b/lib/l10n/ro.json index 5793338e064..5c52aea9cf5 100644 --- a/lib/l10n/ro.json +++ b/lib/l10n/ro.json @@ -1,74 +1,147 @@ { "translations": { "Cannot write into \"config\" directory!" : "Nu se poate scrie în folderul \"config\"!", + "This can usually be fixed by giving the web server write access to the config directory." : "Aceasta se poate rezolva de obicei dând acces în scriere serverului în directorul configurației.", + "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Dar, dacă preferați să păstrați config.php doar în citire, setați opțiunea \"config_is_read_only\" ca true.", "See %s" : "Vezi %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplicația %1$s nu este prezentă sau are o versiune incompatibilă cu acest server. Verificați directorul aplicațiilor.", "Sample configuration detected" : "A fost detectată o configurație exemplu", "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" : "S-a detectat copierea configurației exemplu. Acest lucru poate duce la oprirea instanței tale și nu este suportat. Te rugăm să citești documentația înainte de a face modificări în fișierul config.php", + "The page could not be found on the server." : "Pagina nu a fost găsită.", + "%s email verification" : "%s verificare email", + "Email verification" : "Verificare email", + "Click the following button to confirm your email." : "Apăsați butonul următor pentru confirmare email.", + "Click the following link to confirm your email." : "Click pe linkul următor pentru confirmare email.", + "Confirm your email" : "Confirmați emailul", "Other activities" : "Alte activități", "%1$s and %2$s" : "%1$s și %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s și %3$s", "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s și %4$s", "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s și %5$s", + "Education Edition" : "Ediția pentru educație", + "Enterprise bundle" : "Pachetul enterprise", + "Groupware bundle" : "Pachetul Groupware", + "Hub bundle" : "Pachetul central", + "Social sharing bundle" : "Pachetul de partajare", "PHP %s or higher is required." : "Versiunea PHP %s sau mai mare este necesară.", "PHP with a version lower than %s is required." : "Este necesară o versiune PHP mai mică decât %s", "%sbit or higher PHP required." : "Este necesar PHP %sbit sau mai mare.", + "The following architectures are supported: %s" : "Sunt suportate următoarele arhitecturi: %s", + "The following databases are supported: %s" : "Sunt suportate următoarele baze de date: %s", "The command line tool %s could not be found" : "Unealta în linie de comandă %s nu a fost găsită", "The library %s is not available." : "Biblioteca %s nu este disponibilă.", + "Library %1$s with a version higher than %2$s is required - available version %3$s." : "Biblioteca %1$s cu o versiune superioară %2$s este necesară - versiunea disponibilă %3$s.", + "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Biblioteca %1$s cu o versiune inferioară %2$s este necesară - versiunea disponibilă %3$s.", + "The following platforms are supported: %s" : "Sunt suportate următoarele platforme: %s", + "Server version %s or higher is required." : "Este necesară versiunea %s a serverului sau superioară.", + "Server version %s or lower is required." : "Este necesară versiunea %s a serverului, sau inferioară.", + "Wiping of device %s has started" : "A început curățarea dispozitivului %s ", + "Wiping of device »%s« has started" : "A început curățarea dispozitivului »%s« ", + "»%s« started remote wipe" : "»%s« a pornit curățarea la distanță", + "Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished" : "Dispozitivul sau aplicația »%s« a inițiat procesul de ștergere la distanță. Veți primi un alt mail când procesul se va finaliza", + "Wiping of device %s has finished" : "Curățarea dispozitivului %s s-a finalizat", + "Wiping of device »%s« has finished" : "Curățarea dispozitivului »%s« s-a finalizat", + "»%s« finished remote wipe" : "»%s« a finalizat curățarea la distanță", + "Device or application »%s« has finished the remote wipe process." : "Dispozitivul sau aplicația »%s« a finalizat procesul de curățare la distanță.", + "Remote wipe started" : "Curățarea la distanță a fost inițiată", + "A remote wipe was started on device %s" : "A fost inițiată o curățare la distanță a dispozitivului %s", + "Remote wipe finished" : "Curățarea la distanță a fost finalizată", + "The remote wipe on %s has finished" : "Curățarea la distanță a %s a fost finalizată", "Authentication" : "Autentificare", "Unknown filetype" : "Tip fișier necunoscut", "Invalid image" : "Imagine invalidă", + "Avatar image is not square" : "Imaginea de avatar nu este pătrată", "Files" : "Fișiere", "View profile" : "Vezi profilul", "Local time: %s" : "Timp local: %s", "today" : "astăzi", "tomorrow" : "mâine", "yesterday" : "ieri", - "_%n day ago_::_%n days ago_" : ["Acum o zi","Acum %n zile","Acum %n zile"], + "_in %n day_::_in %n days_" : ["în %n zi","în %n zile","în %n zile"], + "_%n day ago_::_%n days ago_" : ["%n zi în rumă","Acum %n zile","Acum %n zile"], "next month" : "luna viitoare", "last month" : "ultima lună", + "_in %n month_::_in %n months_" : ["în %n lună","în %n luni","în %n luni"], "_%n month ago_::_%n months ago_" : ["%n lună în urmă","%n luni în urmă","%n luni în urmă"], "next year" : "anul viitor", "last year" : "ultimul an", + "_in %n year_::_in %n years_" : ["în %n an","în %n ani","în %n ani"], "_%n year ago_::_%n years ago_" : ["%n an în urmă","%n ani în urmâ","%n ani în urmâ"], + "_in %n hour_::_in %n hours_" : ["în %n oră","în %n ore","în %n ore"], "_%n hour ago_::_%n hours ago_" : ["%n oră în urmă","%n ore în urmă","%n ore în urmă"], + "_in %n minute_::_in %n minutes_" : ["în %n minut","în %n minute","în %n minute"], + "_%n minute ago_::_%n minutes ago_" : ["%n minut în urmă","%n minute în urmă","%n minute în urmă"], "in a few seconds" : "în câteva secunde", "seconds ago" : "secunde în urmă", + "Empty file" : "Fișier gol", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Modulul cu ID: %s nu există. Activați-l din setările aplicației sau contactați administratorul.", "File already exists" : "Fișierul există deja", + "Invalid path" : "Cale invalidă", + "Failed to create file from template" : "Eroare la crearea fișierului pe baza șablonului", "Templates" : "Șabloane", "File name is a reserved word" : "Numele fișierului este un cuvânt rezervat", "File name contains at least one invalid character" : "Numele fișierului conține cel puțin un caracter invalid", "File name is too long" : "Numele fișierului este prea lung", "Dot files are not allowed" : "Fișierele care încep cu caracterul punct nu sunt permise", "Empty filename is not allowed" : "Nu este permis fișier fără nume", + "App \"%s\" cannot be installed because appinfo file cannot be read." : "Aplicația \"%s\" nu poate fi instalată deoarece fișierul appinfo nu poate fi citit.", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Aplicația \"%s\" nu poate fi instalată deoarece nu este compatibilă cu versiunea serverului.", "__language_name__" : "Română", + "This is an automatically sent email, please do not reply." : "Acesta este un email automat, nu răspundeți.", "Help" : "Ajutor", + "Appearance and accessibility" : "Aspect și accesibilitate", "Apps" : "Aplicații", + "Personal settings" : "Setări personale", + "Administration settings" : "Setări de administrare", "Settings" : "Setări", "Log out" : "Ieșire", "Users" : "Utilizatori", "Email" : "E-mail", + "View %s on the fediverse" : "Vedeți %s pe fediverse", "Phone" : "Telefon", + "Call %s" : "Apel %s", "Twitter" : "Twitter", + "View %s on Twitter" : "Vedeți %s pe X", "Website" : "Site web", + "Visit %s" : "Vizitați %s", "Address" : "Adresă", "Profile picture" : "Imagine de profil", "About" : "Despre", + "Display name" : "Nume afișat", + "Headline" : "Titlu", + "Organisation" : "Organizație", "Role" : "Rol", - "Unknown user" : "Utilizator necunoscut", "Additional settings" : "Setări adiționale", + "Enter the database name for %s" : "Introduceți numele bazei de date pentru %s", + "You cannot use dots in the database name %s" : "Nu puteți folosi puncte în numele bazei de date %s", + "You need to enter details of an existing account." : "Sunt necesare detaliile unui cont existent.", "Oracle connection could not be established" : "Conexiunea Oracle nu a putut fi stabilită", - "Oracle username and/or password not valid" : "Numele de utilizator sau / și parola Oracle nu sunt valide", - "PostgreSQL username and/or password not valid" : "Nume utilizator și/sau parolă PostgreSQL greșită", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X nu este suportat și %s nu va funcționa corect pe această platformă. Continuați pe propriul risc! ", "For the best results, please consider using a GNU/Linux server instead." : "Pentru cele mai bune rezultate, ia în calcul folosirea unui server care rulează un sistem de operare GNU/Linux.", - "Set an admin username." : "Setează un nume de administrator.", + "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." : "Se pare că această instanță a %s rulează o versiune 32-bit a PHP și open_basedir a fost configurat în php.ini. Aceasta va conduce la probleme cu fișierele mai mari de 4 GB și nu este deloc recomandată.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Eliminați setarea open_basedir din php.ini utilizați versiunea 64-bit a PHP.", "Set an admin password." : "Setează o parolă de administrator.", + "Cannot create or write into the data directory %s" : "Nu se poate crea sau scrie în dosarul pentru date %s", + "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Backend-ul de partajare %s trebuie să implementeze interfața OCP\\Share_Backend", + "Sharing backend %s not found" : "Backend-ul de partajare %s nu există", + "Sharing backend for %s not found" : "Backend-ul de partajare pentru %s nu a fost găsit", + "%1$s shared »%2$s« with you and wants to add:" : "%1$s a partajat »%2$s« cu tine și vrea să adauge:", + "%1$s shared »%2$s« with you and wants to add" : "%1$s a partajat »%2$s« cu tine și vrea să adauge", "»%s« added a note to a file shared with you" : "%s« a adaugat un comentariu la un fișier partajat cu tine", "Open »%s«" : "Deschide »%s«", "%1$s via %2$s" : "%1$sprin %2$s", "You are not allowed to share %s" : "Nu există permisiunea de partajare %s", + "Cannot increase permissions of %s" : "Nu se pot extinde permisiunile pentru %s", + "Files cannot be shared with delete permissions" : "Fișierele nu pot fi partajate cu permisiunea de ștergere", + "Files cannot be shared with create permissions" : "Fișierele nu pot fi partajate cu permisiunea de creare", "Expiration date is in the past" : "Data expirării este în trecut", - "Sharing %s failed, because this item is already shared with user %s" : "Partajarea %s a eșuat deoarece acest element este deja partajat cu utilizatorul %s", + "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Data expirării nu poate fi mai mult de %n zi în viitor","Data expirării nu poate fi mai mult de %n zile în viitor","Data expirării nu poate fi mai mult de %n zile în viitor"], + "Sharing is only allowed with group members" : "Partajarea este permisă doar cu membrii grupului", + "%1$s shared »%2$s« with you" : "%1$s a partajat »%2$s« cu tine", "%1$s shared »%2$s« with you." : "%1$sa partajat »%2$s« cu tine.", "Click the button below to open it." : "Apasă pe butonul de jos pentru a deschide.", + "The requested share does not exist anymore" : "Partajarea solicitată nu mai există", + "The requested share comes from a disabled user" : "Partajarea solicitată provine de la un utilizator dezactivat", + "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Utilizatorul nu a fost creat deoarece s-a atins limita acestui număr. Verificați notificările pentru a afla mai mult.", "Could not find category \"%s\"" : "Cloud nu a gasit categoria \"%s\"", "Sunday" : "Duminică", "Monday" : "Luni", @@ -116,21 +189,87 @@ "Nov." : "Noi.", "Dec." : "Dec.", "A valid password must be provided" : "Trebuie să furnizaţi o parolă validă", - "The username is already being used" : "Numele de utilizator este deja folosit", - "Could not create user" : "Nu s-a putut crea utilizatorul", - "A valid username must be provided" : "Trebuie să furnizaţi un nume de utilizator valid", - "Username contains whitespace at the beginning or at the end" : "Utilizatorul contine spațiu liber la început sau la sfârșit", - "Username must not consist of dots only" : "Numele utilizatorului nu poate conține numai puncte", - "User disabled" : "Utilizator dezactivat", + "Login canceled by app" : "Autentificare anulată de aplicație", + "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Aplicația \"%1$s\" nu poate fi instalată deoarece următoarele dependențe nu sunt satisfăcute: %2$s", + "a safe home for all your data" : "o casă sigură pentru toate datele dumneavoastră", + "File is currently busy, please try again later" : "Fișierul este blocat momentan, încercați din nou mai târziu", + "Cannot download file" : "Fișierul nu se poate descărca", "Application is not enabled" : "Aplicația nu este activată", "Authentication error" : "Eroare la autentificare", "Token expired. Please reload page." : "Token expirat. Te rugăm să reîncarci pagina.", + "No database drivers (sqlite, mysql, or postgresql) installed." : "Nu sunt instalate drivere pentru baze de date (sqlite, mysql sau postgresql).", + "Cannot write into \"config\" directory." : "Nu se poate scrie în directorul \"config\".", + "This can usually be fixed by giving the web server write access to the config directory. See %s" : "Aceasta se poate remedia de obicei prin asigurarea accesului în scriere serverului la directorul configurației. Vedeți %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" : "Sau, dacă preferați să păstrați config.php doar în citire, setați opțiunea \"config_is_read_only\" ca true. Vedeți %s", + "Cannot write into \"apps\" directory." : "Nu se poate scrie în directorul \"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." : "Aceasta se poate remedia permițând serverului web să acceseze directorul aplicațiilor sau dezactivând App Store în fișierul de configurație.", + "Cannot create \"data\" directory." : "Nu se poate crea directorul \"data\".", + "This can usually be fixed by giving the web server write access to the root directory. See %s" : "Aceasta se remediază de obicei permițând serverului web accesul în scriere în directorul rădăcină. Vedeți %s", + "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Permisiunile se rezolvă de obicei dând serverului web acces în scriere în directorul rădăcină. Vedeți %s.", + "Your data directory is not writable." : "Directorul data nu are acces în scriere.", + "Setting locale to %s failed." : "Setarea localizării la %s a eșuat.", + "Please install one of these locales on your system and restart your web server." : "Instalați una din aceste localizări pe sistem și reporniți serverul web.", "PHP module %s not installed." : "Modulul PHP %s nu este instalat.", + "Please ask your server administrator to install the module." : "Solicitați administratorului să instaleze modulul.", "PHP setting \"%s\" is not set to \"%s\"." : "Setarea PHP \"%s\" nu este setată la \"%s\".", + "Adjusting this setting in php.ini will make Nextcloud run again" : "Ajustând aceste setări în php.ini va permite ca Nextcloud să funcționeze din nou", + "<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>." : "<code>mbstring.func_overload</code> este setată la <code>%s</code> în locul valorii așteptate <code>0</code>.", + "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Pentru a remedia problema setați <code>mbstring.func_overload</code> la <code>0</code> în php.ini.", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP este aparent configurat pentru a elimina blocurile de documente inline. Acest lucru va face mai multe aplicații de bază inaccesibile.", + "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Aceasta se datorează probabil unui accelerator/cache precum Zend OPcache sau eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Modulele PHP au fost instalate, dar apar ca lipsind?", + "Please ask your server administrator to restart the web server." : "Solicitați administratorului să restarteze serverul web.", + "The required %s config variable is not configured in the config.php file." : "Variabila de configurație %s nu este prezentă în config.php.", + "Please ask your server administrator to check the Nextcloud configuration." : "Solicitați administratorului să verifice configurația Nextcloud. ", + "Your data directory must be an absolute path." : "Directorul de date trebuie să fie o cale absolută.", + "Check the value of \"datadirectory\" in your configuration." : "Verificați valoarea \"datadirectory\" în configurație.", + "Your data directory is invalid." : "Directorul de date este invalid.", + "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Asigurați-vă că fișierul \".ocdata\" există în rădăcina directorului de date.", + "Action \"%s\" not supported or implemented." : "Acțiunea \"%s\" nu este suportată sau implementată.", + "Authentication failed, wrong token or provider ID given" : "Autentificare eșuată, token greșit sau ID provider eronat", + "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Parametri lipsă pentru îndeplinirea solicitării. Parametrii lipsă: \"%s\"", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "ID \"%1$s\" deja folosit de providerul cloud federation \"%2$s\"", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "Providerul Cloud Federation cu ID: \"%s\" nu există.", + "Could not obtain lock type %d on \"%s\"." : "Nu se poate aplica tipul %d de blocare pe \"%s\".", + "Storage unauthorized. %s" : "Spațiu de stocare neautorizat. %s", + "Storage incomplete configuration. %s" : "Configurație incompletă a spațiului de stocare. %s", + "Storage connection error. %s" : "Eroare conexiune cu spațiul de stocare. %s", "Storage is temporarily not available" : "Spațiu de stocare este indisponibil temporar", + "Storage connection timeout. %s" : "Timeout la conexiunea cu spațiul de stocare. %s", + "Free prompt" : "Eliberează prompt-ul", + "Runs an arbitrary prompt through the language model." : "Rulează un prompt arbitrar prin modelul lingvistic.", + "Generate headline" : "Generează titlu", + "Generates a possible headline for a text." : "Generează un posibil titlu pentru text", + "Summarize" : "Rezumă", + "Summarizes text by reducing its length without losing key information." : "Rezumă textul prin reducerea lungimii acestuia, fără a pierde informațiile cheie.", + "Extract topics" : "Extrage subiecte", + "Extracts topics from a text and outputs them separated by commas." : "Extrage subiecte din text și le furnizează separate prin virgulă.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Fișierele aplicației %1$s nu au fost înlocuite corect. Asigurați-vă că versiunea este compatibilă cu cea a serverului. ", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Utilizatorul trebuie să fie administrator, sub-administrator sau să aibă permisiunea specială de a accesa această setare", + "Logged in user must be an admin or sub admin" : "Utilizatorul trebuie să fie administrator sau sub-administrator", + "Logged in user must be an admin" : "Utilizatorul trebuie să fie administrator", "Full name" : "Nume complet", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Numai următoarele caractere sunt permise în numele utilizatorului: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" + "Unknown user" : "Utilizator necunoscut", + "Enter the database username and name for %s" : "Introduceți utilizatorul pentru baza de date și numele pentru %s", + "Enter the database username for %s" : "Introduceți utilizatorul pentru %s", + "MySQL username and/or password not valid" : "Utilizatorul sau/și parola MySQL invalide", + "Oracle username and/or password not valid" : "Numele de utilizator sau / și parola Oracle nu sunt valide", + "PostgreSQL username and/or password not valid" : "Nume utilizator și/sau parolă PostgreSQL greșită", + "Set an admin username." : "Setează un nume de administrator.", + "Sharing %s failed, because this item is already shared with user %s" : "Partajarea %s a eșuat deoarece acest element este deja partajat cu utilizatorul %s", + "The username is already being used" : "Numele de utilizator este deja folosit", + "Could not create user" : "Nu s-a putut crea utilizatorul", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Doar următoarele caractere sunt permise în numele de utilizatori: \"a-z\", \"A-Z\", \"0-9\", spații și \"_.@-'\"", + "A valid username must be provided" : "Trebuie să furnizaţi un nume de utilizator valid", + "Username contains whitespace at the beginning or at the end" : "Utilizatorul contine spațiu liber la început sau la sfârșit", + "Username must not consist of dots only" : "Numele utilizatorului nu poate conține numai puncte", + "Username is invalid because files already exist for this user" : "Numele utilizatorului este invalid deoarece există deja fișiere pentru acesta", + "User disabled" : "Utilizator dezactivat", + "libxml2 2.7.0 is at least required. Currently %s is installed." : "Este necesar libxml2 2.7.0, cel puțin. Acum este instalat %s.", + "To fix this issue update your libxml2 version and restart your web server." : "Pentru remediere actualizați versiunea libxml2 și reporniți serverul web.", + "PostgreSQL >= 9 required." : "Este necesar PostgreSQL >= 9 .", + "Please upgrade your database version." : "Faceți upgrade la versiunea bazei de date.", + "Your data directory is readable by other users." : "Directorul de date este accesibil altor utilizatori.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Setați permisiunea 0770 astfel ca directorul să nu poată fi parcurs de alți utilizatori." },"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));" }
\ No newline at end of file diff --git a/lib/l10n/ru.js b/lib/l10n/ru.js index c4eccdb7313..05241ba98ed 100644 --- a/lib/l10n/ru.js +++ b/lib/l10n/ru.js @@ -8,7 +8,6 @@ OC.L10N.register( "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", - "404" : "404", "The page could not be found on the server." : "Страница не найдена на сервере.", "%s email verification" : "Проверка почтового адреса %s", "Email verification" : "Подтверждение адреса электронной почты", @@ -37,9 +36,6 @@ 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 или ниже.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Для доступа к этому параметру необходимо состоять в группе администраторов, суб-администраторов или иметь специальные права", - "Logged in user must be an admin or sub admin" : "Вошедший в систему пользователь должен обладать правами администратора или суб-администратора", - "Logged in user must be an admin" : "Вошедший в систему пользователь должен обладать правами администратора", "Wiping of device %s has started" : "Удаление данных с устройства «%s».", "Wiping of device »%s« has started" : "Удаление данных с устройства «%s».", "»%s« started remote wipe" : "Начало удаления данных с устройства «%s»", @@ -96,7 +92,7 @@ OC.L10N.register( "Help" : "Помощь", "Appearance and accessibility" : "Внешний вид и доступность", "Apps" : "Приложения", - "Personal settings" : "Параметры пользователя", + "Personal settings" : "Личные настройки", "Administration settings" : "Параметры сервера", "Settings" : "Настройки", "Log out" : "Выйти", @@ -118,22 +114,15 @@ OC.L10N.register( "Headline" : "Заголовок", "Organisation" : "Организация", "Role" : "Роль", - "Unknown user" : "Неизвестный пользователь", "Additional settings" : "Дополнительные настройки", - "Enter the database username and name for %s" : "Укажите имя пользователя и название базы данных %s", - "Enter the database username for %s" : "Укажите имя пользователя базы данных %s", "Enter the database name for %s" : "Укажите название базы данных %s", "You cannot use dots in the database name %s" : "Имя базы данных %s не может содержать символ точки", - "MySQL username and/or password not valid" : "Неверное имя пользователя и/или пароль для подключения к MySQL", "You need to enter details of an existing account." : "Необходимо уточнить данные существующего акаунта.", "Oracle connection could not be established" : "Соединение с Oracle не может быть установлено", - "Oracle username and/or password not valid" : "Неверное имя пользователя и/или пароль Oracle", - "PostgreSQL username 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-разрядную сборку.", - "Set an admin username." : "Задать имя пользователя для администратора.", "Set an admin password." : "Задать пароль для admin.", "Cannot create or write into the data directory %s" : "Не удалось создать или записать в каталог данных «%s»", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Бэкенд общего доступа %s должен реализовывать интерфейс OCP\\Share_Backend", @@ -151,11 +140,11 @@ OC.L10N.register( "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_" : ["Срок окончания не может быть более %n дня","Срок окончания не может быть более %n дней","Срок окончания не может быть более %n дней","Срок окончания не может быть более %n дней"], "Sharing is only allowed with group members" : "Разрешено публиковать только для участников группы", - "Sharing %s failed, because this item is already shared with user %s" : "Не удалось поделиться %s, так как элемент находится в общем доступе у %s", "%1$s shared »%2$s« with you" : "%1$s предоставил(а) вам доступ к «%2$s»", "%1$s shared »%2$s« with you." : "%1$s предоставил(а) вам доступ к «%2$s».", "Click the button below to open it." : "Нажмите расположенную ниже кнопку для перехода к полученному общему ресурсу.", "The requested share does not exist anymore" : "Запрошенный общий ресурс более не существует.", + "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» не найдена", "Sunday" : "Воскресенье", @@ -204,14 +193,6 @@ OC.L10N.register( "Nov." : "Нояб.", "Dec." : "Дек.", "A valid password must be provided" : "Укажите допустимый пароль", - "The username is already being used" : "Имя пользователя уже используется", - "Could not create user" : "Не удалось создать пользователя", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "В имени пользователя допускаются следующие символы: «a–z», «A–Z», «0–9» и «_.@-'»", - "A valid username must be provided" : "Укажите допустимое имя пользователя", - "Username contains whitespace at the beginning or at the end" : "Имя пользователя содержит пробел в начале или в конце", - "Username must not consist of dots only" : "Имя пользователя должно состоять не только из точек", - "Username is invalid because files already exist for this user" : "Это имя не может быть использовано, файлы этого пользователя уже существуют", - "User 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" : "надёжный дом для всех ваших данных", @@ -244,8 +225,6 @@ OC.L10N.register( "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 users." : "Каталог данных доступен для чтения другим пользователям.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Измените права доступа на 0770, чтобы другие пользователи не могли получить список файлов этого каталога.", "Your data directory must be an absolute path." : "Каталог данных должен быть указан в виде абсолютного пути.", "Check the value of \"datadirectory\" in your configuration." : "Проверьте в значение параметра «datadirectory» в файле конфигурации.", "Your data directory is invalid." : "Каталог данных задан неверно.", @@ -261,15 +240,41 @@ OC.L10N.register( "Storage connection error. %s" : "Ошибка подключения к хранилищу. %s", "Storage is temporarily not available" : "Хранилище временно недоступно", "Storage connection timeout. %s" : "Истекло время ожидания подключения к хранилищу. %s", + "Free prompt" : "Свободная подсказка", + "Runs an arbitrary prompt through the language model." : "Запускает произвольное приглашение через языковую модель.", + "Generate headline" : "Сгенерировать заголовок", + "Generates a possible headline for a text." : "Генерирует возможный заголовок для текста.", + "Summarize" : "Обобщить", + "Summarizes text by reducing its length without losing key information." : "Обобщает текст, сокращая его длину без потери ключевой информации.", "Extract topics" : "Извлечь темы", "Extracts topics from a text and outputs them separated by commas." : "Извлекает темы из текста и выводит их через запятую.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Файлы приложения %1$s не были заменены корректно. Удостоверьтесь, что устанавливаемая версия этого приложения совместима с версией сервера.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Для доступа к этому параметру необходимо состоять в группе администраторов, суб-администраторов или иметь специальные права", + "Logged in user must be an admin or sub admin" : "Вошедший в систему пользователь должен обладать правами администратора или суб-администратора", + "Logged in user must be an admin" : "Вошедший в систему пользователь должен обладать правами администратора", "Full name" : "Полное имя", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Пользователь не был создан, достигнуто ограничение количества пользователей. Для получения дополнительных сведений проверьте уведомления.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "В составе имени пользователя допускаются следующие символы: «a–z», «A–Z», «0–9» и «_.@-'»", + "Unknown user" : "Неизвестный пользователь", + "Enter the database username and name for %s" : "Укажите имя пользователя и название базы данных %s", + "Enter the database username for %s" : "Укажите имя пользователя базы данных %s", + "MySQL username and/or password not valid" : "Неверное имя пользователя и/или пароль для подключения к MySQL", + "Oracle username and/or password not valid" : "Неверное имя пользователя и/или пароль Oracle", + "PostgreSQL username and/or password not valid" : "Неверное имя пользователя и/или пароль PostgreSQL", + "Set an admin username." : "Задать имя пользователя для администратора.", + "Sharing %s failed, because this item is already shared with user %s" : "Не удалось поделиться %s, так как элемент находится в общем доступе у %s", + "The username is already being used" : "Имя пользователя уже используется", + "Could not create user" : "Не удалось создать пользователя", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "В имени пользователя допускаются следующие символы: «a–z», «A–Z», «0–9» и «_.@-'»", + "A valid username must be provided" : "Укажите допустимое имя пользователя", + "Username contains whitespace at the beginning or at the end" : "Имя пользователя содержит пробел в начале или в конце", + "Username must not consist of dots only" : "Имя пользователя должно состоять не только из точек", + "Username is invalid because files already exist for this user" : "Это имя не может быть использовано, файлы этого пользователя уже существуют", + "User disabled" : "Пользователь отключен", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Требуется как минимум libxml2 версии 2.7.0. На данный момент установлена %s.", "To fix this issue update your libxml2 version and restart your web server." : "Для исправления этой ошибки обновите версию libxml2 и перезапустите ваш веб-сервер.", "PostgreSQL >= 9 required." : "Требуется PostgreSQL версии 9 или более новый.", - "Please upgrade your database version." : "Обновите базу данных." + "Please upgrade your database version." : "Обновите базу данных.", + "Your data directory is readable by other users." : "Каталог данных доступен для чтения другим пользователям.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Измените права доступа на 0770, чтобы другие пользователи не могли получить список файлов этого каталога." }, "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 d6582773e87..eceeeede0a1 100644 --- a/lib/l10n/ru.json +++ b/lib/l10n/ru.json @@ -6,7 +6,6 @@ "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", - "404" : "404", "The page could not be found on the server." : "Страница не найдена на сервере.", "%s email verification" : "Проверка почтового адреса %s", "Email verification" : "Подтверждение адреса электронной почты", @@ -35,9 +34,6 @@ "The following platforms are supported: %s" : "Поддерживаются следующие платформы: %s", "Server version %s or higher is required." : "Требуется сервер версии %s или выше.", "Server version %s or lower is required." : "Требуется сервер версии %s или ниже.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Для доступа к этому параметру необходимо состоять в группе администраторов, суб-администраторов или иметь специальные права", - "Logged in user must be an admin or sub admin" : "Вошедший в систему пользователь должен обладать правами администратора или суб-администратора", - "Logged in user must be an admin" : "Вошедший в систему пользователь должен обладать правами администратора", "Wiping of device %s has started" : "Удаление данных с устройства «%s».", "Wiping of device »%s« has started" : "Удаление данных с устройства «%s».", "»%s« started remote wipe" : "Начало удаления данных с устройства «%s»", @@ -94,7 +90,7 @@ "Help" : "Помощь", "Appearance and accessibility" : "Внешний вид и доступность", "Apps" : "Приложения", - "Personal settings" : "Параметры пользователя", + "Personal settings" : "Личные настройки", "Administration settings" : "Параметры сервера", "Settings" : "Настройки", "Log out" : "Выйти", @@ -116,22 +112,15 @@ "Headline" : "Заголовок", "Organisation" : "Организация", "Role" : "Роль", - "Unknown user" : "Неизвестный пользователь", "Additional settings" : "Дополнительные настройки", - "Enter the database username and name for %s" : "Укажите имя пользователя и название базы данных %s", - "Enter the database username for %s" : "Укажите имя пользователя базы данных %s", "Enter the database name for %s" : "Укажите название базы данных %s", "You cannot use dots in the database name %s" : "Имя базы данных %s не может содержать символ точки", - "MySQL username and/or password not valid" : "Неверное имя пользователя и/или пароль для подключения к MySQL", "You need to enter details of an existing account." : "Необходимо уточнить данные существующего акаунта.", "Oracle connection could not be established" : "Соединение с Oracle не может быть установлено", - "Oracle username and/or password not valid" : "Неверное имя пользователя и/или пароль Oracle", - "PostgreSQL username 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-разрядную сборку.", - "Set an admin username." : "Задать имя пользователя для администратора.", "Set an admin password." : "Задать пароль для admin.", "Cannot create or write into the data directory %s" : "Не удалось создать или записать в каталог данных «%s»", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Бэкенд общего доступа %s должен реализовывать интерфейс OCP\\Share_Backend", @@ -149,11 +138,11 @@ "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_" : ["Срок окончания не может быть более %n дня","Срок окончания не может быть более %n дней","Срок окончания не может быть более %n дней","Срок окончания не может быть более %n дней"], "Sharing is only allowed with group members" : "Разрешено публиковать только для участников группы", - "Sharing %s failed, because this item is already shared with user %s" : "Не удалось поделиться %s, так как элемент находится в общем доступе у %s", "%1$s shared »%2$s« with you" : "%1$s предоставил(а) вам доступ к «%2$s»", "%1$s shared »%2$s« with you." : "%1$s предоставил(а) вам доступ к «%2$s».", "Click the button below to open it." : "Нажмите расположенную ниже кнопку для перехода к полученному общему ресурсу.", "The requested share does not exist anymore" : "Запрошенный общий ресурс более не существует.", + "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» не найдена", "Sunday" : "Воскресенье", @@ -202,14 +191,6 @@ "Nov." : "Нояб.", "Dec." : "Дек.", "A valid password must be provided" : "Укажите допустимый пароль", - "The username is already being used" : "Имя пользователя уже используется", - "Could not create user" : "Не удалось создать пользователя", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "В имени пользователя допускаются следующие символы: «a–z», «A–Z», «0–9» и «_.@-'»", - "A valid username must be provided" : "Укажите допустимое имя пользователя", - "Username contains whitespace at the beginning or at the end" : "Имя пользователя содержит пробел в начале или в конце", - "Username must not consist of dots only" : "Имя пользователя должно состоять не только из точек", - "Username is invalid because files already exist for this user" : "Это имя не может быть использовано, файлы этого пользователя уже существуют", - "User 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" : "надёжный дом для всех ваших данных", @@ -242,8 +223,6 @@ "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 users." : "Каталог данных доступен для чтения другим пользователям.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Измените права доступа на 0770, чтобы другие пользователи не могли получить список файлов этого каталога.", "Your data directory must be an absolute path." : "Каталог данных должен быть указан в виде абсолютного пути.", "Check the value of \"datadirectory\" in your configuration." : "Проверьте в значение параметра «datadirectory» в файле конфигурации.", "Your data directory is invalid." : "Каталог данных задан неверно.", @@ -259,15 +238,41 @@ "Storage connection error. %s" : "Ошибка подключения к хранилищу. %s", "Storage is temporarily not available" : "Хранилище временно недоступно", "Storage connection timeout. %s" : "Истекло время ожидания подключения к хранилищу. %s", + "Free prompt" : "Свободная подсказка", + "Runs an arbitrary prompt through the language model." : "Запускает произвольное приглашение через языковую модель.", + "Generate headline" : "Сгенерировать заголовок", + "Generates a possible headline for a text." : "Генерирует возможный заголовок для текста.", + "Summarize" : "Обобщить", + "Summarizes text by reducing its length without losing key information." : "Обобщает текст, сокращая его длину без потери ключевой информации.", "Extract topics" : "Извлечь темы", "Extracts topics from a text and outputs them separated by commas." : "Извлекает темы из текста и выводит их через запятую.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Файлы приложения %1$s не были заменены корректно. Удостоверьтесь, что устанавливаемая версия этого приложения совместима с версией сервера.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Для доступа к этому параметру необходимо состоять в группе администраторов, суб-администраторов или иметь специальные права", + "Logged in user must be an admin or sub admin" : "Вошедший в систему пользователь должен обладать правами администратора или суб-администратора", + "Logged in user must be an admin" : "Вошедший в систему пользователь должен обладать правами администратора", "Full name" : "Полное имя", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Пользователь не был создан, достигнуто ограничение количества пользователей. Для получения дополнительных сведений проверьте уведомления.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "В составе имени пользователя допускаются следующие символы: «a–z», «A–Z», «0–9» и «_.@-'»", + "Unknown user" : "Неизвестный пользователь", + "Enter the database username and name for %s" : "Укажите имя пользователя и название базы данных %s", + "Enter the database username for %s" : "Укажите имя пользователя базы данных %s", + "MySQL username and/or password not valid" : "Неверное имя пользователя и/или пароль для подключения к MySQL", + "Oracle username and/or password not valid" : "Неверное имя пользователя и/или пароль Oracle", + "PostgreSQL username and/or password not valid" : "Неверное имя пользователя и/или пароль PostgreSQL", + "Set an admin username." : "Задать имя пользователя для администратора.", + "Sharing %s failed, because this item is already shared with user %s" : "Не удалось поделиться %s, так как элемент находится в общем доступе у %s", + "The username is already being used" : "Имя пользователя уже используется", + "Could not create user" : "Не удалось создать пользователя", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "В имени пользователя допускаются следующие символы: «a–z», «A–Z», «0–9» и «_.@-'»", + "A valid username must be provided" : "Укажите допустимое имя пользователя", + "Username contains whitespace at the beginning or at the end" : "Имя пользователя содержит пробел в начале или в конце", + "Username must not consist of dots only" : "Имя пользователя должно состоять не только из точек", + "Username is invalid because files already exist for this user" : "Это имя не может быть использовано, файлы этого пользователя уже существуют", + "User disabled" : "Пользователь отключен", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Требуется как минимум libxml2 версии 2.7.0. На данный момент установлена %s.", "To fix this issue update your libxml2 version and restart your web server." : "Для исправления этой ошибки обновите версию libxml2 и перезапустите ваш веб-сервер.", "PostgreSQL >= 9 required." : "Требуется PostgreSQL версии 9 или более новый.", - "Please upgrade your database version." : "Обновите базу данных." + "Please upgrade your database version." : "Обновите базу данных.", + "Your data directory is readable by other users." : "Каталог данных доступен для чтения другим пользователям.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Измените права доступа на 0770, чтобы другие пользователи не могли получить список файлов этого каталога." },"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/sc.js b/lib/l10n/sc.js index 68f638c9bd8..b33bedc5159 100644 --- a/lib/l10n/sc.js +++ b/lib/l10n/sc.js @@ -6,6 +6,7 @@ OC.L10N.register( "See %s" : "Càstia %s", "Sample configuration detected" : "S'at agatadu una cunfiguratzione de esèmpiu", "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" : "Est istadu iscobertu ca sa cunfiguratzione de esèmpiu est istada copiada. Custu podet blocare s'installatzione e no est suportadu. Leghe sa documentatzione in config.php antis de fàghere càmbios.", + "The page could not be found on the server." : "Impossìbile agatare custa pàgina in su serbidore.", "Other activities" : "Àteras atividades", "%1$s and %2$s" : "%1$s e %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s e %3$s", @@ -28,8 +29,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Sunt suportadas custas prataformas: %s", "Server version %s or higher is required." : "Est rechèdidu sa versione de serbidore %s o superiore.", "Server version %s or lower is required." : "Est rechèdidu sa versione de serbidore %s o inferiore.", - "Logged in user must be an admin or sub admin" : "S'utente devet essere de s'amministratzione o de sa suta-amministratzione ", - "Logged in user must be an admin" : "S'utente devet essere de s'amministratzione ", "Wiping of device %s has started" : "S'at cumintzadu sa cantzelladura de su dispositivu %s", "Wiping of device »%s« has started" : "S'at cumintzadu sa cantzelladura de su dispositivu »%s«", "»%s« started remote wipe" : "»%s« at cumintzadu sa cantzelladura de tesu", @@ -44,30 +43,30 @@ OC.L10N.register( "The remote wipe on %s has finished" : "Sa cantzelladura de tesu in %s est acabbada", "Authentication" : "Autenticatzione", "Unknown filetype" : "Genia de archìviu disconnota", - "Invalid image" : "Imàgine non bàlida", - "Avatar image is not square" : "S'imàgine de s'avatar no est cuadrada", + "Invalid image" : "Immàgine non bàlida", + "Avatar image is not square" : "S'immàgine de s'avatar no est cuadrada", "Files" : "Archìvios", "today" : "oe", "tomorrow" : "cras", "yesterday" : "eris", - "_in %n day_::_in %n days_" : ["tra %n dies","tra %n dies"], + "_in %n day_::_in %n days_" : ["tra %n dies","de immoe a %n dies"], "_%n day ago_::_%n days ago_" : ["%n dies a oe","%n dies a oe"], "next month" : "su mese chi benit", "last month" : "su mese passadu", - "_in %n month_::_in %n months_" : ["tra %n meses","%n meses"], + "_in %n month_::_in %n months_" : ["tra %n meses","de immoe a %n meses"], "_%n month ago_::_%n months ago_" : ["%n meses a oe","%n meses a oe"], "next year" : "s'annu chi benit", "last year" : "s'annu passadu", - "_in %n year_::_in %n years_" : ["tra %n annos","tra %n annos"], + "_in %n year_::_in %n years_" : ["tra %n annos","de immoe a %n annos"], "_%n year ago_::_%n years ago_" : ["%n annos a oe","%n dies a oe"], - "_in %n hour_::_in %n hours_" : ["tra %n oras","tra %n oras"], + "_in %n hour_::_in %n hours_" : ["tra %n oras","de immoe a %n oras"], "_%n hour ago_::_%n hours ago_" : ["%n oras a immoe","%n oras a immoe"], - "_in %n minute_::_in %n minutes_" : ["%n meses","tra %n minutos"], + "_in %n minute_::_in %n minutes_" : ["%n meses","de immoe a %n minutos"], "_%n minute ago_::_%n minutes ago_" : ["%n minutos a immoe","%n minutos a immoe"], - "in a few seconds" : "tra pagos segundos", + "in a few seconds" : "de immoe a pagos segundos", "seconds ago" : "segundos a immoe", "Empty file" : "Archìviu bòidu", - "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Su mòdulu cun ID: %s no esistit. Ativa•ddu in is impostatziones de s'aplicatzione o cuntata s'amministratzione.", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Su mòdulu cun ID: %s no esistit. Ativa·ddu in sa cunfiguratzione de s'aplicatzione o cuntata s'amministratzione.", "File already exists" : "S'archìviu b'est giai", "Invalid path" : "Percursu non bàlidu", "Failed to create file from template" : "No at fatu a creare s'archìviu dae su modellu", @@ -82,8 +81,9 @@ OC.L10N.register( "__language_name__" : "sardu", "This is an automatically sent email, please do not reply." : "Custu est unu messàgiu de posta imbiadu in automàticu, non rispondas.", "Help" : "Agiudu", + "Appearance and accessibility" : "Aspetu e atzessibilidade", "Apps" : "Aplicatziones", - "Settings" : "Impostatziones", + "Settings" : "Cunfiguratzione", "Log out" : "Essi·nche", "Users" : "Utentes", "Email" : "Posta eletrònica", @@ -91,23 +91,18 @@ OC.L10N.register( "Twitter" : "Twitter", "Website" : "Situ ìnternet", "Address" : "Indiritzu", - "Profile picture" : "Imàgine de profilu", + "Profile picture" : "Immàgine de profilu", "About" : "In contu de", "Display name" : "Ammustra nùmene", "Headline" : "Tìtulos", "Role" : "Faina", - "Unknown user" : "Utèntzia disconnota", - "Additional settings" : "Impostatziones in agiunta", - "MySQL username and/or password not valid" : "Su nùmene utente e/o sa crae de MySQL no sunt bàlidos", + "Additional settings" : "Cunfiguratziones in agiunta", "You need to enter details of an existing account." : "Nche depes insertare is detàllios de unu contu chi b'est giai.", "Oracle connection could not be established" : "No at fatu a istabilire sa connessione Oracle", - "Oracle username and/or password not valid" : "Su nùmene utente e/o sa crae de Oracle no sunt bàlidos", - "PostgreSQL username and/or password not valid" : "Su nùmene utente e/o sa crae de Postgre SQL no sunt bàlidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X no est suportadu e %s no at a funtzionare in manera curreta in custa prataforma. Imprea•ddu a arriscu tuo!", "For the best results, please consider using a GNU/Linux server instead." : "Pro su mellus resurtadu, cunsidera in càmbiu de impreare unu serbidore 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." : "Parit ca custa istàntzia %s est traballende in un'ambiente PHP a 32-bit e sa open_basedir est istada cunfigurada in php.ini. Custu at a causare problemas cun archìvios de prus de 4 GB e est iscussigiadu a forte.", - "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Boga•nche s'impostatzione open_basedir in su php.ini tuo o càmbia a su PHP a 64-bit.", - "Set an admin username." : "Imposta unu nùmene utente pro chie amministrat.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Boga·nche sa cunfiguratzione open_basedir in su php.ini tuo o càmbia a su PHP a 64-bit.", "Set an admin password." : "Imposta una crae pro chie amministrat.", "Cannot create or write into the data directory %s" : "No faghet a creare o a iscriere a intro de sa cartella de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Su motore de cumpartzidura %s depet cumpletare s'interfache OCP\\Share_Backend", @@ -125,7 +120,6 @@ OC.L10N.register( "Expiration date is in the past" : "Sa data de iscadèntzia est giai passada", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No faghet a impostare sa data de iscadèntzia a prus de %n die in su benidore","No faghet a impostare sa data de iscadèntzia a prus de %n dies in su benidore"], "Sharing is only allowed with group members" : "Sa cumpartzidura est permìtida isceti cun is partetzipantes de su grupu", - "Sharing %s failed, because this item is already shared with user %s" : "No at fatu a cumpartzire %s, ca custu elementu est giai istadu cumpartzidu cun s'utente %s", "%1$s shared »%2$s« with you" : "%1$s at cumpartzidu »%2$s cun tegus", "%1$s shared »%2$s« with you." : "%1$s at cumpartzidu »%2$s cun tegus.", "Click the button below to open it." : "Incarca su butone a suta pro dd'abèrrere.", @@ -177,13 +171,6 @@ OC.L10N.register( "Nov." : "SAnd.", "Dec." : "Nad.", "A valid password must be provided" : "Depes frunire una crae bàlida", - "The username is already being used" : "Su nùmene utente est giai impreadu", - "Could not create user" : "No at fatu a creare s'utente", - "A valid username must be provided" : "Depes frunire unu nùmene utente bàlidu", - "Username contains whitespace at the beginning or at the end" : "Su nùmene utente cuntenet ispàtzios bòidos a su cumintzu o a sa fine", - "Username must not consist of dots only" : "Su nùmene utente no depet tènnere isceti puntos", - "Username is invalid because files already exist for this user" : "Su nùmene utente no est bàlidu, ca is archìvios bi sunt giai pro cust'utèntzia", - "User disabled" : "Utèntzia disativada", "Login canceled by app" : "Atzessu annulladu dae s'aplicatzione", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Non faghet a installare s'aplicatzione %1$s ca is dipendèntzias in fatu non sunt satisfatos:%2$s", "a safe home for all your data" : "unu logu siguru pro totu is datos tuos", @@ -195,13 +182,12 @@ OC.L10N.register( "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "Ma si preferes allogare s'archìviu de letura isceti congi.php, imposta su sèberu \"config_is_read_only\" a \"true\". Càstia %s", "PHP module %s not installed." : "Su mòdulu PHP %s no est installadu.", "Please ask your server administrator to install the module." : "Pedi a s'amministratzione de serbidore de installare su mòdulu.", - "PHP setting \"%s\" is not set to \"%s\"." : "S'impostatzione PHP %s no est a \"%s\".", - "Adjusting this setting in php.ini will make Nextcloud run again" : "Assentende cust'impostatzione in php.ini at a torrare a fàghere traballare Nextcloud", + "PHP setting \"%s\" is not set to \"%s\"." : "Sa cunfiguratzione PHP %s no est a \"%s\".", + "Adjusting this setting in php.ini will make Nextcloud run again" : "Assentende custa cunfiguratzione in php.ini at a torrare a fàghere traballare Nextcloud", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Parit che PHP siat impostadu pro nde bogare is blocos de documentatzione in lìnia. Custu at a impedire s'atzessu a medas aplicatziones printzipales.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Podet èssere causadu dae una memòria temporànea/atzeleradore cales Zend Opcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Is mòdulos PHP sunt istados installados, ma sunt ancora elencados comente mancantes?", "Please ask your server administrator to restart the web server." : "Pedi a s'amministratzione de su serbidore de torrare a aviare su serbidore ìnternet.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Càmbia is permissos a 0770 aici sa cartella no podet èssere in is elencos de àteras utèntzias.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Assegura•ti chi in sa cartella de datos de orìgine nche siat un'archìviu cun nùmene \".ocdata\".", "Action \"%s\" not supported or implemented." : "S'atzione \"%s\" no est suportada o cumpletada.", "Authentication failed, wrong token or provider ID given" : "No at fatu a fàghere s'autenticatzione, token o ID de su frunidore isballiados", @@ -215,9 +201,24 @@ OC.L10N.register( "Storage is temporarily not available" : "S'archiviatzione no est disponìbile pro immoe.", "Storage connection timeout. %s" : "Tempus de connessione a s'archiviatzione iscadidu. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Is archìvios de s'aplicatzione %1$s no sunt istados cambiados in manera curreta. Assegura•ti chi b'apat una versione cumpatìbile cun su serbidore.", + "Logged in user must be an admin or sub admin" : "S'utente devet essere de s'amministratzione o de sa suta-amministratzione ", + "Logged in user must be an admin" : "S'utente devet essere de s'amministratzione ", "Full name" : "Nùmene cumpletu", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Isceti custos caràteres sunt permìtidos in unu nùmene utente: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Utèntzia disconnota", + "MySQL username and/or password not valid" : "Su nùmene utente e/o sa crae de MySQL no sunt bàlidos", + "Oracle username and/or password not valid" : "Su nùmene utente e/o sa crae de Oracle no sunt bàlidos", + "PostgreSQL username and/or password not valid" : "Su nùmene utente e/o sa crae de Postgre SQL no sunt bàlidos", + "Set an admin username." : "Imposta unu nùmene utente pro chie amministrat.", + "Sharing %s failed, because this item is already shared with user %s" : "No at fatu a cumpartzire %s, ca custu elementu est giai istadu cumpartzidu cun s'utente %s", + "The username is already being used" : "Su nùmene utente est giai impreadu", + "Could not create user" : "No at fatu a creare s'utente", + "A valid username must be provided" : "Depes frunire unu nùmene utente bàlidu", + "Username contains whitespace at the beginning or at the end" : "Su nùmene utente cuntenet ispàtzios bòidos a su cumintzu o a sa fine", + "Username must not consist of dots only" : "Su nùmene utente no depet tènnere isceti puntos", + "Username is invalid because files already exist for this user" : "Su nùmene utente no est bàlidu, ca is archìvios bi sunt giai pro cust'utèntzia", + "User disabled" : "Utèntzia disativada", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Est rechèdida a su mancu sa versione libxml2 2.7.0. Pro immoe cussa installada est sa%s.", - "To fix this issue update your libxml2 version and restart your web server." : "Pro assentare custu problema, agiorna sa versione libxml2 e torra a aviare su serbidore ìnternet." + "To fix this issue update your libxml2 version and restart your web server." : "Pro assentare custu problema, agiorna sa versione libxml2 e torra a aviare su serbidore ìnternet.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Càmbia is permissos a 0770 aici sa cartella no podet èssere in is elencos de àteras utèntzias." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/sc.json b/lib/l10n/sc.json index 87e608c2ea9..bd10da305a7 100644 --- a/lib/l10n/sc.json +++ b/lib/l10n/sc.json @@ -4,6 +4,7 @@ "See %s" : "Càstia %s", "Sample configuration detected" : "S'at agatadu una cunfiguratzione de esèmpiu", "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" : "Est istadu iscobertu ca sa cunfiguratzione de esèmpiu est istada copiada. Custu podet blocare s'installatzione e no est suportadu. Leghe sa documentatzione in config.php antis de fàghere càmbios.", + "The page could not be found on the server." : "Impossìbile agatare custa pàgina in su serbidore.", "Other activities" : "Àteras atividades", "%1$s and %2$s" : "%1$s e %2$s", "%1$s, %2$s and %3$s" : "%1$s, %2$s e %3$s", @@ -26,8 +27,6 @@ "The following platforms are supported: %s" : "Sunt suportadas custas prataformas: %s", "Server version %s or higher is required." : "Est rechèdidu sa versione de serbidore %s o superiore.", "Server version %s or lower is required." : "Est rechèdidu sa versione de serbidore %s o inferiore.", - "Logged in user must be an admin or sub admin" : "S'utente devet essere de s'amministratzione o de sa suta-amministratzione ", - "Logged in user must be an admin" : "S'utente devet essere de s'amministratzione ", "Wiping of device %s has started" : "S'at cumintzadu sa cantzelladura de su dispositivu %s", "Wiping of device »%s« has started" : "S'at cumintzadu sa cantzelladura de su dispositivu »%s«", "»%s« started remote wipe" : "»%s« at cumintzadu sa cantzelladura de tesu", @@ -42,30 +41,30 @@ "The remote wipe on %s has finished" : "Sa cantzelladura de tesu in %s est acabbada", "Authentication" : "Autenticatzione", "Unknown filetype" : "Genia de archìviu disconnota", - "Invalid image" : "Imàgine non bàlida", - "Avatar image is not square" : "S'imàgine de s'avatar no est cuadrada", + "Invalid image" : "Immàgine non bàlida", + "Avatar image is not square" : "S'immàgine de s'avatar no est cuadrada", "Files" : "Archìvios", "today" : "oe", "tomorrow" : "cras", "yesterday" : "eris", - "_in %n day_::_in %n days_" : ["tra %n dies","tra %n dies"], + "_in %n day_::_in %n days_" : ["tra %n dies","de immoe a %n dies"], "_%n day ago_::_%n days ago_" : ["%n dies a oe","%n dies a oe"], "next month" : "su mese chi benit", "last month" : "su mese passadu", - "_in %n month_::_in %n months_" : ["tra %n meses","%n meses"], + "_in %n month_::_in %n months_" : ["tra %n meses","de immoe a %n meses"], "_%n month ago_::_%n months ago_" : ["%n meses a oe","%n meses a oe"], "next year" : "s'annu chi benit", "last year" : "s'annu passadu", - "_in %n year_::_in %n years_" : ["tra %n annos","tra %n annos"], + "_in %n year_::_in %n years_" : ["tra %n annos","de immoe a %n annos"], "_%n year ago_::_%n years ago_" : ["%n annos a oe","%n dies a oe"], - "_in %n hour_::_in %n hours_" : ["tra %n oras","tra %n oras"], + "_in %n hour_::_in %n hours_" : ["tra %n oras","de immoe a %n oras"], "_%n hour ago_::_%n hours ago_" : ["%n oras a immoe","%n oras a immoe"], - "_in %n minute_::_in %n minutes_" : ["%n meses","tra %n minutos"], + "_in %n minute_::_in %n minutes_" : ["%n meses","de immoe a %n minutos"], "_%n minute ago_::_%n minutes ago_" : ["%n minutos a immoe","%n minutos a immoe"], - "in a few seconds" : "tra pagos segundos", + "in a few seconds" : "de immoe a pagos segundos", "seconds ago" : "segundos a immoe", "Empty file" : "Archìviu bòidu", - "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Su mòdulu cun ID: %s no esistit. Ativa•ddu in is impostatziones de s'aplicatzione o cuntata s'amministratzione.", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Su mòdulu cun ID: %s no esistit. Ativa·ddu in sa cunfiguratzione de s'aplicatzione o cuntata s'amministratzione.", "File already exists" : "S'archìviu b'est giai", "Invalid path" : "Percursu non bàlidu", "Failed to create file from template" : "No at fatu a creare s'archìviu dae su modellu", @@ -80,8 +79,9 @@ "__language_name__" : "sardu", "This is an automatically sent email, please do not reply." : "Custu est unu messàgiu de posta imbiadu in automàticu, non rispondas.", "Help" : "Agiudu", + "Appearance and accessibility" : "Aspetu e atzessibilidade", "Apps" : "Aplicatziones", - "Settings" : "Impostatziones", + "Settings" : "Cunfiguratzione", "Log out" : "Essi·nche", "Users" : "Utentes", "Email" : "Posta eletrònica", @@ -89,23 +89,18 @@ "Twitter" : "Twitter", "Website" : "Situ ìnternet", "Address" : "Indiritzu", - "Profile picture" : "Imàgine de profilu", + "Profile picture" : "Immàgine de profilu", "About" : "In contu de", "Display name" : "Ammustra nùmene", "Headline" : "Tìtulos", "Role" : "Faina", - "Unknown user" : "Utèntzia disconnota", - "Additional settings" : "Impostatziones in agiunta", - "MySQL username and/or password not valid" : "Su nùmene utente e/o sa crae de MySQL no sunt bàlidos", + "Additional settings" : "Cunfiguratziones in agiunta", "You need to enter details of an existing account." : "Nche depes insertare is detàllios de unu contu chi b'est giai.", "Oracle connection could not be established" : "No at fatu a istabilire sa connessione Oracle", - "Oracle username and/or password not valid" : "Su nùmene utente e/o sa crae de Oracle no sunt bàlidos", - "PostgreSQL username and/or password not valid" : "Su nùmene utente e/o sa crae de Postgre SQL no sunt bàlidos", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X no est suportadu e %s no at a funtzionare in manera curreta in custa prataforma. Imprea•ddu a arriscu tuo!", "For the best results, please consider using a GNU/Linux server instead." : "Pro su mellus resurtadu, cunsidera in càmbiu de impreare unu serbidore 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." : "Parit ca custa istàntzia %s est traballende in un'ambiente PHP a 32-bit e sa open_basedir est istada cunfigurada in php.ini. Custu at a causare problemas cun archìvios de prus de 4 GB e est iscussigiadu a forte.", - "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Boga•nche s'impostatzione open_basedir in su php.ini tuo o càmbia a su PHP a 64-bit.", - "Set an admin username." : "Imposta unu nùmene utente pro chie amministrat.", + "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Boga·nche sa cunfiguratzione open_basedir in su php.ini tuo o càmbia a su PHP a 64-bit.", "Set an admin password." : "Imposta una crae pro chie amministrat.", "Cannot create or write into the data directory %s" : "No faghet a creare o a iscriere a intro de sa cartella de datos %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Su motore de cumpartzidura %s depet cumpletare s'interfache OCP\\Share_Backend", @@ -123,7 +118,6 @@ "Expiration date is in the past" : "Sa data de iscadèntzia est giai passada", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["No faghet a impostare sa data de iscadèntzia a prus de %n die in su benidore","No faghet a impostare sa data de iscadèntzia a prus de %n dies in su benidore"], "Sharing is only allowed with group members" : "Sa cumpartzidura est permìtida isceti cun is partetzipantes de su grupu", - "Sharing %s failed, because this item is already shared with user %s" : "No at fatu a cumpartzire %s, ca custu elementu est giai istadu cumpartzidu cun s'utente %s", "%1$s shared »%2$s« with you" : "%1$s at cumpartzidu »%2$s cun tegus", "%1$s shared »%2$s« with you." : "%1$s at cumpartzidu »%2$s cun tegus.", "Click the button below to open it." : "Incarca su butone a suta pro dd'abèrrere.", @@ -175,13 +169,6 @@ "Nov." : "SAnd.", "Dec." : "Nad.", "A valid password must be provided" : "Depes frunire una crae bàlida", - "The username is already being used" : "Su nùmene utente est giai impreadu", - "Could not create user" : "No at fatu a creare s'utente", - "A valid username must be provided" : "Depes frunire unu nùmene utente bàlidu", - "Username contains whitespace at the beginning or at the end" : "Su nùmene utente cuntenet ispàtzios bòidos a su cumintzu o a sa fine", - "Username must not consist of dots only" : "Su nùmene utente no depet tènnere isceti puntos", - "Username is invalid because files already exist for this user" : "Su nùmene utente no est bàlidu, ca is archìvios bi sunt giai pro cust'utèntzia", - "User disabled" : "Utèntzia disativada", "Login canceled by app" : "Atzessu annulladu dae s'aplicatzione", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Non faghet a installare s'aplicatzione %1$s ca is dipendèntzias in fatu non sunt satisfatos:%2$s", "a safe home for all your data" : "unu logu siguru pro totu is datos tuos", @@ -193,13 +180,12 @@ "Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "Ma si preferes allogare s'archìviu de letura isceti congi.php, imposta su sèberu \"config_is_read_only\" a \"true\". Càstia %s", "PHP module %s not installed." : "Su mòdulu PHP %s no est installadu.", "Please ask your server administrator to install the module." : "Pedi a s'amministratzione de serbidore de installare su mòdulu.", - "PHP setting \"%s\" is not set to \"%s\"." : "S'impostatzione PHP %s no est a \"%s\".", - "Adjusting this setting in php.ini will make Nextcloud run again" : "Assentende cust'impostatzione in php.ini at a torrare a fàghere traballare Nextcloud", + "PHP setting \"%s\" is not set to \"%s\"." : "Sa cunfiguratzione PHP %s no est a \"%s\".", + "Adjusting this setting in php.ini will make Nextcloud run again" : "Assentende custa cunfiguratzione in php.ini at a torrare a fàghere traballare Nextcloud", "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Parit che PHP siat impostadu pro nde bogare is blocos de documentatzione in lìnia. Custu at a impedire s'atzessu a medas aplicatziones printzipales.", "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Podet èssere causadu dae una memòria temporànea/atzeleradore cales Zend Opcache o eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Is mòdulos PHP sunt istados installados, ma sunt ancora elencados comente mancantes?", "Please ask your server administrator to restart the web server." : "Pedi a s'amministratzione de su serbidore de torrare a aviare su serbidore ìnternet.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Càmbia is permissos a 0770 aici sa cartella no podet èssere in is elencos de àteras utèntzias.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Assegura•ti chi in sa cartella de datos de orìgine nche siat un'archìviu cun nùmene \".ocdata\".", "Action \"%s\" not supported or implemented." : "S'atzione \"%s\" no est suportada o cumpletada.", "Authentication failed, wrong token or provider ID given" : "No at fatu a fàghere s'autenticatzione, token o ID de su frunidore isballiados", @@ -213,9 +199,24 @@ "Storage is temporarily not available" : "S'archiviatzione no est disponìbile pro immoe.", "Storage connection timeout. %s" : "Tempus de connessione a s'archiviatzione iscadidu. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Is archìvios de s'aplicatzione %1$s no sunt istados cambiados in manera curreta. Assegura•ti chi b'apat una versione cumpatìbile cun su serbidore.", + "Logged in user must be an admin or sub admin" : "S'utente devet essere de s'amministratzione o de sa suta-amministratzione ", + "Logged in user must be an admin" : "S'utente devet essere de s'amministratzione ", "Full name" : "Nùmene cumpletu", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Isceti custos caràteres sunt permìtidos in unu nùmene utente: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Utèntzia disconnota", + "MySQL username and/or password not valid" : "Su nùmene utente e/o sa crae de MySQL no sunt bàlidos", + "Oracle username and/or password not valid" : "Su nùmene utente e/o sa crae de Oracle no sunt bàlidos", + "PostgreSQL username and/or password not valid" : "Su nùmene utente e/o sa crae de Postgre SQL no sunt bàlidos", + "Set an admin username." : "Imposta unu nùmene utente pro chie amministrat.", + "Sharing %s failed, because this item is already shared with user %s" : "No at fatu a cumpartzire %s, ca custu elementu est giai istadu cumpartzidu cun s'utente %s", + "The username is already being used" : "Su nùmene utente est giai impreadu", + "Could not create user" : "No at fatu a creare s'utente", + "A valid username must be provided" : "Depes frunire unu nùmene utente bàlidu", + "Username contains whitespace at the beginning or at the end" : "Su nùmene utente cuntenet ispàtzios bòidos a su cumintzu o a sa fine", + "Username must not consist of dots only" : "Su nùmene utente no depet tènnere isceti puntos", + "Username is invalid because files already exist for this user" : "Su nùmene utente no est bàlidu, ca is archìvios bi sunt giai pro cust'utèntzia", + "User disabled" : "Utèntzia disativada", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Est rechèdida a su mancu sa versione libxml2 2.7.0. Pro immoe cussa installada est sa%s.", - "To fix this issue update your libxml2 version and restart your web server." : "Pro assentare custu problema, agiorna sa versione libxml2 e torra a aviare su serbidore ìnternet." + "To fix this issue update your libxml2 version and restart your web server." : "Pro assentare custu problema, agiorna sa versione libxml2 e torra a aviare su serbidore ìnternet.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Càmbia is permissos a 0770 aici sa cartella no podet èssere in is elencos de àteras utèntzias." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/si.js b/lib/l10n/si.js index 1a5aafa2d10..55d0e69f69e 100644 --- a/lib/l10n/si.js +++ b/lib/l10n/si.js @@ -31,7 +31,6 @@ OC.L10N.register( "Address" : "ලිපිනය", "About" : "පිළිබඳව", "Role" : "කාර්යභාරය", - "Unknown user" : "නොදන්නා පරිශීලකයෙකි", "Additional settings" : "අමතර සැකසුම්", "Sunday" : "ඉරිදා", "Monday" : "සඳුදා", @@ -66,6 +65,7 @@ OC.L10N.register( "October" : "ඔක්තෝම්බර්", "November" : "නොවැම්බර්", "December" : "දෙසැම්බර්", - "Full name" : "සම්පූර්ණ නම" + "Full name" : "සම්පූර්ණ නම", + "Unknown user" : "නොදන්නා පරිශීලකයෙකි" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/si.json b/lib/l10n/si.json index d523fd7d59b..fde125f8b15 100644 --- a/lib/l10n/si.json +++ b/lib/l10n/si.json @@ -29,7 +29,6 @@ "Address" : "ලිපිනය", "About" : "පිළිබඳව", "Role" : "කාර්යභාරය", - "Unknown user" : "නොදන්නා පරිශීලකයෙකි", "Additional settings" : "අමතර සැකසුම්", "Sunday" : "ඉරිදා", "Monday" : "සඳුදා", @@ -64,6 +63,7 @@ "October" : "ඔක්තෝම්බර්", "November" : "නොවැම්බර්", "December" : "දෙසැම්බර්", - "Full name" : "සම්පූර්ණ නම" + "Full name" : "සම්පූර්ණ නම", + "Unknown user" : "නොදන්නා පරිශීලකයෙකි" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/sk.js b/lib/l10n/sk.js index 4c2843a76aa..ff0243c32e3 100644 --- a/lib/l10n/sk.js +++ b/lib/l10n/sk.js @@ -5,9 +5,9 @@ OC.L10N.register( "This can usually be fixed by giving the web server write access to the config directory." : "Toto sa zvyčajne dá opraviť poskytnutím práva webového servera na zápis do priečinka s konfiguráciou.", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Alebo, ak preferujete ponechať súbor config.php iba na čítanie, nastavte v ňom parameter \"config_is_read_only\" na true.", "See %s" : "Pozri %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplikácia %1$s nie je prítomná alebo má nekompatibilnú verziu s týmto serverom. Prosím, skontrolujte adresár aplikácií.", "Sample configuration detected" : "Detekovaná bola vzorová konfigurácia", "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" : "Zistilo sa, že konfigurácia bola skopírovaná zo vzorových súborov. Takáto konfigurácia nie je podporovaná a môže poškodiť vašu inštaláciu. Prečítajte si dokumentáciu pred vykonaním zmien v config.php", - "404" : "404", "The page could not be found on the server." : "Stránka nebola nájdená na serveri.", "%s email verification" : "%s overenie e-mailu", "Email verification" : "Overenie e-mailu", @@ -36,9 +36,9 @@ OC.L10N.register( "The following platforms are supported: %s" : "Podporované sú nasledujúce platformy: %s", "Server version %s or higher is required." : "Je vyžadovaná verzia servera %s alebo vyššia.", "Server version %s or lower is required." : "Je vyžadovaná verzia servera %s alebo nižšia.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prihlásený používateľ musí byť správcom, podadministrátorom alebo musí mať špeciálne právo na prístup k tomuto nastaveniu", - "Logged in user must be an admin or sub admin" : "Prihlásený používateľ musí byť správcom alebo správcom pre čiastkovú oblasť.", - "Logged in user must be an admin" : "Prihlásený používateľ musí byť správca", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Prihlásený účet musí byť správcom, podadministrátorom alebo musí mať špeciálne právo na prístup k tomuto nastaveniu.", + "Logged in account must be an admin or sub admin" : "Prihlásený účet musí byť správcom alebo sub správcom.", + "Logged in account must be an admin" : "Prihlásený účet musí byť správcom", "Wiping of device %s has started" : "Začalo sa mazanie zariadenia %s", "Wiping of device »%s« has started" : "Začalo sa mazanie zariadenia „%s“", "»%s« started remote wipe" : "„%s“ začalo mazanie na diaľku", @@ -57,6 +57,7 @@ OC.L10N.register( "Avatar image is not square" : "Obrázok avatara nie je štvorcový", "Files" : "Súbory", "View profile" : "Zobraziť profil", + "Local time: %s" : "Miestny čas: %s", "today" : "dnes", "tomorrow" : "zajtra", "yesterday" : "včera", @@ -112,25 +113,26 @@ OC.L10N.register( "Address" : "Adresa", "Profile picture" : "Profilový obrázok", "About" : "O aplikácii", - "Headline" : "Titulok", + "Display name" : "Zobrazované meno", + "Headline" : "Titul", "Organisation" : "Organizácia", "Role" : "Rola", - "Unknown user" : "Neznámy používateľ", + "Unknown account" : "Neznámy účet", "Additional settings" : "Ďalšie nastavenia", - "Enter the database username and name for %s" : "Zadajte užívateľské meno a názov databázy pre %s", - "Enter the database username for %s" : "Zadajte užívateľské meno databázy pre %s", + "Enter the database Login and name for %s" : "Zadajte prihlasovacie meno a názov databázy pre %s", + "Enter the database Login for %s" : "Zadajte prihlasovacie meno databázy pre %s", "Enter the database name for %s" : "Zadajte názov databázy pre %s", "You cannot use dots in the database name %s" : "V názve databázy %s nemôžete používať bodky", - "MySQL username and/or password not valid" : "Neplatné užívateľské meno a/alebo heslo do MySQL", + "MySQL Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo do MySQL je neplatné", "You need to enter details of an existing account." : "Musíte zadať údaje existujúceho účtu.", "Oracle connection could not be established" : "Nie je možné pripojiť sa k Oracle", - "Oracle username and/or password not valid" : "Používateľské meno a/alebo heslo pre Oracle databázu je neplatné", - "PostgreSQL username and/or password not valid" : "Používateľské meno a/alebo heslo pre PostgreSQL databázu je neplatné", + "Oracle Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo pre Oracle databázu je neplatné", + "PostgreSQL Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo pre PostgreSQL databázu je neplatné", "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 je podporovaný a %s nebude správne fungovať na tejto platforme. Použite ho na vlastné riziko!", "For the best results, please consider using a GNU/Linux server instead." : "Pre dosiahnutie najlepších výsledkov, prosím zvážte použitie GNU/Linux servera.", "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." : "Zdá sa, že táto inštancia %s beží v 32-bitovom prostredí PHP a v php.ini bola nastavená voľba open_basedir. To bude zdrojom problémov so súbormi väčšími ako 4GB a dôrazne sa neodporúča.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Prosím, odstráňte nastavenie open_basedir vo vašom php.ini alebo prejdite na 64-bit PHP.", - "Set an admin username." : "Zadajte používateľské meno administrátora.", + "Set an admin Login." : "Nastaviť prihlasovacie meno administrátora.", "Set an admin password." : "Zadajte heslo administrátora.", "Cannot create or write into the data directory %s" : "Nemožno vytvoriť alebo zapisovať do priečinka dát %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Backend pre sprístupnenie %s musí implementovať rozhranie OCP\\Share_Backend", @@ -148,11 +150,12 @@ OC.L10N.register( "Expiration date is in the past" : "Dátum konca platnosti je v minulosti", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Nie je možné nastaviť dátum konca platnosti viac ako %s deň v budúcnosti","Nie je možné nastaviť dátum konca platnosti viac ako %s dní v budúcnosti","Nie je možné nastaviť dátum konca platnosti viac ako %s dní v budúcnosti","Nie je možné nastaviť dátum konca platnosti viac ako %s dní v budúcnosti"], "Sharing is only allowed with group members" : "Zdieľanie je možné iba s členmi skupiny", - "Sharing %s failed, because this item is already shared with user %s" : "Sprístupnenie %s zlyhalo, táto položka už je používateľovi %s zozdieľaná", + "Sharing %s failed, because this item is already shared with the account %s" : "Zdieľanie %s zlyhalo, pretože táto položka už je užívateľovi %s zozdieľaná.", "%1$s shared »%2$s« with you" : "%1$s vám sprístupnil »%2$s«", "%1$s shared »%2$s« with you." : "%1$s vám sprístupnil »%2$s«.", "Click the button below to open it." : "Pre otvorenie klienta kliknite na tlačítko nižšie.", "The requested share does not exist anymore" : "Požadované sprístupnenie už neexistuje", + "The requested share comes from a disabled user" : "Požadované zdieľanie pochádza od zakázaného užívateľa.", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Bol dosiahnutý limit používateľov a používateľ nebol vytvorený. Pozrite sa do upozornení pre viac informácií.", "Could not find category \"%s\"" : "Nemožno nájsť danú kategóriu \"%s\"", "Sunday" : "Nedeľa", @@ -201,13 +204,14 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Musíte zadať platné heslo", - "The username is already being used" : "Meno používateľa je už použité", - "Could not create user" : "Nepodarilo sa vytvoriť používateľa", - "A valid username must be provided" : "Musíte zadať platné používateľské meno", - "Username contains whitespace at the beginning or at the end" : "Meno používateľa obsahuje na začiatku, alebo na konci medzeru", - "Username must not consist of dots only" : "Používateľské meno sa nesmie skladať len z bodiek", - "Username is invalid because files already exist for this user" : "Používateľské meno je neplatné, pretože pre tohto používateľa už existujú súbory", - "User disabled" : "Používateľ zakázaný", + "The Login is already being used" : "Prihlasovacie meno sa už používa", + "Could not create account" : "Nepodarilo sa vytvoriť účet", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "V prihlasovacom mene je možné použiť iba nasledovné znaky: \"a-z\", \"A-Z\", \"0-9\", medzery a \"_.@-'\"", + "A valid Login must be provided" : "Musíte zadať platné prihlasovacie meno.", + "Login contains whitespace at the beginning or at the end" : "Prihlasovacie meno obsahuje medzeru na začiatku alebo na konci.", + "Login must not consist of dots only" : "Prihlasovacie meno sa nesmie skladať len z bodiek", + "Login is invalid because files already exist for this user" : "Prihlasovacie meno je neplatné, pretože pre tohto užívateľa už existujú súbory.", + "Account disabled" : "Účet bol zakázaný", "Login canceled by app" : "Prihlásenie bolo zrušené aplikáciou", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Aplikáciu \"%1$s\" nie je možné inštalovať, pretože nie sú splnené nasledovné závislosti: %2$s", "a safe home for all your data" : "bezpečný domov pre všetky vaše dáta", @@ -240,8 +244,8 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Prosím, požiadajte administrátora vášho servera o reštartovanie webového servera.", "The required %s config variable is not configured in the config.php file." : "Požadovaná konfiguračná premenná %s nie je nakonfigurovaná v súbore config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Požiadajte správcu servera, aby skontroloval konfiguráciu Nextcloud.", - "Your data directory is readable by other users." : "Váš priečinok s dátami je prístupný na čítanie ostatným užívateľom.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Prosím, zmeňte oprávnenia na 0770, aby tento priečinok nemohli ostatní používatelia otvoriť.", + "Your data directory is readable by other people." : "Váš adresár s dátami je prístupný na čítanie ostatným ľuďom.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Prosím, zmeňte oprávnenia na 0770, aby tento adresár nemohli ostatní ľudia otvoriť.", "Your data directory must be an absolute path." : "Priečinok s dátami musí byť zadaný ako absolútna cesta.", "Check the value of \"datadirectory\" in your configuration." : "Skontrolujte hodnotu \"datadirectory\" vo vašej konfigurácii.", "Your data directory is invalid." : "Priečinok pre dáta je neplatný.", @@ -257,13 +261,41 @@ OC.L10N.register( "Storage connection error. %s" : "Chyba pripojenia k úložisku. %s", "Storage is temporarily not available" : "Úložisko je dočasne nedostupné", "Storage connection timeout. %s" : "Vypršanie pripojenia k úložisku. %s", + "Free prompt" : "Bezplatný formulár", + "Runs an arbitrary prompt through the language model." : "Spúšťa ľubovoľný príkaz cez jazykový model.", + "Generate headline" : "Generovať nadpis", + "Generates a possible headline for a text." : "Generuje možný nadpis pre text.", + "Summarize" : "Zhrnutie", + "Summarizes text by reducing its length without losing key information." : "Zhrňuje text tým, že znižuje jeho dĺžku bez straty kľúčových informácií.", + "Extract topics" : "Extrahovať témy", + "Extracts topics from a text and outputs them separated by commas." : "Extrahuje témy z textu a vypisuje ich oddelené čiarkami.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Súbory aplikácie %1$s neboli správne nahradené. Uistite sa, že to je verzia kompatibilná so serverom.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prihlásený používateľ musí byť správcom, podadministrátorom alebo musí mať špeciálne právo na prístup k tomuto nastaveniu", + "Logged in user must be an admin or sub admin" : "Prihlásený používateľ musí byť správcom alebo správcom pre čiastkovú oblasť.", + "Logged in user must be an admin" : "Prihlásený používateľ musí byť správca", "Full name" : "Celé meno", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Bol dosiahnutý limit používateľov a používateľ nebol vytvorený. Pozrite sa do upozornení pre viac informácií.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "V mene používateľa je možné použiť iba nasledovné znaky: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Neznámy používateľ", + "Enter the database username and name for %s" : "Zadajte užívateľské meno a názov databázy pre %s", + "Enter the database username for %s" : "Zadajte užívateľské meno databázy pre %s", + "MySQL username and/or password not valid" : "Neplatné užívateľské meno a/alebo heslo do MySQL", + "Oracle username and/or password not valid" : "Používateľské meno a/alebo heslo pre Oracle databázu je neplatné", + "PostgreSQL username and/or password not valid" : "Používateľské meno a/alebo heslo pre PostgreSQL databázu je neplatné", + "Set an admin username." : "Zadajte používateľské meno administrátora.", + "Sharing %s failed, because this item is already shared with user %s" : "Sprístupnenie %s zlyhalo, táto položka už je používateľovi %s zozdieľaná", + "The username is already being used" : "Meno používateľa je už použité", + "Could not create user" : "Nepodarilo sa vytvoriť používateľa", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "V mene užívateľa je možné použiť iba nasledovné znaky: \"a-z\", \"A-Z\", \"0-9\", medzery a \"_.@-'\"", + "A valid username must be provided" : "Musíte zadať platné používateľské meno", + "Username contains whitespace at the beginning or at the end" : "Meno používateľa obsahuje na začiatku, alebo na konci medzeru", + "Username must not consist of dots only" : "Používateľské meno sa nesmie skladať len z bodiek", + "Username is invalid because files already exist for this user" : "Používateľské meno je neplatné, pretože pre tohto používateľa už existujú súbory", + "User disabled" : "Používateľ zakázaný", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Vyžadovaná verzia libxml2 je 2.7.0 a vyššia. Momentálne je nainštalovaná verzia %s.", "To fix this issue update your libxml2 version and restart your web server." : "Pre vyriešenie tohto problému aktualizujte prosím verziu libxml2 a reštartujte webový server.", "PostgreSQL >= 9 required." : "Vyžadované PostgreSQL >= 9.", - "Please upgrade your database version." : "Prosím, aktualizujte verziu svojej databázy." + "Please upgrade your database version." : "Prosím, aktualizujte verziu svojej databázy.", + "Your data directory is readable by other users." : "Váš priečinok s dátami je prístupný na čítanie ostatným užívateľom.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Prosím, zmeňte oprávnenia na 0770, aby tento priečinok nemohli ostatní používatelia otvoriť." }, "nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);"); diff --git a/lib/l10n/sk.json b/lib/l10n/sk.json index 23c783f5e3e..b3d9edb7d52 100644 --- a/lib/l10n/sk.json +++ b/lib/l10n/sk.json @@ -3,9 +3,9 @@ "This can usually be fixed by giving the web server write access to the config directory." : "Toto sa zvyčajne dá opraviť poskytnutím práva webového servera na zápis do priečinka s konfiguráciou.", "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Alebo, ak preferujete ponechať súbor config.php iba na čítanie, nastavte v ňom parameter \"config_is_read_only\" na true.", "See %s" : "Pozri %s", + "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Aplikácia %1$s nie je prítomná alebo má nekompatibilnú verziu s týmto serverom. Prosím, skontrolujte adresár aplikácií.", "Sample configuration detected" : "Detekovaná bola vzorová konfigurácia", "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" : "Zistilo sa, že konfigurácia bola skopírovaná zo vzorových súborov. Takáto konfigurácia nie je podporovaná a môže poškodiť vašu inštaláciu. Prečítajte si dokumentáciu pred vykonaním zmien v config.php", - "404" : "404", "The page could not be found on the server." : "Stránka nebola nájdená na serveri.", "%s email verification" : "%s overenie e-mailu", "Email verification" : "Overenie e-mailu", @@ -34,9 +34,9 @@ "The following platforms are supported: %s" : "Podporované sú nasledujúce platformy: %s", "Server version %s or higher is required." : "Je vyžadovaná verzia servera %s alebo vyššia.", "Server version %s or lower is required." : "Je vyžadovaná verzia servera %s alebo nižšia.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prihlásený používateľ musí byť správcom, podadministrátorom alebo musí mať špeciálne právo na prístup k tomuto nastaveniu", - "Logged in user must be an admin or sub admin" : "Prihlásený používateľ musí byť správcom alebo správcom pre čiastkovú oblasť.", - "Logged in user must be an admin" : "Prihlásený používateľ musí byť správca", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Prihlásený účet musí byť správcom, podadministrátorom alebo musí mať špeciálne právo na prístup k tomuto nastaveniu.", + "Logged in account must be an admin or sub admin" : "Prihlásený účet musí byť správcom alebo sub správcom.", + "Logged in account must be an admin" : "Prihlásený účet musí byť správcom", "Wiping of device %s has started" : "Začalo sa mazanie zariadenia %s", "Wiping of device »%s« has started" : "Začalo sa mazanie zariadenia „%s“", "»%s« started remote wipe" : "„%s“ začalo mazanie na diaľku", @@ -55,6 +55,7 @@ "Avatar image is not square" : "Obrázok avatara nie je štvorcový", "Files" : "Súbory", "View profile" : "Zobraziť profil", + "Local time: %s" : "Miestny čas: %s", "today" : "dnes", "tomorrow" : "zajtra", "yesterday" : "včera", @@ -110,25 +111,26 @@ "Address" : "Adresa", "Profile picture" : "Profilový obrázok", "About" : "O aplikácii", - "Headline" : "Titulok", + "Display name" : "Zobrazované meno", + "Headline" : "Titul", "Organisation" : "Organizácia", "Role" : "Rola", - "Unknown user" : "Neznámy používateľ", + "Unknown account" : "Neznámy účet", "Additional settings" : "Ďalšie nastavenia", - "Enter the database username and name for %s" : "Zadajte užívateľské meno a názov databázy pre %s", - "Enter the database username for %s" : "Zadajte užívateľské meno databázy pre %s", + "Enter the database Login and name for %s" : "Zadajte prihlasovacie meno a názov databázy pre %s", + "Enter the database Login for %s" : "Zadajte prihlasovacie meno databázy pre %s", "Enter the database name for %s" : "Zadajte názov databázy pre %s", "You cannot use dots in the database name %s" : "V názve databázy %s nemôžete používať bodky", - "MySQL username and/or password not valid" : "Neplatné užívateľské meno a/alebo heslo do MySQL", + "MySQL Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo do MySQL je neplatné", "You need to enter details of an existing account." : "Musíte zadať údaje existujúceho účtu.", "Oracle connection could not be established" : "Nie je možné pripojiť sa k Oracle", - "Oracle username and/or password not valid" : "Používateľské meno a/alebo heslo pre Oracle databázu je neplatné", - "PostgreSQL username and/or password not valid" : "Používateľské meno a/alebo heslo pre PostgreSQL databázu je neplatné", + "Oracle Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo pre Oracle databázu je neplatné", + "PostgreSQL Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo pre PostgreSQL databázu je neplatné", "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 je podporovaný a %s nebude správne fungovať na tejto platforme. Použite ho na vlastné riziko!", "For the best results, please consider using a GNU/Linux server instead." : "Pre dosiahnutie najlepších výsledkov, prosím zvážte použitie GNU/Linux servera.", "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." : "Zdá sa, že táto inštancia %s beží v 32-bitovom prostredí PHP a v php.ini bola nastavená voľba open_basedir. To bude zdrojom problémov so súbormi väčšími ako 4GB a dôrazne sa neodporúča.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Prosím, odstráňte nastavenie open_basedir vo vašom php.ini alebo prejdite na 64-bit PHP.", - "Set an admin username." : "Zadajte používateľské meno administrátora.", + "Set an admin Login." : "Nastaviť prihlasovacie meno administrátora.", "Set an admin password." : "Zadajte heslo administrátora.", "Cannot create or write into the data directory %s" : "Nemožno vytvoriť alebo zapisovať do priečinka dát %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Backend pre sprístupnenie %s musí implementovať rozhranie OCP\\Share_Backend", @@ -146,11 +148,12 @@ "Expiration date is in the past" : "Dátum konca platnosti je v minulosti", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Nie je možné nastaviť dátum konca platnosti viac ako %s deň v budúcnosti","Nie je možné nastaviť dátum konca platnosti viac ako %s dní v budúcnosti","Nie je možné nastaviť dátum konca platnosti viac ako %s dní v budúcnosti","Nie je možné nastaviť dátum konca platnosti viac ako %s dní v budúcnosti"], "Sharing is only allowed with group members" : "Zdieľanie je možné iba s členmi skupiny", - "Sharing %s failed, because this item is already shared with user %s" : "Sprístupnenie %s zlyhalo, táto položka už je používateľovi %s zozdieľaná", + "Sharing %s failed, because this item is already shared with the account %s" : "Zdieľanie %s zlyhalo, pretože táto položka už je užívateľovi %s zozdieľaná.", "%1$s shared »%2$s« with you" : "%1$s vám sprístupnil »%2$s«", "%1$s shared »%2$s« with you." : "%1$s vám sprístupnil »%2$s«.", "Click the button below to open it." : "Pre otvorenie klienta kliknite na tlačítko nižšie.", "The requested share does not exist anymore" : "Požadované sprístupnenie už neexistuje", + "The requested share comes from a disabled user" : "Požadované zdieľanie pochádza od zakázaného užívateľa.", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Bol dosiahnutý limit používateľov a používateľ nebol vytvorený. Pozrite sa do upozornení pre viac informácií.", "Could not find category \"%s\"" : "Nemožno nájsť danú kategóriu \"%s\"", "Sunday" : "Nedeľa", @@ -199,13 +202,14 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Musíte zadať platné heslo", - "The username is already being used" : "Meno používateľa je už použité", - "Could not create user" : "Nepodarilo sa vytvoriť používateľa", - "A valid username must be provided" : "Musíte zadať platné používateľské meno", - "Username contains whitespace at the beginning or at the end" : "Meno používateľa obsahuje na začiatku, alebo na konci medzeru", - "Username must not consist of dots only" : "Používateľské meno sa nesmie skladať len z bodiek", - "Username is invalid because files already exist for this user" : "Používateľské meno je neplatné, pretože pre tohto používateľa už existujú súbory", - "User disabled" : "Používateľ zakázaný", + "The Login is already being used" : "Prihlasovacie meno sa už používa", + "Could not create account" : "Nepodarilo sa vytvoriť účet", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "V prihlasovacom mene je možné použiť iba nasledovné znaky: \"a-z\", \"A-Z\", \"0-9\", medzery a \"_.@-'\"", + "A valid Login must be provided" : "Musíte zadať platné prihlasovacie meno.", + "Login contains whitespace at the beginning or at the end" : "Prihlasovacie meno obsahuje medzeru na začiatku alebo na konci.", + "Login must not consist of dots only" : "Prihlasovacie meno sa nesmie skladať len z bodiek", + "Login is invalid because files already exist for this user" : "Prihlasovacie meno je neplatné, pretože pre tohto užívateľa už existujú súbory.", + "Account disabled" : "Účet bol zakázaný", "Login canceled by app" : "Prihlásenie bolo zrušené aplikáciou", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Aplikáciu \"%1$s\" nie je možné inštalovať, pretože nie sú splnené nasledovné závislosti: %2$s", "a safe home for all your data" : "bezpečný domov pre všetky vaše dáta", @@ -238,8 +242,8 @@ "Please ask your server administrator to restart the web server." : "Prosím, požiadajte administrátora vášho servera o reštartovanie webového servera.", "The required %s config variable is not configured in the config.php file." : "Požadovaná konfiguračná premenná %s nie je nakonfigurovaná v súbore config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Požiadajte správcu servera, aby skontroloval konfiguráciu Nextcloud.", - "Your data directory is readable by other users." : "Váš priečinok s dátami je prístupný na čítanie ostatným užívateľom.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Prosím, zmeňte oprávnenia na 0770, aby tento priečinok nemohli ostatní používatelia otvoriť.", + "Your data directory is readable by other people." : "Váš adresár s dátami je prístupný na čítanie ostatným ľuďom.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Prosím, zmeňte oprávnenia na 0770, aby tento adresár nemohli ostatní ľudia otvoriť.", "Your data directory must be an absolute path." : "Priečinok s dátami musí byť zadaný ako absolútna cesta.", "Check the value of \"datadirectory\" in your configuration." : "Skontrolujte hodnotu \"datadirectory\" vo vašej konfigurácii.", "Your data directory is invalid." : "Priečinok pre dáta je neplatný.", @@ -255,13 +259,41 @@ "Storage connection error. %s" : "Chyba pripojenia k úložisku. %s", "Storage is temporarily not available" : "Úložisko je dočasne nedostupné", "Storage connection timeout. %s" : "Vypršanie pripojenia k úložisku. %s", + "Free prompt" : "Bezplatný formulár", + "Runs an arbitrary prompt through the language model." : "Spúšťa ľubovoľný príkaz cez jazykový model.", + "Generate headline" : "Generovať nadpis", + "Generates a possible headline for a text." : "Generuje možný nadpis pre text.", + "Summarize" : "Zhrnutie", + "Summarizes text by reducing its length without losing key information." : "Zhrňuje text tým, že znižuje jeho dĺžku bez straty kľúčových informácií.", + "Extract topics" : "Extrahovať témy", + "Extracts topics from a text and outputs them separated by commas." : "Extrahuje témy z textu a vypisuje ich oddelené čiarkami.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Súbory aplikácie %1$s neboli správne nahradené. Uistite sa, že to je verzia kompatibilná so serverom.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prihlásený používateľ musí byť správcom, podadministrátorom alebo musí mať špeciálne právo na prístup k tomuto nastaveniu", + "Logged in user must be an admin or sub admin" : "Prihlásený používateľ musí byť správcom alebo správcom pre čiastkovú oblasť.", + "Logged in user must be an admin" : "Prihlásený používateľ musí byť správca", "Full name" : "Celé meno", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Bol dosiahnutý limit používateľov a používateľ nebol vytvorený. Pozrite sa do upozornení pre viac informácií.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "V mene používateľa je možné použiť iba nasledovné znaky: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Neznámy používateľ", + "Enter the database username and name for %s" : "Zadajte užívateľské meno a názov databázy pre %s", + "Enter the database username for %s" : "Zadajte užívateľské meno databázy pre %s", + "MySQL username and/or password not valid" : "Neplatné užívateľské meno a/alebo heslo do MySQL", + "Oracle username and/or password not valid" : "Používateľské meno a/alebo heslo pre Oracle databázu je neplatné", + "PostgreSQL username and/or password not valid" : "Používateľské meno a/alebo heslo pre PostgreSQL databázu je neplatné", + "Set an admin username." : "Zadajte používateľské meno administrátora.", + "Sharing %s failed, because this item is already shared with user %s" : "Sprístupnenie %s zlyhalo, táto položka už je používateľovi %s zozdieľaná", + "The username is already being used" : "Meno používateľa je už použité", + "Could not create user" : "Nepodarilo sa vytvoriť používateľa", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "V mene užívateľa je možné použiť iba nasledovné znaky: \"a-z\", \"A-Z\", \"0-9\", medzery a \"_.@-'\"", + "A valid username must be provided" : "Musíte zadať platné používateľské meno", + "Username contains whitespace at the beginning or at the end" : "Meno používateľa obsahuje na začiatku, alebo na konci medzeru", + "Username must not consist of dots only" : "Používateľské meno sa nesmie skladať len z bodiek", + "Username is invalid because files already exist for this user" : "Používateľské meno je neplatné, pretože pre tohto používateľa už existujú súbory", + "User disabled" : "Používateľ zakázaný", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Vyžadovaná verzia libxml2 je 2.7.0 a vyššia. Momentálne je nainštalovaná verzia %s.", "To fix this issue update your libxml2 version and restart your web server." : "Pre vyriešenie tohto problému aktualizujte prosím verziu libxml2 a reštartujte webový server.", "PostgreSQL >= 9 required." : "Vyžadované PostgreSQL >= 9.", - "Please upgrade your database version." : "Prosím, aktualizujte verziu svojej databázy." + "Please upgrade your database version." : "Prosím, aktualizujte verziu svojej databázy.", + "Your data directory is readable by other users." : "Váš priečinok s dátami je prístupný na čítanie ostatným užívateľom.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Prosím, zmeňte oprávnenia na 0770, aby tento priečinok nemohli ostatní používatelia otvoriť." },"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);" }
\ No newline at end of file diff --git a/lib/l10n/sl.js b/lib/l10n/sl.js index 7de5d7dad30..e5a5358eb9f 100644 --- a/lib/l10n/sl.js +++ b/lib/l10n/sl.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Program %1$s ni na voljo ali pa je nameščena neskladna različica za ta strežnik. Preverite mapo programov.", "Sample configuration detected" : "Zaznana je neustrezna vzorčna nastavitev", "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" : "V sistem je bila kopirana datoteka s vzorčnimi nastavitvami. To lahko vpliva na namestitev in zato možnost ni podprta. Pred spremembami datoteke config.php si natančno preberite dokumentacijo.", - "404" : "404", "The page could not be found on the server." : "Strani na strežniku ni mogoče najti.", "Email verification" : "Overjanje elektronskega naslova", "Click the following link to confirm your email." : "Kliknite na povezavo za potrditev elektronskega naslova.", @@ -35,9 +34,6 @@ OC.L10N.register( "The following platforms are supported: %s" : "Podprta so okolja: %s", "Server version %s or higher is required." : "Zahtevana je različica strežnika %s ali višja.", "Server version %s or lower is required." : "Zahtevana je različica strežnika %s ali nižja.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prijavljen uporabnik mora biti določen za skrbnika, pomočnika skrbnika ali pa mora imeti dodeljene posebna dovoljenja za dostop do nastavitve.", - "Logged in user must be an admin or sub admin" : "Prijavljen uporabnik mora imeti dovoljenja skrbnika ali podpornega skrbnika", - "Logged in user must be an admin" : "Prijavljen uporabnik mora biti tudi skrbnik", "Wiping of device %s has started" : "Začeto je brisanje podatkov na napravi %s.", "Wiping of device »%s« has started" : "Začeto je brisanje podatkov na napravi »%s«", "»%s« started remote wipe" : "Program »%s« je začel izvajati oddaljeno varnostno brisanje", @@ -116,22 +112,15 @@ OC.L10N.register( "Headline" : "Naslov", "Organisation" : "Ustanova", "Role" : "Vloga", - "Unknown user" : "Neznan uporabnik", "Additional settings" : "Dodatne nastavitve", - "Enter the database username and name for %s" : "Vpis uporabniškega imena in imena podatkovne zbirke za %s.", - "Enter the database username for %s" : "Vpis uporabniškega imena podatkovne zbirke za %s.", "Enter the database name for %s" : "Vpis imena podatkovne zbirke za %s.", "You cannot use dots in the database name %s" : "V imenu podatkovne zbirke %s ni dovoljeno uporabljati pik.", - "MySQL username and/or password not valid" : "Uporabniško ime ali geslo MySQL ni veljavno", "You need to enter details of an existing account." : "Vpisati je treba podrobnosti obstoječega računa.", "Oracle connection could not be established" : "Povezave s sistemom Oracle ni mogoče vzpostaviti.", - "Oracle username and/or password not valid" : "Uporabniško ime ali geslo Oracle ni veljavno", - "PostgreSQL username and/or password not valid" : "Uporabniško ime ali geslo PostgreSQL ni veljavno", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Sistem Mac OS X ni podprt, zato %s v tem okolju ne bo deloval zanesljivo. Program uporabljate na lastno odgovornost! ", "For the best results, please consider using a GNU/Linux server instead." : "Za najboljše rezultate je priporočljivo uporabljati strežnik 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." : "Kaže, da je dejavna seja %s zagnana v 32-bitnem okolju PHP in, da je v datoteki php.ini nastavljen open_basedir . Tako delovanje ni priporočljivo, saj se lahko pojavijo težave z datotekami, večjimi od 4GB.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Odstraniti je treba nastavitev open_basedir v datoteki php.ini ali pa preklopiti na 64-bitno okolje PHP.", - "Set an admin username." : "Nastavi uporabniško ime skrbnika.", "Set an admin password." : "Nastavi skrbniško geslo.", "Cannot create or write into the data directory %s" : "Ni mogoče zapisati podatkov v podatkovno mapo %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Souporaba ozadnjega programa %s mora vsebovati tudi vmesnik OCP\\Share_Backend", @@ -149,7 +138,6 @@ OC.L10N.register( "Expiration date is in the past" : "Datum preteka je že mimo!", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Datuma pretaka ni mogoče nastaviti za več kot %n dan v prihodnost.","Datuma pretaka ni mogoče nastaviti za več kot %n dneva v prihodnost.","Datuma pretaka ni mogoče nastaviti za več kot %n dni v prihodnost.","Datuma pretaka ni mogoče nastaviti za več kot %n dni v prihodnost."], "Sharing is only allowed with group members" : "Souporaba je dovoljena le med člani skupine", - "Sharing %s failed, because this item is already shared with user %s" : "Nastavljanje souporabe %s je spodletelo, ker je predmet že v souporabi z uporabnikom %s.", "%1$s shared »%2$s« with you" : "%1$s vam omogoča souporabo »%2$s«", "%1$s shared »%2$s« with you." : "%1$s vam omogoča souporabo »%2$s«.", "Click the button below to open it." : "Kliknite na gumb za odpiranje.", @@ -201,14 +189,6 @@ OC.L10N.register( "Nov." : "nov", "Dec." : "dec", "A valid password must be provided" : "Navedeno mora biti veljavno geslo", - "The username is already being used" : "Vpisano uporabniško ime je že v uporabi", - "Could not create user" : "Uporabnika ni mogoče ustvariti", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "V uporabniškem imenu je dovoljeno uporabiti le znake: »a–z«, »A–Z«, »0–9«, presledki in »_.@-«\".", - "A valid username must be provided" : "Navedeno mora biti veljavno uporabniško ime", - "Username contains whitespace at the beginning or at the end" : "Uporabniško ime vsebuje presledni znak na začetku ali na koncu imena.", - "Username must not consist of dots only" : "Uporabniško ime ne sme biti zgolj iz pik", - "Username is invalid because files already exist for this user" : "Uporabniško ime ni veljavno, ker za tega uporabnika že obstajajo datoteke", - "User disabled" : "Uporabnik je onemogočen", "Login canceled by app" : "Program onemogoča prijavo", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Programa »%1$s« ni mogoče namestiti zaradi nerešenih odvisnosti: %2$s", "a safe home for all your data" : "Varno okolje za vaše podatke!", @@ -239,7 +219,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Napako je najverjetneje povzročil predpomnilnik ali pospeševalnik, kot sta Zend OPcache ali eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Ali so bili moduli PHP nameščeni, pa so še vedno označeni kot manjkajoči?", "Please ask your server administrator to restart the web server." : "Obvestite skrbnika strežnika, da je treba ponovno zagnati spletni strežnik.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Spremenite dovoljenja mape na 0770 in s tem onemogočite branje vsebine drugim uporabnikom.", "Your data directory must be an absolute path." : "Podatkovna mapa mora imeti navedeno celotno pot.", "Your data directory is invalid." : "Podatkovna mapa ni veljavna.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Prepričajte se, da je datoteka ».ocdata« v korenu podatkovne mape.", @@ -255,9 +234,29 @@ OC.L10N.register( "Storage is temporarily not available" : "Shramba trenutno ni na voljo", "Storage connection timeout. %s" : "Povezava do shrambe je časovno potekla. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Datoteke programa %1$s niso bile zamenjane na pravi način. Prepričajte se, da je na strežniku nameščena podprta različica.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prijavljen uporabnik mora biti določen za skrbnika, pomočnika skrbnika ali pa mora imeti dodeljene posebna dovoljenja za dostop do nastavitve.", + "Logged in user must be an admin or sub admin" : "Prijavljen uporabnik mora imeti dovoljenja skrbnika ali podpornega skrbnika", + "Logged in user must be an admin" : "Prijavljen uporabnik mora biti tudi skrbnik", "Full name" : "Polno ime", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "V uporabniškem imenu je dovoljeno uporabiti le znake: »a–z«, »A–Z«, »0–9« in »_.@-«\".", + "Unknown user" : "Neznan uporabnik", + "Enter the database username and name for %s" : "Vpis uporabniškega imena in imena podatkovne zbirke za %s.", + "Enter the database username for %s" : "Vpis uporabniškega imena podatkovne zbirke za %s.", + "MySQL username and/or password not valid" : "Uporabniško ime ali geslo MySQL ni veljavno", + "Oracle username and/or password not valid" : "Uporabniško ime ali geslo Oracle ni veljavno", + "PostgreSQL username and/or password not valid" : "Uporabniško ime ali geslo PostgreSQL ni veljavno", + "Set an admin username." : "Nastavi uporabniško ime skrbnika.", + "Sharing %s failed, because this item is already shared with user %s" : "Nastavljanje souporabe %s je spodletelo, ker je predmet že v souporabi z uporabnikom %s.", + "The username is already being used" : "Vpisano uporabniško ime je že v uporabi", + "Could not create user" : "Uporabnika ni mogoče ustvariti", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "V uporabniškem imenu je dovoljeno uporabiti le znake: »a–z«, »A–Z«, »0–9«, presledki in »_.@-«\".", + "A valid username must be provided" : "Navedeno mora biti veljavno uporabniško ime", + "Username contains whitespace at the beginning or at the end" : "Uporabniško ime vsebuje presledni znak na začetku ali na koncu imena.", + "Username must not consist of dots only" : "Uporabniško ime ne sme biti zgolj iz pik", + "Username is invalid because files already exist for this user" : "Uporabniško ime ni veljavno, ker za tega uporabnika že obstajajo datoteke", + "User disabled" : "Uporabnik je onemogočen", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Različica knjižnice libxml2 mora biti 2.7.0 ali višja. Trenutno je nameščena %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Za rešitev te težave je treba posodobiti knjižnico libxml2 in nato ponovno zagnati spletni strežnik." + "To fix this issue update your libxml2 version and restart your web server." : "Za rešitev te težave je treba posodobiti knjižnico libxml2 in nato ponovno zagnati spletni strežnik.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Spremenite dovoljenja mape na 0770 in s tem onemogočite branje vsebine drugim uporabnikom." }, "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"); diff --git a/lib/l10n/sl.json b/lib/l10n/sl.json index 0a2a0b69bea..47dfbda5f67 100644 --- a/lib/l10n/sl.json +++ b/lib/l10n/sl.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Program %1$s ni na voljo ali pa je nameščena neskladna različica za ta strežnik. Preverite mapo programov.", "Sample configuration detected" : "Zaznana je neustrezna vzorčna nastavitev", "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" : "V sistem je bila kopirana datoteka s vzorčnimi nastavitvami. To lahko vpliva na namestitev in zato možnost ni podprta. Pred spremembami datoteke config.php si natančno preberite dokumentacijo.", - "404" : "404", "The page could not be found on the server." : "Strani na strežniku ni mogoče najti.", "Email verification" : "Overjanje elektronskega naslova", "Click the following link to confirm your email." : "Kliknite na povezavo za potrditev elektronskega naslova.", @@ -33,9 +32,6 @@ "The following platforms are supported: %s" : "Podprta so okolja: %s", "Server version %s or higher is required." : "Zahtevana je različica strežnika %s ali višja.", "Server version %s or lower is required." : "Zahtevana je različica strežnika %s ali nižja.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prijavljen uporabnik mora biti določen za skrbnika, pomočnika skrbnika ali pa mora imeti dodeljene posebna dovoljenja za dostop do nastavitve.", - "Logged in user must be an admin or sub admin" : "Prijavljen uporabnik mora imeti dovoljenja skrbnika ali podpornega skrbnika", - "Logged in user must be an admin" : "Prijavljen uporabnik mora biti tudi skrbnik", "Wiping of device %s has started" : "Začeto je brisanje podatkov na napravi %s.", "Wiping of device »%s« has started" : "Začeto je brisanje podatkov na napravi »%s«", "»%s« started remote wipe" : "Program »%s« je začel izvajati oddaljeno varnostno brisanje", @@ -114,22 +110,15 @@ "Headline" : "Naslov", "Organisation" : "Ustanova", "Role" : "Vloga", - "Unknown user" : "Neznan uporabnik", "Additional settings" : "Dodatne nastavitve", - "Enter the database username and name for %s" : "Vpis uporabniškega imena in imena podatkovne zbirke za %s.", - "Enter the database username for %s" : "Vpis uporabniškega imena podatkovne zbirke za %s.", "Enter the database name for %s" : "Vpis imena podatkovne zbirke za %s.", "You cannot use dots in the database name %s" : "V imenu podatkovne zbirke %s ni dovoljeno uporabljati pik.", - "MySQL username and/or password not valid" : "Uporabniško ime ali geslo MySQL ni veljavno", "You need to enter details of an existing account." : "Vpisati je treba podrobnosti obstoječega računa.", "Oracle connection could not be established" : "Povezave s sistemom Oracle ni mogoče vzpostaviti.", - "Oracle username and/or password not valid" : "Uporabniško ime ali geslo Oracle ni veljavno", - "PostgreSQL username and/or password not valid" : "Uporabniško ime ali geslo PostgreSQL ni veljavno", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Sistem Mac OS X ni podprt, zato %s v tem okolju ne bo deloval zanesljivo. Program uporabljate na lastno odgovornost! ", "For the best results, please consider using a GNU/Linux server instead." : "Za najboljše rezultate je priporočljivo uporabljati strežnik 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." : "Kaže, da je dejavna seja %s zagnana v 32-bitnem okolju PHP in, da je v datoteki php.ini nastavljen open_basedir . Tako delovanje ni priporočljivo, saj se lahko pojavijo težave z datotekami, večjimi od 4GB.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Odstraniti je treba nastavitev open_basedir v datoteki php.ini ali pa preklopiti na 64-bitno okolje PHP.", - "Set an admin username." : "Nastavi uporabniško ime skrbnika.", "Set an admin password." : "Nastavi skrbniško geslo.", "Cannot create or write into the data directory %s" : "Ni mogoče zapisati podatkov v podatkovno mapo %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Souporaba ozadnjega programa %s mora vsebovati tudi vmesnik OCP\\Share_Backend", @@ -147,7 +136,6 @@ "Expiration date is in the past" : "Datum preteka je že mimo!", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Datuma pretaka ni mogoče nastaviti za več kot %n dan v prihodnost.","Datuma pretaka ni mogoče nastaviti za več kot %n dneva v prihodnost.","Datuma pretaka ni mogoče nastaviti za več kot %n dni v prihodnost.","Datuma pretaka ni mogoče nastaviti za več kot %n dni v prihodnost."], "Sharing is only allowed with group members" : "Souporaba je dovoljena le med člani skupine", - "Sharing %s failed, because this item is already shared with user %s" : "Nastavljanje souporabe %s je spodletelo, ker je predmet že v souporabi z uporabnikom %s.", "%1$s shared »%2$s« with you" : "%1$s vam omogoča souporabo »%2$s«", "%1$s shared »%2$s« with you." : "%1$s vam omogoča souporabo »%2$s«.", "Click the button below to open it." : "Kliknite na gumb za odpiranje.", @@ -199,14 +187,6 @@ "Nov." : "nov", "Dec." : "dec", "A valid password must be provided" : "Navedeno mora biti veljavno geslo", - "The username is already being used" : "Vpisano uporabniško ime je že v uporabi", - "Could not create user" : "Uporabnika ni mogoče ustvariti", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "V uporabniškem imenu je dovoljeno uporabiti le znake: »a–z«, »A–Z«, »0–9«, presledki in »_.@-«\".", - "A valid username must be provided" : "Navedeno mora biti veljavno uporabniško ime", - "Username contains whitespace at the beginning or at the end" : "Uporabniško ime vsebuje presledni znak na začetku ali na koncu imena.", - "Username must not consist of dots only" : "Uporabniško ime ne sme biti zgolj iz pik", - "Username is invalid because files already exist for this user" : "Uporabniško ime ni veljavno, ker za tega uporabnika že obstajajo datoteke", - "User disabled" : "Uporabnik je onemogočen", "Login canceled by app" : "Program onemogoča prijavo", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Programa »%1$s« ni mogoče namestiti zaradi nerešenih odvisnosti: %2$s", "a safe home for all your data" : "Varno okolje za vaše podatke!", @@ -237,7 +217,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Napako je najverjetneje povzročil predpomnilnik ali pospeševalnik, kot sta Zend OPcache ali eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Ali so bili moduli PHP nameščeni, pa so še vedno označeni kot manjkajoči?", "Please ask your server administrator to restart the web server." : "Obvestite skrbnika strežnika, da je treba ponovno zagnati spletni strežnik.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Spremenite dovoljenja mape na 0770 in s tem onemogočite branje vsebine drugim uporabnikom.", "Your data directory must be an absolute path." : "Podatkovna mapa mora imeti navedeno celotno pot.", "Your data directory is invalid." : "Podatkovna mapa ni veljavna.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Prepričajte se, da je datoteka ».ocdata« v korenu podatkovne mape.", @@ -253,9 +232,29 @@ "Storage is temporarily not available" : "Shramba trenutno ni na voljo", "Storage connection timeout. %s" : "Povezava do shrambe je časovno potekla. %s", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Datoteke programa %1$s niso bile zamenjane na pravi način. Prepričajte se, da je na strežniku nameščena podprta različica.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Prijavljen uporabnik mora biti določen za skrbnika, pomočnika skrbnika ali pa mora imeti dodeljene posebna dovoljenja za dostop do nastavitve.", + "Logged in user must be an admin or sub admin" : "Prijavljen uporabnik mora imeti dovoljenja skrbnika ali podpornega skrbnika", + "Logged in user must be an admin" : "Prijavljen uporabnik mora biti tudi skrbnik", "Full name" : "Polno ime", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "V uporabniškem imenu je dovoljeno uporabiti le znake: »a–z«, »A–Z«, »0–9« in »_.@-«\".", + "Unknown user" : "Neznan uporabnik", + "Enter the database username and name for %s" : "Vpis uporabniškega imena in imena podatkovne zbirke za %s.", + "Enter the database username for %s" : "Vpis uporabniškega imena podatkovne zbirke za %s.", + "MySQL username and/or password not valid" : "Uporabniško ime ali geslo MySQL ni veljavno", + "Oracle username and/or password not valid" : "Uporabniško ime ali geslo Oracle ni veljavno", + "PostgreSQL username and/or password not valid" : "Uporabniško ime ali geslo PostgreSQL ni veljavno", + "Set an admin username." : "Nastavi uporabniško ime skrbnika.", + "Sharing %s failed, because this item is already shared with user %s" : "Nastavljanje souporabe %s je spodletelo, ker je predmet že v souporabi z uporabnikom %s.", + "The username is already being used" : "Vpisano uporabniško ime je že v uporabi", + "Could not create user" : "Uporabnika ni mogoče ustvariti", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "V uporabniškem imenu je dovoljeno uporabiti le znake: »a–z«, »A–Z«, »0–9«, presledki in »_.@-«\".", + "A valid username must be provided" : "Navedeno mora biti veljavno uporabniško ime", + "Username contains whitespace at the beginning or at the end" : "Uporabniško ime vsebuje presledni znak na začetku ali na koncu imena.", + "Username must not consist of dots only" : "Uporabniško ime ne sme biti zgolj iz pik", + "Username is invalid because files already exist for this user" : "Uporabniško ime ni veljavno, ker za tega uporabnika že obstajajo datoteke", + "User disabled" : "Uporabnik je onemogočen", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Različica knjižnice libxml2 mora biti 2.7.0 ali višja. Trenutno je nameščena %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Za rešitev te težave je treba posodobiti knjižnico libxml2 in nato ponovno zagnati spletni strežnik." + "To fix this issue update your libxml2 version and restart your web server." : "Za rešitev te težave je treba posodobiti knjižnico libxml2 in nato ponovno zagnati spletni strežnik.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Spremenite dovoljenja mape na 0770 in s tem onemogočite branje vsebine drugim uporabnikom." },"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" }
\ No newline at end of file diff --git a/lib/l10n/sq.js b/lib/l10n/sq.js index 67c7f8148db..baf7981f7f1 100644 --- a/lib/l10n/sq.js +++ b/lib/l10n/sq.js @@ -58,17 +58,13 @@ OC.L10N.register( "Address" : "Adresa", "Profile picture" : "Foto profili", "About" : "Rreth ", - "Unknown user" : "Përdorues i panjohur", "Additional settings" : "Konfigurime shtesë", "You need to enter details of an existing account." : "Duhet të futni detajet e një llogarie ekzistuese.", "Oracle connection could not be established" : "S’u vendos dot lidhje me Oracle", - "Oracle username and/or password not valid" : "Emër përdoruesi dhe/ose fjalëkalim Oracle-i i pavlefshëm", - "PostgreSQL username and/or password not valid" : "Emër përdoruesi dhe/ose fjalëkalim PostgreSQL jo të vlefshëm", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X nuk mbulohet dhe %s s’do të funksionojë si duhet në këtë platformë. Përdoreni nën përgjegjësinë tuaj! ", "For the best results, please consider using a GNU/Linux server instead." : "Për përfundimet më të mira, ju lutemi, më mirë konsideroni përdorimin e një shërbyesi 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." : "Duket se kjo instancë %s xhiron një mjedis PHP 32-bitësh dhe open_basedir është e formësuar, te php.ini. Kjo do të shpjerë në probleme me kartela më të mëdha se 4 GB dhe këshillohet me forcë të mos ndodhë.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Ju lutemi, hiqeni rregullimin open_basedir nga php.ini juaj ose hidhuni te PHP për 64-bit.", - "Set an admin username." : "Caktoni një emër përdoruesi për përgjegjësin.", "Set an admin password." : "Caktoni një fjalëkalim për përgjegjësin.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Mekanizmi i shërbimit për ndarje %s duhet të sendërtojë ndërfaqen OCP\\Share_Backend", "Sharing backend %s not found" : "S’u gjet mekanizmi i shërbimit për ndarje %s", @@ -77,7 +73,6 @@ OC.L10N.register( "You are not allowed to share %s" : "Nuk ju lejohet ta ndani %s me të tjerët", "Cannot increase permissions of %s" : "S’mund të shtohen lejet për %s", "Expiration date is in the past" : "Data e skadimit bie në të kaluarën", - "Sharing %s failed, because this item is already shared with user %s" : "Ndarja e %s me të tjerët dështoi, ngaqë ky objekt është ndarë tashmë me përdoruesin %s", "Click the button below to open it." : "Kliko butonin më poshtë për të hapur atë.", "The requested share does not exist anymore" : "Ndarja e kërkuar nuk ekziston më", "Could not find category \"%s\"" : "S’u gjet kategori \"%s\"", @@ -127,11 +122,6 @@ OC.L10N.register( "Nov." : "Nën.", "Dec." : "Dhj.", "A valid password must be provided" : "Duhet dhënë një fjalëkalim i vlefshëm", - "The username is already being used" : "Emri i përdoruesit është tashmë i përdorur", - "A valid username must be provided" : "Duhet dhënë një emër i vlefshëm përdoruesi", - "Username contains whitespace at the beginning or at the end" : "Emri i përdoruesit përmban hapësirë në fillim ose në fund", - "Username must not consist of dots only" : "Emri i përdoruesit nuk duhet të përbëhet vetëm nga pika", - "User disabled" : "Përdorues i çaktivizuar", "Login canceled by app" : "Hyrja u anulua nga aplikacioni", "a safe home for all your data" : "Një shtëpi e sigurt për të dhënat e tua", "File is currently busy, please try again later" : "Kartela tani është e zënë, ju lutemi, riprovoni më vonë.", @@ -147,7 +137,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Kjo ka gjasa të jetë shkaktuar nga një fshehtinë/përshpejtues i tillë si Zend OPcache ose eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Modulet PHP janë instaluar, por tregohen ende sikur mungojnë?", "Please ask your server administrator to restart the web server." : "Ju lutemi, kërkojini përgjegjësit të shërbyesit tuaj të rinisë shërbyesin web.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ju lutemi, kalojani lejet në 0770, që kështu atë drejtori të mos mund ta shfaqin përdorues të tjerë.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Sigurohu që ekziston një skedar i quajtur \".ocdata\" në rrënjën e direktorisë së të dhënave.", "Could not obtain lock type %d on \"%s\"." : "S’u mor dot lloj kyçjeje %d në \"%s\".", "Storage unauthorized. %s" : "Depozitë e paautorizuar. %s", @@ -156,8 +145,18 @@ OC.L10N.register( "Storage is temporarily not available" : "Hapsira ruajtëse nuk është në dispozicion përkohësisht", "Storage connection timeout. %s" : "Mbarim kohe lidhjeje për depozitën. %s", "Full name" : "Emri i plotë", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Në një emër përdoruesi lejohen vetëm shenjat vijuese: \"a-z\", \"A-Z\", \"0-9\", dhe \"_.@-\"", + "Unknown user" : "Përdorues i panjohur", + "Oracle username and/or password not valid" : "Emër përdoruesi dhe/ose fjalëkalim Oracle-i i pavlefshëm", + "PostgreSQL username and/or password not valid" : "Emër përdoruesi dhe/ose fjalëkalim PostgreSQL jo të vlefshëm", + "Set an admin username." : "Caktoni një emër përdoruesi për përgjegjësin.", + "Sharing %s failed, because this item is already shared with user %s" : "Ndarja e %s me të tjerët dështoi, ngaqë ky objekt është ndarë tashmë me përdoruesin %s", + "The username is already being used" : "Emri i përdoruesit është tashmë i përdorur", + "A valid username must be provided" : "Duhet dhënë një emër i vlefshëm përdoruesi", + "Username contains whitespace at the beginning or at the end" : "Emri i përdoruesit përmban hapësirë në fillim ose në fund", + "Username must not consist of dots only" : "Emri i përdoruesit nuk duhet të përbëhet vetëm nga pika", + "User disabled" : "Përdorues i çaktivizuar", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Lypset të paktën libxml2 2.7.0. Hëpërhë e instaluar është %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Për të ndrequr këtë problem, përditësoni libxml2 dhe rinisni shërbyesin tuaj web." + "To fix this issue update your libxml2 version and restart your web server." : "Për të ndrequr këtë problem, përditësoni libxml2 dhe rinisni shërbyesin tuaj web.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ju lutemi, kalojani lejet në 0770, që kështu atë drejtori të mos mund ta shfaqin përdorues të tjerë." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/sq.json b/lib/l10n/sq.json index 98ea9064e36..594d502da55 100644 --- a/lib/l10n/sq.json +++ b/lib/l10n/sq.json @@ -56,17 +56,13 @@ "Address" : "Adresa", "Profile picture" : "Foto profili", "About" : "Rreth ", - "Unknown user" : "Përdorues i panjohur", "Additional settings" : "Konfigurime shtesë", "You need to enter details of an existing account." : "Duhet të futni detajet e një llogarie ekzistuese.", "Oracle connection could not be established" : "S’u vendos dot lidhje me Oracle", - "Oracle username and/or password not valid" : "Emër përdoruesi dhe/ose fjalëkalim Oracle-i i pavlefshëm", - "PostgreSQL username and/or password not valid" : "Emër përdoruesi dhe/ose fjalëkalim PostgreSQL jo të vlefshëm", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X nuk mbulohet dhe %s s’do të funksionojë si duhet në këtë platformë. Përdoreni nën përgjegjësinë tuaj! ", "For the best results, please consider using a GNU/Linux server instead." : "Për përfundimet më të mira, ju lutemi, më mirë konsideroni përdorimin e një shërbyesi 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." : "Duket se kjo instancë %s xhiron një mjedis PHP 32-bitësh dhe open_basedir është e formësuar, te php.ini. Kjo do të shpjerë në probleme me kartela më të mëdha se 4 GB dhe këshillohet me forcë të mos ndodhë.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Ju lutemi, hiqeni rregullimin open_basedir nga php.ini juaj ose hidhuni te PHP për 64-bit.", - "Set an admin username." : "Caktoni një emër përdoruesi për përgjegjësin.", "Set an admin password." : "Caktoni një fjalëkalim për përgjegjësin.", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Mekanizmi i shërbimit për ndarje %s duhet të sendërtojë ndërfaqen OCP\\Share_Backend", "Sharing backend %s not found" : "S’u gjet mekanizmi i shërbimit për ndarje %s", @@ -75,7 +71,6 @@ "You are not allowed to share %s" : "Nuk ju lejohet ta ndani %s me të tjerët", "Cannot increase permissions of %s" : "S’mund të shtohen lejet për %s", "Expiration date is in the past" : "Data e skadimit bie në të kaluarën", - "Sharing %s failed, because this item is already shared with user %s" : "Ndarja e %s me të tjerët dështoi, ngaqë ky objekt është ndarë tashmë me përdoruesin %s", "Click the button below to open it." : "Kliko butonin më poshtë për të hapur atë.", "The requested share does not exist anymore" : "Ndarja e kërkuar nuk ekziston më", "Could not find category \"%s\"" : "S’u gjet kategori \"%s\"", @@ -125,11 +120,6 @@ "Nov." : "Nën.", "Dec." : "Dhj.", "A valid password must be provided" : "Duhet dhënë një fjalëkalim i vlefshëm", - "The username is already being used" : "Emri i përdoruesit është tashmë i përdorur", - "A valid username must be provided" : "Duhet dhënë një emër i vlefshëm përdoruesi", - "Username contains whitespace at the beginning or at the end" : "Emri i përdoruesit përmban hapësirë në fillim ose në fund", - "Username must not consist of dots only" : "Emri i përdoruesit nuk duhet të përbëhet vetëm nga pika", - "User disabled" : "Përdorues i çaktivizuar", "Login canceled by app" : "Hyrja u anulua nga aplikacioni", "a safe home for all your data" : "Një shtëpi e sigurt për të dhënat e tua", "File is currently busy, please try again later" : "Kartela tani është e zënë, ju lutemi, riprovoni më vonë.", @@ -145,7 +135,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Kjo ka gjasa të jetë shkaktuar nga një fshehtinë/përshpejtues i tillë si Zend OPcache ose eAccelerator.", "PHP modules have been installed, but they are still listed as missing?" : "Modulet PHP janë instaluar, por tregohen ende sikur mungojnë?", "Please ask your server administrator to restart the web server." : "Ju lutemi, kërkojini përgjegjësit të shërbyesit tuaj të rinisë shërbyesin web.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ju lutemi, kalojani lejet në 0770, që kështu atë drejtori të mos mund ta shfaqin përdorues të tjerë.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Sigurohu që ekziston një skedar i quajtur \".ocdata\" në rrënjën e direktorisë së të dhënave.", "Could not obtain lock type %d on \"%s\"." : "S’u mor dot lloj kyçjeje %d në \"%s\".", "Storage unauthorized. %s" : "Depozitë e paautorizuar. %s", @@ -154,8 +143,18 @@ "Storage is temporarily not available" : "Hapsira ruajtëse nuk është në dispozicion përkohësisht", "Storage connection timeout. %s" : "Mbarim kohe lidhjeje për depozitën. %s", "Full name" : "Emri i plotë", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Në një emër përdoruesi lejohen vetëm shenjat vijuese: \"a-z\", \"A-Z\", \"0-9\", dhe \"_.@-\"", + "Unknown user" : "Përdorues i panjohur", + "Oracle username and/or password not valid" : "Emër përdoruesi dhe/ose fjalëkalim Oracle-i i pavlefshëm", + "PostgreSQL username and/or password not valid" : "Emër përdoruesi dhe/ose fjalëkalim PostgreSQL jo të vlefshëm", + "Set an admin username." : "Caktoni një emër përdoruesi për përgjegjësin.", + "Sharing %s failed, because this item is already shared with user %s" : "Ndarja e %s me të tjerët dështoi, ngaqë ky objekt është ndarë tashmë me përdoruesin %s", + "The username is already being used" : "Emri i përdoruesit është tashmë i përdorur", + "A valid username must be provided" : "Duhet dhënë një emër i vlefshëm përdoruesi", + "Username contains whitespace at the beginning or at the end" : "Emri i përdoruesit përmban hapësirë në fillim ose në fund", + "Username must not consist of dots only" : "Emri i përdoruesit nuk duhet të përbëhet vetëm nga pika", + "User disabled" : "Përdorues i çaktivizuar", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Lypset të paktën libxml2 2.7.0. Hëpërhë e instaluar është %s.", - "To fix this issue update your libxml2 version and restart your web server." : "Për të ndrequr këtë problem, përditësoni libxml2 dhe rinisni shërbyesin tuaj web." + "To fix this issue update your libxml2 version and restart your web server." : "Për të ndrequr këtë problem, përditësoni libxml2 dhe rinisni shërbyesin tuaj web.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ju lutemi, kalojani lejet në 0770, që kështu atë drejtori të mos mund ta shfaqin përdorues të tjerë." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/sr.js b/lib/l10n/sr.js index 478da21bb72..ee343f2cd01 100644 --- a/lib/l10n/sr.js +++ b/lib/l10n/sr.js @@ -8,7 +8,6 @@ OC.L10N.register( "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", - "404" : "404", "The page could not be found on the server." : "На серверу не може да се пронађе ова страница.", "%s email verification" : "%s потврђивање и-мејла", "Email verification" : "Потврђивање и-мејла", @@ -24,6 +23,7 @@ OC.L10N.register( "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." : "Потребна је PHP верзија старија од верзије %s.", @@ -37,9 +37,9 @@ 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 или нижа.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Пријављени корисник мора бити админ, под админ или да поседује специјално право да приступи овом подешавању", - "Logged in user must be an admin or sub admin" : "Пријављени корисник мора бити администратор или подадминистратор", - "Logged in user must be an admin" : "Пријављени корисник мора бити администратор", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Пријављени налог мора бити админ, подадмин или мора да поседује специјално право да приступи овом подешавању", + "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“ је започео удаљено брисање", @@ -118,22 +118,22 @@ OC.L10N.register( "Headline" : "Наслов", "Organisation" : "Организација", "Role" : "Улога", - "Unknown user" : "Непознат корисник", + "Unknown account" : "Непознати налог", "Additional settings" : "Додатне поставке", - "Enter the database username and name for %s" : "Унесите корисничко име базе података и назив за %s", - "Enter the database username for %s" : "Унесите корисничко име базе података за %s", + "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 username and/or password not valid" : "MySQL корисничко име и/или лозинка нису исправни", + "MySQL Login and/or password not valid" : "MySQL име за пријаву и/или лозинка нису исправни", "You need to enter details of an existing account." : "Потребно је да унесете детаље постојећег налога.", "Oracle connection could not be established" : "Веза са базом података Oracle не може бити успостављена", - "Oracle username and/or password not valid" : "Oracle корисничко име и/или лозинка нису исправни", - "PostgreSQL username and/or password not valid" : "PostgreSQL корисничко име и/или лозинка нису исправни", + "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! " : "Мек ОС Икс није подржан и %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 ради у 32-битном PHP окружењу а open_basedir је подешен у php.ini фајлу. То може довести до проблема са фајловима већим од 4 GB, те стога није препоручљиво.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Уклоните open_basedir поставку из php.ini фајла или пређите на 64-битни PHP.", - "Set an admin username." : "Поставите име за администратора.", + "Set an admin Login." : "Поставите име за пријаву админа.", "Set an admin password." : "Поставите лозинку за администратора.", "Cannot create or write into the data directory %s" : "Не може да се креира или уписује у директоријум са подацима %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Позадина дељења %s мора користити корисничко окружење OCP\\Share_Backend", @@ -151,11 +151,12 @@ OC.L10N.register( "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_" : ["Датум истека не може да се постави више од %n дан у будућност","Датум истека не може да се постави више од %n дана у будућност","Датум истека не може да се постави више од %n дана у будућност"], "Sharing is only allowed with group members" : "Дељење је дозвољено само са члановима групе", - "Sharing %s failed, because this item is already shared with user %s" : "Дељење %s није успело зато што се ова ставка већ дели са корисником %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Дељење %s није успело зато што се ова ставка већ дели са налогом %s", "%1$s shared »%2$s« with you" : "%1$s је поделио „%2$s“ са Вама", "%1$s shared »%2$s« with you." : "%1$s је поделио „%2$s“ са Вама.", "Click the button below to open it." : "Кликните дугме испод да га отворите.", "The requested share does not exist anymore" : "Захтевано дељење више не постоји", + "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“.", "Sunday" : "Недеља", @@ -204,14 +205,14 @@ OC.L10N.register( "Nov." : "Нов.", "Dec." : "Дец.", "A valid password must be provided" : "Морате унети исправну лозинку", - "The username is already being used" : "Корисничко име се већ користи", - "Could not create user" : "Не могу да направим корисника", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "У корисничком имену су дозвољени само следећи карактери: „a-z”, „A-Z”, „0-9”, размаци и „_.@-'", - "A valid username must be provided" : "Морате унети исправно корисничко име", - "Username contains whitespace at the beginning or at the end" : "Корисничко име садржи белине на почетку или на крају", - "Username must not consist of dots only" : "Корисничко име не могу бити само тачке", - "Username is invalid because files already exist for this user" : "Корисничко име није исправно пошто већ постоје фајлови за овог корисника", - "User disabled" : "Корисник онемогућен", + "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" : "Име за пријаву не може да се састоји само од тачака", + "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" : "сигурно место за све Ваше податке", @@ -244,8 +245,8 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Замолите вашег администратора сервера да поново покрене веб сервер.", "The required %s config variable is not configured in the config.php file." : "У config.php фајлу није подешена потребна config променљива %s.", "Please ask your server administrator to check the Nextcloud configuration." : "Молимо вас да замолите свог систем администратора да провери Некстклауд конфигурацију.", - "Your data directory is readable by other users." : "Ваш директоријум са подацима могу да читају остали корисници.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Промените дозволе у 0770 како директоријуми не би могли бити излистани од стране других корисника.", + "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." : "Ваш директоријум са подацима је неисправан.", @@ -261,8 +262,8 @@ OC.L10N.register( "Storage connection error. %s" : "Грешка приликом повезивања на складиште. %s", "Storage is temporarily not available" : "Складиште привремено није доступно", "Storage connection timeout. %s" : "Истекло је време за повезивање на складиште. %s", - "Free prompt" : "Произвољни одзив", - "Runs an arbitrary prompt through the language model." : "Извршава произвољни одзив кроз језички модел.", + "Free prompt" : "Произвољни захтев", + "Runs an arbitrary prompt through the language model." : "Извршава произвољни захтев кроз језички модел.", "Generate headline" : "Генериши линију наслова", "Generates a possible headline for a text." : "Генерише могућу насловну линију текста.", "Summarize" : "Резимирај", @@ -270,12 +271,32 @@ OC.L10N.register( "Extract topics" : "Издвој теме", "Extracts topics from a text and outputs them separated by commas." : "Издваја теме из текста и исписује их раздвојене запетама.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Фајлови апликације „%1$s“ нису правилно замењени. Проверите да ли је верзија компатибилна са сервером.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Пријављени корисник мора бити админ, под админ или да поседује специјално право да приступи овом подешавању", + "Logged in user must be an admin or sub admin" : "Пријављени корисник мора бити администратор или подадминистратор", + "Logged in user must be an admin" : "Пријављени корисник мора бити администратор", "Full name" : "Пуно име", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Достигнуто је ограничење броја корисника и корисник није креиран. За више детаља погледајте своја обавештења.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "У корисничком имену су дозвољени само следећи карактери: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Непознат корисник", + "Enter the database username and name for %s" : "Унесите корисничко име базе података и назив за %s", + "Enter the database username for %s" : "Унесите корисничко име базе података за %s", + "MySQL username and/or password not valid" : "MySQL корисничко име и/или лозинка нису исправни", + "Oracle username and/or password not valid" : "Oracle корисничко име и/или лозинка нису исправни", + "PostgreSQL username and/or password not valid" : "PostgreSQL корисничко име и/или лозинка нису исправни", + "Set an admin username." : "Поставите име за администратора.", + "Sharing %s failed, because this item is already shared with user %s" : "Дељење %s није успело зато што се ова ставка већ дели са корисником %s", + "The username is already being used" : "Корисничко име се већ користи", + "Could not create user" : "Не могу да направим корисника", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "У корисничком имену су дозвољени само следећи карактери: „a-z”, „A-Z”, „0-9”, размаци и „_.@-'", + "A valid username must be provided" : "Морате унети исправно корисничко име", + "Username contains whitespace at the beginning or at the end" : "Корисничко име садржи белине на почетку или на крају", + "Username must not consist of dots only" : "Корисничко име не могу бити само тачке", + "Username is invalid because files already exist for this user" : "Корисничко име није исправно пошто већ постоје фајлови за овог корисника", + "User disabled" : "Корисник онемогућен", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Потребан је бар libxml2 2.7.0. Тренутно је инсталиран %s.", "To fix this issue update your libxml2 version and restart your web server." : "Да поправите овај проблем, ажурирајте верзију библиотеке libxml2 и рестартујте веб сервер.", "PostgreSQL >= 9 required." : "Потребан је PostgreSQL >= 9.", - "Please upgrade your database version." : "Молимо вас да ажурирате верзију базе података." + "Please upgrade your database version." : "Молимо вас да ажурирате верзију базе података.", + "Your data directory is readable by other users." : "Ваш директоријум са подацима могу да читају остали корисници.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Промените дозволе у 0770 како директоријуми не би могли бити излистани од стране других корисника." }, "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 9c6c413cd8b..6b9cedd3f20 100644 --- a/lib/l10n/sr.json +++ b/lib/l10n/sr.json @@ -6,7 +6,6 @@ "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", - "404" : "404", "The page could not be found on the server." : "На серверу не може да се пронађе ова страница.", "%s email verification" : "%s потврђивање и-мејла", "Email verification" : "Потврђивање и-мејла", @@ -22,6 +21,7 @@ "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." : "Потребна је PHP верзија старија од верзије %s.", @@ -35,9 +35,9 @@ "The following platforms are supported: %s" : "Подржане су следеће платформе: %s", "Server version %s or higher is required." : "Потребна је верзија сервера %s или виша.", "Server version %s or lower is required." : "Потребна је верзија сервера %s или нижа.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Пријављени корисник мора бити админ, под админ или да поседује специјално право да приступи овом подешавању", - "Logged in user must be an admin or sub admin" : "Пријављени корисник мора бити администратор или подадминистратор", - "Logged in user must be an admin" : "Пријављени корисник мора бити администратор", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Пријављени налог мора бити админ, подадмин или мора да поседује специјално право да приступи овом подешавању", + "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“ је започео удаљено брисање", @@ -116,22 +116,22 @@ "Headline" : "Наслов", "Organisation" : "Организација", "Role" : "Улога", - "Unknown user" : "Непознат корисник", + "Unknown account" : "Непознати налог", "Additional settings" : "Додатне поставке", - "Enter the database username and name for %s" : "Унесите корисничко име базе података и назив за %s", - "Enter the database username for %s" : "Унесите корисничко име базе података за %s", + "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 username and/or password not valid" : "MySQL корисничко име и/или лозинка нису исправни", + "MySQL Login and/or password not valid" : "MySQL име за пријаву и/или лозинка нису исправни", "You need to enter details of an existing account." : "Потребно је да унесете детаље постојећег налога.", "Oracle connection could not be established" : "Веза са базом података Oracle не може бити успостављена", - "Oracle username and/or password not valid" : "Oracle корисничко име и/или лозинка нису исправни", - "PostgreSQL username and/or password not valid" : "PostgreSQL корисничко име и/или лозинка нису исправни", + "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! " : "Мек ОС Икс није подржан и %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 ради у 32-битном PHP окружењу а open_basedir је подешен у php.ini фајлу. То може довести до проблема са фајловима већим од 4 GB, те стога није препоручљиво.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Уклоните open_basedir поставку из php.ini фајла или пређите на 64-битни PHP.", - "Set an admin username." : "Поставите име за администратора.", + "Set an admin Login." : "Поставите име за пријаву админа.", "Set an admin password." : "Поставите лозинку за администратора.", "Cannot create or write into the data directory %s" : "Не може да се креира или уписује у директоријум са подацима %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Позадина дељења %s мора користити корисничко окружење OCP\\Share_Backend", @@ -149,11 +149,12 @@ "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_" : ["Датум истека не може да се постави више од %n дан у будућност","Датум истека не може да се постави више од %n дана у будућност","Датум истека не може да се постави више од %n дана у будућност"], "Sharing is only allowed with group members" : "Дељење је дозвољено само са члановима групе", - "Sharing %s failed, because this item is already shared with user %s" : "Дељење %s није успело зато што се ова ставка већ дели са корисником %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Дељење %s није успело зато што се ова ставка већ дели са налогом %s", "%1$s shared »%2$s« with you" : "%1$s је поделио „%2$s“ са Вама", "%1$s shared »%2$s« with you." : "%1$s је поделио „%2$s“ са Вама.", "Click the button below to open it." : "Кликните дугме испод да га отворите.", "The requested share does not exist anymore" : "Захтевано дељење више не постоји", + "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“.", "Sunday" : "Недеља", @@ -202,14 +203,14 @@ "Nov." : "Нов.", "Dec." : "Дец.", "A valid password must be provided" : "Морате унети исправну лозинку", - "The username is already being used" : "Корисничко име се већ користи", - "Could not create user" : "Не могу да направим корисника", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "У корисничком имену су дозвољени само следећи карактери: „a-z”, „A-Z”, „0-9”, размаци и „_.@-'", - "A valid username must be provided" : "Морате унети исправно корисничко име", - "Username contains whitespace at the beginning or at the end" : "Корисничко име садржи белине на почетку или на крају", - "Username must not consist of dots only" : "Корисничко име не могу бити само тачке", - "Username is invalid because files already exist for this user" : "Корисничко име није исправно пошто већ постоје фајлови за овог корисника", - "User disabled" : "Корисник онемогућен", + "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" : "Име за пријаву не може да се састоји само од тачака", + "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" : "сигурно место за све Ваше податке", @@ -242,8 +243,8 @@ "Please ask your server administrator to restart the web server." : "Замолите вашег администратора сервера да поново покрене веб сервер.", "The required %s config variable is not configured in the config.php file." : "У config.php фајлу није подешена потребна config променљива %s.", "Please ask your server administrator to check the Nextcloud configuration." : "Молимо вас да замолите свог систем администратора да провери Некстклауд конфигурацију.", - "Your data directory is readable by other users." : "Ваш директоријум са подацима могу да читају остали корисници.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Промените дозволе у 0770 како директоријуми не би могли бити излистани од стране других корисника.", + "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." : "Ваш директоријум са подацима је неисправан.", @@ -259,8 +260,8 @@ "Storage connection error. %s" : "Грешка приликом повезивања на складиште. %s", "Storage is temporarily not available" : "Складиште привремено није доступно", "Storage connection timeout. %s" : "Истекло је време за повезивање на складиште. %s", - "Free prompt" : "Произвољни одзив", - "Runs an arbitrary prompt through the language model." : "Извршава произвољни одзив кроз језички модел.", + "Free prompt" : "Произвољни захтев", + "Runs an arbitrary prompt through the language model." : "Извршава произвољни захтев кроз језички модел.", "Generate headline" : "Генериши линију наслова", "Generates a possible headline for a text." : "Генерише могућу насловну линију текста.", "Summarize" : "Резимирај", @@ -268,12 +269,32 @@ "Extract topics" : "Издвој теме", "Extracts topics from a text and outputs them separated by commas." : "Издваја теме из текста и исписује их раздвојене запетама.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Фајлови апликације „%1$s“ нису правилно замењени. Проверите да ли је верзија компатибилна са сервером.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Пријављени корисник мора бити админ, под админ или да поседује специјално право да приступи овом подешавању", + "Logged in user must be an admin or sub admin" : "Пријављени корисник мора бити администратор или подадминистратор", + "Logged in user must be an admin" : "Пријављени корисник мора бити администратор", "Full name" : "Пуно име", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Достигнуто је ограничење броја корисника и корисник није креиран. За више детаља погледајте своја обавештења.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "У корисничком имену су дозвољени само следећи карактери: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Непознат корисник", + "Enter the database username and name for %s" : "Унесите корисничко име базе података и назив за %s", + "Enter the database username for %s" : "Унесите корисничко име базе података за %s", + "MySQL username and/or password not valid" : "MySQL корисничко име и/или лозинка нису исправни", + "Oracle username and/or password not valid" : "Oracle корисничко име и/или лозинка нису исправни", + "PostgreSQL username and/or password not valid" : "PostgreSQL корисничко име и/или лозинка нису исправни", + "Set an admin username." : "Поставите име за администратора.", + "Sharing %s failed, because this item is already shared with user %s" : "Дељење %s није успело зато што се ова ставка већ дели са корисником %s", + "The username is already being used" : "Корисничко име се већ користи", + "Could not create user" : "Не могу да направим корисника", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "У корисничком имену су дозвољени само следећи карактери: „a-z”, „A-Z”, „0-9”, размаци и „_.@-'", + "A valid username must be provided" : "Морате унети исправно корисничко име", + "Username contains whitespace at the beginning or at the end" : "Корисничко име садржи белине на почетку или на крају", + "Username must not consist of dots only" : "Корисничко име не могу бити само тачке", + "Username is invalid because files already exist for this user" : "Корисничко име није исправно пошто већ постоје фајлови за овог корисника", + "User disabled" : "Корисник онемогућен", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Потребан је бар libxml2 2.7.0. Тренутно је инсталиран %s.", "To fix this issue update your libxml2 version and restart your web server." : "Да поправите овај проблем, ажурирајте верзију библиотеке libxml2 и рестартујте веб сервер.", "PostgreSQL >= 9 required." : "Потребан је PostgreSQL >= 9.", - "Please upgrade your database version." : "Молимо вас да ажурирате верзију базе података." + "Please upgrade your database version." : "Молимо вас да ажурирате верзију базе података.", + "Your data directory is readable by other users." : "Ваш директоријум са подацима могу да читају остали корисници.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Промените дозволе у 0770 како директоријуми не би могли бити излистани од стране других корисника." },"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 bb6aa050151..4a6921e8d82 100644 --- a/lib/l10n/sv.js +++ b/lib/l10n/sv.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Appen %1$s finns inte eller har en icke-kompatibel version med denna server. Kontrollera appkatalogen.", "Sample configuration detected" : "Exempel-konfiguration detekterad", "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" : "Det har upptäckts att provkonfigurationen har kopierats. Detta kan bryta din installation och stöds inte. Läs dokumentationen innan du utför ändringar på config.php", - "404" : "404", "The page could not be found on the server." : "Sidan kunde inte hittas på servern.", "%s email verification" : "%s e-postverifikation", "Email verification" : "E-postverifikation", @@ -24,6 +23,7 @@ OC.L10N.register( "Enterprise bundle" : "Företagspaketet", "Groupware bundle" : "Gruppvarupaket", "Hub bundle" : "Hub-paket", + "Public sector bundle" : "Paket för offentlig sektor", "Social sharing bundle" : "Kommunikationspaket", "PHP %s or higher is required." : "PHP %s eller högre krävs.", "PHP with a version lower than %s is required." : "PHP med version lägre än %s krävs.", @@ -37,9 +37,9 @@ OC.L10N.register( "The following platforms are supported: %s" : "Följande plattformar stöds: %s", "Server version %s or higher is required." : "Serverversion %s eller nyare krävs.", "Server version %s or lower is required." : "Serverversion %s eller äldre krävs.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Inloggad användare måste vara en admin, sub-admin eller ha tilldelats speciella rättigheter för att komma åt denna inställning", - "Logged in user must be an admin or sub admin" : "Inloggad användare måste vara administratör eller del-administratör", - "Logged in user must be an admin" : "Inloggad användare måste vara administratör", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Inloggat konto måste vara en admin, underadministratör eller ha tilldelats speciella rättigheter för att komma åt denna inställning", + "Logged in account must be an admin or sub admin" : "Inloggat konto måste vara en admin eller underadministratör", + "Logged in account must be an admin" : "Inloggat konto måste vara admin", "Wiping of device %s has started" : "Rensning av enhet %s har startat", "Wiping of device »%s« has started" : "Rensning av enhet »%s« har startat", "»%s« started remote wipe" : "»%s« startade fjärrensning", @@ -118,22 +118,22 @@ OC.L10N.register( "Headline" : "Rubrik", "Organisation" : "Organisation", "Role" : "Roll", - "Unknown user" : "Okänd användare", + "Unknown account" : "Okänt konto", "Additional settings" : "Övriga inställningar", - "Enter the database username and name for %s" : "Ange databasanvändarnamn och lösenord för %s", - "Enter the database username for %s" : "Ange databasanvändare för %s", + "Enter the database Login and name for %s" : "Ange databas-inloggning och namn för %s", + "Enter the database Login for %s" : "Ange databas-inloggning för %s", "Enter the database name for %s" : "Ange databasnamn för %s", "You cannot use dots in the database name %s" : "Du kan inte använda punkter i databasnamnet %s", - "MySQL username and/or password not valid" : "MySQL-användarnamn och/eller lösenord är felaktigt", + "MySQL Login and/or password not valid" : "MySQL-inloggning och/eller lösenord är felaktigt", "You need to enter details of an existing account." : "Du måste ange inloggningsuppgifter av ett aktuellt konto.", "Oracle connection could not be established" : "Oracle-anslutning kunde inte etableras", - "Oracle username and/or password not valid" : "Oracle-användarnamnet och/eller lösenordet är felaktigt", - "PostgreSQL username and/or password not valid" : "PostgreSQL-användarnamnet och/eller lösenordet är felaktigt", + "Oracle Login and/or password not valid" : "Oracle-inloggning och/eller lösenord är felaktigt", + "PostgreSQL Login and/or password not valid" : "PostgreSQL-inloggning och/eller lösenord är felaktigt", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X stöds inte och %s kommer inte att fungera korrekt på denna plattform. Använd på egen risk!", "For the best results, please consider using a GNU/Linux server instead." : "För bästa resultat, överväg att använda en GNU/Linux-server istället.", "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." : "Det verkar som om denna %s instans körs på en 32-bitars PHP miljö och open_basedir har konfigurerats i php.ini. Detta kommer att leda till problem med filer över 4 GB och är verkligen inte rekommenderat!", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Ta bort open_basedir-inställningen i din php.ini eller växla till 64-bitars PHP.", - "Set an admin username." : "Ange ett användarnamn för administratören.", + "Set an admin Login." : "Ange en admin-inloggning.", "Set an admin password." : "Ange ett administratörslösenord.", "Cannot create or write into the data directory %s" : "Kan inte skapa eller skriva till data-katalogen %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Delningsgränssnittet %s måste implementera gränssnittet OCP\\Share_Backend", @@ -151,11 +151,12 @@ OC.L10N.register( "Expiration date is in the past" : "Utgångsdatum är i det förflutna", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Kan inte sätta ett utgångsdatum längre fram än %n dag","Kan inte sätta ett utgångsdatum längre fram än %n dagar"], "Sharing is only allowed with group members" : "Delning är endast tillåten med gruppmedlemmar", - "Sharing %s failed, because this item is already shared with user %s" : "Delning av %s misslyckades eftersom detta redan är delat med användaren %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Delning av %s misslyckades, eftersom det här objektet redan delas med kontot %s", "%1$s shared »%2$s« with you" : "%1$s delade »%2$s« med dig", "%1$s shared »%2$s« with you." : "%1$s delade »%2$s« med dig.", "Click the button below to open it." : "Klicka på knappen nedan för att öppna det.", "The requested share does not exist anymore" : "Den begärda delningen finns inte mer", + "The requested share comes from a disabled user" : "Den begärda delningen kommer från en inaktiverad användare", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Användaren skapades inte eftersom användargränsen har nåtts. Kontrollera dina aviseringar för att läsa mer.", "Could not find category \"%s\"" : "Kunde inte hitta kategorin \"%s\"", "Sunday" : "Söndag", @@ -204,14 +205,14 @@ OC.L10N.register( "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Ett giltigt lösenord måste anges", - "The username is already being used" : "Användarnamnet används redan", - "Could not create user" : "Kunde inte skapa användare", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Endast följande tecken är tillåtna i ett användarnamn: \"a-z\", \"A-Z\", \"0-9\", mellanslag och \"_.@-'\"", - "A valid username must be provided" : "Ett giltigt användarnamn måste anges", - "Username contains whitespace at the beginning or at the end" : "Användarnamnet består av ett mellanslag i början eller i slutet", - "Username must not consist of dots only" : "Användarnamnet får inte innehålla enbart punkter", - "Username is invalid because files already exist for this user" : "Användarnamnet är ogiltigt eftersom det redan finns filer för den här användaren", - "User disabled" : "Användare inaktiverad", + "The Login is already being used" : "Inloggningen används redan", + "Could not create account" : "Kunde inte skapa konto", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Endast följande tecken är tillåtna i en inloggning: \"a-z\", \"A-Z\", \"0-9\", mellanslag och \"_.@-'\"", + "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 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", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Appen \"%1$s\" kan inte installeras eftersom följande beroenden inte är uppfyllda: %2$s", "a safe home for all your data" : "ett säkert hem för all din data", @@ -244,8 +245,8 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Be din serveradministratör att starta om webbservern.", "The required %s config variable is not configured in the config.php file." : "Den nödvändiga konfigurationsvariabeln %s är inte konfigurerad i filen config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Be din serveradministratör att kontrollera Nextcloud-konfigurationen.", - "Your data directory is readable by other users." : "Din datakatalog kan läsas av andra användare.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare.", + "Your data directory is readable by other people." : "Din datakatalog kan läsas av andra användare.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare.", "Your data directory must be an absolute path." : "Din datakatalog måste vara en absolut sökväg.", "Check the value of \"datadirectory\" in your configuration." : "Kontrollera värdet på \"datadirectory\" i din konfiguration.", "Your data directory is invalid." : "Din datakatalog är ogiltig.", @@ -268,12 +269,32 @@ OC.L10N.register( "Extract topics" : "Extrahera ämnen", "Extracts topics from a text and outputs them separated by commas." : "Extraherar ämnen från en text och matar ut dem separerade med kommatecken.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Filerna i appen %1$s ersattes inte korrekt. Kontrollera att det är en version som är kompatibel med servern.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Inloggad användare måste vara en admin, sub-admin eller ha tilldelats speciella rättigheter för att komma åt denna inställning", + "Logged in user must be an admin or sub admin" : "Inloggad användare måste vara administratör eller del-administratör", + "Logged in user must be an admin" : "Inloggad användare måste vara administratör", "Full name" : "Fullständigt namn", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Användargränsen har nåtts och användaren skapades inte. Kontrollera dina aviseringar om du vill veta mer.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Endast följande tecken är tillåtna i användarnamnet: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Okänd användare", + "Enter the database username and name for %s" : "Ange databasanvändarnamn och lösenord för %s", + "Enter the database username for %s" : "Ange databasanvändare för %s", + "MySQL username and/or password not valid" : "MySQL-användarnamn och/eller lösenord är felaktigt", + "Oracle username and/or password not valid" : "Oracle-användarnamnet och/eller lösenordet är felaktigt", + "PostgreSQL username and/or password not valid" : "PostgreSQL-användarnamnet och/eller lösenordet är felaktigt", + "Set an admin username." : "Ange ett användarnamn för administratören.", + "Sharing %s failed, because this item is already shared with user %s" : "Delning av %s misslyckades eftersom detta redan är delat med användaren %s", + "The username is already being used" : "Användarnamnet används redan", + "Could not create user" : "Kunde inte skapa användare", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Endast följande tecken är tillåtna i ett användarnamn: \"a-z\", \"A-Z\", \"0-9\", mellanslag och \"_.@-'\"", + "A valid username must be provided" : "Ett giltigt användarnamn måste anges", + "Username contains whitespace at the beginning or at the end" : "Användarnamnet består av ett mellanslag i början eller i slutet", + "Username must not consist of dots only" : "Användarnamnet får inte innehålla enbart punkter", + "Username is invalid because files already exist for this user" : "Användarnamnet är ogiltigt eftersom det redan finns filer för den här användaren", + "User disabled" : "Användare inaktiverad", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 är det minsta som krävs. För närvarande är %s installerat.", "To fix this issue update your libxml2 version and restart your web server." : "För att åtgärda detta problem uppdatera libxml2 versionen och starta om din webbserver.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 krävs.", - "Please upgrade your database version." : "Uppgradera din databasversion." + "Please upgrade your database version." : "Uppgradera din databasversion.", + "Your data directory is readable by other users." : "Din datakatalog kan läsas av andra användare.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare." }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/sv.json b/lib/l10n/sv.json index 3d0525677e8..5efe75310a6 100644 --- a/lib/l10n/sv.json +++ b/lib/l10n/sv.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Appen %1$s finns inte eller har en icke-kompatibel version med denna server. Kontrollera appkatalogen.", "Sample configuration detected" : "Exempel-konfiguration detekterad", "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" : "Det har upptäckts att provkonfigurationen har kopierats. Detta kan bryta din installation och stöds inte. Läs dokumentationen innan du utför ändringar på config.php", - "404" : "404", "The page could not be found on the server." : "Sidan kunde inte hittas på servern.", "%s email verification" : "%s e-postverifikation", "Email verification" : "E-postverifikation", @@ -22,6 +21,7 @@ "Enterprise bundle" : "Företagspaketet", "Groupware bundle" : "Gruppvarupaket", "Hub bundle" : "Hub-paket", + "Public sector bundle" : "Paket för offentlig sektor", "Social sharing bundle" : "Kommunikationspaket", "PHP %s or higher is required." : "PHP %s eller högre krävs.", "PHP with a version lower than %s is required." : "PHP med version lägre än %s krävs.", @@ -35,9 +35,9 @@ "The following platforms are supported: %s" : "Följande plattformar stöds: %s", "Server version %s or higher is required." : "Serverversion %s eller nyare krävs.", "Server version %s or lower is required." : "Serverversion %s eller äldre krävs.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Inloggad användare måste vara en admin, sub-admin eller ha tilldelats speciella rättigheter för att komma åt denna inställning", - "Logged in user must be an admin or sub admin" : "Inloggad användare måste vara administratör eller del-administratör", - "Logged in user must be an admin" : "Inloggad användare måste vara administratör", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Inloggat konto måste vara en admin, underadministratör eller ha tilldelats speciella rättigheter för att komma åt denna inställning", + "Logged in account must be an admin or sub admin" : "Inloggat konto måste vara en admin eller underadministratör", + "Logged in account must be an admin" : "Inloggat konto måste vara admin", "Wiping of device %s has started" : "Rensning av enhet %s har startat", "Wiping of device »%s« has started" : "Rensning av enhet »%s« har startat", "»%s« started remote wipe" : "»%s« startade fjärrensning", @@ -116,22 +116,22 @@ "Headline" : "Rubrik", "Organisation" : "Organisation", "Role" : "Roll", - "Unknown user" : "Okänd användare", + "Unknown account" : "Okänt konto", "Additional settings" : "Övriga inställningar", - "Enter the database username and name for %s" : "Ange databasanvändarnamn och lösenord för %s", - "Enter the database username for %s" : "Ange databasanvändare för %s", + "Enter the database Login and name for %s" : "Ange databas-inloggning och namn för %s", + "Enter the database Login for %s" : "Ange databas-inloggning för %s", "Enter the database name for %s" : "Ange databasnamn för %s", "You cannot use dots in the database name %s" : "Du kan inte använda punkter i databasnamnet %s", - "MySQL username and/or password not valid" : "MySQL-användarnamn och/eller lösenord är felaktigt", + "MySQL Login and/or password not valid" : "MySQL-inloggning och/eller lösenord är felaktigt", "You need to enter details of an existing account." : "Du måste ange inloggningsuppgifter av ett aktuellt konto.", "Oracle connection could not be established" : "Oracle-anslutning kunde inte etableras", - "Oracle username and/or password not valid" : "Oracle-användarnamnet och/eller lösenordet är felaktigt", - "PostgreSQL username and/or password not valid" : "PostgreSQL-användarnamnet och/eller lösenordet är felaktigt", + "Oracle Login and/or password not valid" : "Oracle-inloggning och/eller lösenord är felaktigt", + "PostgreSQL Login and/or password not valid" : "PostgreSQL-inloggning och/eller lösenord är felaktigt", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X stöds inte och %s kommer inte att fungera korrekt på denna plattform. Använd på egen risk!", "For the best results, please consider using a GNU/Linux server instead." : "För bästa resultat, överväg att använda en GNU/Linux-server istället.", "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." : "Det verkar som om denna %s instans körs på en 32-bitars PHP miljö och open_basedir har konfigurerats i php.ini. Detta kommer att leda till problem med filer över 4 GB och är verkligen inte rekommenderat!", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Ta bort open_basedir-inställningen i din php.ini eller växla till 64-bitars PHP.", - "Set an admin username." : "Ange ett användarnamn för administratören.", + "Set an admin Login." : "Ange en admin-inloggning.", "Set an admin password." : "Ange ett administratörslösenord.", "Cannot create or write into the data directory %s" : "Kan inte skapa eller skriva till data-katalogen %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Delningsgränssnittet %s måste implementera gränssnittet OCP\\Share_Backend", @@ -149,11 +149,12 @@ "Expiration date is in the past" : "Utgångsdatum är i det förflutna", "_Cannot set expiration date more than %n day in the future_::_Cannot set expiration date more than %n days in the future_" : ["Kan inte sätta ett utgångsdatum längre fram än %n dag","Kan inte sätta ett utgångsdatum längre fram än %n dagar"], "Sharing is only allowed with group members" : "Delning är endast tillåten med gruppmedlemmar", - "Sharing %s failed, because this item is already shared with user %s" : "Delning av %s misslyckades eftersom detta redan är delat med användaren %s", + "Sharing %s failed, because this item is already shared with the account %s" : "Delning av %s misslyckades, eftersom det här objektet redan delas med kontot %s", "%1$s shared »%2$s« with you" : "%1$s delade »%2$s« med dig", "%1$s shared »%2$s« with you." : "%1$s delade »%2$s« med dig.", "Click the button below to open it." : "Klicka på knappen nedan för att öppna det.", "The requested share does not exist anymore" : "Den begärda delningen finns inte mer", + "The requested share comes from a disabled user" : "Den begärda delningen kommer från en inaktiverad användare", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Användaren skapades inte eftersom användargränsen har nåtts. Kontrollera dina aviseringar för att läsa mer.", "Could not find category \"%s\"" : "Kunde inte hitta kategorin \"%s\"", "Sunday" : "Söndag", @@ -202,14 +203,14 @@ "Nov." : "Nov.", "Dec." : "Dec.", "A valid password must be provided" : "Ett giltigt lösenord måste anges", - "The username is already being used" : "Användarnamnet används redan", - "Could not create user" : "Kunde inte skapa användare", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Endast följande tecken är tillåtna i ett användarnamn: \"a-z\", \"A-Z\", \"0-9\", mellanslag och \"_.@-'\"", - "A valid username must be provided" : "Ett giltigt användarnamn måste anges", - "Username contains whitespace at the beginning or at the end" : "Användarnamnet består av ett mellanslag i början eller i slutet", - "Username must not consist of dots only" : "Användarnamnet får inte innehålla enbart punkter", - "Username is invalid because files already exist for this user" : "Användarnamnet är ogiltigt eftersom det redan finns filer för den här användaren", - "User disabled" : "Användare inaktiverad", + "The Login is already being used" : "Inloggningen används redan", + "Could not create account" : "Kunde inte skapa konto", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Endast följande tecken är tillåtna i en inloggning: \"a-z\", \"A-Z\", \"0-9\", mellanslag och \"_.@-'\"", + "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 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", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Appen \"%1$s\" kan inte installeras eftersom följande beroenden inte är uppfyllda: %2$s", "a safe home for all your data" : "ett säkert hem för all din data", @@ -242,8 +243,8 @@ "Please ask your server administrator to restart the web server." : "Be din serveradministratör att starta om webbservern.", "The required %s config variable is not configured in the config.php file." : "Den nödvändiga konfigurationsvariabeln %s är inte konfigurerad i filen config.php.", "Please ask your server administrator to check the Nextcloud configuration." : "Be din serveradministratör att kontrollera Nextcloud-konfigurationen.", - "Your data directory is readable by other users." : "Din datakatalog kan läsas av andra användare.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare.", + "Your data directory is readable by other people." : "Din datakatalog kan läsas av andra användare.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare.", "Your data directory must be an absolute path." : "Din datakatalog måste vara en absolut sökväg.", "Check the value of \"datadirectory\" in your configuration." : "Kontrollera värdet på \"datadirectory\" i din konfiguration.", "Your data directory is invalid." : "Din datakatalog är ogiltig.", @@ -266,12 +267,32 @@ "Extract topics" : "Extrahera ämnen", "Extracts topics from a text and outputs them separated by commas." : "Extraherar ämnen från en text och matar ut dem separerade med kommatecken.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Filerna i appen %1$s ersattes inte korrekt. Kontrollera att det är en version som är kompatibel med servern.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Inloggad användare måste vara en admin, sub-admin eller ha tilldelats speciella rättigheter för att komma åt denna inställning", + "Logged in user must be an admin or sub admin" : "Inloggad användare måste vara administratör eller del-administratör", + "Logged in user must be an admin" : "Inloggad användare måste vara administratör", "Full name" : "Fullständigt namn", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Användargränsen har nåtts och användaren skapades inte. Kontrollera dina aviseringar om du vill veta mer.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Endast följande tecken är tillåtna i användarnamnet: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"", + "Unknown user" : "Okänd användare", + "Enter the database username and name for %s" : "Ange databasanvändarnamn och lösenord för %s", + "Enter the database username for %s" : "Ange databasanvändare för %s", + "MySQL username and/or password not valid" : "MySQL-användarnamn och/eller lösenord är felaktigt", + "Oracle username and/or password not valid" : "Oracle-användarnamnet och/eller lösenordet är felaktigt", + "PostgreSQL username and/or password not valid" : "PostgreSQL-användarnamnet och/eller lösenordet är felaktigt", + "Set an admin username." : "Ange ett användarnamn för administratören.", + "Sharing %s failed, because this item is already shared with user %s" : "Delning av %s misslyckades eftersom detta redan är delat med användaren %s", + "The username is already being used" : "Användarnamnet används redan", + "Could not create user" : "Kunde inte skapa användare", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Endast följande tecken är tillåtna i ett användarnamn: \"a-z\", \"A-Z\", \"0-9\", mellanslag och \"_.@-'\"", + "A valid username must be provided" : "Ett giltigt användarnamn måste anges", + "Username contains whitespace at the beginning or at the end" : "Användarnamnet består av ett mellanslag i början eller i slutet", + "Username must not consist of dots only" : "Användarnamnet får inte innehålla enbart punkter", + "Username is invalid because files already exist for this user" : "Användarnamnet är ogiltigt eftersom det redan finns filer för den här användaren", + "User disabled" : "Användare inaktiverad", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 är det minsta som krävs. För närvarande är %s installerat.", "To fix this issue update your libxml2 version and restart your web server." : "För att åtgärda detta problem uppdatera libxml2 versionen och starta om din webbserver.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 krävs.", - "Please upgrade your database version." : "Uppgradera din databasversion." + "Please upgrade your database version." : "Uppgradera din databasversion.", + "Your data directory is readable by other users." : "Din datakatalog kan läsas av andra användare.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/lib/l10n/th.js b/lib/l10n/th.js index b78d58379d8..cd7e222156a 100644 --- a/lib/l10n/th.js +++ b/lib/l10n/th.js @@ -2,10 +2,22 @@ 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." : "โดยปกติสามารถแก้ไขได้โดยการให้สิทธิ์การเขียนสำหรับเว็บเซิร์ฟเวอร์ไปยังไดเร็กทอรี config", + "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", "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." : "ไม่พบหน้านี้บนเซิร์ฟเวอร์", + "%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", "PHP %s or higher is required." : "จำเป็นต้องมี PHP รุ่น %s หรือที่สูงกว่า ", "PHP with a version lower than %s is required." : "จำเป็นต้องมี PHP รุ่นต่ำกว่า %s", "%sbit or higher PHP required." : "จำเป็นต้องมี PHP %s บิตหรือสูงกว่า", @@ -43,13 +55,17 @@ OC.L10N.register( "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\" เนื่องจากแอปเข้ากับเซิร์ฟเวอร์รุ่นนี้ไม่ได้", - "__language_name__" : "ภาษาไทย - Thai", + "__language_name__" : "ไทย", "Help" : "ช่วยเหลือ", "Apps" : "แอป", + "Personal settings" : "การตั้งค่าส่วนบุคคล", + "Administration settings" : "การตั้งค่าการดูแลระบบ", "Settings" : "การตั้งค่า", "Log out" : "ออกจากระบบ", "Users" : "ผู้ใช้งาน", "Email" : "อีเมล", + "Fediverse" : "เฟดิเวิร์ส", + "View %s on the fediverse" : "ดู %s บนเฟดิเวิร์ส", "Phone" : "โทรศัพท์", "Twitter" : "ทวิตเตอร์", "Website" : "เว็บไซต์", @@ -57,16 +73,12 @@ OC.L10N.register( "Profile picture" : "รูปภาพโปรไฟล์", "About" : "เกี่ยวกับ", "Display name" : "ชื่อที่แสดง", - "Unknown user" : "ผู้ใช้ที่ไม่รู้จัก", "Additional settings" : "การตั้งค่าเพิ่มเติม", "Oracle connection could not be established" : "ไม่สามารถสร้างการเชื่อมต่อกับ Oracle ", - "Oracle username and/or password not valid" : "ชื่อผู้ใช้และ/หรือรหัสผ่าน Oracle ไม่ถูกต้อง", - "PostgreSQL username 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 นี้ทำงานบน PHP 32 บิต และ open_basedir ได้ถูกกำหนดค่าใน php.ini ซึ่งจะมีปัญหากับไฟล์ที่มีขนาดใหญ่กว่า 4 GB และไม่แนะนำให้ใช้", "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 username." : "ตั้งค่าชื่อผู้ดูแลระบบ", "Set an admin password." : "ตั้งค่ารหัสผ่านผู้ดูแลระบบ", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "แบ็กเอนด์การแชร์ %s ต้องใช้อินเตอร์เฟซ OCP\\Share_Backend", "Sharing backend %s not found" : "ไม่พบแบ็กเอนด์การแชร์ %s", @@ -75,7 +87,6 @@ OC.L10N.register( "You are not allowed to share %s" : "คุณไม่ได้รับอนุญาตให้แชร์ %s", "Cannot increase permissions of %s" : "ไม่สามารถเพิ่มสิทธิ์ของ %s", "Expiration date is in the past" : "วันหมดอายุอยู่ในอดีต", - "Sharing %s failed, because this item is already shared with user %s" : "การแชร์ %s ล้มเหลว เพราะรายการนี้ได้แชร์กับผู้ใช้ %s ไปแล้ว", "Could not find category \"%s\"" : "ไม่สามารถหาหมวดหมู่ \"%s\"", "Sunday" : "วันอาทิตย์", "Monday" : "วันจันทร์", @@ -123,10 +134,6 @@ OC.L10N.register( "Nov." : "พ.ย.", "Dec." : "ธ.ค.", "A valid password must be provided" : "ต้องระบุรหัสผ่านที่ถูกต้อง", - "The username is already being used" : "ชื่อผู้ใช้นี้ถูกใช้ไปแล้ว", - "A valid username must be provided" : "ต้องระบุชื่อผู้ใช้ที่ถูกต้อง", - "Username contains whitespace at the beginning or at the end" : "ชื่อผู้ใช้มีช่องว่างอยู่ด้านหน้าหรือด้านหลัง", - "User disabled" : "ผู้ใช้ถูกปิดใช้งาน", "Login canceled by app" : "การเข้าสู่ระบบถูกยกเลิกโดยแอป", "a safe home for all your data" : "บ้านที่ปลอดภัยสำหรับข้อมูลทั้งหมดของคุณ", "File is currently busy, please try again later" : "ไฟล์กำลังใช้งานอยู่ โปรดลองอีกครั้งในภายหลัง", @@ -142,7 +149,6 @@ OC.L10N.register( "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "ปัญหานี้อาจเกิดจาก cache/accelerator เช่น 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." : "โปรดสอบถามผู้ดูแลระบบเซิร์ฟเวอร์ของคุณเพื่อเริ่มระบบเว็บเซิร์ฟเวอร์ใหม่", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "กรุณาเปลี่ยนสิทธิ์การเข้าถึงเป็น 0770 เพื่อให้ไดเรกทอรีไม่สามารถแก้ไขโดยผู้ใช้อื่น", "Could not obtain lock type %d on \"%s\"." : "ไม่สามารถรับล็อคชนิด %d บน \"%s\"", "Storage unauthorized. %s" : "การจัดเก็บข้อมูลไม่ได้รับอนุญาต %s", "Storage incomplete configuration. %s" : "การตั้งค่าการจัดเก็บข้อมูลไม่ครบ %s", @@ -150,8 +156,17 @@ OC.L10N.register( "Storage is temporarily not available" : "พื้นที่จัดเก็บข้อมูลไม่สามารถใช้งานได้ชั่วคราว", "Storage connection timeout. %s" : "หมดเวลาการเชื่อมต่อพื้นที่จัดเก็บข้อมูล %s", "Full name" : "ชื่อเต็ม", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ชื่อผู้ใช้จะใช้ได้แค่อักษรดังต่อไปนี้: \"a-z\", \"A-Z\", \"0-9\" และ \"_.@-'\"", + "Unknown user" : "ผู้ใช้ที่ไม่รู้จัก", + "Oracle username and/or password not valid" : "ชื่อผู้ใช้และ/หรือรหัสผ่าน Oracle ไม่ถูกต้อง", + "PostgreSQL username and/or password not valid" : "ชื่อผู้ใช้และ/หรือรหัสผ่าน PostgreSQL ไม่ถูกต้อง", + "Set an admin username." : "ตั้งค่าชื่อผู้ดูแลระบบ", + "Sharing %s failed, because this item is already shared with user %s" : "การแชร์ %s ล้มเหลว เพราะรายการนี้ได้แชร์กับผู้ใช้ %s ไปแล้ว", + "The username is already being used" : "ชื่อผู้ใช้นี้ถูกใช้ไปแล้ว", + "A valid username must be provided" : "ต้องระบุชื่อผู้ใช้ที่ถูกต้อง", + "Username contains whitespace at the beginning or at the end" : "ชื่อผู้ใช้มีช่องว่างอยู่ด้านหน้าหรือด้านหลัง", + "User disabled" : "ผู้ใช้ถูกปิดใช้งาน", "libxml2 2.7.0 is at least required. Currently %s is installed." : "จำเป็นต้องมี libxml2 รุ่นอย่างน้อย 2.7.0 ตอนนี้ %s ติดตั้งอยู่", - "To fix this issue update your libxml2 version and restart your web server." : "เพื่อแก้ไขปัญหานี้ กรุณาอัปเดตรุ่นของ libxml2 และรีสตาร์ทเว็บเซิร์ฟเวอร์ของคุณ" + "To fix this issue update your libxml2 version and restart your web server." : "เพื่อแก้ไขปัญหานี้ กรุณาอัปเดตรุ่นของ libxml2 และรีสตาร์ทเว็บเซิร์ฟเวอร์ของคุณ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "กรุณาเปลี่ยนสิทธิ์การเข้าถึงเป็น 0770 เพื่อให้ไดเรกทอรีไม่สามารถแก้ไขโดยผู้ใช้อื่น" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/th.json b/lib/l10n/th.json index 30cc82d864d..47715cf2465 100644 --- a/lib/l10n/th.json +++ b/lib/l10n/th.json @@ -1,9 +1,21 @@ { "translations": { "Cannot write into \"config\" directory!" : "ไม่สามารถเขียนลงในไดเรกทอรี \"config\"!", + "This can usually be fixed by giving the web server write access to the config directory." : "โดยปกติสามารถแก้ไขได้โดยการให้สิทธิ์การเขียนสำหรับเว็บเซิร์ฟเวอร์ไปยังไดเร็กทอรี config", + "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", "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." : "ไม่พบหน้านี้บนเซิร์ฟเวอร์", + "%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", "PHP %s or higher is required." : "จำเป็นต้องมี PHP รุ่น %s หรือที่สูงกว่า ", "PHP with a version lower than %s is required." : "จำเป็นต้องมี PHP รุ่นต่ำกว่า %s", "%sbit or higher PHP required." : "จำเป็นต้องมี PHP %s บิตหรือสูงกว่า", @@ -41,13 +53,17 @@ "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\" เนื่องจากแอปเข้ากับเซิร์ฟเวอร์รุ่นนี้ไม่ได้", - "__language_name__" : "ภาษาไทย - Thai", + "__language_name__" : "ไทย", "Help" : "ช่วยเหลือ", "Apps" : "แอป", + "Personal settings" : "การตั้งค่าส่วนบุคคล", + "Administration settings" : "การตั้งค่าการดูแลระบบ", "Settings" : "การตั้งค่า", "Log out" : "ออกจากระบบ", "Users" : "ผู้ใช้งาน", "Email" : "อีเมล", + "Fediverse" : "เฟดิเวิร์ส", + "View %s on the fediverse" : "ดู %s บนเฟดิเวิร์ส", "Phone" : "โทรศัพท์", "Twitter" : "ทวิตเตอร์", "Website" : "เว็บไซต์", @@ -55,16 +71,12 @@ "Profile picture" : "รูปภาพโปรไฟล์", "About" : "เกี่ยวกับ", "Display name" : "ชื่อที่แสดง", - "Unknown user" : "ผู้ใช้ที่ไม่รู้จัก", "Additional settings" : "การตั้งค่าเพิ่มเติม", "Oracle connection could not be established" : "ไม่สามารถสร้างการเชื่อมต่อกับ Oracle ", - "Oracle username and/or password not valid" : "ชื่อผู้ใช้และ/หรือรหัสผ่าน Oracle ไม่ถูกต้อง", - "PostgreSQL username 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 นี้ทำงานบน PHP 32 บิต และ open_basedir ได้ถูกกำหนดค่าใน php.ini ซึ่งจะมีปัญหากับไฟล์ที่มีขนาดใหญ่กว่า 4 GB และไม่แนะนำให้ใช้", "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 username." : "ตั้งค่าชื่อผู้ดูแลระบบ", "Set an admin password." : "ตั้งค่ารหัสผ่านผู้ดูแลระบบ", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "แบ็กเอนด์การแชร์ %s ต้องใช้อินเตอร์เฟซ OCP\\Share_Backend", "Sharing backend %s not found" : "ไม่พบแบ็กเอนด์การแชร์ %s", @@ -73,7 +85,6 @@ "You are not allowed to share %s" : "คุณไม่ได้รับอนุญาตให้แชร์ %s", "Cannot increase permissions of %s" : "ไม่สามารถเพิ่มสิทธิ์ของ %s", "Expiration date is in the past" : "วันหมดอายุอยู่ในอดีต", - "Sharing %s failed, because this item is already shared with user %s" : "การแชร์ %s ล้มเหลว เพราะรายการนี้ได้แชร์กับผู้ใช้ %s ไปแล้ว", "Could not find category \"%s\"" : "ไม่สามารถหาหมวดหมู่ \"%s\"", "Sunday" : "วันอาทิตย์", "Monday" : "วันจันทร์", @@ -121,10 +132,6 @@ "Nov." : "พ.ย.", "Dec." : "ธ.ค.", "A valid password must be provided" : "ต้องระบุรหัสผ่านที่ถูกต้อง", - "The username is already being used" : "ชื่อผู้ใช้นี้ถูกใช้ไปแล้ว", - "A valid username must be provided" : "ต้องระบุชื่อผู้ใช้ที่ถูกต้อง", - "Username contains whitespace at the beginning or at the end" : "ชื่อผู้ใช้มีช่องว่างอยู่ด้านหน้าหรือด้านหลัง", - "User disabled" : "ผู้ใช้ถูกปิดใช้งาน", "Login canceled by app" : "การเข้าสู่ระบบถูกยกเลิกโดยแอป", "a safe home for all your data" : "บ้านที่ปลอดภัยสำหรับข้อมูลทั้งหมดของคุณ", "File is currently busy, please try again later" : "ไฟล์กำลังใช้งานอยู่ โปรดลองอีกครั้งในภายหลัง", @@ -140,7 +147,6 @@ "This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "ปัญหานี้อาจเกิดจาก cache/accelerator เช่น 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." : "โปรดสอบถามผู้ดูแลระบบเซิร์ฟเวอร์ของคุณเพื่อเริ่มระบบเว็บเซิร์ฟเวอร์ใหม่", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "กรุณาเปลี่ยนสิทธิ์การเข้าถึงเป็น 0770 เพื่อให้ไดเรกทอรีไม่สามารถแก้ไขโดยผู้ใช้อื่น", "Could not obtain lock type %d on \"%s\"." : "ไม่สามารถรับล็อคชนิด %d บน \"%s\"", "Storage unauthorized. %s" : "การจัดเก็บข้อมูลไม่ได้รับอนุญาต %s", "Storage incomplete configuration. %s" : "การตั้งค่าการจัดเก็บข้อมูลไม่ครบ %s", @@ -148,8 +154,17 @@ "Storage is temporarily not available" : "พื้นที่จัดเก็บข้อมูลไม่สามารถใช้งานได้ชั่วคราว", "Storage connection timeout. %s" : "หมดเวลาการเชื่อมต่อพื้นที่จัดเก็บข้อมูล %s", "Full name" : "ชื่อเต็ม", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ชื่อผู้ใช้จะใช้ได้แค่อักษรดังต่อไปนี้: \"a-z\", \"A-Z\", \"0-9\" และ \"_.@-'\"", + "Unknown user" : "ผู้ใช้ที่ไม่รู้จัก", + "Oracle username and/or password not valid" : "ชื่อผู้ใช้และ/หรือรหัสผ่าน Oracle ไม่ถูกต้อง", + "PostgreSQL username and/or password not valid" : "ชื่อผู้ใช้และ/หรือรหัสผ่าน PostgreSQL ไม่ถูกต้อง", + "Set an admin username." : "ตั้งค่าชื่อผู้ดูแลระบบ", + "Sharing %s failed, because this item is already shared with user %s" : "การแชร์ %s ล้มเหลว เพราะรายการนี้ได้แชร์กับผู้ใช้ %s ไปแล้ว", + "The username is already being used" : "ชื่อผู้ใช้นี้ถูกใช้ไปแล้ว", + "A valid username must be provided" : "ต้องระบุชื่อผู้ใช้ที่ถูกต้อง", + "Username contains whitespace at the beginning or at the end" : "ชื่อผู้ใช้มีช่องว่างอยู่ด้านหน้าหรือด้านหลัง", + "User disabled" : "ผู้ใช้ถูกปิดใช้งาน", "libxml2 2.7.0 is at least required. Currently %s is installed." : "จำเป็นต้องมี libxml2 รุ่นอย่างน้อย 2.7.0 ตอนนี้ %s ติดตั้งอยู่", - "To fix this issue update your libxml2 version and restart your web server." : "เพื่อแก้ไขปัญหานี้ กรุณาอัปเดตรุ่นของ libxml2 และรีสตาร์ทเว็บเซิร์ฟเวอร์ของคุณ" + "To fix this issue update your libxml2 version and restart your web server." : "เพื่อแก้ไขปัญหานี้ กรุณาอัปเดตรุ่นของ libxml2 และรีสตาร์ทเว็บเซิร์ฟเวอร์ของคุณ", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "กรุณาเปลี่ยนสิทธิ์การเข้าถึงเป็น 0770 เพื่อให้ไดเรกทอรีไม่สามารถแก้ไขโดยผู้ใช้อื่น" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/tr.js b/lib/l10n/tr.js index 5eee8ded0d6..ebd604aec76 100644 --- a/lib/l10n/tr.js +++ b/lib/l10n/tr.js @@ -8,7 +8,6 @@ OC.L10N.register( "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "%1$s uygulaması yok ya da bu sunucuyla uyumlu olmayan bir sürümü var. Lütfen apps klasörünü kontrol edin.", "Sample configuration detected" : "Örnek yapılandırma algılandı", "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" : "Örnek yapılandırmanın kopyalanmış olabileceği tespit edildi. Bu durum kurulumunuzu bozabilir ve desteklenmez. Lütfen config.php dosyasında değişiklik yapmadan önce belgeleri okuyun", - "404" : "404", "The page could not be found on the server." : "Sayfa sunucuda bulunamadı.", "%s email verification" : "%s e-posta doğrulaması", "Email verification" : "E-posta doğrulaması", @@ -37,9 +36,9 @@ OC.L10N.register( "The following platforms are supported: %s" : "Şu platformlar destekleniyor: %s", "Server version %s or higher is required." : "Sunucu %s ya da daha sonraki bir sürüm olmalıdır.", "Server version %s or lower is required." : "Sunucu %s ya da daha önceki bir sürüm olmalıdır.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Oturum açmış kullanıcı bir yönetici, bir alt yönetici veya bu ayara erişmek için özel izne sahip olmalıdır", - "Logged in user must be an admin or sub admin" : "Oturum açmış kullanıcı bir yönetici ya da alt yönetici olmalıdır", - "Logged in user must be an admin" : "Oturum açmış kullanıcı bir yönetici olmalıdır", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Oturum açmış hesap bir yönetici, bir alt yönetici veya bu ayara erişmek için özel izne sahip olmalıdır", + "Logged in account must be an admin or sub admin" : "Oturum açmış hesap bir yönetici ya da alt yönetici olmalıdır", + "Logged in account must be an admin" : "Oturum açmış hesap bir yönetici olmalıdır", "Wiping of device %s has started" : "%s aygıtının silinmesine başlandı", "Wiping of device »%s« has started" : "»%s« aygıtının silinmesine başlandı", "»%s« started remote wipe" : "»%s« uzaktan silme işlemi başladı", @@ -64,12 +63,12 @@ OC.L10N.register( "yesterday" : "dün", "_in %n day_::_in %n days_" : ["%n gün içinde","%n gün içinde"], "_%n day ago_::_%n days ago_" : ["%n gün önce","%n gün önce"], - "next month" : "gelecek ay", - "last month" : "geçen ay", + "next month" : "sonraki ay", + "last month" : "önceki ay", "_in %n month_::_in %n months_" : ["%n ay içinde","%n ay içinde"], "_%n month ago_::_%n months ago_" : ["%n ay önce","%n ay önce"], - "next year" : "gelecek yıl", - "last year" : "geçen yıl", + "next year" : "sonraki yıl", + "last year" : "önceki yıl", "_in %n year_::_in %n years_" : ["%n yıl içinde","%n yıl içinde"], "_%n year ago_::_%n years ago_" : ["%n yıl önce","%n yıl önce"], "_in %n hour_::_in %n hours_" : ["%n saat içinde","%n saat içinde"], @@ -79,7 +78,7 @@ OC.L10N.register( "in a few seconds" : "bir kaç saniye içinde", "seconds ago" : "saniyeler önce", "Empty file" : "Dosya boş", - "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "%s kodlu modül bulunamadı. Lütfen uygulamalarınız içinden modülü etkinleştirin ya da BT yöneticinizle görüşün.", + "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ü etkinleştirin ya da BT yöneticinizle görüşün.", "File already exists" : "Dosya zaten var", "Invalid path" : "Yol geçersiz", "Failed to create file from template" : "Kalıptan dosya oluşturulamadı", @@ -118,22 +117,22 @@ OC.L10N.register( "Headline" : "Başlık", "Organisation" : "Kuruluş", "Role" : "Pozisyon", - "Unknown user" : "Kullanıcı bilinmiyor", + "Unknown account" : "Hesap bilinmiyor", "Additional settings" : "Ek ayarlar", - "Enter the database username and name for %s" : "%s için veri tabanı adını ve kullanıcı adını yazın", - "Enter the database username for %s" : "%s için veri tabanı kullanıcı adını yazın", + "Enter the database Login and name for %s" : "%s için veri tabanı adını ve kullanıcı adını yazın", + "Enter the database Login for %s" : "%s için veri tabanı kullanıcı adını yazın", "Enter the database name for %s" : "%s için veri tabanı adını yazın", "You cannot use dots in the database name %s" : "%s veri tabanı adında nokta kullanamazsınız", - "MySQL username and/or password not valid" : "MySQL kullanıcı adı ya da parolası geçersiz", + "MySQL Login and/or password not valid" : "MySQL kullanıcı adı ve/veya parolası geçersiz", "You need to enter details of an existing account." : "Var olan bir hesabın bilgilerini yazmalısınız.", "Oracle connection could not be established" : "Oracle ile bağlantı kurulamadı", - "Oracle username and/or password not valid" : "Oracle kullanıcı adı ya da parolası geçersiz", - "PostgreSQL username and/or password not valid" : "PostgreSQL kullanıcı adı ya da parolası geçersiz", + "Oracle Login and/or password not valid" : "Oracle kullanıcı adı ve/veya parolası geçersiz", + "PostgreSQL Login and/or password not valid" : "PostgreSQL kullanıcı adı ve/veya parolası geçersiz", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X desteklenmiyor ve %s bu platformda düzgün çalışmayacak. Kullanmaktan doğacak riskler size aittir!", "For the best results, please consider using a GNU/Linux server instead." : "En iyi sonucu almak için GNU/Linux sunucusu kullanın.", "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." : "Bu %s kopyası 32 bit PHP ortamında çalıştırılıyor ve open_basedir seçeneği php.ini dosyasından ayarlanmış gibi görünüyor. Bu yapılandırma 4 GB boyutundan büyük dosyalarda sorun çıkarır ve kullanılması önerilmez.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Lütfen php.ini dosyasındaki open_basedir ayarını kaldırın ya da 64-bit PHP sürümüne geçin.", - "Set an admin username." : "Bir yönetici kullanıcı adı yazın.", + "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", @@ -148,14 +147,15 @@ OC.L10N.register( "Cannot increase permissions of %s" : "%s izinleri yükseltilemedi", "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" : "Son kullanma tarihi geçmişte", - "_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 son kullanım süreleri, gelecekte %n günden fazla olamaz","Paylaşımların son kullanım süreleri, gelecekte %n günden fazla olamaz"], + "Expiration date is in the past" : "Geçerlilik sonu tarihi geçmişte", + "_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 user %s" : "%s paylaşılamadı. Bu öge zaten %s kullanıcısı ile paylaşılmış", + "Sharing %s failed, because this item is already shared with the account %s" : "%s paylaşılamadı. Bu öge zaten %s hesabı ile paylaşılmış", "%1$s shared »%2$s« with you" : "%1$s, sizinle »%2$s« ögesini paylaştı", "%1$s shared »%2$s« with you." : "%1$s, sizinle »%2$s« ögesini paylaştı.", "Click the button below to open it." : "Açmak için aşağıdaki düğmeye tıklayın.", "The requested share does not exist anymore" : "Erişilmek istenilen paylaşım artık yok", + "The requested share comes from a disabled user" : "Erişilmek istenilen paylaşım devre dışı bırakılmış bir kullanıcıdan geliyor", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Kullanıcı sayısı sınırına ulaşıldığından kullanıcı eklenemedi. Ayrıntılı bilgi almak için bildirimlerinize bakın.", "Could not find category \"%s\"" : "\"%s\" kategorisi bulunamadı", "Sunday" : "Pazar", @@ -204,14 +204,14 @@ OC.L10N.register( "Nov." : "Kas", "Dec." : "Ara", "A valid password must be provided" : "Geçerli bir parola yazmalısınız", - "The username is already being used" : "Bu kullanıcı adı zaten var", - "Could not create user" : "Kullanıcı oluşturulamadı", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kullanıcı adında yalnızca şu karakterler kullanılabilir: \"a-z\", \"A-Z\", \"0-9\", boşluk ve \"_.@-'\"", - "A valid username must be provided" : "Geçerli bir kullanıcı adı yazmalısınız", - "Username contains whitespace at the beginning or at the end" : "Kullanıcı adının başı ya da sonunda boşluk var", - "Username must not consist of dots only" : "Kullanıcı adı yalnızca noktalardan oluşamaz", - "Username is invalid because files already exist for this user" : "Kullanıcı adı geçersiz, bu kullanıcı için zaten bazı dosyalar var", - "User disabled" : "Kullanıcı devre dışı", + "The Login is already being used" : "Bu kullanıcı adı zaten var", + "Could not create account" : "Hesap oluşturulamadı", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kullanıcı adında yalnızca şu karakterler kullanılabilir: \"a-z\", \"A-Z\", \"0-9\", boşluk ve \"_.@-'\"", + "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 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 devre dışı", "Login canceled by app" : "Oturum açma uygulama tarafından iptal edildi", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "\"%1$s\" uygulaması, şu gereklilikler sağlanmadığı için kurulamıyor: %2$s", "a safe home for all your data" : "verileriniz için güvenli bir barınak", @@ -244,17 +244,17 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "Lütfen site sunucusunu yeniden başlatması için BT yöneticinizle görüşün.", "The required %s config variable is not configured in the config.php file." : "Gereken %s yapılandırma değişkeni config.php dosyasında ayarlanmamış.", "Please ask your server administrator to check the Nextcloud configuration." : "Lütfen Nextcloud yapılandırmasını denetlemesi için BT yöneticinizle görüşün.", - "Your data directory is readable by other users." : "Veri klasörünüz diğer kullanıcılar tarafından okunabilir.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Lütfen izinleri 0770 olarak ayarlayarak diğer kullanıcıların klasörü görebilmesini sağlayın.", + "Your data directory is readable by other people." : "Veri klasörünüz diğer kişiler tarafından okunabilir.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Lütfen izinleri 0770 olarak ayarlayarak diğer kişilerin klasörü görebilmesini sağlayın.", "Your data directory must be an absolute path." : "Veri klasörünüz mutlak bir yol olmalıdır.", "Check the value of \"datadirectory\" in your configuration." : "Yapılandırmanızdaki \"datadirectory\" değerini denetleyin.", "Your data directory is invalid." : "Veri klasörünüz geçersiz.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Veri klasörü kökünde \".ocdata\" adında bir dosya bulunduğundan emin olun.", "Action \"%s\" not supported or implemented." : "\"%s\" işlemi desteklenmiyor ya da henüz kullanılamıyor.", - "Authentication failed, wrong token or provider ID given" : "Kimlik doğrulanamadı. Belirtilen kod ya da hizmet sağlayıcı kodu hatalı", + "Authentication failed, wrong token or provider ID given" : "Kimlik doğrulanamadı. Belirtilen kod ya da hizmet sağlayıcı kimliği hatalı", "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "İsteğin tamamlanması için gerekli parametreler eksik: \"%s\"", - "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "\"%1$s\" kodu zaten \"%2$s\" birleşik hizmet sağlayıcısı tarafından kullanılıyor", - "Cloud Federation Provider with ID: \"%s\" does not exist." : "\"%s\" kodlu birleşik bulut hizmeti sağlayıcısı bulunamadı.", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "\"%1$s\" kimliği zaten \"%2$s\" birleşik hizmet sağlayıcısı tarafından kullanılıyor", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "\"%s\" kimlikli birleşik bulut hizmeti sağlayıcısı bulunamadı.", "Could not obtain lock type %d on \"%s\"." : "\"%s\" için %d kilit türü alınamadı.", "Storage unauthorized. %s" : "Depolamaya erişim izni yok. %s", "Storage incomplete configuration. %s" : "Depolama yapılandırması tamamlanmamış. %s", @@ -270,12 +270,32 @@ OC.L10N.register( "Extract topics" : "Başlıklar ayıklansın", "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.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "%1$s uygulamasının dosyaları doğru şekilde değiştirilmedi. Sunucu ile uyumlu dosyaların yüklü olduğundan emin olun.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Oturum açmış kullanıcı bir yönetici, bir alt yönetici veya bu ayara erişmek için özel izne sahip olmalıdır", + "Logged in user must be an admin or sub admin" : "Oturum açmış kullanıcı bir yönetici ya da alt yönetici olmalıdır", + "Logged in user must be an admin" : "Oturum açmış kullanıcı bir yönetici olmalıdır", "Full name" : "Tam ad", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Kullanıcı sayısı sınırına ulaşıldığından kullanıcı eklenemedi. Ayrıntılı bilgi almak için bildirimlerinize bakın.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Kullanıcı adında yalnızca şu karakterler kullanılabilir: \"a-z\", \"A-Z\", \"0-9\", ve \"_.@-'\"", + "Unknown user" : "Kullanıcı bilinmiyor", + "Enter the database username and name for %s" : "%s için veri tabanı adını ve kullanıcı adını yazın", + "Enter the database username for %s" : "%s için veri tabanı kullanıcı adını yazın", + "MySQL username and/or password not valid" : "MySQL kullanıcı adı ya da parolası geçersiz", + "Oracle username and/or password not valid" : "Oracle kullanıcı adı ya da parolası geçersiz", + "PostgreSQL username and/or password not valid" : "PostgreSQL kullanıcı adı ya da parolası geçersiz", + "Set an admin username." : "Bir yönetici kullanıcı adı yazın.", + "Sharing %s failed, because this item is already shared with user %s" : "%s paylaşılamadı. Bu öge zaten %s kullanıcısı ile paylaşılmış", + "The username is already being used" : "Bu kullanıcı adı zaten var", + "Could not create user" : "Kullanıcı oluşturulamadı", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kullanıcı adında yalnızca şu karakterler kullanılabilir: \"a-z\", \"A-Z\", \"0-9\", boşluk ve \"_.@-'\"", + "A valid username must be provided" : "Geçerli bir kullanıcı adı yazmalısınız", + "Username contains whitespace at the beginning or at the end" : "Kullanıcı adının başı ya da sonunda boşluk var", + "Username must not consist of dots only" : "Kullanıcı adı yalnızca noktalardan oluşamaz", + "Username is invalid because files already exist for this user" : "Kullanıcı adı geçersiz, bu kullanıcı için zaten bazı dosyalar var", + "User disabled" : "Kullanıcı devre dışı", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 sürümü en az 2.7.0 olmalıdır. Şu anda %s kurulu.", "To fix this issue update your libxml2 version and restart your web server." : "Bu sorunu çözmek için libxml2 sürümünüzü güncelleyin ve site sunucusunu yeniden başlatın.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 gerekli.", - "Please upgrade your database version." : "Lütfen veri tabanı sürümünüzü yükseltin." + "Please upgrade your database version." : "Lütfen veri tabanı sürümünüzü yükseltin.", + "Your data directory is readable by other users." : "Veri klasörünüz diğer kullanıcılar tarafından okunabilir.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Lütfen izinleri 0770 olarak ayarlayarak diğer kullanıcıların klasörü görebilmesini sağlayın." }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/tr.json b/lib/l10n/tr.json index a719db23f9a..09623974930 100644 --- a/lib/l10n/tr.json +++ b/lib/l10n/tr.json @@ -6,7 +6,6 @@ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "%1$s uygulaması yok ya da bu sunucuyla uyumlu olmayan bir sürümü var. Lütfen apps klasörünü kontrol edin.", "Sample configuration detected" : "Örnek yapılandırma algılandı", "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" : "Örnek yapılandırmanın kopyalanmış olabileceği tespit edildi. Bu durum kurulumunuzu bozabilir ve desteklenmez. Lütfen config.php dosyasında değişiklik yapmadan önce belgeleri okuyun", - "404" : "404", "The page could not be found on the server." : "Sayfa sunucuda bulunamadı.", "%s email verification" : "%s e-posta doğrulaması", "Email verification" : "E-posta doğrulaması", @@ -35,9 +34,9 @@ "The following platforms are supported: %s" : "Şu platformlar destekleniyor: %s", "Server version %s or higher is required." : "Sunucu %s ya da daha sonraki bir sürüm olmalıdır.", "Server version %s or lower is required." : "Sunucu %s ya da daha önceki bir sürüm olmalıdır.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Oturum açmış kullanıcı bir yönetici, bir alt yönetici veya bu ayara erişmek için özel izne sahip olmalıdır", - "Logged in user must be an admin or sub admin" : "Oturum açmış kullanıcı bir yönetici ya da alt yönetici olmalıdır", - "Logged in user must be an admin" : "Oturum açmış kullanıcı bir yönetici olmalıdır", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Oturum açmış hesap bir yönetici, bir alt yönetici veya bu ayara erişmek için özel izne sahip olmalıdır", + "Logged in account must be an admin or sub admin" : "Oturum açmış hesap bir yönetici ya da alt yönetici olmalıdır", + "Logged in account must be an admin" : "Oturum açmış hesap bir yönetici olmalıdır", "Wiping of device %s has started" : "%s aygıtının silinmesine başlandı", "Wiping of device »%s« has started" : "»%s« aygıtının silinmesine başlandı", "»%s« started remote wipe" : "»%s« uzaktan silme işlemi başladı", @@ -62,12 +61,12 @@ "yesterday" : "dün", "_in %n day_::_in %n days_" : ["%n gün içinde","%n gün içinde"], "_%n day ago_::_%n days ago_" : ["%n gün önce","%n gün önce"], - "next month" : "gelecek ay", - "last month" : "geçen ay", + "next month" : "sonraki ay", + "last month" : "önceki ay", "_in %n month_::_in %n months_" : ["%n ay içinde","%n ay içinde"], "_%n month ago_::_%n months ago_" : ["%n ay önce","%n ay önce"], - "next year" : "gelecek yıl", - "last year" : "geçen yıl", + "next year" : "sonraki yıl", + "last year" : "önceki yıl", "_in %n year_::_in %n years_" : ["%n yıl içinde","%n yıl içinde"], "_%n year ago_::_%n years ago_" : ["%n yıl önce","%n yıl önce"], "_in %n hour_::_in %n hours_" : ["%n saat içinde","%n saat içinde"], @@ -77,7 +76,7 @@ "in a few seconds" : "bir kaç saniye içinde", "seconds ago" : "saniyeler önce", "Empty file" : "Dosya boş", - "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "%s kodlu modül bulunamadı. Lütfen uygulamalarınız içinden modülü etkinleştirin ya da BT yöneticinizle görüşün.", + "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ü etkinleştirin ya da BT yöneticinizle görüşün.", "File already exists" : "Dosya zaten var", "Invalid path" : "Yol geçersiz", "Failed to create file from template" : "Kalıptan dosya oluşturulamadı", @@ -116,22 +115,22 @@ "Headline" : "Başlık", "Organisation" : "Kuruluş", "Role" : "Pozisyon", - "Unknown user" : "Kullanıcı bilinmiyor", + "Unknown account" : "Hesap bilinmiyor", "Additional settings" : "Ek ayarlar", - "Enter the database username and name for %s" : "%s için veri tabanı adını ve kullanıcı adını yazın", - "Enter the database username for %s" : "%s için veri tabanı kullanıcı adını yazın", + "Enter the database Login and name for %s" : "%s için veri tabanı adını ve kullanıcı adını yazın", + "Enter the database Login for %s" : "%s için veri tabanı kullanıcı adını yazın", "Enter the database name for %s" : "%s için veri tabanı adını yazın", "You cannot use dots in the database name %s" : "%s veri tabanı adında nokta kullanamazsınız", - "MySQL username and/or password not valid" : "MySQL kullanıcı adı ya da parolası geçersiz", + "MySQL Login and/or password not valid" : "MySQL kullanıcı adı ve/veya parolası geçersiz", "You need to enter details of an existing account." : "Var olan bir hesabın bilgilerini yazmalısınız.", "Oracle connection could not be established" : "Oracle ile bağlantı kurulamadı", - "Oracle username and/or password not valid" : "Oracle kullanıcı adı ya da parolası geçersiz", - "PostgreSQL username and/or password not valid" : "PostgreSQL kullanıcı adı ya da parolası geçersiz", + "Oracle Login and/or password not valid" : "Oracle kullanıcı adı ve/veya parolası geçersiz", + "PostgreSQL Login and/or password not valid" : "PostgreSQL kullanıcı adı ve/veya parolası geçersiz", "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X desteklenmiyor ve %s bu platformda düzgün çalışmayacak. Kullanmaktan doğacak riskler size aittir!", "For the best results, please consider using a GNU/Linux server instead." : "En iyi sonucu almak için GNU/Linux sunucusu kullanın.", "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." : "Bu %s kopyası 32 bit PHP ortamında çalıştırılıyor ve open_basedir seçeneği php.ini dosyasından ayarlanmış gibi görünüyor. Bu yapılandırma 4 GB boyutundan büyük dosyalarda sorun çıkarır ve kullanılması önerilmez.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Lütfen php.ini dosyasındaki open_basedir ayarını kaldırın ya da 64-bit PHP sürümüne geçin.", - "Set an admin username." : "Bir yönetici kullanıcı adı yazın.", + "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", @@ -146,14 +145,15 @@ "Cannot increase permissions of %s" : "%s izinleri yükseltilemedi", "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" : "Son kullanma tarihi geçmişte", - "_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 son kullanım süreleri, gelecekte %n günden fazla olamaz","Paylaşımların son kullanım süreleri, gelecekte %n günden fazla olamaz"], + "Expiration date is in the past" : "Geçerlilik sonu tarihi geçmişte", + "_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 user %s" : "%s paylaşılamadı. Bu öge zaten %s kullanıcısı ile paylaşılmış", + "Sharing %s failed, because this item is already shared with the account %s" : "%s paylaşılamadı. Bu öge zaten %s hesabı ile paylaşılmış", "%1$s shared »%2$s« with you" : "%1$s, sizinle »%2$s« ögesini paylaştı", "%1$s shared »%2$s« with you." : "%1$s, sizinle »%2$s« ögesini paylaştı.", "Click the button below to open it." : "Açmak için aşağıdaki düğmeye tıklayın.", "The requested share does not exist anymore" : "Erişilmek istenilen paylaşım artık yok", + "The requested share comes from a disabled user" : "Erişilmek istenilen paylaşım devre dışı bırakılmış bir kullanıcıdan geliyor", "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Kullanıcı sayısı sınırına ulaşıldığından kullanıcı eklenemedi. Ayrıntılı bilgi almak için bildirimlerinize bakın.", "Could not find category \"%s\"" : "\"%s\" kategorisi bulunamadı", "Sunday" : "Pazar", @@ -202,14 +202,14 @@ "Nov." : "Kas", "Dec." : "Ara", "A valid password must be provided" : "Geçerli bir parola yazmalısınız", - "The username is already being used" : "Bu kullanıcı adı zaten var", - "Could not create user" : "Kullanıcı oluşturulamadı", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kullanıcı adında yalnızca şu karakterler kullanılabilir: \"a-z\", \"A-Z\", \"0-9\", boşluk ve \"_.@-'\"", - "A valid username must be provided" : "Geçerli bir kullanıcı adı yazmalısınız", - "Username contains whitespace at the beginning or at the end" : "Kullanıcı adının başı ya da sonunda boşluk var", - "Username must not consist of dots only" : "Kullanıcı adı yalnızca noktalardan oluşamaz", - "Username is invalid because files already exist for this user" : "Kullanıcı adı geçersiz, bu kullanıcı için zaten bazı dosyalar var", - "User disabled" : "Kullanıcı devre dışı", + "The Login is already being used" : "Bu kullanıcı adı zaten var", + "Could not create account" : "Hesap oluşturulamadı", + "Only the following characters are allowed in an Login: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kullanıcı adında yalnızca şu karakterler kullanılabilir: \"a-z\", \"A-Z\", \"0-9\", boşluk ve \"_.@-'\"", + "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 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 devre dışı", "Login canceled by app" : "Oturum açma uygulama tarafından iptal edildi", "App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "\"%1$s\" uygulaması, şu gereklilikler sağlanmadığı için kurulamıyor: %2$s", "a safe home for all your data" : "verileriniz için güvenli bir barınak", @@ -242,17 +242,17 @@ "Please ask your server administrator to restart the web server." : "Lütfen site sunucusunu yeniden başlatması için BT yöneticinizle görüşün.", "The required %s config variable is not configured in the config.php file." : "Gereken %s yapılandırma değişkeni config.php dosyasında ayarlanmamış.", "Please ask your server administrator to check the Nextcloud configuration." : "Lütfen Nextcloud yapılandırmasını denetlemesi için BT yöneticinizle görüşün.", - "Your data directory is readable by other users." : "Veri klasörünüz diğer kullanıcılar tarafından okunabilir.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Lütfen izinleri 0770 olarak ayarlayarak diğer kullanıcıların klasörü görebilmesini sağlayın.", + "Your data directory is readable by other people." : "Veri klasörünüz diğer kişiler tarafından okunabilir.", + "Please change the permissions to 0770 so that the directory cannot be listed by other people." : "Lütfen izinleri 0770 olarak ayarlayarak diğer kişilerin klasörü görebilmesini sağlayın.", "Your data directory must be an absolute path." : "Veri klasörünüz mutlak bir yol olmalıdır.", "Check the value of \"datadirectory\" in your configuration." : "Yapılandırmanızdaki \"datadirectory\" değerini denetleyin.", "Your data directory is invalid." : "Veri klasörünüz geçersiz.", "Ensure there is a file called \".ocdata\" in the root of the data directory." : "Veri klasörü kökünde \".ocdata\" adında bir dosya bulunduğundan emin olun.", "Action \"%s\" not supported or implemented." : "\"%s\" işlemi desteklenmiyor ya da henüz kullanılamıyor.", - "Authentication failed, wrong token or provider ID given" : "Kimlik doğrulanamadı. Belirtilen kod ya da hizmet sağlayıcı kodu hatalı", + "Authentication failed, wrong token or provider ID given" : "Kimlik doğrulanamadı. Belirtilen kod ya da hizmet sağlayıcı kimliği hatalı", "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "İsteğin tamamlanması için gerekli parametreler eksik: \"%s\"", - "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "\"%1$s\" kodu zaten \"%2$s\" birleşik hizmet sağlayıcısı tarafından kullanılıyor", - "Cloud Federation Provider with ID: \"%s\" does not exist." : "\"%s\" kodlu birleşik bulut hizmeti sağlayıcısı bulunamadı.", + "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "\"%1$s\" kimliği zaten \"%2$s\" birleşik hizmet sağlayıcısı tarafından kullanılıyor", + "Cloud Federation Provider with ID: \"%s\" does not exist." : "\"%s\" kimlikli birleşik bulut hizmeti sağlayıcısı bulunamadı.", "Could not obtain lock type %d on \"%s\"." : "\"%s\" için %d kilit türü alınamadı.", "Storage unauthorized. %s" : "Depolamaya erişim izni yok. %s", "Storage incomplete configuration. %s" : "Depolama yapılandırması tamamlanmamış. %s", @@ -268,12 +268,32 @@ "Extract topics" : "Başlıklar ayıklansın", "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.", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "%1$s uygulamasının dosyaları doğru şekilde değiştirilmedi. Sunucu ile uyumlu dosyaların yüklü olduğundan emin olun.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Oturum açmış kullanıcı bir yönetici, bir alt yönetici veya bu ayara erişmek için özel izne sahip olmalıdır", + "Logged in user must be an admin or sub admin" : "Oturum açmış kullanıcı bir yönetici ya da alt yönetici olmalıdır", + "Logged in user must be an admin" : "Oturum açmış kullanıcı bir yönetici olmalıdır", "Full name" : "Tam ad", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Kullanıcı sayısı sınırına ulaşıldığından kullanıcı eklenemedi. Ayrıntılı bilgi almak için bildirimlerinize bakın.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Kullanıcı adında yalnızca şu karakterler kullanılabilir: \"a-z\", \"A-Z\", \"0-9\", ve \"_.@-'\"", + "Unknown user" : "Kullanıcı bilinmiyor", + "Enter the database username and name for %s" : "%s için veri tabanı adını ve kullanıcı adını yazın", + "Enter the database username for %s" : "%s için veri tabanı kullanıcı adını yazın", + "MySQL username and/or password not valid" : "MySQL kullanıcı adı ya da parolası geçersiz", + "Oracle username and/or password not valid" : "Oracle kullanıcı adı ya da parolası geçersiz", + "PostgreSQL username and/or password not valid" : "PostgreSQL kullanıcı adı ya da parolası geçersiz", + "Set an admin username." : "Bir yönetici kullanıcı adı yazın.", + "Sharing %s failed, because this item is already shared with user %s" : "%s paylaşılamadı. Bu öge zaten %s kullanıcısı ile paylaşılmış", + "The username is already being used" : "Bu kullanıcı adı zaten var", + "Could not create user" : "Kullanıcı oluşturulamadı", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Kullanıcı adında yalnızca şu karakterler kullanılabilir: \"a-z\", \"A-Z\", \"0-9\", boşluk ve \"_.@-'\"", + "A valid username must be provided" : "Geçerli bir kullanıcı adı yazmalısınız", + "Username contains whitespace at the beginning or at the end" : "Kullanıcı adının başı ya da sonunda boşluk var", + "Username must not consist of dots only" : "Kullanıcı adı yalnızca noktalardan oluşamaz", + "Username is invalid because files already exist for this user" : "Kullanıcı adı geçersiz, bu kullanıcı için zaten bazı dosyalar var", + "User disabled" : "Kullanıcı devre dışı", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 sürümü en az 2.7.0 olmalıdır. Şu anda %s kurulu.", "To fix this issue update your libxml2 version and restart your web server." : "Bu sorunu çözmek için libxml2 sürümünüzü güncelleyin ve site sunucusunu yeniden başlatın.", "PostgreSQL >= 9 required." : "PostgreSQL >= 9 gerekli.", - "Please upgrade your database version." : "Lütfen veri tabanı sürümünüzü yükseltin." + "Please upgrade your database version." : "Lütfen veri tabanı sürümünüzü yükseltin.", + "Your data directory is readable by other users." : "Veri klasörünüz diğer kullanıcılar tarafından okunabilir.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Lütfen izinleri 0770 olarak ayarlayarak diğer kullanıcıların klasörü görebilmesini sağlayın." },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/lib/l10n/ug.js b/lib/l10n/ug.js index d70aa2c3ab7..30fa39527f9 100644 --- a/lib/l10n/ug.js +++ b/lib/l10n/ug.js @@ -52,7 +52,7 @@ OC.L10N.register( "Nov." : "ئوغلاق", "Dec." : "كۆنەك", "A valid password must be provided" : "چوقۇم ئىناۋەتلىك ئىم تەمىنلەش كېرەك", - "A valid username must be provided" : "چوقۇم ئىناۋەتلىك ئىشلەتكۈچى ئىسمىدىن بىرنى تەمىنلەش كېرەك", - "Authentication error" : "سالاھىيەت دەلىللەش خاتالىقى" + "Authentication error" : "سالاھىيەت دەلىللەش خاتالىقى", + "A valid username must be provided" : "چوقۇم ئىناۋەتلىك ئىشلەتكۈچى ئىسمىدىن بىرنى تەمىنلەش كېرەك" }, "nplurals=2; plural=(n != 1);"); diff --git a/lib/l10n/ug.json b/lib/l10n/ug.json index d7cbd89776e..bab73fadc75 100644 --- a/lib/l10n/ug.json +++ b/lib/l10n/ug.json @@ -50,7 +50,7 @@ "Nov." : "ئوغلاق", "Dec." : "كۆنەك", "A valid password must be provided" : "چوقۇم ئىناۋەتلىك ئىم تەمىنلەش كېرەك", - "A valid username must be provided" : "چوقۇم ئىناۋەتلىك ئىشلەتكۈچى ئىسمىدىن بىرنى تەمىنلەش كېرەك", - "Authentication error" : "سالاھىيەت دەلىللەش خاتالىقى" + "Authentication error" : "سالاھىيەت دەلىللەش خاتالىقى", + "A valid username must be provided" : "چوقۇم ئىناۋەتلىك ئىشلەتكۈچى ئىسمىدىن بىرنى تەمىنلەش كېرەك" },"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 66cdea90e01..d72a4a09a8d 100644 --- a/lib/l10n/uk.js +++ b/lib/l10n/uk.js @@ -8,7 +8,6 @@ OC.L10N.register( "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", - "404" : "404", "The page could not be found on the server." : "Сторінку не знайдено на сервері.", "%s email verification" : "%s підтвердження електронної пошти", "Email verification" : "Підтвердження електронної пошти", @@ -37,9 +36,9 @@ 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 або нижча.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Користувач, який увійшов у систему, має бути адміністратором, підадміністратором або мати спеціальні права доступу до цього налаштування", - "Logged in user must be an admin or sub admin" : "Увійшовши в систему користувач повинен бути адміністратором або підадміністратором", - "Logged in user must be an admin" : "Зареєстрований користувач має бути адміністратором", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Обліковий запис для входу має бути адміністратором, заступником адміністратора або мати спеціальні права доступу до цих налаштувань.", + "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\" розпочато віддалене стирання даних", @@ -79,7 +78,7 @@ 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." : "Модуль з ID: %s не існує. Будь ласка, увімкніть це в налаштуваннях програми або зверніться до адміністратора.", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Модуль з ID: %s не існує. Будь ласка, увімкніть це в налаштуваннях застосунку або зверніться до адміністратора.", "File already exists" : "Файл вже існує", "Invalid path" : "Недійсний шлях", "Failed to create file from template" : "Не вдалося створити файл із шаблону", @@ -90,9 +89,9 @@ OC.L10N.register( "Dot files are not allowed" : "Файли які починаються з крапки не допустимі", "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\" неможливо встановити, оскільки вона не сумісна з цією версією сервера.", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Застосунок \"%s\" неможливо встановити, оскільки він не сумісний з цією версією сервера.", "__language_name__" : "Українська", - "This is an automatically sent email, please do not reply." : "Це автоматично надісланий електронний лист, будь ласка, не відповідайте.", + "This is an automatically sent email, please do not reply." : "Це автоматично надісланий електронний лист, будь ласка, не відповідайте на нього.", "Help" : "Допомога", "Appearance and accessibility" : "Тема та вигляд", "Apps" : "Застосунки", @@ -103,7 +102,7 @@ OC.L10N.register( "Users" : "Користувачі", "Email" : "Електронна пошта", "Mail %s" : "Пошта %s", - "Fediverse" : "Федіверс", + "Fediverse" : "Fediverse", "View %s on the fediverse" : "Переглянути %s у Fediverse", "Phone" : "Телефон", "Call %s" : "Телефонуйте %s", @@ -118,22 +117,22 @@ OC.L10N.register( "Headline" : "Заголовок", "Organisation" : "Організація", "Role" : "Роль", - "Unknown user" : "Невідомий користувач", + "Unknown account" : "Невідомий обліковий запис", "Additional settings" : "Додатково", - "Enter the database username and name for %s" : "Введіть ім’я користувача та назву бази даних %s", - "Enter the database username for %s" : "Введіть ім’я користувача бази даних для %s", + "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 username and/or password not valid" : "Ім'я користувача та/або пароль MySQL недійсні", + "MySQL Login and/or password not valid" : "Ім'я користувача та/або пароль MySQL недійсні", "You need to enter details of an existing account." : "Потрібно ввести дані наявного облікового запису.", "Oracle connection could not be established" : "Не можемо з'єднатися з Oracle ", - "Oracle username and/or password not valid" : "Oracle ім'я користувача та/або пароль не дійсні", - "PostgreSQL username and/or password not valid" : "PostgreSQL ім'я користувача та/або пароль не дійсні", + "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 середовищі і 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 або перейдіть на 64-бітний PHP.", - "Set an admin username." : "Встановіть ім'я адміністратора.", + "Set an admin Login." : "Встановіть ім'я облікового запису адміністратора.", "Set an admin password." : "Встановіть пароль адміністратора.", "Cannot create or write into the data directory %s" : "Неможливо створити або записати в каталог даних %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Бекенд спільного доступу %s повинен реалізовувати інтерфейс OCP\\Share_Backend", @@ -151,11 +150,12 @@ OC.L10N.register( "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_" : ["Неможливо встановити дату закінчення більше ніж %n день у майбутньому","Неможливо встановити дату закінчення більше ніж %n днів у майбутньому","Неможливо встановити дату закінчення більше ніж %n днів у майбутньому","Неможливо встановити дату закінчення більше ніж %n днів у майбутньому"], "Sharing is only allowed with group members" : "Спільний доступ дозволений лише для учасників групи", - "Sharing %s failed, because this item is already shared with user %s" : "Не вдалося поділитися %s, оскільки %s вже має до нього доступ", + "Sharing %s failed, because this item is already shared with the account %s" : "Не вдалося надати у спільний доступ%s, оскільки цей ресурс вже у спільному доступі з обліковим записом %s", "%1$s shared »%2$s« with you" : "%1$s надав(-ла) доступ до \"%2$s\"", "%1$s shared »%2$s« with you." : "%1$s надав(-ла) доступ до \"%2$s\".", "Click the button below to open it." : "Щоб відкрити файл, натисніть кнопку нижче.", "The requested share does not exist anymore" : "Запитуваний спільний ресурс більше недоступний", + "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\"", "Sunday" : "Неділя", @@ -204,16 +204,16 @@ OC.L10N.register( "Nov." : "Лис.", "Dec." : "Гру.", "A valid password must be provided" : "Потрібно задати вірний пароль", - "The username is already being used" : "Ім'я користувача вже використовується", - "Could not create user" : "Не вдалося створити користувача", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Лише такі символи дозволено у імені користувача: \"a-z\", \"A-Z\", \"0-9\", пробіл та \"_.@-'\"", - "A valid username must be provided" : "Потрібно задати вірне ім'я користувача", - "Username contains whitespace at the beginning or at the end" : "Ім'я користувача містить символ пробілу в початку або в кінці", - "Username must not consist of dots only" : "Ім'я користувача не повинно складатися лише з крапок", - "Username is invalid because files already exist for this user" : "Ім'я користувача недійсне, оскільки файли для цього користувача вже існують", - "User disabled" : "Користувач виключений", + "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" : "Ім'я користувача не може складатися лише з крапок", + "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", + "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" : "безпечний дім для ваших даних", "File is currently busy, please try again later" : "Файл на разі зайнятий, будь ласка, спробуйте пізніше", "Cannot download file" : "Неможливо завантажити файл", @@ -224,8 +224,8 @@ OC.L10N.register( "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." : "Не вдається записати в каталог \"програми\".", - "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." : "Зазвичай це можна виправити, надавши веб-серверу доступ для запису до каталогу програм або вимкнувши App Store у конфігураційному файлі.", + "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." : "Зазвичай це можна виправити, якщо надати вебсерверу доступ для запису до каталогу застосунків або вимкнути App Store у конфігураційному файлі.", "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. ", @@ -244,8 +244,8 @@ OC.L10N.register( "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 users." : "Ваш каталог даних доступний для читання іншим користувачам.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Змініть права доступу на 0770, щоб інші користувачі не могли отримати список файлів цього каталогу.", + "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." : "Перевірте значення «каталогу даних» у вашій конфігурації.", "Your data directory is invalid." : "Ваш каталог даних недійсний.", @@ -269,13 +269,33 @@ OC.L10N.register( "Summarizes text by reducing its length without losing key information." : "Викокремлює головне у тексті шляхом зменшення довжини тексту без втрати ключової інформації.", "Extract topics" : "Виділити теми", "Extracts topics from a text and outputs them separated by commas." : "Виділяє теми, які висвітлює текст, зводить їх у перелік, що розділено комами.", - "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Файли програми %1$s замінено неправильно. Переконайтеся, що це версія, сумісна з сервером.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Файли застосунку %1$s не було коректно оновлено. Переконайтеся, що ця версія, сумісна із сервером.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Користувач, який увійшов у систему, має бути адміністратором, підадміністратором або мати спеціальні права доступу до цього налаштування", + "Logged in user must be an admin or sub admin" : "Увійшовши в систему користувач повинен бути адміністратором або підадміністратором", + "Logged in user must be an admin" : "Зареєстрований користувач має бути адміністратором", "Full name" : "Повна назва", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Досягнуто обмеження на кількість користувачів, користувача не було створено. Перевірте сповіщення для докладної інформації.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Тільки такі символи допускаються в імені користувача: \"a-z\", \"A-Z\", \"0-9\", і \"_.@-'\"", + "Unknown user" : "Невідомий користувач", + "Enter the database username and name for %s" : "Введіть ім’я користувача та назву бази даних %s", + "Enter the database username for %s" : "Введіть ім’я користувача бази даних для %s", + "MySQL username and/or password not valid" : "Ім'я користувача та/або пароль MySQL недійсні", + "Oracle username and/or password not valid" : "Oracle ім'я користувача та/або пароль не дійсні", + "PostgreSQL username and/or password not valid" : "PostgreSQL ім'я користувача та/або пароль не дійсні", + "Set an admin username." : "Встановіть ім'я адміністратора.", + "Sharing %s failed, because this item is already shared with user %s" : "Не вдалося поділитися %s, оскільки %s вже має до нього доступ", + "The username is already being used" : "Ім'я користувача вже використовується", + "Could not create user" : "Не вдалося створити користувача", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Лише такі символи дозволено у імені користувача: \"a-z\", \"A-Z\", \"0-9\", пробіл та \"_.@-'\"", + "A valid username must be provided" : "Потрібно задати вірне ім'я користувача", + "Username contains whitespace at the beginning or at the end" : "Ім'я користувача містить символ пробілу в початку або в кінці", + "Username must not consist of dots only" : "Ім'я користувача не повинно складатися лише з крапок", + "Username is invalid because files already exist for this user" : "Ім'я користувача недійсне, оскільки файли для цього користувача вже існують", + "User disabled" : "Користувач виключений", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Необхідно libxml2 версії принаймні 2.7.0. На разі встановлена %s.", "To fix this issue update your libxml2 version and restart your web server." : "Що виправити це оновіть версію libxml2 та перезапустіть веб-сервер.", "PostgreSQL >= 9 required." : "Необхідно PostgreSQL >= 9.", - "Please upgrade your database version." : "Оновіть версію бази даних." + "Please upgrade your database version." : "Оновіть версію бази даних.", + "Your data directory is readable by other users." : "Ваш каталог даних доступний для читання іншим користувачам.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Змініть права доступу на 0770, щоб інші користувачі не могли отримати список файлів цього каталогу." }, "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 9c102a738e0..c290f60e5ec 100644 --- a/lib/l10n/uk.json +++ b/lib/l10n/uk.json @@ -6,7 +6,6 @@ "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", - "404" : "404", "The page could not be found on the server." : "Сторінку не знайдено на сервері.", "%s email verification" : "%s підтвердження електронної пошти", "Email verification" : "Підтвердження електронної пошти", @@ -35,9 +34,9 @@ "The following platforms are supported: %s" : "Підтримуються такі платформи: %s", "Server version %s or higher is required." : "Потрібна версія сервера %s або вище.", "Server version %s or lower is required." : "Потрібна версія сервера %s або нижча.", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Користувач, який увійшов у систему, має бути адміністратором, підадміністратором або мати спеціальні права доступу до цього налаштування", - "Logged in user must be an admin or sub admin" : "Увійшовши в систему користувач повинен бути адміністратором або підадміністратором", - "Logged in user must be an admin" : "Зареєстрований користувач має бути адміністратором", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Обліковий запис для входу має бути адміністратором, заступником адміністратора або мати спеціальні права доступу до цих налаштувань.", + "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\" розпочато віддалене стирання даних", @@ -77,7 +76,7 @@ "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." : "Модуль з ID: %s не існує. Будь ласка, увімкніть це в налаштуваннях програми або зверніться до адміністратора.", + "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Модуль з ID: %s не існує. Будь ласка, увімкніть це в налаштуваннях застосунку або зверніться до адміністратора.", "File already exists" : "Файл вже існує", "Invalid path" : "Недійсний шлях", "Failed to create file from template" : "Не вдалося створити файл із шаблону", @@ -88,9 +87,9 @@ "Dot files are not allowed" : "Файли які починаються з крапки не допустимі", "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\" неможливо встановити, оскільки вона не сумісна з цією версією сервера.", + "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Застосунок \"%s\" неможливо встановити, оскільки він не сумісний з цією версією сервера.", "__language_name__" : "Українська", - "This is an automatically sent email, please do not reply." : "Це автоматично надісланий електронний лист, будь ласка, не відповідайте.", + "This is an automatically sent email, please do not reply." : "Це автоматично надісланий електронний лист, будь ласка, не відповідайте на нього.", "Help" : "Допомога", "Appearance and accessibility" : "Тема та вигляд", "Apps" : "Застосунки", @@ -101,7 +100,7 @@ "Users" : "Користувачі", "Email" : "Електронна пошта", "Mail %s" : "Пошта %s", - "Fediverse" : "Федіверс", + "Fediverse" : "Fediverse", "View %s on the fediverse" : "Переглянути %s у Fediverse", "Phone" : "Телефон", "Call %s" : "Телефонуйте %s", @@ -116,22 +115,22 @@ "Headline" : "Заголовок", "Organisation" : "Організація", "Role" : "Роль", - "Unknown user" : "Невідомий користувач", + "Unknown account" : "Невідомий обліковий запис", "Additional settings" : "Додатково", - "Enter the database username and name for %s" : "Введіть ім’я користувача та назву бази даних %s", - "Enter the database username for %s" : "Введіть ім’я користувача бази даних для %s", + "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 username and/or password not valid" : "Ім'я користувача та/або пароль MySQL недійсні", + "MySQL Login and/or password not valid" : "Ім'я користувача та/або пароль MySQL недійсні", "You need to enter details of an existing account." : "Потрібно ввести дані наявного облікового запису.", "Oracle connection could not be established" : "Не можемо з'єднатися з Oracle ", - "Oracle username and/or password not valid" : "Oracle ім'я користувача та/або пароль не дійсні", - "PostgreSQL username and/or password not valid" : "PostgreSQL ім'я користувача та/або пароль не дійсні", + "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 середовищі і 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 або перейдіть на 64-бітний PHP.", - "Set an admin username." : "Встановіть ім'я адміністратора.", + "Set an admin Login." : "Встановіть ім'я облікового запису адміністратора.", "Set an admin password." : "Встановіть пароль адміністратора.", "Cannot create or write into the data directory %s" : "Неможливо створити або записати в каталог даних %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "Бекенд спільного доступу %s повинен реалізовувати інтерфейс OCP\\Share_Backend", @@ -149,11 +148,12 @@ "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_" : ["Неможливо встановити дату закінчення більше ніж %n день у майбутньому","Неможливо встановити дату закінчення більше ніж %n днів у майбутньому","Неможливо встановити дату закінчення більше ніж %n днів у майбутньому","Неможливо встановити дату закінчення більше ніж %n днів у майбутньому"], "Sharing is only allowed with group members" : "Спільний доступ дозволений лише для учасників групи", - "Sharing %s failed, because this item is already shared with user %s" : "Не вдалося поділитися %s, оскільки %s вже має до нього доступ", + "Sharing %s failed, because this item is already shared with the account %s" : "Не вдалося надати у спільний доступ%s, оскільки цей ресурс вже у спільному доступі з обліковим записом %s", "%1$s shared »%2$s« with you" : "%1$s надав(-ла) доступ до \"%2$s\"", "%1$s shared »%2$s« with you." : "%1$s надав(-ла) доступ до \"%2$s\".", "Click the button below to open it." : "Щоб відкрити файл, натисніть кнопку нижче.", "The requested share does not exist anymore" : "Запитуваний спільний ресурс більше недоступний", + "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\"", "Sunday" : "Неділя", @@ -202,16 +202,16 @@ "Nov." : "Лис.", "Dec." : "Гру.", "A valid password must be provided" : "Потрібно задати вірний пароль", - "The username is already being used" : "Ім'я користувача вже використовується", - "Could not create user" : "Не вдалося створити користувача", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Лише такі символи дозволено у імені користувача: \"a-z\", \"A-Z\", \"0-9\", пробіл та \"_.@-'\"", - "A valid username must be provided" : "Потрібно задати вірне ім'я користувача", - "Username contains whitespace at the beginning or at the end" : "Ім'я користувача містить символ пробілу в початку або в кінці", - "Username must not consist of dots only" : "Ім'я користувача не повинно складатися лише з крапок", - "Username is invalid because files already exist for this user" : "Ім'я користувача недійсне, оскільки файли для цього користувача вже існують", - "User disabled" : "Користувач виключений", + "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" : "Ім'я користувача не може складатися лише з крапок", + "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", + "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" : "безпечний дім для ваших даних", "File is currently busy, please try again later" : "Файл на разі зайнятий, будь ласка, спробуйте пізніше", "Cannot download file" : "Неможливо завантажити файл", @@ -222,8 +222,8 @@ "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." : "Не вдається записати в каталог \"програми\".", - "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." : "Зазвичай це можна виправити, надавши веб-серверу доступ для запису до каталогу програм або вимкнувши App Store у конфігураційному файлі.", + "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." : "Зазвичай це можна виправити, якщо надати вебсерверу доступ для запису до каталогу застосунків або вимкнути App Store у конфігураційному файлі.", "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. ", @@ -242,8 +242,8 @@ "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 users." : "Ваш каталог даних доступний для читання іншим користувачам.", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Змініть права доступу на 0770, щоб інші користувачі не могли отримати список файлів цього каталогу.", + "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." : "Перевірте значення «каталогу даних» у вашій конфігурації.", "Your data directory is invalid." : "Ваш каталог даних недійсний.", @@ -267,13 +267,33 @@ "Summarizes text by reducing its length without losing key information." : "Викокремлює головне у тексті шляхом зменшення довжини тексту без втрати ключової інформації.", "Extract topics" : "Виділити теми", "Extracts topics from a text and outputs them separated by commas." : "Виділяє теми, які висвітлює текст, зводить їх у перелік, що розділено комами.", - "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Файли програми %1$s замінено неправильно. Переконайтеся, що це версія, сумісна з сервером.", + "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Файли застосунку %1$s не було коректно оновлено. Переконайтеся, що ця версія, сумісна із сервером.", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "Користувач, який увійшов у систему, має бути адміністратором, підадміністратором або мати спеціальні права доступу до цього налаштування", + "Logged in user must be an admin or sub admin" : "Увійшовши в систему користувач повинен бути адміністратором або підадміністратором", + "Logged in user must be an admin" : "Зареєстрований користувач має бути адміністратором", "Full name" : "Повна назва", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "Досягнуто обмеження на кількість користувачів, користувача не було створено. Перевірте сповіщення для докладної інформації.", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Тільки такі символи допускаються в імені користувача: \"a-z\", \"A-Z\", \"0-9\", і \"_.@-'\"", + "Unknown user" : "Невідомий користувач", + "Enter the database username and name for %s" : "Введіть ім’я користувача та назву бази даних %s", + "Enter the database username for %s" : "Введіть ім’я користувача бази даних для %s", + "MySQL username and/or password not valid" : "Ім'я користувача та/або пароль MySQL недійсні", + "Oracle username and/or password not valid" : "Oracle ім'я користувача та/або пароль не дійсні", + "PostgreSQL username and/or password not valid" : "PostgreSQL ім'я користувача та/або пароль не дійсні", + "Set an admin username." : "Встановіть ім'я адміністратора.", + "Sharing %s failed, because this item is already shared with user %s" : "Не вдалося поділитися %s, оскільки %s вже має до нього доступ", + "The username is already being used" : "Ім'я користувача вже використовується", + "Could not create user" : "Не вдалося створити користувача", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "Лише такі символи дозволено у імені користувача: \"a-z\", \"A-Z\", \"0-9\", пробіл та \"_.@-'\"", + "A valid username must be provided" : "Потрібно задати вірне ім'я користувача", + "Username contains whitespace at the beginning or at the end" : "Ім'я користувача містить символ пробілу в початку або в кінці", + "Username must not consist of dots only" : "Ім'я користувача не повинно складатися лише з крапок", + "Username is invalid because files already exist for this user" : "Ім'я користувача недійсне, оскільки файли для цього користувача вже існують", + "User disabled" : "Користувач виключений", "libxml2 2.7.0 is at least required. Currently %s is installed." : "Необхідно libxml2 версії принаймні 2.7.0. На разі встановлена %s.", "To fix this issue update your libxml2 version and restart your web server." : "Що виправити це оновіть версію libxml2 та перезапустіть веб-сервер.", "PostgreSQL >= 9 required." : "Необхідно PostgreSQL >= 9.", - "Please upgrade your database version." : "Оновіть версію бази даних." + "Please upgrade your database version." : "Оновіть версію бази даних.", + "Your data directory is readable by other users." : "Ваш каталог даних доступний для читання іншим користувачам.", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Змініть права доступу на 0770, щоб інші користувачі не могли отримати список файлів цього каталогу." },"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/uz.js b/lib/l10n/uz.js index 66304ff84dc..769e6a42331 100644 --- a/lib/l10n/uz.js +++ b/lib/l10n/uz.js @@ -16,11 +16,11 @@ OC.L10N.register( "Address" : "Address", "Profile picture" : "Profil rasmi", "About" : "About", - "Unknown user" : "Unknown user", "Set an admin password." : "Set an admin password.", "January" : "January", "Authentication error" : "Authentication error", "Storage is temporarily not available" : "Storage is temporarily not available", - "Full name" : "Full name" + "Full name" : "Full name", + "Unknown user" : "Unknown user" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/uz.json b/lib/l10n/uz.json index 083f124fd7b..8f52cd3ef3a 100644 --- a/lib/l10n/uz.json +++ b/lib/l10n/uz.json @@ -14,11 +14,11 @@ "Address" : "Address", "Profile picture" : "Profil rasmi", "About" : "About", - "Unknown user" : "Unknown user", "Set an admin password." : "Set an admin password.", "January" : "January", "Authentication error" : "Authentication error", "Storage is temporarily not available" : "Storage is temporarily not available", - "Full name" : "Full name" + "Full name" : "Full name", + "Unknown user" : "Unknown user" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/vi.js b/lib/l10n/vi.js index 7ea1f68dca5..e16e92f8427 100644 --- a/lib/l10n/vi.js +++ b/lib/l10n/vi.js @@ -23,6 +23,7 @@ OC.L10N.register( "Unknown filetype" : "Không biết kiểu tập tin", "Invalid image" : "Hình ảnh không hợp lệ", "Files" : "Tệp", + "View profile" : "Xem hồ sơ", "today" : "hôm nay", "yesterday" : "hôm qua", "last month" : "tháng trước", @@ -36,6 +37,7 @@ OC.L10N.register( "Templates" : "Mẫu", "__language_name__" : "Tiếng Việt", "Help" : "Giúp đỡ", + "Appearance and accessibility" : "Ngoại hình và khả năng tiếp cận", "Apps" : "Ứng dụng", "Settings" : "Thiết lập", "Log out" : "Đăng xuất", @@ -47,7 +49,9 @@ OC.L10N.register( "Address" : "Địa chỉ", "Profile picture" : "Ảnh đại diện", "About" : "Giới thiệu", - "Unknown user" : "Người dùng không tồn tại", + "Headline" : "Tiêu đề", + "Organisation" : "Tổ chức", + "Role" : "Vai trò", "Additional settings" : "Cài đặt bổ sung", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Hãy xóa thiết lập open_basedir tại tập tin cấu hình php.ini hoặc chuyển sang dùng PHP 64-bit.", "Set an admin password." : "Thiết lập mật khẩu quản trị", @@ -93,14 +97,15 @@ OC.L10N.register( "Oct." : "Tháng 10", "Nov." : "Tháng 11", "Dec." : "Tháng 12", - "The username is already being used" : "Tên đăng nhập đã được sử dụng", - "User disabled" : "Vô hiệu hóa sử dụng", "a safe home for all your data" : "Một ngôi nhà an toàn cho toàn bộ dữ liệu của bạn", "Application is not enabled" : "Ứng dụng không được BẬT", "Authentication error" : "Lỗi xác thực", "Token expired. Please reload page." : "Mã Token đã hết hạn. Hãy tải lại trang.", "PHP module %s not installed." : "PHP mô đun %s chưa được cài đặt", "Storage is temporarily not available" : "Kho lưu trữ tạm thời không khả dụng", - "Full name" : "Tên đầy đủ" + "Full name" : "Tên đầy đủ", + "Unknown user" : "Người dùng không tồn tại", + "The username is already being used" : "Tên đăng nhập đã được sử dụng", + "User disabled" : "Vô hiệu hóa sử dụng" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/vi.json b/lib/l10n/vi.json index 31603bf9c63..12c9ebfc8a3 100644 --- a/lib/l10n/vi.json +++ b/lib/l10n/vi.json @@ -21,6 +21,7 @@ "Unknown filetype" : "Không biết kiểu tập tin", "Invalid image" : "Hình ảnh không hợp lệ", "Files" : "Tệp", + "View profile" : "Xem hồ sơ", "today" : "hôm nay", "yesterday" : "hôm qua", "last month" : "tháng trước", @@ -34,6 +35,7 @@ "Templates" : "Mẫu", "__language_name__" : "Tiếng Việt", "Help" : "Giúp đỡ", + "Appearance and accessibility" : "Ngoại hình và khả năng tiếp cận", "Apps" : "Ứng dụng", "Settings" : "Thiết lập", "Log out" : "Đăng xuất", @@ -45,7 +47,9 @@ "Address" : "Địa chỉ", "Profile picture" : "Ảnh đại diện", "About" : "Giới thiệu", - "Unknown user" : "Người dùng không tồn tại", + "Headline" : "Tiêu đề", + "Organisation" : "Tổ chức", + "Role" : "Vai trò", "Additional settings" : "Cài đặt bổ sung", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Hãy xóa thiết lập open_basedir tại tập tin cấu hình php.ini hoặc chuyển sang dùng PHP 64-bit.", "Set an admin password." : "Thiết lập mật khẩu quản trị", @@ -91,14 +95,15 @@ "Oct." : "Tháng 10", "Nov." : "Tháng 11", "Dec." : "Tháng 12", - "The username is already being used" : "Tên đăng nhập đã được sử dụng", - "User disabled" : "Vô hiệu hóa sử dụng", "a safe home for all your data" : "Một ngôi nhà an toàn cho toàn bộ dữ liệu của bạn", "Application is not enabled" : "Ứng dụng không được BẬT", "Authentication error" : "Lỗi xác thực", "Token expired. Please reload page." : "Mã Token đã hết hạn. Hãy tải lại trang.", "PHP module %s not installed." : "PHP mô đun %s chưa được cài đặt", "Storage is temporarily not available" : "Kho lưu trữ tạm thời không khả dụng", - "Full name" : "Tên đầy đủ" + "Full name" : "Tên đầy đủ", + "Unknown user" : "Người dùng không tồn tại", + "The username is already being used" : "Tên đăng nhập đã được sử dụng", + "User disabled" : "Vô hiệu hóa sử dụng" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/l10n/zh_CN.js b/lib/l10n/zh_CN.js index 834a20822c3..caed607c4e0 100644 --- a/lib/l10n/zh_CN.js +++ b/lib/l10n/zh_CN.js @@ -5,9 +5,9 @@ OC.L10N.register( "This can usually be fixed by giving the web server write access to the config directory." : "通常可以为 Web 服务器授予对 config 目录的写入权限来修复这个问题。", "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." : "应用程序%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 的样例文件直接复制使用。这可能会破坏您的安装。在对 config.php 进行修改之前请先阅读相关文档。", - "404" : "404", "The page could not be found on the server." : "无法在服务器上找到此页面", "%s email verification" : "%s 电子邮件验证", "Email verification" : "电子邮件验证", @@ -36,9 +36,6 @@ 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 或更低版本。", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登录用户必须是管理员、子管理员或具有访问此设置的特殊权限", - "Logged in user must be an admin or sub admin" : "当前登录用户必须为管理员或子管理员", - "Logged in user must be an admin" : "当前登录用户必须为管理员", "Wiping of device %s has started" : "设备%s的擦除操作已开始", "Wiping of device »%s« has started" : "设备 »%s« 的擦除操作已开始", "»%s« started remote wipe" : "»%s« 已开始远程擦除", @@ -117,22 +114,15 @@ OC.L10N.register( "Headline" : "标题", "Organisation" : "组织", "Role" : "角色", - "Unknown user" : "未知用户", "Additional settings" : "其他设置", - "Enter the database username and name for %s" : "输入 %s 的数据库用户名和名称", - "Enter the database username for %s" : "输入 %s 的数据库用户名", "Enter the database name for %s" : "输入 %s 的数据库名称", "You cannot use dots in the database name %s" : "您不能在数据库名称 %s 中使用句点", - "MySQL username and/or password not valid" : "MySQL 数据库用户名和/或密码无效", "You need to enter details of an existing account." : "您需要输入现有账号的详细信息。", "Oracle connection could not be established" : "无法建立 Oracle 连接", - "Oracle username and/or password not valid" : "Oracle 数据库用户名和/或密码无效", - "PostgreSQL username 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。这将在文件超过4GB时出现问题,强烈不建议这样做。", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "请删除 php.ini 中的 open_basedir 设置或切换到64位PHP。", - "Set an admin username." : "请设置一个管理员用户名。", "Set an admin password." : "请设置一个管理员密码。", "Cannot create or write into the data directory %s" : "无法创建或写入数据文件夹 %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "共享后端 %s 必须实现 OCP\\Share_Backend 接口", @@ -150,11 +140,12 @@ OC.L10N.register( "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_" : ["允许设置的最远截止期是从今天算起的 %n-1 天之后"], "Sharing is only allowed with group members" : "只允许与群组成员共享", - "Sharing %s failed, because this item is already shared with user %s" : "共享 %s 失败了,因为该项目已和用户 %s 进行了分享。", "%1$s shared »%2$s« with you" : "%1$s 对您共享了 »%2$s«", "%1$s shared »%2$s« with you." : "%1$s 对您共享了 »%2$s«。", "Click the button below to open it." : "点击下方按钮可打开它。", "The requested share does not exist anymore" : "当前请求的共享已经不存在", + "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\"", "Sunday" : "星期日", "Monday" : "星期一", @@ -202,13 +193,6 @@ OC.L10N.register( "Nov." : "十一月", "Dec." : "十二月", "A valid password must be provided" : "必须提供合法的密码", - "The username is already being used" : "用户名已被使用", - "Could not create user" : "无法创建用户", - "A valid username must be provided" : "必须提供合法的用户名", - "Username contains whitespace at the beginning or at the end" : "用户名在开头或结尾处包含空格", - "Username must not consist of dots only" : "用户名不能仅由点组成", - "Username is invalid because files already exist for this user" : "用户名无效,因为该用户已经存在文件", - "User 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" : "给您所有数据一个安全的家", @@ -241,8 +225,6 @@ OC.L10N.register( "Please ask your server administrator to restart the web server." : "请联系您的服务器管理员重启 Web 服务器。", "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 users." : "您的数据目录可被其他用户读取。", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "请更改权限为 0770 以避免其他用户查看目录。", "Your data directory must be an absolute path." : "您的数据目录必须是绝对路径。", "Check the value of \"datadirectory\" in your configuration." : "请检查配置文件中 \"datadirectory\" 的值。", "Your data directory is invalid." : "您的数据目录无效。", @@ -258,13 +240,41 @@ OC.L10N.register( "Storage connection error. %s" : "存储连接错误。%s", "Storage is temporarily not available" : "存储暂时不可用", "Storage connection timeout. %s" : "存储连接超时。%s", + "Free prompt" : "自由提示", + "Runs an arbitrary prompt through the language model." : "向语言模型中输入任何提示词", + "Generate headline" : "产生标题", + "Generates a possible headline for a text." : "为一段文本生成一个可能的标题", + "Summarize" : "总结归纳", + "Summarizes text by reducing its length without losing key information." : "总结一段文本以减少长度而不丢失关键信息", + "Extract topics" : "提取主题", + "Extracts topics from a text and outputs them separated by commas." : "从文本中摘出主题,输出逗号分隔的结果", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "应用%1$s的文件替换不正确。请确认版本与当前服务器兼容。", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登录用户必须是管理员、子管理员或具有访问此设置的特殊权限", + "Logged in user must be an admin or sub admin" : "当前登录用户必须为管理员或子管理员", + "Logged in user must be an admin" : "当前登录用户必须为管理员", "Full name" : "全名", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "已达到用户上限,未创建该用户。请检查您的通知以了解更多。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "在用户名中只允许使用以下字符:“a-z”、“A-Z”、“0-9” 和 \"_.@-'\"", + "Unknown user" : "未知用户", + "Enter the database username and name for %s" : "输入 %s 的数据库用户名和名称", + "Enter the database username for %s" : "输入 %s 的数据库用户名", + "MySQL username and/or password not valid" : "MySQL 数据库用户名和/或密码无效", + "Oracle username and/or password not valid" : "Oracle 数据库用户名和/或密码无效", + "PostgreSQL username and/or password not valid" : "PostgreSQL 数据库用户名和/或密码无效", + "Set an admin username." : "请设置一个管理员用户名。", + "Sharing %s failed, because this item is already shared with user %s" : "共享 %s 失败了,因为该项目已和用户 %s 进行了分享。", + "The username is already being used" : "用户名已被使用", + "Could not create user" : "无法创建用户", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "在用户名中只允许使用以下字符:“a-z”、“A-Z”、“0-9”、空格和 \"_.@-'\"", + "A valid username must be provided" : "必须提供合法的用户名", + "Username contains whitespace at the beginning or at the end" : "用户名在开头或结尾处包含空格", + "Username must not consist of dots only" : "用户名不能仅由点组成", + "Username is invalid because files already exist for this user" : "用户名无效,因为该用户已经存在文件", + "User disabled" : "用户已禁用", "libxml2 2.7.0 is at least required. Currently %s is installed." : "至少需要 libxml2 2.7.0. 当前安装 %s。", "To fix this issue update your libxml2 version and restart your web server." : "升级您的libxml2版本然后重启Web服务器以解决该问题。", "PostgreSQL >= 9 required." : "需要 PostgreSQL >= 9。", - "Please upgrade your database version." : "请升级您的数据库版本。" + "Please upgrade your database version." : "请升级您的数据库版本。", + "Your data directory is readable by other users." : "您的数据目录可被其他用户读取。", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "请更改权限为 0770 以避免其他用户查看目录。" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/zh_CN.json b/lib/l10n/zh_CN.json index 87a73aec9b4..4c98560777e 100644 --- a/lib/l10n/zh_CN.json +++ b/lib/l10n/zh_CN.json @@ -3,9 +3,9 @@ "This can usually be fixed by giving the web server write access to the config directory." : "通常可以为 Web 服务器授予对 config 目录的写入权限来修复这个问题。", "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." : "应用程序%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 的样例文件直接复制使用。这可能会破坏您的安装。在对 config.php 进行修改之前请先阅读相关文档。", - "404" : "404", "The page could not be found on the server." : "无法在服务器上找到此页面", "%s email verification" : "%s 电子邮件验证", "Email verification" : "电子邮件验证", @@ -34,9 +34,6 @@ "The following platforms are supported: %s" : "支持以下平台:%s", "Server version %s or higher is required." : "需要服务器版本 %s 或更高版本。", "Server version %s or lower is required." : "需要服务器版本 %s 或更低版本。", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登录用户必须是管理员、子管理员或具有访问此设置的特殊权限", - "Logged in user must be an admin or sub admin" : "当前登录用户必须为管理员或子管理员", - "Logged in user must be an admin" : "当前登录用户必须为管理员", "Wiping of device %s has started" : "设备%s的擦除操作已开始", "Wiping of device »%s« has started" : "设备 »%s« 的擦除操作已开始", "»%s« started remote wipe" : "»%s« 已开始远程擦除", @@ -115,22 +112,15 @@ "Headline" : "标题", "Organisation" : "组织", "Role" : "角色", - "Unknown user" : "未知用户", "Additional settings" : "其他设置", - "Enter the database username and name for %s" : "输入 %s 的数据库用户名和名称", - "Enter the database username for %s" : "输入 %s 的数据库用户名", "Enter the database name for %s" : "输入 %s 的数据库名称", "You cannot use dots in the database name %s" : "您不能在数据库名称 %s 中使用句点", - "MySQL username and/or password not valid" : "MySQL 数据库用户名和/或密码无效", "You need to enter details of an existing account." : "您需要输入现有账号的详细信息。", "Oracle connection could not be established" : "无法建立 Oracle 连接", - "Oracle username and/or password not valid" : "Oracle 数据库用户名和/或密码无效", - "PostgreSQL username 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。这将在文件超过4GB时出现问题,强烈不建议这样做。", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "请删除 php.ini 中的 open_basedir 设置或切换到64位PHP。", - "Set an admin username." : "请设置一个管理员用户名。", "Set an admin password." : "请设置一个管理员密码。", "Cannot create or write into the data directory %s" : "无法创建或写入数据文件夹 %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "共享后端 %s 必须实现 OCP\\Share_Backend 接口", @@ -148,11 +138,12 @@ "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_" : ["允许设置的最远截止期是从今天算起的 %n-1 天之后"], "Sharing is only allowed with group members" : "只允许与群组成员共享", - "Sharing %s failed, because this item is already shared with user %s" : "共享 %s 失败了,因为该项目已和用户 %s 进行了分享。", "%1$s shared »%2$s« with you" : "%1$s 对您共享了 »%2$s«", "%1$s shared »%2$s« with you." : "%1$s 对您共享了 »%2$s«。", "Click the button below to open it." : "点击下方按钮可打开它。", "The requested share does not exist anymore" : "当前请求的共享已经不存在", + "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\"", "Sunday" : "星期日", "Monday" : "星期一", @@ -200,13 +191,6 @@ "Nov." : "十一月", "Dec." : "十二月", "A valid password must be provided" : "必须提供合法的密码", - "The username is already being used" : "用户名已被使用", - "Could not create user" : "无法创建用户", - "A valid username must be provided" : "必须提供合法的用户名", - "Username contains whitespace at the beginning or at the end" : "用户名在开头或结尾处包含空格", - "Username must not consist of dots only" : "用户名不能仅由点组成", - "Username is invalid because files already exist for this user" : "用户名无效,因为该用户已经存在文件", - "User 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" : "给您所有数据一个安全的家", @@ -239,8 +223,6 @@ "Please ask your server administrator to restart the web server." : "请联系您的服务器管理员重启 Web 服务器。", "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 users." : "您的数据目录可被其他用户读取。", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "请更改权限为 0770 以避免其他用户查看目录。", "Your data directory must be an absolute path." : "您的数据目录必须是绝对路径。", "Check the value of \"datadirectory\" in your configuration." : "请检查配置文件中 \"datadirectory\" 的值。", "Your data directory is invalid." : "您的数据目录无效。", @@ -256,13 +238,41 @@ "Storage connection error. %s" : "存储连接错误。%s", "Storage is temporarily not available" : "存储暂时不可用", "Storage connection timeout. %s" : "存储连接超时。%s", + "Free prompt" : "自由提示", + "Runs an arbitrary prompt through the language model." : "向语言模型中输入任何提示词", + "Generate headline" : "产生标题", + "Generates a possible headline for a text." : "为一段文本生成一个可能的标题", + "Summarize" : "总结归纳", + "Summarizes text by reducing its length without losing key information." : "总结一段文本以减少长度而不丢失关键信息", + "Extract topics" : "提取主题", + "Extracts topics from a text and outputs them separated by commas." : "从文本中摘出主题,输出逗号分隔的结果", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "应用%1$s的文件替换不正确。请确认版本与当前服务器兼容。", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登录用户必须是管理员、子管理员或具有访问此设置的特殊权限", + "Logged in user must be an admin or sub admin" : "当前登录用户必须为管理员或子管理员", + "Logged in user must be an admin" : "当前登录用户必须为管理员", "Full name" : "全名", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "已达到用户上限,未创建该用户。请检查您的通知以了解更多。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "在用户名中只允许使用以下字符:“a-z”、“A-Z”、“0-9” 和 \"_.@-'\"", + "Unknown user" : "未知用户", + "Enter the database username and name for %s" : "输入 %s 的数据库用户名和名称", + "Enter the database username for %s" : "输入 %s 的数据库用户名", + "MySQL username and/or password not valid" : "MySQL 数据库用户名和/或密码无效", + "Oracle username and/or password not valid" : "Oracle 数据库用户名和/或密码无效", + "PostgreSQL username and/or password not valid" : "PostgreSQL 数据库用户名和/或密码无效", + "Set an admin username." : "请设置一个管理员用户名。", + "Sharing %s failed, because this item is already shared with user %s" : "共享 %s 失败了,因为该项目已和用户 %s 进行了分享。", + "The username is already being used" : "用户名已被使用", + "Could not create user" : "无法创建用户", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "在用户名中只允许使用以下字符:“a-z”、“A-Z”、“0-9”、空格和 \"_.@-'\"", + "A valid username must be provided" : "必须提供合法的用户名", + "Username contains whitespace at the beginning or at the end" : "用户名在开头或结尾处包含空格", + "Username must not consist of dots only" : "用户名不能仅由点组成", + "Username is invalid because files already exist for this user" : "用户名无效,因为该用户已经存在文件", + "User disabled" : "用户已禁用", "libxml2 2.7.0 is at least required. Currently %s is installed." : "至少需要 libxml2 2.7.0. 当前安装 %s。", "To fix this issue update your libxml2 version and restart your web server." : "升级您的libxml2版本然后重启Web服务器以解决该问题。", "PostgreSQL >= 9 required." : "需要 PostgreSQL >= 9。", - "Please upgrade your database version." : "请升级您的数据库版本。" + "Please upgrade your database version." : "请升级您的数据库版本。", + "Your data directory is readable by other users." : "您的数据目录可被其他用户读取。", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "请更改权限为 0770 以避免其他用户查看目录。" },"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 345cf40a584..8e0f2ad517d 100644 --- a/lib/l10n/zh_HK.js +++ b/lib/l10n/zh_HK.js @@ -8,7 +8,6 @@ OC.L10N.register( "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 進行更改之前閱讀說明書", - "404" : "404", "The page could not be found on the server." : "無法在伺服器上找到此頁面。", "%s email verification" : "%s 電郵地址驗證", "Email verification" : "電郵地址驗證", @@ -37,9 +36,9 @@ 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 或更低", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登錄用戶必須是管理員、子管理員或具有存取此設定的特殊權限", - "Logged in user must be an admin or sub admin" : "登入的用戶必須要是管理員或是子管理員", - "Logged in user must be an admin" : "登入的用戶必須有管理員權限", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "登錄賬戶必須是管理員、子管理員或具有存取此設定的特殊權限", + "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」開始遠端抹除", @@ -118,22 +117,22 @@ OC.L10N.register( "Headline" : "標題", "Organisation" : "機構", "Role" : "角色", - "Unknown user" : "用戶不詳", + "Unknown account" : "賬戶不詳", "Additional settings" : "其他設定", - "Enter the database username and name for %s" : "輸入 %s 的數據庫用戶名及名稱", - "Enter the database username for %s" : "輸入 %s 的數據庫用戶名", + "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 username and/or password not valid" : "MySQL 用戶名稱或密碼不正確", + "MySQL Login and/or password not valid" : "MySQL 賬戶或密碼不正確", "You need to enter details of an existing account." : "您必須輸入現有帳號的資訊", "Oracle connection could not be established" : "無法建立 Oracle 數據庫連線", - "Oracle username and/or password not valid" : "Oracle 用戶名和/或密碼無效", - "PostgreSQL username and/or password not valid" : "PostgreSQL 用戶名和/或密碼無效", + "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 參數,這將讓超過 4GB 的檔案操作發生問題,強烈建議您更改設定。", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "請移除 php.ini 中的 open_basedir 設定,或是改用 64 位元的 PHP", - "Set an admin username." : "設定管理員帳號", + "Set an admin Login." : "設定管理員賬戶。", "Set an admin password." : "設定管理員密碼", "Cannot create or write into the data directory %s" : "無法建立或寫入資料目錄 %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "分享後端 %s 必須實作 OCP\\Share_Backend 界面", @@ -151,7 +150,7 @@ OC.L10N.register( "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_" : ["到期日不能設定為 %n 天以後的日期"], "Sharing is only allowed with group members" : "僅允許在群組成員中共享", - "Sharing %s failed, because this item is already shared with user %s" : "分享 %s 失敗,此項目已經與用戶 %s 分享", + "Sharing %s failed, because this item is already shared with the account %s" : "分享 %s 失敗,因為此項目已與賬戶 %s 分享", "%1$s shared »%2$s« with you" : "%1$s 與您分享了 %2$s", "%1$s shared »%2$s« with you." : "%1$s 與您分享了 %2$s", "Click the button below to open it." : "點下方連結開啟", @@ -205,14 +204,14 @@ OC.L10N.register( "Nov." : "十一月", "Dec." : "十二月", "A valid password must be provided" : "須提供有效的密碼", - "The username is already being used" : "這個用戶名稱已經有人使用了", - "Could not create user" : "無法建立用戶", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "用戶名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\",空格 和 \"_.@-'\"", - "A valid username must be provided" : "必須提供一個有效的用戶名", - "Username contains whitespace at the beginning or at the end" : "用戶名的開頭或結尾有空白", - "Username must not consist of dots only" : "用戶名稱不能只包含小數點", - "Username is invalid because files already exist for this user" : "用戶名稱無效,因為用戶的檔案已經存在", - "User disabled" : "用戶已停用", + "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" : "賬戶不能只包含小數點", + "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" : "您資料的安全屋", @@ -245,8 +244,8 @@ OC.L10N.register( "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 users." : "您的資料目錄可以被其他用戶讀取。", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他用戶讀取目錄列表", + "Your data directory is readable by other people." : "您的 data 目錄可被其他人仕讀取。", + "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." : "您的數據目錄無效。", @@ -271,12 +270,32 @@ OC.L10N.register( "Extract topics" : "解壓縮主題", "Extracts topics from a text and outputs them separated by commas." : "從文字中提取主題並輸出,並用逗號分隔。", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "無法正確取代應用程式 %1$s 的檔案。請確保它們的版本與伺服器的版本兼容。", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登錄用戶必須是管理員、子管理員或具有存取此設定的特殊權限", + "Logged in user must be an admin or sub admin" : "登入的用戶必須要是管理員或是子管理員", + "Logged in user must be an admin" : "登入的用戶必須有管理員權限", "Full name" : "全名", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "用戶數量已達上限,無法創建新用戶。請查看您的通知以獲取更多資料。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "用戶名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\", 和 \"_.@-'\"", + "Unknown user" : "用戶不詳", + "Enter the database username and name for %s" : "輸入 %s 的數據庫用戶名及名稱", + "Enter the database username for %s" : "輸入 %s 的數據庫用戶名", + "MySQL username and/or password not valid" : "MySQL 用戶名稱或密碼不正確", + "Oracle username and/or password not valid" : "Oracle 用戶名和/或密碼無效", + "PostgreSQL username and/or password not valid" : "PostgreSQL 用戶名和/或密碼無效", + "Set an admin username." : "設定管理員帳號", + "Sharing %s failed, because this item is already shared with user %s" : "分享 %s 失敗,此項目已經與用戶 %s 分享", + "The username is already being used" : "這個用戶名稱已經有人使用了", + "Could not create user" : "無法建立用戶", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "用戶名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\",空格 和 \"_.@-'\"", + "A valid username must be provided" : "必須提供一個有效的用戶名", + "Username contains whitespace at the beginning or at the end" : "用戶名的開頭或結尾有空白", + "Username must not consist of dots only" : "用戶名稱不能只包含小數點", + "Username is invalid because files already exist for this user" : "用戶名稱無效,因為用戶的檔案已經存在", + "User disabled" : "用戶已停用", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 版本最低需求為 2.7.0。目前安裝版本為 %s。", "To fix this issue update your libxml2 version and restart your web server." : "修正方式為更新您的 libxml2 為 2.7.0 以上版本,再重啟網頁伺服器。", "PostgreSQL >= 9 required." : "需要 PostgreSQL 版本 >= 9", - "Please upgrade your database version." : "請升級您數據庫的版本。" + "Please upgrade your database version." : "請升級您數據庫的版本。", + "Your data directory is readable by other users." : "您的資料目錄可以被其他用戶讀取。", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他用戶讀取目錄列表" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/zh_HK.json b/lib/l10n/zh_HK.json index 08e823d5723..91c47ccdc32 100644 --- a/lib/l10n/zh_HK.json +++ b/lib/l10n/zh_HK.json @@ -6,7 +6,6 @@ "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 進行更改之前閱讀說明書", - "404" : "404", "The page could not be found on the server." : "無法在伺服器上找到此頁面。", "%s email verification" : "%s 電郵地址驗證", "Email verification" : "電郵地址驗證", @@ -35,9 +34,9 @@ "The following platforms are supported: %s" : "支援下列平台:%s", "Server version %s or higher is required." : "需要伺服器版本 %s 或更高", "Server version %s or lower is required." : "需要伺服器版本 %s 或更低", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登錄用戶必須是管理員、子管理員或具有存取此設定的特殊權限", - "Logged in user must be an admin or sub admin" : "登入的用戶必須要是管理員或是子管理員", - "Logged in user must be an admin" : "登入的用戶必須有管理員權限", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "登錄賬戶必須是管理員、子管理員或具有存取此設定的特殊權限", + "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」開始遠端抹除", @@ -116,22 +115,22 @@ "Headline" : "標題", "Organisation" : "機構", "Role" : "角色", - "Unknown user" : "用戶不詳", + "Unknown account" : "賬戶不詳", "Additional settings" : "其他設定", - "Enter the database username and name for %s" : "輸入 %s 的數據庫用戶名及名稱", - "Enter the database username for %s" : "輸入 %s 的數據庫用戶名", + "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 username and/or password not valid" : "MySQL 用戶名稱或密碼不正確", + "MySQL Login and/or password not valid" : "MySQL 賬戶或密碼不正確", "You need to enter details of an existing account." : "您必須輸入現有帳號的資訊", "Oracle connection could not be established" : "無法建立 Oracle 數據庫連線", - "Oracle username and/or password not valid" : "Oracle 用戶名和/或密碼無效", - "PostgreSQL username and/or password not valid" : "PostgreSQL 用戶名和/或密碼無效", + "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 參數,這將讓超過 4GB 的檔案操作發生問題,強烈建議您更改設定。", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "請移除 php.ini 中的 open_basedir 設定,或是改用 64 位元的 PHP", - "Set an admin username." : "設定管理員帳號", + "Set an admin Login." : "設定管理員賬戶。", "Set an admin password." : "設定管理員密碼", "Cannot create or write into the data directory %s" : "無法建立或寫入資料目錄 %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "分享後端 %s 必須實作 OCP\\Share_Backend 界面", @@ -149,7 +148,7 @@ "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_" : ["到期日不能設定為 %n 天以後的日期"], "Sharing is only allowed with group members" : "僅允許在群組成員中共享", - "Sharing %s failed, because this item is already shared with user %s" : "分享 %s 失敗,此項目已經與用戶 %s 分享", + "Sharing %s failed, because this item is already shared with the account %s" : "分享 %s 失敗,因為此項目已與賬戶 %s 分享", "%1$s shared »%2$s« with you" : "%1$s 與您分享了 %2$s", "%1$s shared »%2$s« with you." : "%1$s 與您分享了 %2$s", "Click the button below to open it." : "點下方連結開啟", @@ -203,14 +202,14 @@ "Nov." : "十一月", "Dec." : "十二月", "A valid password must be provided" : "須提供有效的密碼", - "The username is already being used" : "這個用戶名稱已經有人使用了", - "Could not create user" : "無法建立用戶", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "用戶名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\",空格 和 \"_.@-'\"", - "A valid username must be provided" : "必須提供一個有效的用戶名", - "Username contains whitespace at the beginning or at the end" : "用戶名的開頭或結尾有空白", - "Username must not consist of dots only" : "用戶名稱不能只包含小數點", - "Username is invalid because files already exist for this user" : "用戶名稱無效,因為用戶的檔案已經存在", - "User disabled" : "用戶已停用", + "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" : "賬戶不能只包含小數點", + "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" : "您資料的安全屋", @@ -243,8 +242,8 @@ "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 users." : "您的資料目錄可以被其他用戶讀取。", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他用戶讀取目錄列表", + "Your data directory is readable by other people." : "您的 data 目錄可被其他人仕讀取。", + "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." : "您的數據目錄無效。", @@ -269,12 +268,32 @@ "Extract topics" : "解壓縮主題", "Extracts topics from a text and outputs them separated by commas." : "從文字中提取主題並輸出,並用逗號分隔。", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "無法正確取代應用程式 %1$s 的檔案。請確保它們的版本與伺服器的版本兼容。", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登錄用戶必須是管理員、子管理員或具有存取此設定的特殊權限", + "Logged in user must be an admin or sub admin" : "登入的用戶必須要是管理員或是子管理員", + "Logged in user must be an admin" : "登入的用戶必須有管理員權限", "Full name" : "全名", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "用戶數量已達上限,無法創建新用戶。請查看您的通知以獲取更多資料。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "用戶名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\", 和 \"_.@-'\"", + "Unknown user" : "用戶不詳", + "Enter the database username and name for %s" : "輸入 %s 的數據庫用戶名及名稱", + "Enter the database username for %s" : "輸入 %s 的數據庫用戶名", + "MySQL username and/or password not valid" : "MySQL 用戶名稱或密碼不正確", + "Oracle username and/or password not valid" : "Oracle 用戶名和/或密碼無效", + "PostgreSQL username and/or password not valid" : "PostgreSQL 用戶名和/或密碼無效", + "Set an admin username." : "設定管理員帳號", + "Sharing %s failed, because this item is already shared with user %s" : "分享 %s 失敗,此項目已經與用戶 %s 分享", + "The username is already being used" : "這個用戶名稱已經有人使用了", + "Could not create user" : "無法建立用戶", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "用戶名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\",空格 和 \"_.@-'\"", + "A valid username must be provided" : "必須提供一個有效的用戶名", + "Username contains whitespace at the beginning or at the end" : "用戶名的開頭或結尾有空白", + "Username must not consist of dots only" : "用戶名稱不能只包含小數點", + "Username is invalid because files already exist for this user" : "用戶名稱無效,因為用戶的檔案已經存在", + "User disabled" : "用戶已停用", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 版本最低需求為 2.7.0。目前安裝版本為 %s。", "To fix this issue update your libxml2 version and restart your web server." : "修正方式為更新您的 libxml2 為 2.7.0 以上版本,再重啟網頁伺服器。", "PostgreSQL >= 9 required." : "需要 PostgreSQL 版本 >= 9", - "Please upgrade your database version." : "請升級您數據庫的版本。" + "Please upgrade your database version." : "請升級您數據庫的版本。", + "Your data directory is readable by other users." : "您的資料目錄可以被其他用戶讀取。", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他用戶讀取目錄列表" },"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 c950bc7636d..0b280163a13 100644 --- a/lib/l10n/zh_TW.js +++ b/lib/l10n/zh_TW.js @@ -1,14 +1,13 @@ OC.L10N.register( "lib", { - "Cannot write into \"config\" directory!" : "無法寫入 \"config\" 目錄!", + "Cannot write into \"config\" directory!" : "無法寫入「config」目錄!", "This can usually be fixed by giving the web server write access to the config directory." : "允許網頁伺服器寫入 config 目錄通常可以解決這個問題。", "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." : "應用程式 %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 進行適當的修改", - "404" : "404", "The page could not be found on the server." : "無法在伺服器上找到此頁面。", "%s email verification" : "%s 電子郵件驗證", "Email verification" : "電子郵件驗證", @@ -24,7 +23,8 @@ OC.L10N.register( "Enterprise bundle" : "企業組合包", "Groupware bundle" : "協作組合包", "Hub bundle" : "Hub 套裝", - "Social sharing bundle" : "社交網絡組合包", + "Public sector bundle" : "公部門組合包", + "Social sharing bundle" : "社交分享組合包", "PHP %s or higher is required." : "需要 PHP %s 或更高版本", "PHP with a version lower than %s is required." : "需要 PHP 版本低於 %s ", "%sbit or higher PHP required." : "%s 或需要更高階版本的php", @@ -37,9 +37,9 @@ 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 或更低", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登入使用者必須為管理員、子管理員或有可存取此設定的特殊權限的使用者", - "Logged in user must be an admin or sub admin" : "登入的使用者必須要是管理員或是子管理員", - "Logged in user must be an admin" : "登入的使用者必須有管理員權限", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "登入帳號必須為管理員、子管理員或有可存取此設定的特殊權限的使用者", + "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」開始遠端抹除", @@ -118,22 +118,22 @@ OC.L10N.register( "Headline" : "標題", "Organisation" : "組織", "Role" : "角色", - "Unknown user" : "未知的使用者", + "Unknown account" : "未知的帳號", "Additional settings" : "其他設定", - "Enter the database username and name for %s" : "輸入 %s 的資料庫名稱及使用者名稱", - "Enter the database username for %s" : "輸入 %s 的資料庫使用者暱稱", + "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 username and/or password not valid" : "MySQL 使用者名稱或密碼不正確", + "MySQL Login and/or password not valid" : "MySQL 帳號或密碼不正確", "You need to enter details of an existing account." : "您必須輸入現有帳號的資訊", "Oracle connection could not be established" : "無法建立 Oracle 資料庫連線", - "Oracle username and/or password not valid" : "Oracle 用戶名和/或密碼無效", - "PostgreSQL username and/or password not valid" : "PostgreSQL 用戶名和/或密碼無效", + "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 參數,這將讓超過 4GB 的檔案操作發生問題,強烈建議您更改設定。", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "請移除 php.ini 中的 open_basedir 設定,或是改用 64 位元的 PHP", - "Set an admin username." : "設定管理員帳號", + "Set an admin Login." : "設定管理員帳號。", "Set an admin password." : "設定管理員密碼", "Cannot create or write into the data directory %s" : "無法建立或寫入資料目錄 %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "分享後端 %s 必須實作 OCP\\Share_Backend 界面", @@ -151,7 +151,7 @@ OC.L10N.register( "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_" : ["無法設定到期日超過未來%n天"], "Sharing is only allowed with group members" : "僅允許與群組成員分享", - "Sharing %s failed, because this item is already shared with user %s" : "分享 %s 失敗,因為此項目已與使用者 %s 分享", + "Sharing %s failed, because this item is already shared with the account %s" : "分享 %s 失敗,因為此項目已與帳號 %s 分享", "%1$s shared »%2$s« with you" : "%1$s 與您分享了 %2$s", "%1$s shared »%2$s« with you." : "%1$s 與您分享了 %2$s", "Click the button below to open it." : "點下方連結開啟", @@ -205,14 +205,14 @@ OC.L10N.register( "Nov." : "十一月", "Dec." : "十二月", "A valid password must be provided" : "須提供有效的密碼", - "The username is already being used" : "這個使用者名稱已經有人使用了", - "Could not create user" : "無法建立使用者", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "使用者名稱僅允許以下字元:\"a-z\"、\"A-Z\"、\"0-9\"、空格與 \"_.@-'\"", - "A valid username must be provided" : "必須提供一個有效的用戶名", - "Username contains whitespace at the beginning or at the end" : "用戶名的開頭或結尾有空白", - "Username must not consist of dots only" : "使用者名稱不能只包含小數點", - "Username is invalid because files already exist for this user" : "使用者名稱無效,因為使用者的檔案已經存在", - "User disabled" : "使用者已停用", + "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" : "帳號不能只包含小數點", + "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" : "您資料的安全屋", @@ -245,8 +245,8 @@ OC.L10N.register( "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 users." : "您的 data 目錄可被其他使用讀取。", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他使用者讀取目錄列表", + "Your data directory is readable by other people." : "您的 data 目錄可被其他使用者讀取。", + "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." : "您的 data 目錄必須是絕對路徑。", "Check the value of \"datadirectory\" in your configuration." : "請檢查您設定檔中「datadirectory」的值。", "Your data directory is invalid." : "您的 data 目錄無效。", @@ -271,12 +271,32 @@ OC.L10N.register( "Extract topics" : "擷取主題", "Extracts topics from a text and outputs them separated by commas." : "從文字中擷取主題並輸出,然後用逗號分隔。", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "應用程式 %1$s 中的檔案沒有被正確取代,請確認它的版本與伺服器相容。", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登入使用者必須為管理員、子管理員或有可存取此設定的特殊權限的使用者", + "Logged in user must be an admin or sub admin" : "登入的使用者必須要是管理員或是子管理員", + "Logged in user must be an admin" : "登入的使用者必須有管理員權限", "Full name" : "全名", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "已達使用者限制,所以未建立使用者。請檢查您的通知以取得更多資訊。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "使用者名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\", 和 \"_.@-'\"", + "Unknown user" : "未知的使用者", + "Enter the database username and name for %s" : "輸入 %s 的資料庫名稱及使用者名稱", + "Enter the database username for %s" : "輸入 %s 的資料庫使用者暱稱", + "MySQL username and/or password not valid" : "MySQL 使用者名稱或密碼不正確", + "Oracle username and/or password not valid" : "Oracle 用戶名和/或密碼無效", + "PostgreSQL username and/or password not valid" : "PostgreSQL 用戶名和/或密碼無效", + "Set an admin username." : "設定管理員帳號", + "Sharing %s failed, because this item is already shared with user %s" : "分享 %s 失敗,因為此項目已與使用者 %s 分享", + "The username is already being used" : "這個使用者名稱已經有人使用了", + "Could not create user" : "無法建立使用者", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "使用者名稱僅允許以下字元:\"a-z\"、\"A-Z\"、\"0-9\"、空格與 \"_.@-'\"", + "A valid username must be provided" : "必須提供一個有效的用戶名", + "Username contains whitespace at the beginning or at the end" : "用戶名的開頭或結尾有空白", + "Username must not consist of dots only" : "使用者名稱不能只包含小數點", + "Username is invalid because files already exist for this user" : "使用者名稱無效,因為使用者的檔案已經存在", + "User disabled" : "使用者已停用", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 版本最低需求為 2.7.0。目前安裝版本為 %s 。", "To fix this issue update your libxml2 version and restart your web server." : "修正方式為更新您的 libxml2 為 2.7.0 以上版本,再重啟網頁伺服器。", "PostgreSQL >= 9 required." : "需要 PostgreSQL 版本 >= 9。", - "Please upgrade your database version." : "請升級您的資料庫版本。" + "Please upgrade your database version." : "請升級您的資料庫版本。", + "Your data directory is readable by other users." : "您的 data 目錄可被其他使用讀取。", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他使用者讀取目錄列表" }, "nplurals=1; plural=0;"); diff --git a/lib/l10n/zh_TW.json b/lib/l10n/zh_TW.json index f767cb5a8b3..5ee9076db78 100644 --- a/lib/l10n/zh_TW.json +++ b/lib/l10n/zh_TW.json @@ -1,12 +1,11 @@ { "translations": { - "Cannot write into \"config\" directory!" : "無法寫入 \"config\" 目錄!", + "Cannot write into \"config\" directory!" : "無法寫入「config」目錄!", "This can usually be fixed by giving the web server write access to the config directory." : "允許網頁伺服器寫入 config 目錄通常可以解決這個問題。", "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." : "應用程式 %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 進行適當的修改", - "404" : "404", "The page could not be found on the server." : "無法在伺服器上找到此頁面。", "%s email verification" : "%s 電子郵件驗證", "Email verification" : "電子郵件驗證", @@ -22,7 +21,8 @@ "Enterprise bundle" : "企業組合包", "Groupware bundle" : "協作組合包", "Hub bundle" : "Hub 套裝", - "Social sharing bundle" : "社交網絡組合包", + "Public sector bundle" : "公部門組合包", + "Social sharing bundle" : "社交分享組合包", "PHP %s or higher is required." : "需要 PHP %s 或更高版本", "PHP with a version lower than %s is required." : "需要 PHP 版本低於 %s ", "%sbit or higher PHP required." : "%s 或需要更高階版本的php", @@ -35,9 +35,9 @@ "The following platforms are supported: %s" : "支援下列平台:%s", "Server version %s or higher is required." : "需要伺服器版本 %s 或更高", "Server version %s or lower is required." : "需要伺服器版本 %s 或更低", - "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登入使用者必須為管理員、子管理員或有可存取此設定的特殊權限的使用者", - "Logged in user must be an admin or sub admin" : "登入的使用者必須要是管理員或是子管理員", - "Logged in user must be an admin" : "登入的使用者必須有管理員權限", + "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "登入帳號必須為管理員、子管理員或有可存取此設定的特殊權限的使用者", + "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」開始遠端抹除", @@ -116,22 +116,22 @@ "Headline" : "標題", "Organisation" : "組織", "Role" : "角色", - "Unknown user" : "未知的使用者", + "Unknown account" : "未知的帳號", "Additional settings" : "其他設定", - "Enter the database username and name for %s" : "輸入 %s 的資料庫名稱及使用者名稱", - "Enter the database username for %s" : "輸入 %s 的資料庫使用者暱稱", + "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 username and/or password not valid" : "MySQL 使用者名稱或密碼不正確", + "MySQL Login and/or password not valid" : "MySQL 帳號或密碼不正確", "You need to enter details of an existing account." : "您必須輸入現有帳號的資訊", "Oracle connection could not be established" : "無法建立 Oracle 資料庫連線", - "Oracle username and/or password not valid" : "Oracle 用戶名和/或密碼無效", - "PostgreSQL username and/or password not valid" : "PostgreSQL 用戶名和/或密碼無效", + "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 參數,這將讓超過 4GB 的檔案操作發生問題,強烈建議您更改設定。", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "請移除 php.ini 中的 open_basedir 設定,或是改用 64 位元的 PHP", - "Set an admin username." : "設定管理員帳號", + "Set an admin Login." : "設定管理員帳號。", "Set an admin password." : "設定管理員密碼", "Cannot create or write into the data directory %s" : "無法建立或寫入資料目錄 %s", "Sharing backend %s must implement the interface OCP\\Share_Backend" : "分享後端 %s 必須實作 OCP\\Share_Backend 界面", @@ -149,7 +149,7 @@ "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_" : ["無法設定到期日超過未來%n天"], "Sharing is only allowed with group members" : "僅允許與群組成員分享", - "Sharing %s failed, because this item is already shared with user %s" : "分享 %s 失敗,因為此項目已與使用者 %s 分享", + "Sharing %s failed, because this item is already shared with the account %s" : "分享 %s 失敗,因為此項目已與帳號 %s 分享", "%1$s shared »%2$s« with you" : "%1$s 與您分享了 %2$s", "%1$s shared »%2$s« with you." : "%1$s 與您分享了 %2$s", "Click the button below to open it." : "點下方連結開啟", @@ -203,14 +203,14 @@ "Nov." : "十一月", "Dec." : "十二月", "A valid password must be provided" : "須提供有效的密碼", - "The username is already being used" : "這個使用者名稱已經有人使用了", - "Could not create user" : "無法建立使用者", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "使用者名稱僅允許以下字元:\"a-z\"、\"A-Z\"、\"0-9\"、空格與 \"_.@-'\"", - "A valid username must be provided" : "必須提供一個有效的用戶名", - "Username contains whitespace at the beginning or at the end" : "用戶名的開頭或結尾有空白", - "Username must not consist of dots only" : "使用者名稱不能只包含小數點", - "Username is invalid because files already exist for this user" : "使用者名稱無效,因為使用者的檔案已經存在", - "User disabled" : "使用者已停用", + "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" : "帳號不能只包含小數點", + "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" : "您資料的安全屋", @@ -243,8 +243,8 @@ "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 users." : "您的 data 目錄可被其他使用讀取。", - "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他使用者讀取目錄列表", + "Your data directory is readable by other people." : "您的 data 目錄可被其他使用者讀取。", + "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." : "您的 data 目錄必須是絕對路徑。", "Check the value of \"datadirectory\" in your configuration." : "請檢查您設定檔中「datadirectory」的值。", "Your data directory is invalid." : "您的 data 目錄無效。", @@ -269,12 +269,32 @@ "Extract topics" : "擷取主題", "Extracts topics from a text and outputs them separated by commas." : "從文字中擷取主題並輸出,然後用逗號分隔。", "The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "應用程式 %1$s 中的檔案沒有被正確取代,請確認它的版本與伺服器相容。", + "404" : "404", + "Logged in user must be an admin, a sub admin or gotten special right to access this setting" : "登入使用者必須為管理員、子管理員或有可存取此設定的特殊權限的使用者", + "Logged in user must be an admin or sub admin" : "登入的使用者必須要是管理員或是子管理員", + "Logged in user must be an admin" : "登入的使用者必須有管理員權限", "Full name" : "全名", - "The user limit has been reached and the user was not created. Check your notifications to learn more." : "已達使用者限制,所以未建立使用者。請檢查您的通知以取得更多資訊。", - "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "使用者名稱當中只能包含下列字元:\"a-z\", \"A-Z\", \"0-9\", 和 \"_.@-'\"", + "Unknown user" : "未知的使用者", + "Enter the database username and name for %s" : "輸入 %s 的資料庫名稱及使用者名稱", + "Enter the database username for %s" : "輸入 %s 的資料庫使用者暱稱", + "MySQL username and/or password not valid" : "MySQL 使用者名稱或密碼不正確", + "Oracle username and/or password not valid" : "Oracle 用戶名和/或密碼無效", + "PostgreSQL username and/or password not valid" : "PostgreSQL 用戶名和/或密碼無效", + "Set an admin username." : "設定管理員帳號", + "Sharing %s failed, because this item is already shared with user %s" : "分享 %s 失敗,因為此項目已與使用者 %s 分享", + "The username is already being used" : "這個使用者名稱已經有人使用了", + "Could not create user" : "無法建立使用者", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", spaces and \"_.@-'\"" : "使用者名稱僅允許以下字元:\"a-z\"、\"A-Z\"、\"0-9\"、空格與 \"_.@-'\"", + "A valid username must be provided" : "必須提供一個有效的用戶名", + "Username contains whitespace at the beginning or at the end" : "用戶名的開頭或結尾有空白", + "Username must not consist of dots only" : "使用者名稱不能只包含小數點", + "Username is invalid because files already exist for this user" : "使用者名稱無效,因為使用者的檔案已經存在", + "User disabled" : "使用者已停用", "libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 版本最低需求為 2.7.0。目前安裝版本為 %s 。", "To fix this issue update your libxml2 version and restart your web server." : "修正方式為更新您的 libxml2 為 2.7.0 以上版本,再重啟網頁伺服器。", "PostgreSQL >= 9 required." : "需要 PostgreSQL 版本 >= 9。", - "Please upgrade your database version." : "請升級您的資料庫版本。" + "Please upgrade your database version." : "請升級您的資料庫版本。", + "Your data directory is readable by other users." : "您的 data 目錄可被其他使用讀取。", + "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "請將該目錄權限設定為 0770 ,以免其他使用者讀取目錄列表" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/lib/private/Accounts/AccountManager.php b/lib/private/Accounts/AccountManager.php index 9865438161b..97156a027e6 100644 --- a/lib/private/Accounts/AccountManager.php +++ b/lib/private/Accounts/AccountManager.php @@ -37,25 +37,23 @@ namespace OC\Accounts; use Exception; use InvalidArgumentException; -use libphonenumber\NumberParseException; -use libphonenumber\PhoneNumberFormat; -use libphonenumber\PhoneNumberUtil; use OC\Profile\TProfileHelper; -use OCP\Accounts\UserUpdatedEvent; -use OCP\Cache\CappedMemoryCache; use OCA\Settings\BackgroundJobs\VerifyUserData; use OCP\Accounts\IAccount; use OCP\Accounts\IAccountManager; use OCP\Accounts\IAccountProperty; use OCP\Accounts\IAccountPropertyCollection; use OCP\Accounts\PropertyDoesNotExistException; +use OCP\Accounts\UserUpdatedEvent; use OCP\BackgroundJob\IJobList; +use OCP\Cache\CappedMemoryCache; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IDBConnection; use OCP\IL10N; +use OCP\IPhoneNumberUtil; use OCP\IURLGenerator; use OCP\IUser; use OCP\L10N\IFactory; @@ -119,6 +117,7 @@ class AccountManager implements IAccountManager { private IFactory $l10nFactory, private IURLGenerator $urlGenerator, private ICrypto $crypto, + private IPhoneNumberUtil $phoneNumberUtil, ) { $this->internalCache = new CappedMemoryCache(); } @@ -139,13 +138,9 @@ class AccountManager implements IAccountManager { $defaultRegion = 'EN'; } - $phoneUtil = PhoneNumberUtil::getInstance(); - try { - $phoneNumber = $phoneUtil->parse($input, $defaultRegion); - if ($phoneUtil->isValidNumber($phoneNumber)) { - return $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164); - } - } catch (NumberParseException $e) { + $phoneNumber = $this->phoneNumberUtil->convertToStandardFormat($input, $defaultRegion); + if ($phoneNumber !== null) { + return $phoneNumber; } throw new InvalidArgumentException(self::PROPERTY_PHONE); diff --git a/lib/private/Activity/Manager.php b/lib/private/Activity/Manager.php index a7d24510d53..14069260c6c 100644 --- a/lib/private/Activity/Manager.php +++ b/lib/private/Activity/Manager.php @@ -70,11 +70,11 @@ class Manager implements IManager { protected $l10n; public function __construct( - IRequest $request, - IUserSession $session, - IConfig $config, - IValidator $validator, - IL10N $l10n + IRequest $request, + IUserSession $session, + IConfig $config, + IValidator $validator, + IL10N $l10n ) { $this->request = $request; $this->session = $session; diff --git a/lib/private/AllConfig.php b/lib/private/AllConfig.php index 2a0e8f53b14..ab4359c798f 100644 --- a/lib/private/AllConfig.php +++ b/lib/private/AllConfig.php @@ -32,6 +32,7 @@ */ namespace OC; +use Doctrine\DBAL\Platforms\OraclePlatform; use OCP\Cache\CappedMemoryCache; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IConfig; @@ -42,7 +43,6 @@ use OCP\PreConditionNotMetException; * Class to combine all the configuration options ownCloud offers */ class AllConfig implements IConfig { - private SystemConfig $systemConfig; private ?IDBConnection $connection = null; /** @@ -67,9 +67,10 @@ class AllConfig implements IConfig { */ private CappedMemoryCache $userCache; - public function __construct(SystemConfig $systemConfig) { + public function __construct( + private SystemConfig $systemConfig + ) { $this->userCache = new CappedMemoryCache(); - $this->systemConfig = $systemConfig; } /** @@ -189,6 +190,7 @@ class AllConfig implements IConfig { * * @param string $appName the appName that we stored the value under * @return string[] the keys stored for the app + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function getAppKeys($appName) { return \OC::$server->get(AppConfig::class)->getKeys($appName); @@ -200,6 +202,7 @@ class AllConfig implements IConfig { * @param string $appName the appName that we want to store the value under * @param string $key the key of the value, under which will be saved * @param string|float|int $value the value that should be stored + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function setAppValue($appName, $key, $value) { \OC::$server->get(AppConfig::class)->setValue($appName, $key, $value); @@ -212,6 +215,7 @@ class AllConfig implements IConfig { * @param string $key the key of the value, under which it was saved * @param string $default the default value to be returned if the value isn't set * @return string the saved value + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function getAppValue($appName, $key, $default = '') { return \OC::$server->get(AppConfig::class)->getValue($appName, $key, $default); @@ -222,6 +226,7 @@ class AllConfig implements IConfig { * * @param string $appName the appName that we stored the value under * @param string $key the key of the value, under which it was saved + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function deleteAppValue($appName, $key) { \OC::$server->get(AppConfig::class)->deleteKey($appName, $key); @@ -231,6 +236,7 @@ class AllConfig implements IConfig { * Removes all keys in appconfig belonging to the app * * @param string $appName the appName the configs are stored under + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function deleteAppValues($appName) { \OC::$server->get(AppConfig::class)->deleteApp($appName); @@ -490,12 +496,15 @@ class AllConfig implements IConfig { $this->fixDIInit(); $qb = $this->connection->getQueryBuilder(); + $configValueColumn = ($this->connection->getDatabasePlatform() instanceof OraclePlatform) + ? $qb->expr()->castColumn('configvalue', IQueryBuilder::PARAM_STR) + : 'configvalue'; $result = $qb->select('userid') ->from('preferences') ->where($qb->expr()->eq('appid', $qb->createNamedParameter($appName, IQueryBuilder::PARAM_STR))) ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key, IQueryBuilder::PARAM_STR))) ->andWhere($qb->expr()->eq( - $qb->expr()->castColumn('configvalue', IQueryBuilder::PARAM_STR), + $configValueColumn, $qb->createNamedParameter($value, IQueryBuilder::PARAM_STR)) )->orderBy('userid') ->executeQuery(); @@ -524,13 +533,18 @@ class AllConfig implements IConfig { // Email address is always stored lowercase in the database return $this->getUsersForUserValue($appName, $key, strtolower($value)); } + $qb = $this->connection->getQueryBuilder(); + $configValueColumn = ($this->connection->getDatabasePlatform() instanceof OraclePlatform) + ? $qb->expr()->castColumn('configvalue', IQueryBuilder::PARAM_STR) + : 'configvalue'; + $result = $qb->select('userid') ->from('preferences') ->where($qb->expr()->eq('appid', $qb->createNamedParameter($appName, IQueryBuilder::PARAM_STR))) ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key, IQueryBuilder::PARAM_STR))) ->andWhere($qb->expr()->eq( - $qb->func()->lower($qb->expr()->castColumn('configvalue', IQueryBuilder::PARAM_STR)), + $qb->func()->lower($configValueColumn), $qb->createNamedParameter(strtolower($value), IQueryBuilder::PARAM_STR)) )->orderBy('userid') ->executeQuery(); diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 88044fbf7b6..c6e6ba2975e 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -38,6 +38,7 @@ */ namespace OC\App; +use InvalidArgumentException; use OC\AppConfig; use OC\AppFramework\Bootstrap\Coordinator; use OC\ServerNotAvailableException; @@ -47,14 +48,15 @@ use OCP\App\Events\AppDisableEvent; use OCP\App\Events\AppEnableEvent; use OCP\App\IAppManager; use OCP\App\ManagerEvent; -use OCP\EventDispatcher\IEventDispatcher; use OCP\Collaboration\AutoComplete\IManager as IAutoCompleteManager; use OCP\Collaboration\Collaborators\ISearch as ICollaboratorSearch; use OCP\Diagnostics\IEventLogger; +use OCP\EventDispatcher\IEventDispatcher; use OCP\ICacheFactory; use OCP\IConfig; use OCP\IGroup; use OCP\IGroupManager; +use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserSession; use OCP\Settings\IManager as ISettingsManager; @@ -73,14 +75,6 @@ class AppManager implements IAppManager { 'prevent_group_restriction', ]; - private IUserSession $userSession; - private IConfig $config; - private AppConfig $appConfig; - private IGroupManager $groupManager; - private ICacheFactory $memCacheFactory; - private IEventDispatcher $dispatcher; - private LoggerInterface $logger; - /** @var string[] $appId => $enabled */ private array $installedAppsCache = []; @@ -103,20 +97,30 @@ class AppManager implements IAppManager { /** @var array<string, true> */ private array $loadedApps = []; - public function __construct(IUserSession $userSession, - IConfig $config, - AppConfig $appConfig, - IGroupManager $groupManager, - ICacheFactory $memCacheFactory, - IEventDispatcher $dispatcher, - LoggerInterface $logger) { - $this->userSession = $userSession; - $this->config = $config; - $this->appConfig = $appConfig; - $this->groupManager = $groupManager; - $this->memCacheFactory = $memCacheFactory; - $this->dispatcher = $dispatcher; - $this->logger = $logger; + public function __construct( + private IUserSession $userSession, + private IConfig $config, + private AppConfig $appConfig, + private IGroupManager $groupManager, + private ICacheFactory $memCacheFactory, + private IEventDispatcher $dispatcher, + private LoggerInterface $logger, + private IURLGenerator $urlGenerator, + ) { + } + + public function getAppIcon(string $appId, bool $dark = false): ?string { + $possibleIcons = $dark ? [$appId . '-dark.svg', 'app-dark.svg'] : [$appId . '.svg', 'app.svg']; + $icon = null; + foreach ($possibleIcons as $iconName) { + try { + $icon = $this->urlGenerator->imagePath($appId, $iconName); + break; + } catch (\RuntimeException $e) { + // ignore + } + } + return $icon; } /** @@ -288,7 +292,7 @@ class AppManager implements IAppManager { * Check if an app is enabled for user * * @param string $appId - * @param \OCP\IUser $user (optional) if not defined, the currently logged in user will be used + * @param \OCP\IUser|null $user (optional) if not defined, the currently logged in user will be used * @return bool */ public function isEnabledForUser($appId, $user = null) { @@ -701,10 +705,7 @@ class AppManager implements IAppManager { /** * Returns the app information from "appinfo/info.xml". * - * @param string $appId app id - * - * @param bool $path - * @param null $lang + * @param string|null $lang * @return array|null app info */ public function getAppInfo(string $appId, bool $path = false, $lang = null) { @@ -816,22 +817,39 @@ class AppManager implements IAppManager { /** * @inheritdoc */ - public function getDefaultEnabledApps():array { + public function getDefaultEnabledApps(): array { $this->loadShippedJson(); return $this->defaultEnabled; } - public function getDefaultAppForUser(?IUser $user = null): string { + public function getDefaultAppForUser(?IUser $user = null, bool $withFallbacks = true): string { // Set fallback to always-enabled files app - $appId = 'files'; - $defaultApps = explode(',', $this->config->getSystemValueString('defaultapp', 'dashboard,files')); + $appId = $withFallbacks ? 'files' : ''; + $defaultApps = explode(',', $this->config->getSystemValueString('defaultapp', '')); + $defaultApps = array_filter($defaultApps); $user ??= $this->userSession->getUser(); if ($user !== null) { $userDefaultApps = explode(',', $this->config->getUserValue($user->getUID(), 'core', 'defaultapp')); $defaultApps = array_filter(array_merge($userDefaultApps, $defaultApps)); + if (empty($defaultApps) && $withFallbacks) { + /* Fallback on user defined apporder */ + $customOrders = json_decode($this->config->getUserValue($user->getUID(), 'core', 'apporder', '[]'), true, flags:JSON_THROW_ON_ERROR); + if (!empty($customOrders)) { + // filter only entries with app key (when added using closures or NavigationManager::add the app is not guranteed to be set) + $customOrders = array_filter($customOrders, fn ($entry) => isset($entry['app'])); + // sort apps by order + usort($customOrders, fn ($a, $b) => $a['order'] - $b['order']); + // set default apps to sorted apps + $defaultApps = array_map(fn ($entry) => $entry['app'], $customOrders); + } + } + } + + if (empty($defaultApps) && $withFallbacks) { + $defaultApps = ['dashboard','files']; } // Find the first app that is enabled for the current user @@ -845,4 +863,19 @@ class AppManager implements IAppManager { return $appId; } + + public function getDefaultApps(): array { + return explode(',', $this->config->getSystemValueString('defaultapp', 'dashboard,files')); + } + + public function setDefaultApps(array $defaultApps): void { + foreach ($defaultApps as $app) { + if (!$this->isInstalled($app)) { + $this->logger->debug('Can not set not installed app as default app', ['missing_app' => $app]); + throw new InvalidArgumentException('App is not installed'); + } + } + + $this->config->setSystemValue('defaultapp', join(',', $defaultApps)); + } } diff --git a/lib/private/App/AppStore/Bundles/Bundle.php b/lib/private/App/AppStore/Bundles/Bundle.php index dfc93fdfaa2..fb86edff559 100644 --- a/lib/private/App/AppStore/Bundles/Bundle.php +++ b/lib/private/App/AppStore/Bundles/Bundle.php @@ -26,14 +26,12 @@ namespace OC\App\AppStore\Bundles; use OCP\IL10N; abstract class Bundle { - /** @var IL10N */ - protected $l10n; - /** * @param IL10N $l10n */ - public function __construct(IL10N $l10n) { - $this->l10n = $l10n; + public function __construct( + protected IL10N $l10n, + ) { } /** diff --git a/lib/private/App/AppStore/Bundles/BundleFetcher.php b/lib/private/App/AppStore/Bundles/BundleFetcher.php index 0d2bb61495f..53e82b39b81 100644 --- a/lib/private/App/AppStore/Bundles/BundleFetcher.php +++ b/lib/private/App/AppStore/Bundles/BundleFetcher.php @@ -27,10 +27,9 @@ namespace OC\App\AppStore\Bundles; use OCP\IL10N; class BundleFetcher { - private IL10N $l10n; - - public function __construct(IL10N $l10n) { - $this->l10n = $l10n; + public function __construct( + private IL10N $l10n, + ) { } /** @@ -43,6 +42,7 @@ class BundleFetcher { new GroupwareBundle($this->l10n), new SocialSharingBundle($this->l10n), new EducationBundle($this->l10n), + new PublicSectorBundle($this->l10n), ]; } diff --git a/lib/private/App/AppStore/Bundles/PublicSectorBundle.php b/lib/private/App/AppStore/Bundles/PublicSectorBundle.php new file mode 100644 index 00000000000..6634e2ff41e --- /dev/null +++ b/lib/private/App/AppStore/Bundles/PublicSectorBundle.php @@ -0,0 +1,51 @@ +<?php +/** + * @copyright Copyright (c) 2024 Stephan Orbaugh <stephan.orbaugh@nextcloud.com> + * + * @author Stephan Orbaugh <stephan.orbaugh@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OC\App\AppStore\Bundles; + +class PublicSectorBundle extends Bundle { + /** + * {@inheritDoc} + */ + public function getName(): string { + return $this->l10n->t('Public sector bundle'); + } + + /** + * {@inheritDoc} + */ + public function getAppIdentifiers(): array { + + return [ + 'files_confidential', + 'forms', + 'collectives', + 'files_antivirus', + 'twofactor_nextcloud_notification', + 'tables', + 'richdocuments', + 'admin_audit', + 'files_retention', + ]; + } + +} diff --git a/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php b/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php new file mode 100644 index 00000000000..48dba6d48dc --- /dev/null +++ b/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php @@ -0,0 +1,116 @@ +<?php +/** + * @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de> + * + * @author Ferdinand Thiessen <opensource@fthiessen.de> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\App\AppStore\Fetcher; + +use DateTimeImmutable; +use OC\App\CompareVersion; +use OC\Files\AppData\Factory; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Http\Client\IClientService; +use OCP\IConfig; +use OCP\Support\Subscription\IRegistry; +use Psr\Log\LoggerInterface; + +class AppDiscoverFetcher extends Fetcher { + + public const INVALIDATE_AFTER_SECONDS = 86400; + + public function __construct( + Factory $appDataFactory, + IClientService $clientService, + ITimeFactory $timeFactory, + IConfig $config, + LoggerInterface $logger, + IRegistry $registry, + private CompareVersion $compareVersion, + ) { + parent::__construct( + $appDataFactory, + $clientService, + $timeFactory, + $config, + $logger, + $registry + ); + + $this->fileName = 'discover.json'; + $this->endpointName = 'discover.json'; + } + + /** + * Get the app discover section entries + * + * @param bool $allowUnstable Include also expired and upcoming entries + */ + public function get($allowUnstable = false) { + $entries = parent::get(false); + + if (!$allowUnstable) { + $now = new DateTimeImmutable(); + + // Remove expired or future entries + return array_filter($entries, function (array $entry) use ($now) { + try { + $date = new DateTimeImmutable($entry['date'] ?? ''); + if ($date > $now) { + return false; + } + } catch (\Throwable $e) { + // Invalid date format + return false; + } + + try { + $expiryDate = new DateTimeImmutable($entry['expiryDate'] ?? ''); + if ($expiryDate < $now) { + return false; + } + } catch (\Throwable $e) { + // Invalid expiryDate format + return false; + } + + return true; + }); + } + + return $entries; + } + + public function getETag(): string|null { + $rootFolder = $this->appData->getFolder('/'); + + try { + $file = $rootFolder->getFile($this->fileName); + $jsonBlob = json_decode($file->getContent(), true); + + if (is_array($jsonBlob) && isset($jsonBlob['ETag'])) { + return (string)$jsonBlob['ETag']; + } + } catch (\Throwable $e) { + // ignore + } + return null; + } +} diff --git a/lib/private/App/AppStore/Fetcher/AppFetcher.php b/lib/private/App/AppStore/Fetcher/AppFetcher.php index 47bdece372d..bb1a0e89484 100644 --- a/lib/private/App/AppStore/Fetcher/AppFetcher.php +++ b/lib/private/App/AppStore/Fetcher/AppFetcher.php @@ -39,22 +39,17 @@ use OCP\Support\Subscription\IRegistry; use Psr\Log\LoggerInterface; class AppFetcher extends Fetcher { - /** @var CompareVersion */ - private $compareVersion; - - /** @var IRegistry */ - protected $registry; - /** @var bool */ private $ignoreMaxVersion; public function __construct(Factory $appDataFactory, - IClientService $clientService, - ITimeFactory $timeFactory, - IConfig $config, - CompareVersion $compareVersion, - LoggerInterface $logger, - IRegistry $registry) { + IClientService $clientService, + ITimeFactory $timeFactory, + IConfig $config, + private CompareVersion $compareVersion, + LoggerInterface $logger, + protected IRegistry $registry, + ) { parent::__construct( $appDataFactory, $clientService, @@ -64,9 +59,6 @@ class AppFetcher extends Fetcher { $registry ); - $this->compareVersion = $compareVersion; - $this->registry = $registry; - $this->fileName = 'apps.json'; $this->endpointName = 'apps.json'; $this->ignoreMaxVersion = true; diff --git a/lib/private/App/AppStore/Fetcher/CategoryFetcher.php b/lib/private/App/AppStore/Fetcher/CategoryFetcher.php index afe051e6281..9b84d2a6196 100644 --- a/lib/private/App/AppStore/Fetcher/CategoryFetcher.php +++ b/lib/private/App/AppStore/Fetcher/CategoryFetcher.php @@ -34,12 +34,14 @@ use OCP\Support\Subscription\IRegistry; use Psr\Log\LoggerInterface; class CategoryFetcher extends Fetcher { - public function __construct(Factory $appDataFactory, - IClientService $clientService, - ITimeFactory $timeFactory, - IConfig $config, - LoggerInterface $logger, - IRegistry $registry) { + public function __construct( + Factory $appDataFactory, + IClientService $clientService, + ITimeFactory $timeFactory, + IConfig $config, + LoggerInterface $logger, + IRegistry $registry, + ) { parent::__construct( $appDataFactory, $clientService, diff --git a/lib/private/App/AppStore/Fetcher/Fetcher.php b/lib/private/App/AppStore/Fetcher/Fetcher.php index 095b026cb44..bd5c2ba8213 100644 --- a/lib/private/App/AppStore/Fetcher/Fetcher.php +++ b/lib/private/App/AppStore/Fetcher/Fetcher.php @@ -44,19 +44,10 @@ use Psr\Log\LoggerInterface; abstract class Fetcher { public const INVALIDATE_AFTER_SECONDS = 3600; public const RETRY_AFTER_FAILURE_SECONDS = 300; + public const APP_STORE_URL = 'https://apps.nextcloud.com/api/v1'; /** @var IAppData */ protected $appData; - /** @var IClientService */ - protected $clientService; - /** @var ITimeFactory */ - protected $timeFactory; - /** @var IConfig */ - protected $config; - /** @var LoggerInterface */ - protected $logger; - /** @var IRegistry */ - protected $registry; /** @var string */ protected $fileName; @@ -67,18 +58,15 @@ abstract class Fetcher { /** @var ?string */ protected $channel = null; - public function __construct(Factory $appDataFactory, - IClientService $clientService, - ITimeFactory $timeFactory, - IConfig $config, - LoggerInterface $logger, - IRegistry $registry) { + public function __construct( + Factory $appDataFactory, + protected IClientService $clientService, + protected ITimeFactory $timeFactory, + protected IConfig $config, + protected LoggerInterface $logger, + protected IRegistry $registry, + ) { $this->appData = $appDataFactory->get('appstore'); - $this->clientService = $clientService; - $this->timeFactory = $timeFactory; - $this->config = $config; - $this->logger = $logger; - $this->registry = $registry; } /** @@ -109,10 +97,13 @@ abstract class Fetcher { ]; } - // If we have a valid subscription key, send it to the appstore - $subscriptionKey = $this->config->getAppValue('support', 'subscription_key'); - if ($this->registry->delegateHasValidSubscription() && $subscriptionKey) { - $options['headers']['X-NC-Subscription-Key'] = $subscriptionKey; + if ($this->config->getSystemValueString('appstoreurl', self::APP_STORE_URL) === self::APP_STORE_URL) { + // If we have a valid subscription key, send it to the appstore + $subscriptionKey = $this->config->getAppValue('support', 'subscription_key'); + if ($this->registry->delegateHasValidSubscription() && $subscriptionKey) { + $options['headers'] ??= []; + $options['headers']['X-NC-Subscription-Key'] = $subscriptionKey; + } } $client = $this->clientService->newClient(); @@ -142,7 +133,7 @@ abstract class Fetcher { } /** - * Returns the array with the categories on the appstore server + * Returns the array with the entries on the appstore server * * @param bool [$allowUnstable] Allow unstable releases * @return array @@ -150,8 +141,9 @@ abstract class Fetcher { public function get($allowUnstable = false) { $appstoreenabled = $this->config->getSystemValueBool('appstoreenabled', true); $internetavailable = $this->config->getSystemValueBool('has_internet_connection', true); + $isDefaultAppStore = $this->config->getSystemValueString('appstoreurl', self::APP_STORE_URL) === self::APP_STORE_URL; - if (!$appstoreenabled || !$internetavailable) { + if (!$appstoreenabled || (!$internetavailable && $isDefaultAppStore)) { return []; } diff --git a/lib/private/App/AppStore/Version/Version.php b/lib/private/App/AppStore/Version/Version.php index d41ca1770f0..5bd0226528f 100644 --- a/lib/private/App/AppStore/Version/Version.php +++ b/lib/private/App/AppStore/Version/Version.php @@ -23,18 +23,14 @@ namespace OC\App\AppStore\Version; class Version { - /** @var string */ - private $minVersion; - /** @var string */ - private $maxVersion; - /** * @param string $minVersion * @param string $maxVersion */ - public function __construct($minVersion, $maxVersion) { - $this->minVersion = $minVersion; - $this->maxVersion = $maxVersion; + public function __construct( + private string $minVersion, + private string $maxVersion, + ) { } /** diff --git a/lib/private/App/AppStore/Version/VersionParser.php b/lib/private/App/AppStore/Version/VersionParser.php index 2b88399b9fd..eac9c935517 100644 --- a/lib/private/App/AppStore/Version/VersionParser.php +++ b/lib/private/App/AppStore/Version/VersionParser.php @@ -54,9 +54,9 @@ class VersionParser { // Count the amount of =, if it is one then it's either maximum or minimum // version. If it is two then it is maximum and minimum. $versionElements = explode(' ', $versionSpec); - $firstVersion = isset($versionElements[0]) ? $versionElements[0] : ''; + $firstVersion = $versionElements[0] ?? ''; $firstVersionNumber = substr($firstVersion, 2); - $secondVersion = isset($versionElements[1]) ? $versionElements[1] : ''; + $secondVersion = $versionElements[1] ?? ''; $secondVersionNumber = substr($secondVersion, 2); switch (count($versionElements)) { diff --git a/lib/private/App/DependencyAnalyzer.php b/lib/private/App/DependencyAnalyzer.php index 3bdc551ea5a..2974e31dc5d 100644 --- a/lib/private/App/DependencyAnalyzer.php +++ b/lib/private/App/DependencyAnalyzer.php @@ -33,10 +33,6 @@ namespace OC\App; use OCP\IL10N; class DependencyAnalyzer { - /** @var Platform */ - private $platform; - /** @var \OCP\IL10N */ - private $l; /** @var array */ private $appInfo; @@ -44,9 +40,10 @@ class DependencyAnalyzer { * @param Platform $platform * @param \OCP\IL10N $l */ - public function __construct(Platform $platform, IL10N $l) { - $this->platform = $platform; - $this->l = $l; + public function __construct( + private Platform $platform, + private IL10N $l, + ) { } /** diff --git a/lib/private/App/InfoParser.php b/lib/private/App/InfoParser.php index 79d051fd2a1..2461d587bbd 100644 --- a/lib/private/App/InfoParser.php +++ b/lib/private/App/InfoParser.php @@ -34,14 +34,12 @@ use function libxml_disable_entity_loader; use function simplexml_load_string; class InfoParser { - /** @var \OCP\ICache|null */ - private $cache; - /** * @param ICache|null $cache */ - public function __construct(ICache $cache = null) { - $this->cache = $cache; + public function __construct( + private ?ICache $cache = null, + ) { } /** diff --git a/lib/private/App/Platform.php b/lib/private/App/Platform.php index 1cab740bebb..c5565e9e0c2 100644 --- a/lib/private/App/Platform.php +++ b/lib/private/App/Platform.php @@ -25,8 +25,8 @@ */ namespace OC\App; -use OCP\IConfig; use OCP\IBinaryFinder; +use OCP\IConfig; /** * Class Platform @@ -36,10 +36,9 @@ use OCP\IBinaryFinder; * @package OC\App */ class Platform { - private IConfig $config; - - public function __construct(IConfig $config) { - $this->config = $config; + public function __construct( + private IConfig $config, + ) { } public function getPhpVersion(): string { diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php index 84f0d5b9e5a..518ba6ebf7a 100644 --- a/lib/private/AppConfig.php +++ b/lib/private/AppConfig.php @@ -1,4 +1,6 @@ <?php + +declare(strict_types=1); /** * @copyright Copyright (c) 2017, Joas Schilling <coding@schilljs.com> * @copyright Copyright (c) 2016, ownCloud, Inc. @@ -9,6 +11,7 @@ * @author Jakob Sack <mail@jakobsack.de> * @author Joas Schilling <coding@schilljs.com> * @author Jörn Friedrich Dreyer <jfd@butonic.de> + * @author Maxence Lange <maxence@artificial-owl.com> * @author michaelletzgus <michaelletzgus@users.noreply.github.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> @@ -30,413 +33,1477 @@ * along with this program. If not, see <http://www.gnu.org/licenses/> * */ + namespace OC; -use OC\DB\Connection; -use OC\DB\OracleConnection; +use InvalidArgumentException; +use JsonException; +use OCP\DB\Exception as DBException; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Exceptions\AppConfigIncorrectTypeException; +use OCP\Exceptions\AppConfigTypeConflictException; +use OCP\Exceptions\AppConfigUnknownKeyException; use OCP\IAppConfig; use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Security\ICrypto; +use Psr\Log\LoggerInterface; /** * This class provides an easy way for apps to store config values in the * database. + * + * **Note:** since 29.0.0, it supports **lazy loading** + * + * ### What is lazy loading ? + * In order to avoid loading useless config values into memory for each request, + * only non-lazy values are now loaded. + * + * Once a value that is lazy is requested, all lazy values will be loaded. + * + * Similarly, some methods from this class are marked with a warning about ignoring + * lazy loading. Use them wisely and only on parts of the code that are called + * during specific requests or actions to avoid loading the lazy values all the time. + * + * @since 7.0.0 + * @since 29.0.0 - Supporting types and lazy loading */ class AppConfig implements IAppConfig { - /** @var array[] */ - protected $sensitiveValues = [ - 'circles' => [ - '/^key_pairs$/', - '/^local_gskey$/', - ], - 'external' => [ - '/^sites$/', - ], - 'integration_discourse' => [ - '/^private_key$/', - '/^public_key$/', - ], - 'integration_dropbox' => [ - '/^client_id$/', - '/^client_secret$/', - ], - 'integration_github' => [ - '/^client_id$/', - '/^client_secret$/', - ], - 'integration_gitlab' => [ - '/^client_id$/', - '/^client_secret$/', - '/^oauth_instance_url$/', - ], - 'integration_google' => [ - '/^client_id$/', - '/^client_secret$/', - ], - 'integration_jira' => [ - '/^client_id$/', - '/^client_secret$/', - '/^forced_instance_url$/', - ], - 'integration_onedrive' => [ - '/^client_id$/', - '/^client_secret$/', - ], - 'integration_openproject' => [ - '/^client_id$/', - '/^client_secret$/', - '/^oauth_instance_url$/', - ], - 'integration_reddit' => [ - '/^client_id$/', - '/^client_secret$/', - ], - 'integration_suitecrm' => [ - '/^client_id$/', - '/^client_secret$/', - '/^oauth_instance_url$/', - ], - 'integration_twitter' => [ - '/^consumer_key$/', - '/^consumer_secret$/', - '/^followed_user$/', - ], - 'integration_zammad' => [ - '/^client_id$/', - '/^client_secret$/', - '/^oauth_instance_url$/', - ], - 'notify_push' => [ - '/^cookie$/', - ], - 'spreed' => [ - '/^bridge_bot_password$/', - '/^hosted-signaling-server-(.*)$/', - '/^recording_servers$/', - '/^signaling_servers$/', - '/^signaling_ticket_secret$/', - '/^signaling_token_privkey_(.*)$/', - '/^signaling_token_pubkey_(.*)$/', - '/^sip_bridge_dialin_info$/', - '/^sip_bridge_shared_secret$/', - '/^stun_servers$/', - '/^turn_servers$/', - '/^turn_server_secret$/', - ], - 'support' => [ - '/^last_response$/', - '/^potential_subscription_key$/', - '/^subscription_key$/', - ], - 'theming' => [ - '/^imprintUrl$/', - '/^privacyUrl$/', - '/^slogan$/', - '/^url$/', - ], - 'user_ldap' => [ - '/^(s..)?ldap_agent_password$/', - ], - 'user_saml' => [ - '/^idp-x509cert$/', - ], - ]; - - /** @var Connection */ - protected $conn; - - /** @var array[] */ - private $cache = []; - - /** @var bool */ - private $configLoaded = false; - - /** - * @param Connection $conn - */ - public function __construct(Connection $conn) { - $this->conn = $conn; + private const APP_MAX_LENGTH = 32; + private const KEY_MAX_LENGTH = 64; + private const ENCRYPTION_PREFIX = '$AppConfigEncryption$'; + private const ENCRYPTION_PREFIX_LENGTH = 21; // strlen(self::ENCRYPTION_PREFIX) + + /** @var array<string, array<string, mixed>> ['app_id' => ['config_key' => 'config_value']] */ + private array $fastCache = []; // cache for normal config keys + /** @var array<string, array<string, mixed>> ['app_id' => ['config_key' => 'config_value']] */ + private array $lazyCache = []; // cache for lazy config keys + /** @var array<string, array<string, int>> ['app_id' => ['config_key' => bitflag]] */ + private array $valueTypes = []; // type for all config values + private bool $fastLoaded = false; + private bool $lazyLoaded = false; + + /** + * $migrationCompleted is only needed to manage the previous structure + * of the database during the upgrading process to nc29. + * + * only when upgrading from a version prior 28.0.2 + * + * @TODO: remove this value in Nextcloud 30+ + */ + private bool $migrationCompleted = true; + + public function __construct( + protected IDBConnection $connection, + protected LoggerInterface $logger, + protected ICrypto $crypto, + ) { } /** - * @param string $app - * @return array + * @inheritDoc + * + * @return string[] list of app ids + * @since 7.0.0 + */ + public function getApps(): array { + $this->loadConfigAll(); + $apps = array_merge(array_keys($this->fastCache), array_keys($this->lazyCache)); + sort($apps); + + return array_values(array_unique($apps)); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * + * @return string[] list of stored config keys + * @since 29.0.0 + */ + public function getKeys(string $app): array { + $this->assertParams($app); + $this->loadConfigAll(); + $keys = array_merge(array_keys($this->fastCache[$app] ?? []), array_keys($this->lazyCache[$app] ?? [])); + sort($keys); + + return array_values(array_unique($keys)); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param bool|null $lazy TRUE to search within lazy loaded config, NULL to search within all config + * + * @return bool TRUE if key exists + * @since 7.0.0 + * @since 29.0.0 Added the $lazy argument + */ + public function hasKey(string $app, string $key, ?bool $lazy = false): bool { + $this->assertParams($app, $key); + $this->loadConfig($lazy); + + if ($lazy === null) { + $appCache = $this->getAllValues($app); + return isset($appCache[$key]); + } + + if ($lazy) { + return isset($this->lazyCache[$app][$key]); + } + + return isset($this->fastCache[$app][$key]); + } + + /** + * @param string $app id of the app + * @param string $key config key + * @param bool|null $lazy TRUE to search within lazy loaded config, NULL to search within all config + * + * @return bool + * @throws AppConfigUnknownKeyException if config key is not known + * @since 29.0.0 */ - private function getAppValues($app) { - $this->loadConfigValues(); + public function isSensitive(string $app, string $key, ?bool $lazy = false): bool { + $this->assertParams($app, $key); + $this->loadConfig($lazy); - if (isset($this->cache[$app])) { - return $this->cache[$app]; + if (!isset($this->valueTypes[$app][$key])) { + throw new AppConfigUnknownKeyException('unknown config key'); } - return []; + return $this->isTyped(self::VALUE_SENSITIVE, $this->valueTypes[$app][$key]); } /** - * Get all apps using the config + * @inheritDoc * - * @return string[] an array of app ids + * @param string $app if of the app + * @param string $key config key * - * This function returns a list of all apps that have at least one - * entry in the appconfig table. + * @return bool TRUE if config is lazy loaded + * @throws AppConfigUnknownKeyException if config key is not known + * @see IAppConfig for details about lazy loading + * @since 29.0.0 */ - public function getApps() { - $this->loadConfigValues(); + public function isLazy(string $app, string $key): bool { + // there is a huge probability the non-lazy config are already loaded + if ($this->hasKey($app, $key, false)) { + return false; + } - return $this->getSortedKeys($this->cache); + // key not found, we search in the lazy config + if ($this->hasKey($app, $key, true)) { + return true; + } + + throw new AppConfigUnknownKeyException('unknown config key'); } + /** - * Get the available keys for an app + * @inheritDoc * - * @param string $app the app we are looking for - * @return array an array of key names + * @param string $app id of the app + * @param string $prefix config keys prefix to search + * @param bool $filtered TRUE to hide sensitive config values. Value are replaced by {@see IConfig::SENSITIVE_VALUE} * - * This function gets all keys of an app. Please note that the values are - * not returned. + * @return array<string, string> [configKey => configValue] + * @since 29.0.0 */ - public function getKeys($app) { - $this->loadConfigValues(); + public function getAllValues(string $app, string $prefix = '', bool $filtered = false): array { + $this->assertParams($app, $prefix); + // if we want to filter values, we need to get sensitivity + $this->loadConfigAll(); + // array_merge() will remove numeric keys (here config keys), so addition arrays instead + $values = array_filter( + (($this->fastCache[$app] ?? []) + ($this->lazyCache[$app] ?? [])), + function (string $key) use ($prefix): bool { + return str_starts_with($key, $prefix); // filter values based on $prefix + }, ARRAY_FILTER_USE_KEY + ); + + if (!$filtered) { + return $values; + } - if (isset($this->cache[$app])) { - return $this->getSortedKeys($this->cache[$app]); + /** + * Using the old (deprecated) list of sensitive values. + */ + foreach ($this->getSensitiveKeys($app) as $sensitiveKeyExp) { + $sensitiveKeys = preg_grep($sensitiveKeyExp, array_keys($values)); + foreach ($sensitiveKeys as $sensitiveKey) { + $this->valueTypes[$app][$sensitiveKey] = ($this->valueTypes[$app][$sensitiveKey] ?? 0) | self::VALUE_SENSITIVE; + } } - return []; + $result = []; + foreach ($values as $key => $value) { + $result[$key] = $this->isTyped(self::VALUE_SENSITIVE, $this->valueTypes[$app][$key] ?? 0) ? IConfig::SENSITIVE_VALUE : $value; + } + + return $result; } - public function getSortedKeys($data) { - $keys = array_keys($data); - sort($keys); - return $keys; + /** + * @inheritDoc + * + * @param string $key config key + * @param bool $lazy search within lazy loaded config + * + * @return array<string, string> [appId => configValue] + * @since 29.0.0 + */ + public function searchValues(string $key, bool $lazy = false): array { + $this->assertParams('', $key, true); + $this->loadConfig($lazy); + $values = []; + + /** @var array<array-key, array<array-key, mixed>> $cache */ + if ($lazy) { + $cache = $this->lazyCache; + } else { + $cache = $this->fastCache; + } + + foreach (array_keys($cache) as $app) { + if (isset($cache[$app][$key])) { + $values[$app] = $cache[$app][$key]; + } + } + + return $values; } + /** - * Gets the config value + * Get the config value as string. + * If the value does not exist the given default will be returned. + * + * Set lazy to `null` to ignore it and get the value from either source. + * + * **WARNING:** Method is internal and **SHOULD** not be used, as it is better to get the value with a type. + * + * @param string $app id of the app + * @param string $key config key + * @param string $default config value + * @param null|bool $lazy get config as lazy loaded or not. can be NULL * - * @param string $app app - * @param string $key key - * @param string $default = null, default value if the key does not exist * @return string the value or $default + * @internal + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see getValueString() + * @see getValueInt() + * @see getValueFloat() + * @see getValueBool() + * @see getValueArray() + */ + public function getValueMixed( + string $app, + string $key, + string $default = '', + ?bool $lazy = false + ): string { + try { + $lazy = ($lazy === null) ? $this->isLazy($app, $key) : $lazy; + } catch (AppConfigUnknownKeyException $e) { + return $default; + } + + return $this->getTypedValue( + $app, + $key, + $default, + $lazy, + self::VALUE_MIXED + ); + } + + /** + * @inheritDoc * - * This function gets a value from the appconfig table. If the key does - * not exist the default value will be returned + * @param string $app id of the app + * @param string $key config key + * @param string $default default value + * @param bool $lazy search within lazy loaded config + * + * @return string stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading */ - public function getValue($app, $key, $default = null) { - $this->loadConfigValues(); + public function getValueString( + string $app, + string $key, + string $default = '', + bool $lazy = false + ): string { + return $this->getTypedValue($app, $key, $default, $lazy, self::VALUE_STRING); + } - if ($this->hasKey($app, $key)) { - return $this->cache[$app][$key]; + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param int $default default value + * @param bool $lazy search within lazy loaded config + * + * @return int stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + */ + public function getValueInt( + string $app, + string $key, + int $default = 0, + bool $lazy = false + ): int { + return (int)$this->getTypedValue($app, $key, (string)$default, $lazy, self::VALUE_INT); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param float $default default value + * @param bool $lazy search within lazy loaded config + * + * @return float stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + */ + public function getValueFloat(string $app, string $key, float $default = 0, bool $lazy = false): float { + return (float)$this->getTypedValue($app, $key, (string)$default, $lazy, self::VALUE_FLOAT); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param bool $default default value + * @param bool $lazy search within lazy loaded config + * + * @return bool stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + */ + public function getValueBool(string $app, string $key, bool $default = false, bool $lazy = false): bool { + $b = strtolower($this->getTypedValue($app, $key, $default ? 'true' : 'false', $lazy, self::VALUE_BOOL)); + return in_array($b, ['1', 'true', 'yes', 'on']); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param array $default default value + * @param bool $lazy search within lazy loaded config + * + * @return array stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + */ + public function getValueArray( + string $app, + string $key, + array $default = [], + bool $lazy = false + ): array { + try { + $defaultJson = json_encode($default, JSON_THROW_ON_ERROR); + $value = json_decode($this->getTypedValue($app, $key, $defaultJson, $lazy, self::VALUE_ARRAY), true, flags: JSON_THROW_ON_ERROR); + + return is_array($value) ? $value : []; + } catch (JsonException) { + return []; + } + } + + /** + * @param string $app id of the app + * @param string $key config key + * @param string $default default value + * @param bool $lazy search within lazy loaded config + * @param int $type value type {@see VALUE_STRING} {@see VALUE_INT}{@see VALUE_FLOAT} {@see VALUE_BOOL} {@see VALUE_ARRAY} + * + * @return string + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @throws InvalidArgumentException + */ + private function getTypedValue( + string $app, + string $key, + string $default, + bool $lazy, + int $type + ): string { + $this->assertParams($app, $key, valueType: $type); + $this->loadConfig($lazy); + + /** + * We ignore check if mixed type is requested. + * If type of stored value is set as mixed, we don't filter. + * If type of stored value is defined, we compare with the one requested. + */ + $knownType = $this->valueTypes[$app][$key] ?? 0; + if (!$this->isTyped(self::VALUE_MIXED, $type) + && $knownType > 0 + && !$this->isTyped(self::VALUE_MIXED, $knownType) + && !$this->isTyped($type, $knownType)) { + $this->logger->warning('conflict with value type from database', ['app' => $app, 'key' => $key, 'type' => $type, 'knownType' => $knownType]); + throw new AppConfigTypeConflictException('conflict with value type from database'); + } + + /** + * - the pair $app/$key cannot exist in both array, + * - we should still return an existing non-lazy value even if current method + * is called with $lazy is true + * + * This way, lazyCache will be empty until the load for lazy config value is requested. + */ + if (isset($this->lazyCache[$app][$key])) { + $value = $this->lazyCache[$app][$key]; + } elseif (isset($this->fastCache[$app][$key])) { + $value = $this->fastCache[$app][$key]; + } else { + return $default; + } + + $sensitive = $this->isTyped(self::VALUE_SENSITIVE, $knownType); + if ($sensitive && str_starts_with($value, self::ENCRYPTION_PREFIX)) { + // Only decrypt values that are stored encrypted + $value = $this->crypto->decrypt(substr($value, self::ENCRYPTION_PREFIX_LENGTH)); } - return $default; + return $value; } /** - * check if a key is set in the appconfig + * @inheritDoc * - * @param string $app - * @param string $key - * @return bool + * @param string $app id of the app + * @param string $key config key + * + * @return int type of the value + * @throws AppConfigUnknownKeyException if config key is not known + * @since 29.0.0 + * @see VALUE_STRING + * @see VALUE_INT + * @see VALUE_FLOAT + * @see VALUE_BOOL + * @see VALUE_ARRAY */ - public function hasKey($app, $key) { - $this->loadConfigValues(); + public function getValueType(string $app, string $key): int { + $this->assertParams($app, $key); + $this->loadConfigAll(); - return isset($this->cache[$app][$key]); + if (!isset($this->valueTypes[$app][$key])) { + throw new AppConfigUnknownKeyException('unknown config key'); + } + + $type = $this->valueTypes[$app][$key]; + $type &= ~self::VALUE_SENSITIVE; + return $type; } + /** - * Sets a value. If the key did not exist before it will be created. + * Store a config key and its value in database as VALUE_MIXED * - * @param string $app app - * @param string $key key - * @param string|float|int $value value - * @return bool True if the value was inserted or updated, false if the value was the same + * **WARNING:** Method is internal and **MUST** not be used as it is best to set a real value type + * + * @param string $app id of the app + * @param string $key config key + * @param string $value config value + * @param bool $lazy set config as lazy loaded + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED + * @internal + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see setValueString() + * @see setValueInt() + * @see setValueFloat() + * @see setValueBool() + * @see setValueArray() */ - public function setValue($app, $key, $value) { - if (!$this->hasKey($app, $key)) { - $inserted = (bool) $this->conn->insertIfNotExist('*PREFIX*appconfig', [ - 'appid' => $app, - 'configkey' => $key, - 'configvalue' => $value, - ], [ - 'appid', - 'configkey', - ]); - - if ($inserted) { - if (!isset($this->cache[$app])) { - $this->cache[$app] = []; - } + public function setValueMixed( + string $app, + string $key, + string $value, + bool $lazy = false, + bool $sensitive = false + ): bool { + return $this->setTypedValue( + $app, + $key, + $value, + $lazy, + self::VALUE_MIXED | ($sensitive ? self::VALUE_SENSITIVE : 0) + ); + } - $this->cache[$app][$key] = $value; - return true; - } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param string $value config value + * @param bool $lazy set config as lazy loaded + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + */ + public function setValueString( + string $app, + string $key, + string $value, + bool $lazy = false, + bool $sensitive = false + ): bool { + return $this->setTypedValue( + $app, + $key, + $value, + $lazy, + self::VALUE_STRING | ($sensitive ? self::VALUE_SENSITIVE : 0) + ); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param int $value config value + * @param bool $lazy set config as lazy loaded + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + */ + public function setValueInt( + string $app, + string $key, + int $value, + bool $lazy = false, + bool $sensitive = false + ): bool { + if ($value > 2000000000) { + $this->logger->debug('You are trying to store an integer value around/above 2,147,483,647. This is a reminder that reaching this theoretical limit on 32 bits system will throw an exception.'); + } + + return $this->setTypedValue( + $app, + $key, + (string)$value, + $lazy, + self::VALUE_INT | ($sensitive ? self::VALUE_SENSITIVE : 0) + ); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param float $value config value + * @param bool $lazy set config as lazy loaded + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + */ + public function setValueFloat( + string $app, + string $key, + float $value, + bool $lazy = false, + bool $sensitive = false + ): bool { + return $this->setTypedValue( + $app, + $key, + (string)$value, + $lazy, + self::VALUE_FLOAT | ($sensitive ? self::VALUE_SENSITIVE : 0) + ); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param bool $value config value + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + */ + public function setValueBool( + string $app, + string $key, + bool $value, + bool $lazy = false + ): bool { + return $this->setTypedValue( + $app, + $key, + ($value) ? '1' : '0', + $lazy, + self::VALUE_BOOL + ); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * @param array $value config value + * @param bool $lazy set config as lazy loaded + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @throws JsonException + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + */ + public function setValueArray( + string $app, + string $key, + array $value, + bool $lazy = false, + bool $sensitive = false + ): bool { + try { + return $this->setTypedValue( + $app, + $key, + json_encode($value, JSON_THROW_ON_ERROR), + $lazy, + self::VALUE_ARRAY | ($sensitive ? self::VALUE_SENSITIVE : 0) + ); + } catch (JsonException $e) { + $this->logger->warning('could not setValueArray', ['app' => $app, 'key' => $key, 'exception' => $e]); + throw $e; } + } - $sql = $this->conn->getQueryBuilder(); - $sql->update('appconfig') - ->set('configvalue', $sql->createNamedParameter($value)) - ->where($sql->expr()->eq('appid', $sql->createNamedParameter($app))) - ->andWhere($sql->expr()->eq('configkey', $sql->createNamedParameter($key))); + /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value and same sensitive/lazy status, the + * database is not updated. If config value was previously stored as sensitive, status will not be + * altered. + * + * @param string $app id of the app + * @param string $key config key + * @param string $value config value + * @param bool $lazy config set as lazy loaded + * @param int $type value type {@see VALUE_STRING} {@see VALUE_INT} {@see VALUE_FLOAT} {@see VALUE_BOOL} {@see VALUE_ARRAY} + * + * @return bool TRUE if value was updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @see IAppConfig for explanation about lazy loading + */ + private function setTypedValue( + string $app, + string $key, + string $value, + bool $lazy, + int $type + ): bool { + $this->assertParams($app, $key); + $this->loadConfig($lazy); + + $sensitive = $this->isTyped(self::VALUE_SENSITIVE, $type); + $inserted = $refreshCache = false; + + if ($sensitive || ($this->hasKey($app, $key, $lazy) && $this->isSensitive($app, $key, $lazy))) { + $value = self::ENCRYPTION_PREFIX . $this->crypto->encrypt($value); + } - /* - * Only limit to the existing value for non-Oracle DBs: - * http://docs.oracle.com/cd/E11882_01/server.112/e26088/conditions002.htm#i1033286 - * > Large objects (LOBs) are not supported in comparison conditions. + if ($this->hasKey($app, $key, $lazy)) { + /** + * no update if key is already known with set lazy status and value is + * not different, unless sensitivity is switched from false to true. + */ + if ($value === $this->getTypedValue($app, $key, $value, $lazy, $type) + && (!$sensitive || $this->isSensitive($app, $key, $lazy))) { + return false; + } + } else { + /** + * if key is not known yet, we try to insert. + * It might fail if the key exists with a different lazy flag. + */ + try { + $insert = $this->connection->getQueryBuilder(); + $insert->insert('appconfig') + ->setValue('appid', $insert->createNamedParameter($app)) + ->setValue('lazy', $insert->createNamedParameter(($lazy) ? 1 : 0, IQueryBuilder::PARAM_INT)) + ->setValue('type', $insert->createNamedParameter($type, IQueryBuilder::PARAM_INT)) + ->setValue('configkey', $insert->createNamedParameter($key)) + ->setValue('configvalue', $insert->createNamedParameter($value)); + $insert->executeStatement(); + $inserted = true; + } catch (DBException $e) { + if ($e->getReason() !== DBException::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + throw $e; // TODO: throw exception or just log and returns false !? + } + } + } + + /** + * We cannot insert a new row, meaning we need to update an already existing one */ - if (!($this->conn instanceof OracleConnection)) { - /* - * Only update the value when it is not the same - * Note that NULL requires some special handling. Since comparing - * against null can have special results. + if (!$inserted) { + $currType = $this->valueTypes[$app][$key] ?? 0; + if ($currType === 0) { // this might happen when switching lazy loading status + $this->loadConfigAll(); + $currType = $this->valueTypes[$app][$key] ?? 0; + } + + /** + * This should only happen during the upgrade process from 28 to 29. + * We only log a warning and set it to VALUE_MIXED. */ + if ($currType === 0) { + $this->logger->warning('Value type is set to zero (0) in database. This is fine only during the upgrade process from 28 to 29.', ['app' => $app, 'key' => $key]); + $currType = self::VALUE_MIXED; + } - if ($value === null) { - $sql->andWhere( - $sql->expr()->isNotNull('configvalue') - ); - } else { - $sql->andWhere( - $sql->expr()->orX( - $sql->expr()->isNull('configvalue'), - $sql->expr()->neq('configvalue', $sql->createNamedParameter($value), IQueryBuilder::PARAM_STR) - ) - ); + /** + * 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)) { + try { + $currType = $this->convertTypeToString($currType); + $type = $this->convertTypeToString($type); + } catch (AppConfigIncorrectTypeException) { + // can be ignored, this was just needed for a better exception message. + } + throw new AppConfigTypeConflictException('conflict between new type (' . $type . ') and old type (' . $currType . ')'); + } + + // we fix $type if the stored value, or the new value as it might be changed, is set as sensitive + if ($sensitive || $this->isTyped(self::VALUE_SENSITIVE, $currType)) { + $type |= self::VALUE_SENSITIVE; } + + if ($lazy !== $this->isLazy($app, $key)) { + $refreshCache = true; + } + + $update = $this->connection->getQueryBuilder(); + $update->update('appconfig') + ->set('configvalue', $update->createNamedParameter($value)) + ->set('lazy', $update->createNamedParameter(($lazy) ? 1 : 0, IQueryBuilder::PARAM_INT)) + ->set('type', $update->createNamedParameter($type, IQueryBuilder::PARAM_INT)) + ->where($update->expr()->eq('appid', $update->createNamedParameter($app))) + ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key))); + + $update->executeStatement(); } - $changedRow = (bool) $sql->execute(); + if ($refreshCache) { + $this->clearCache(); + return true; + } - $this->cache[$app][$key] = $value; + // update local cache + if ($lazy) { + $cache = &$this->lazyCache; + } else { + $cache = &$this->fastCache; + } + $cache[$app][$key] = $value; + $this->valueTypes[$app][$key] = $type; - return $changedRow; + return true; } /** - * Deletes a key + * Change the type of config value. * - * @param string $app app - * @param string $key key - * @return boolean + * **WARNING:** Method is internal and **MUST** not be used as it may break things. + * + * @param string $app id of the app + * @param string $key config key + * @param int $type value type {@see VALUE_STRING} {@see VALUE_INT} {@see VALUE_FLOAT} {@see VALUE_BOOL} {@see VALUE_ARRAY} + * + * @return bool TRUE if database update were necessary + * @throws AppConfigUnknownKeyException if $key is now known in database + * @throws AppConfigIncorrectTypeException if $type is not valid + * @internal + * @since 29.0.0 */ - public function deleteKey($app, $key) { - $this->loadConfigValues(); + public function updateType(string $app, string $key, int $type = self::VALUE_MIXED): bool { + $this->assertParams($app, $key); + $this->loadConfigAll(); + $lazy = $this->isLazy($app, $key); - $sql = $this->conn->getQueryBuilder(); - $sql->delete('appconfig') - ->where($sql->expr()->eq('appid', $sql->createParameter('app'))) - ->andWhere($sql->expr()->eq('configkey', $sql->createParameter('configkey'))) - ->setParameter('app', $app) - ->setParameter('configkey', $key); - $sql->execute(); + // 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])) { + throw new AppConfigIncorrectTypeException('Unknown value type'); + } - unset($this->cache[$app][$key]); - return false; + $currType = $this->valueTypes[$app][$key]; + if (($type | self::VALUE_SENSITIVE) === ($currType | self::VALUE_SENSITIVE)) { + return false; + } + + // we complete with sensitive flag if the stored value is set as sensitive + if ($this->isTyped(self::VALUE_SENSITIVE, $currType)) { + $type = $type | self::VALUE_SENSITIVE; + } + + $update = $this->connection->getQueryBuilder(); + $update->update('appconfig') + ->set('type', $update->createNamedParameter($type, IQueryBuilder::PARAM_INT)) + ->where($update->expr()->eq('appid', $update->createNamedParameter($app))) + ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key))); + $update->executeStatement(); + $this->valueTypes[$app][$key] = $type; + + return true; } + /** - * Remove app from appconfig + * @inheritDoc * - * @param string $app app - * @return boolean + * @param string $app id of the app + * @param string $key config key + * @param bool $sensitive TRUE to set as sensitive, FALSE to unset * - * Removes all keys in appconfig belonging to the app. + * @return bool TRUE if entry was found in database and an update was necessary + * @since 29.0.0 */ - public function deleteApp($app) { - $this->loadConfigValues(); + public function updateSensitive(string $app, string $key, bool $sensitive): bool { + $this->assertParams($app, $key); + $this->loadConfigAll(); + + try { + if ($sensitive === $this->isSensitive($app, $key, null)) { + return false; + } + } catch (AppConfigUnknownKeyException $e) { + return false; + } - $sql = $this->conn->getQueryBuilder(); - $sql->delete('appconfig') - ->where($sql->expr()->eq('appid', $sql->createParameter('app'))) - ->setParameter('app', $app); - $sql->execute(); + $lazy = $this->isLazy($app, $key); + if ($lazy) { + $cache = $this->lazyCache; + } else { + $cache = $this->fastCache; + } - unset($this->cache[$app]); - return false; + if (!isset($cache[$app][$key])) { + throw new AppConfigUnknownKeyException('unknown config key'); + } + + /** + * type returned by getValueType() is already cleaned from sensitive flag + * we just need to update it based on $sensitive and store it in database + */ + $type = $this->getValueType($app, $key); + $value = $cache[$app][$key]; + if ($sensitive) { + $type |= self::VALUE_SENSITIVE; + $value = self::ENCRYPTION_PREFIX . $this->crypto->encrypt($value); + } else { + $value = $this->crypto->decrypt(substr($value, self::ENCRYPTION_PREFIX_LENGTH)); + } + + $update = $this->connection->getQueryBuilder(); + $update->update('appconfig') + ->set('type', $update->createNamedParameter($type, IQueryBuilder::PARAM_INT)) + ->set('configvalue', $update->createNamedParameter($value)) + ->where($update->expr()->eq('appid', $update->createNamedParameter($app))) + ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key))); + $update->executeStatement(); + + $this->valueTypes[$app][$key] = $type; + + return true; } /** - * get multiple values, either the app or key can be used as wildcard by setting it to false + * @inheritDoc * - * @param string|false $app - * @param string|false $key - * @return array|false + * @param string $app id of the app + * @param string $key config key + * @param bool $lazy TRUE to set as lazy loaded, FALSE to unset + * + * @return bool TRUE if entry was found in database and an update was necessary + * @since 29.0.0 */ - public function getValues($app, $key) { - if (($app !== false) === ($key !== false)) { + public function updateLazy(string $app, string $key, bool $lazy): bool { + $this->assertParams($app, $key); + $this->loadConfigAll(); + + try { + if ($lazy === $this->isLazy($app, $key)) { + return false; + } + } catch (AppConfigUnknownKeyException $e) { return false; } - if ($key === false) { - return $this->getAppValues($app); + $update = $this->connection->getQueryBuilder(); + $update->update('appconfig') + ->set('lazy', $update->createNamedParameter($lazy ? 1 : 0, IQueryBuilder::PARAM_INT)) + ->where($update->expr()->eq('appid', $update->createNamedParameter($app))) + ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key))); + $update->executeStatement(); + + // At this point, it is a lot safer to clean cache + $this->clearCache(); + + return true; + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * + * @return array + * @throws AppConfigUnknownKeyException if config key is not known in database + * @since 29.0.0 + */ + public function getDetails(string $app, string $key): array { + $this->assertParams($app, $key); + $this->loadConfigAll(); + $lazy = $this->isLazy($app, $key); + + if ($lazy) { + $cache = $this->lazyCache; } else { - $appIds = $this->getApps(); - $values = array_map(function ($appId) use ($key) { - return isset($this->cache[$appId][$key]) ? $this->cache[$appId][$key] : null; - }, $appIds); - $result = array_combine($appIds, $values); + $cache = $this->fastCache; + } - return array_filter($result); + $type = $this->getValueType($app, $key); + try { + $typeString = $this->convertTypeToString($type); + } catch (AppConfigIncorrectTypeException $e) { + $this->logger->warning('type stored in database is not correct', ['exception' => $e, 'type' => $type]); + $typeString = (string)$type; } + + if (!isset($cache[$app][$key])) { + throw new AppConfigUnknownKeyException('unknown config key'); + } + + return [ + 'app' => $app, + 'key' => $key, + 'value' => $cache[$app][$key], + 'type' => $type, + 'lazy' => $lazy, + 'typeString' => $typeString, + 'sensitive' => $this->isSensitive($app, $key, null) + ]; } /** - * get all values of the app or and filters out sensitive data + * @param string $type + * + * @return int + * @throws AppConfigIncorrectTypeException + * @since 29.0.0 + */ + public function convertTypeToInt(string $type): int { + return match (strtolower($type)) { + 'mixed' => IAppConfig::VALUE_MIXED, + 'string' => IAppConfig::VALUE_STRING, + 'integer' => IAppConfig::VALUE_INT, + 'float' => IAppConfig::VALUE_FLOAT, + 'boolean' => IAppConfig::VALUE_BOOL, + 'array' => IAppConfig::VALUE_ARRAY, + default => throw new AppConfigIncorrectTypeException('Unknown type ' . $type) + }; + } + + /** + * @param int $type + * + * @return string + * @throws AppConfigIncorrectTypeException + * @since 29.0.0 + */ + public function convertTypeToString(int $type): string { + $type &= ~self::VALUE_SENSITIVE; + + return match ($type) { + IAppConfig::VALUE_MIXED => 'mixed', + IAppConfig::VALUE_STRING => 'string', + IAppConfig::VALUE_INT => 'integer', + IAppConfig::VALUE_FLOAT => 'float', + IAppConfig::VALUE_BOOL => 'boolean', + IAppConfig::VALUE_ARRAY => 'array', + default => throw new AppConfigIncorrectTypeException('Unknown numeric type ' . $type) + }; + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * @param string $key config key + * + * @since 29.0.0 + */ + public function deleteKey(string $app, string $key): void { + $this->assertParams($app, $key); + $qb = $this->connection->getQueryBuilder(); + $qb->delete('appconfig') + ->where($qb->expr()->eq('appid', $qb->createNamedParameter($app))) + ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key))); + $qb->executeStatement(); + + unset($this->lazyCache[$app][$key]); + unset($this->fastCache[$app][$key]); + } + + /** + * @inheritDoc + * + * @param string $app id of the app + * + * @since 29.0.0 + */ + public function deleteApp(string $app): void { + $this->assertParams($app); + $qb = $this->connection->getQueryBuilder(); + $qb->delete('appconfig') + ->where($qb->expr()->eq('appid', $qb->createNamedParameter($app))); + $qb->executeStatement(); + + $this->clearCache(); + } + + /** + * @inheritDoc + * + * @param bool $reload set to TRUE to refill cache instantly after clearing it + * + * @since 29.0.0 + */ + public function clearCache(bool $reload = false): void { + $this->lazyLoaded = $this->fastLoaded = false; + $this->lazyCache = $this->fastCache = $this->valueTypes = []; + + if (!$reload) { + return; + } + + $this->loadConfigAll(); + } + + + /** + * For debug purpose. + * Returns the cached data. * - * @param string $app * @return array + * @since 29.0.0 + * @internal */ - public function getFilteredValues($app) { - $values = $this->getValues($app, false); + public function statusCache(): array { + return [ + 'fastLoaded' => $this->fastLoaded, + 'fastCache' => $this->fastCache, + 'lazyLoaded' => $this->lazyLoaded, + 'lazyCache' => $this->lazyCache, + ]; + } - if (isset($this->sensitiveValues[$app])) { - foreach ($this->sensitiveValues[$app] as $sensitiveKeyExp) { - $sensitiveKeys = preg_grep($sensitiveKeyExp, array_keys($values)); - foreach ($sensitiveKeys as $sensitiveKey) { - $values[$sensitiveKey] = IConfig::SENSITIVE_VALUE; - } + /** + * @param int $needle bitflag to search + * @param int $type known value + * + * @return bool TRUE if bitflag $needle is set in $type + */ + private function isTyped(int $needle, int $type): bool { + return (($needle & $type) !== 0); + } + + /** + * Confirm the string set for app and key fit the database description + * + * @param string $app assert $app fit in database + * @param string $configKey assert config key fit in database + * @param bool $allowEmptyApp $app can be empty string + * @param int $valueType assert value type is only one type + * + * @throws InvalidArgumentException + */ + private function assertParams(string $app = '', string $configKey = '', bool $allowEmptyApp = false, int $valueType = -1): void { + if (!$allowEmptyApp && $app === '') { + throw new InvalidArgumentException('app cannot be an empty string'); + } + if (strlen($app) > self::APP_MAX_LENGTH) { + throw new InvalidArgumentException( + 'Value (' . $app . ') for app is too long (' . self::APP_MAX_LENGTH . ')' + ); + } + if (strlen($configKey) > self::KEY_MAX_LENGTH) { + throw new InvalidArgumentException('Value (' . $configKey . ') for key is too long (' . self::KEY_MAX_LENGTH . ')'); + } + if ($valueType > -1) { + $valueType &= ~self::VALUE_SENSITIVE; + if (!in_array($valueType, [self::VALUE_MIXED, self::VALUE_STRING, self::VALUE_INT, self::VALUE_FLOAT, self::VALUE_BOOL, self::VALUE_ARRAY])) { + throw new InvalidArgumentException('Unknown value type'); } } + } - return $values; + private function loadConfigAll(): void { + $this->loadConfig(null); } /** - * Load all the app config values + * Load normal config or config set as lazy loaded + * + * @param bool|null $lazy set to TRUE to load config set as lazy loaded, set to NULL to load all config */ - protected function loadConfigValues() { - if ($this->configLoaded) { + private function loadConfig(?bool $lazy = false): void { + if ($this->isLoaded($lazy)) { return; } - $this->cache = []; + if (($lazy ?? true) !== false) { // if lazy is null or true, we debug log + $this->logger->debug('The loading of lazy AppConfig values have been requested', ['exception' => new \RuntimeException('ignorable exception')]); + } + + $qb = $this->connection->getQueryBuilder(); + $qb->from('appconfig'); + + /** + * The use of $this->>migrationCompleted is only needed to manage the + * database during the upgrading process to nc29. + */ + if (!$this->migrationCompleted) { + $qb->select('appid', 'configkey', 'configvalue'); + } else { + // we only need value from lazy when loadConfig does not specify it + $qb->select('appid', 'configkey', 'configvalue', 'type'); + + if ($lazy !== null) { + $qb->where($qb->expr()->eq('lazy', $qb->createNamedParameter($lazy ? 1 : 0, IQueryBuilder::PARAM_INT))); + } else { + $qb->addSelect('lazy'); + } + } + + try { + $result = $qb->executeQuery(); + } catch (DBException $e) { + /** + * in case of issue with field name, it means that migration is not completed. + * Falling back to a request without select on lazy. + * This whole try/catch and the migrationCompleted variable can be removed in NC30. + */ + if ($e->getReason() !== DBException::REASON_INVALID_FIELD_NAME) { + throw $e; + } + + $this->migrationCompleted = false; + $this->loadConfig($lazy); - $sql = $this->conn->getQueryBuilder(); - $sql->select('*') - ->from('appconfig'); - $result = $sql->execute(); + return; + } - // we are going to store the result in memory anyway $rows = $result->fetchAll(); foreach ($rows as $row) { - if (!isset($this->cache[$row['appid']])) { - $this->cache[(string)$row['appid']] = []; + // most of the time, 'lazy' is not in the select because its value is already known + if (($row['lazy'] ?? ($lazy ?? 0) ? 1 : 0) === 1) { + $cache = &$this->lazyCache; + } else { + $cache = &$this->fastCache; } - - $this->cache[(string)$row['appid']][(string)$row['configkey']] = (string)$row['configvalue']; + $cache[$row['appid']][$row['configkey']] = $row['configvalue'] ?? ''; + $this->valueTypes[$row['appid']][$row['configkey']] = (int)($row['type'] ?? 0); } $result->closeCursor(); + $this->setAsLoaded($lazy); + } + + /** + * if $lazy is: + * - false: will returns true if fast config is loaded + * - true : will returns true if lazy config is loaded + * - null : will returns true if both config are loaded + * + * @param bool $lazy + * + * @return bool + */ + private function isLoaded(?bool $lazy): bool { + if ($lazy === null) { + return $this->lazyLoaded && $this->fastLoaded; + } + + return $lazy ? $this->lazyLoaded : $this->fastLoaded; + } + + /** + * if $lazy is: + * - false: set fast config as loaded + * - true : set lazy config as loaded + * - null : set both config as loaded + * + * @param bool $lazy + */ + private function setAsLoaded(?bool $lazy): void { + if ($lazy === null) { + $this->fastLoaded = true; + $this->lazyLoaded = true; + + return; + } + + if ($lazy) { + $this->lazyLoaded = true; + } else { + $this->fastLoaded = true; + } + } + + /** + * Gets the config value + * + * @param string $app app + * @param string $key key + * @param string $default = null, default value if the key does not exist + * + * @return string the value or $default + * @deprecated - use getValue*() + * + * This function gets a value from the appconfig table. If the key does + * not exist the default value will be returned + */ + public function getValue($app, $key, $default = null) { + $this->loadConfig(); - $this->configLoaded = true; + return $this->fastCache[$app][$key] ?? $default; + } + + /** + * Sets a value. If the key did not exist before it will be created. + * + * @param string $app app + * @param string $key key + * @param string|float|int $value value + * + * @return bool True if the value was inserted or updated, false if the value was the same + * @throws AppConfigTypeConflictException + * @throws AppConfigUnknownKeyException + * @deprecated + */ + public function setValue($app, $key, $value) { + /** + * TODO: would it be overkill, or decently improve performance, to catch + * call to this method with $key='enabled' and 'hide' config value related + * to $app when the app is disabled (by modifying entry in database: lazy=lazy+2) + * or enabled (lazy=lazy-2) + * + * this solution would remove the loading of config values from disabled app + * unless calling the method {@see loadConfigAll()} + */ + return $this->setTypedValue($app, $key, (string)$value, false, self::VALUE_MIXED); } /** + * get multiple values, either the app or key can be used as wildcard by setting it to false + * + * @param string|false $app + * @param string|false $key + * + * @return array|false + * @deprecated 29.0.0 use {@see getAllValues()} + */ + public function getValues($app, $key) { + if (($app !== false) === ($key !== false)) { + return false; + } + + $key = ($key === false) ? '' : $key; + if (!$app) { + return $this->searchValues($key); + } else { + return $this->getAllValues($app, $key); + } + } + + /** + * get all values of the app or and filters out sensitive data + * + * @param string $app + * + * @return array + * @deprecated 29.0.0 use {@see getAllValues()} + */ + public function getFilteredValues($app) { + return $this->getAllValues($app, filtered: true); + } + + /** + * @param string $app + * + * @return string[] + * @deprecated data sensitivity should be set when calling setValue*() + */ + private function getSensitiveKeys(string $app): array { + $sensitiveValues = [ + 'circles' => [ + '/^key_pairs$/', + '/^local_gskey$/', + ], + 'external' => [ + '/^sites$/', + ], + 'integration_discourse' => [ + '/^private_key$/', + '/^public_key$/', + ], + 'integration_dropbox' => [ + '/^client_id$/', + '/^client_secret$/', + ], + 'integration_github' => [ + '/^client_id$/', + '/^client_secret$/', + ], + 'integration_gitlab' => [ + '/^client_id$/', + '/^client_secret$/', + '/^oauth_instance_url$/', + ], + 'integration_google' => [ + '/^client_id$/', + '/^client_secret$/', + ], + 'integration_jira' => [ + '/^client_id$/', + '/^client_secret$/', + '/^forced_instance_url$/', + ], + 'integration_onedrive' => [ + '/^client_id$/', + '/^client_secret$/', + ], + 'integration_openproject' => [ + '/^client_id$/', + '/^client_secret$/', + '/^oauth_instance_url$/', + ], + 'integration_reddit' => [ + '/^client_id$/', + '/^client_secret$/', + ], + 'integration_suitecrm' => [ + '/^client_id$/', + '/^client_secret$/', + '/^oauth_instance_url$/', + ], + 'integration_twitter' => [ + '/^consumer_key$/', + '/^consumer_secret$/', + '/^followed_user$/', + ], + 'integration_zammad' => [ + '/^client_id$/', + '/^client_secret$/', + '/^oauth_instance_url$/', + ], + 'notify_push' => [ + '/^cookie$/', + ], + 'serverinfo' => [ + '/^token$/', + ], + 'spreed' => [ + '/^bridge_bot_password$/', + '/^hosted-signaling-server-(.*)$/', + '/^recording_servers$/', + '/^signaling_servers$/', + '/^signaling_ticket_secret$/', + '/^signaling_token_privkey_(.*)$/', + '/^signaling_token_pubkey_(.*)$/', + '/^sip_bridge_dialin_info$/', + '/^sip_bridge_shared_secret$/', + '/^stun_servers$/', + '/^turn_servers$/', + '/^turn_server_secret$/', + ], + 'support' => [ + '/^last_response$/', + '/^potential_subscription_key$/', + '/^subscription_key$/', + ], + 'theming' => [ + '/^imprintUrl$/', + '/^privacyUrl$/', + '/^slogan$/', + '/^url$/', + ], + 'user_ldap' => [ + '/^(s..)?ldap_agent_password$/', + ], + 'user_saml' => [ + '/^idp-x509cert$/', + ], + ]; + + return $sensitiveValues[$app] ?? []; + } + + /** * Clear all the cached app config values * New cache will be generated next time a config value is retrieved + * + * @deprecated use {@see clearCache()} */ public function clearCachedConfig(): void { - $this->configLoaded = false; + $this->clearCache(); } } diff --git a/lib/private/AppFramework/App.php b/lib/private/AppFramework/App.php index ffd77da888e..b18c95a2f0d 100644 --- a/lib/private/AppFramework/App.php +++ b/lib/private/AppFramework/App.php @@ -34,16 +34,16 @@ namespace OC\AppFramework; use OC\AppFramework\DependencyInjection\DIContainer; use OC\AppFramework\Http\Dispatcher; use OC\AppFramework\Http\Request; -use OCP\App\IAppManager; -use OCP\Profiler\IProfiler; use OC\Profiler\RoutingDataCollector; -use OCP\AppFramework\QueryException; +use OCP\App\IAppManager; use OCP\AppFramework\Http; use OCP\AppFramework\Http\ICallbackResponse; use OCP\AppFramework\Http\IOutput; +use OCP\AppFramework\QueryException; use OCP\Diagnostics\IEventLogger; use OCP\HintException; use OCP\IRequest; +use OCP\Profiler\IProfiler; /** * Entry point for every request in your app. You can consider this as your @@ -257,7 +257,7 @@ class App { * @param DIContainer $container an instance of a pimple container. */ public static function part(string $controllerName, string $methodName, array $urlParams, - DIContainer $container) { + DIContainer $container) { $container['urlParams'] = $urlParams; $controller = $container[$controllerName]; diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php index f41b734a25b..8526a3dc1a1 100644 --- a/lib/private/AppFramework/Bootstrap/Coordinator.php +++ b/lib/private/AppFramework/Bootstrap/Coordinator.php @@ -30,20 +30,20 @@ declare(strict_types=1); namespace OC\AppFramework\Bootstrap; -use OCP\Diagnostics\IEventLogger; -use function class_exists; -use function class_implements; -use function in_array; -use OC_App; use OC\Support\CrashReport\Registry; +use OC_App; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\QueryException; use OCP\Dashboard\IManager; +use OCP\Diagnostics\IEventLogger; use OCP\EventDispatcher\IEventDispatcher; use OCP\IServerContainer; use Psr\Log\LoggerInterface; use Throwable; +use function class_exists; +use function class_implements; +use function in_array; class Coordinator { /** @var IServerContainer */ diff --git a/lib/private/AppFramework/Bootstrap/EventListenerRegistration.php b/lib/private/AppFramework/Bootstrap/EventListenerRegistration.php index 2ad410be26f..12801e62763 100644 --- a/lib/private/AppFramework/Bootstrap/EventListenerRegistration.php +++ b/lib/private/AppFramework/Bootstrap/EventListenerRegistration.php @@ -37,9 +37,9 @@ class EventListenerRegistration extends ServiceRegistration { private $priority; public function __construct(string $appId, - string $event, - string $service, - int $priority) { + string $event, + string $service, + int $priority) { parent::__construct($appId, $service); $this->event = $event; $this->priority = $priority; diff --git a/lib/private/AppFramework/Bootstrap/ParameterRegistration.php b/lib/private/AppFramework/Bootstrap/ParameterRegistration.php index b501a757abd..958f24cb600 100644 --- a/lib/private/AppFramework/Bootstrap/ParameterRegistration.php +++ b/lib/private/AppFramework/Bootstrap/ParameterRegistration.php @@ -36,8 +36,8 @@ final class ParameterRegistration extends ARegistration { private $value; public function __construct(string $appId, - string $name, - $value) { + string $name, + $value) { parent::__construct($appId); $this->name = $name; $this->value = $value; diff --git a/lib/private/AppFramework/Bootstrap/PreviewProviderRegistration.php b/lib/private/AppFramework/Bootstrap/PreviewProviderRegistration.php index 36c5cae7db3..e4d75f75bc8 100644 --- a/lib/private/AppFramework/Bootstrap/PreviewProviderRegistration.php +++ b/lib/private/AppFramework/Bootstrap/PreviewProviderRegistration.php @@ -34,8 +34,8 @@ class PreviewProviderRegistration extends ServiceRegistration { private $mimeTypeRegex; public function __construct(string $appId, - string $service, - string $mimeTypeRegex) { + string $service, + string $mimeTypeRegex) { parent::__construct($appId, $service); $this->mimeTypeRegex = $mimeTypeRegex; } diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php index 5aea2a7a744..b1b2c57da55 100644 --- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -30,15 +30,6 @@ declare(strict_types=1); namespace OC\AppFramework\Bootstrap; use Closure; -use OCP\Calendar\Resource\IBackend as IResourceBackend; -use OCP\Calendar\Room\IBackend as IRoomBackend; -use OCP\Collaboration\Reference\IReferenceProvider; -use OCP\TextProcessing\IProvider as ITextProcessingProvider; -use OCP\SpeechToText\ISpeechToTextProvider; -use OCP\Talk\ITalkBackend; -use OCP\Translation\ITranslationProvider; -use RuntimeException; -use function array_shift; use OC\Support\CrashReport\Registry; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IRegistrationContext; @@ -46,7 +37,10 @@ use OCP\AppFramework\Middleware; use OCP\AppFramework\Services\InitialStateProvider; use OCP\Authentication\IAlternativeLogin; use OCP\Calendar\ICalendarProvider; +use OCP\Calendar\Resource\IBackend as IResourceBackend; +use OCP\Calendar\Room\IBackend as IRoomBackend; use OCP\Capabilities\ICapability; +use OCP\Collaboration\Reference\IReferenceProvider; use OCP\Dashboard\IManager; use OCP\Dashboard\IWidget; use OCP\EventDispatcher\IEventDispatcher; @@ -55,11 +49,20 @@ use OCP\Http\WellKnown\IHandler; use OCP\Notification\INotifier; use OCP\Profile\ILinkAction; use OCP\Search\IProvider; +use OCP\Settings\IDeclarativeSettingsForm; +use OCP\SetupCheck\ISetupCheck; use OCP\Share\IPublicShareTemplateProvider; +use OCP\SpeechToText\ISpeechToTextProvider; use OCP\Support\CrashReport\IReporter; +use OCP\Talk\ITalkBackend; +use OCP\Teams\ITeamResourceProvider; +use OCP\TextProcessing\IProvider as ITextProcessingProvider; +use OCP\Translation\ITranslationProvider; use OCP\UserMigration\IMigrator as IUserMigrator; use Psr\Log\LoggerInterface; +use RuntimeException; use Throwable; +use function array_shift; class RegistrationContext { /** @var ServiceRegistration<ICapability>[] */ @@ -137,8 +140,8 @@ class RegistrationContext { /** @var ServiceRegistration<IReferenceProvider>[] */ private array $referenceProviders = []; - - + /** @var ServiceRegistration<\OCP\TextToImage\IProvider>[] */ + private $textToImageProviders = []; /** @var ParameterRegistration[] */ private $sensitiveMethods = []; @@ -146,11 +149,19 @@ class RegistrationContext { /** @var ServiceRegistration<IPublicShareTemplateProvider>[] */ private $publicShareTemplateProviders = []; - /** @var LoggerInterface */ - private $logger; + private LoggerInterface $logger; + + /** @var ServiceRegistration<ISetupCheck>[] */ + private array $setupChecks = []; /** @var PreviewProviderRegistration[] */ - private $previewProviders = []; + private array $previewProviders = []; + + /** @var ServiceRegistration<IDeclarativeSettingsForm>[] */ + private array $declarativeSettings = []; + + /** @var ServiceRegistration<ITeamResourceProvider>[] */ + private array $teamResourceProviders = []; public function __construct(LoggerInterface $logger) { $this->logger = $logger; @@ -273,6 +284,13 @@ class RegistrationContext { ); } + public function registerTextToImageProvider(string $providerClass): void { + $this->context->registerTextToImageProvider( + $this->appId, + $providerClass + ); + } + public function registerTemplateProvider(string $providerClass): void { $this->context->registerTemplateProvider( $this->appId, @@ -344,6 +362,13 @@ class RegistrationContext { ); } + public function registerTeamResourceProvider(string $class) : void { + $this->context->registerTeamResourceProvider( + $this->appId, + $class + ); + } + public function registerCalendarRoomBackend(string $class): void { $this->context->registerCalendarRoomBackend( $this->appId, @@ -372,6 +397,20 @@ class RegistrationContext { $class ); } + + public function registerSetupCheck(string $setupCheckClass): void { + $this->context->registerSetupCheck( + $this->appId, + $setupCheckClass + ); + } + + public function registerDeclarativeSettings(string $declarativeSettingsClass): void { + $this->context->registerDeclarativeSettings( + $this->appId, + $declarativeSettingsClass + ); + } }; } @@ -383,14 +422,14 @@ class RegistrationContext { } /** - * @psalm-param class-string<IReporter> $capability + * @psalm-param class-string<IReporter> $reporterClass */ public function registerCrashReporter(string $appId, string $reporterClass): void { $this->crashReporters[] = new ServiceRegistration($appId, $reporterClass); } /** - * @psalm-param class-string<IWidget> $capability + * @psalm-param class-string<IWidget> $panelClass */ public function registerDashboardPanel(string $appId, string $panelClass): void { $this->dashboardPanels[] = new ServiceRegistration($appId, $panelClass); @@ -443,6 +482,10 @@ class RegistrationContext { $this->textProcessingProviders[] = new ServiceRegistration($appId, $class); } + public function registerTextToImageProvider(string $appId, string $class): void { + $this->textToImageProviders[] = new ServiceRegistration($appId, $class); + } + public function registerTemplateProvider(string $appId, string $class): void { $this->templateProviders[] = new ServiceRegistration($appId, $class); } @@ -508,6 +551,16 @@ class RegistrationContext { } /** + * @psalm-param class-string<ITeamResourceProvider> $class + */ + public function registerTeamResourceProvider(string $appId, string $class) { + $this->teamResourceProviders[] = new ServiceRegistration( + $appId, + $class + ); + } + + /** * @psalm-param class-string<IUserMigrator> $migratorClass */ public function registerUserMigrator(string $appId, string $migratorClass): void { @@ -524,6 +577,20 @@ class RegistrationContext { } /** + * @psalm-param class-string<ISetupCheck> $setupCheckClass + */ + public function registerSetupCheck(string $appId, string $setupCheckClass): void { + $this->setupChecks[] = new ServiceRegistration($appId, $setupCheckClass); + } + + /** + * @psalm-param class-string<IDeclarativeSettingsForm> $declarativeSettingsClass + */ + public function registerDeclarativeSettings(string $appId, string $declarativeSettingsClass): void { + $this->declarativeSettings[] = new ServiceRegistration($appId, $declarativeSettingsClass); + } + + /** * @param App[] $apps */ public function delegateCapabilityRegistrations(array $apps): void { @@ -565,9 +632,6 @@ class RegistrationContext { } } - /** - * @param App[] $apps - */ public function delegateDashboardPanelRegistrations(IManager $dashboardManager): void { while (($panel = array_shift($this->dashboardPanels)) !== null) { try { @@ -729,6 +793,13 @@ class RegistrationContext { } /** + * @return ServiceRegistration<\OCP\TextToImage\IProvider>[] + */ + public function getTextToImageProviders(): array { + return $this->textToImageProviders; + } + + /** * @return ServiceRegistration<ICustomTemplateProvider>[] */ public function getTemplateProviders(): array { @@ -828,4 +899,25 @@ class RegistrationContext { public function getPublicShareTemplateProviders(): array { return $this->publicShareTemplateProviders; } + + /** + * @return ServiceRegistration<ISetupCheck>[] + */ + public function getSetupChecks(): array { + return $this->setupChecks; + } + + /** + * @return ServiceRegistration<ITeamResourceProvider>[] + */ + public function getTeamResourceProviders(): array { + return $this->teamResourceProviders; + } + + /** + * @return ServiceRegistration<IDeclarativeSettingsForm>[] + */ + public function getDeclarativeSettings(): array { + return $this->declarativeSettings; + } } diff --git a/lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php b/lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php index e2b115e0353..62c7169a7ee 100644 --- a/lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php +++ b/lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php @@ -46,8 +46,8 @@ class ServiceAliasRegistration extends ARegistration { * @paslm-param string|class-string $target */ public function __construct(string $appId, - string $alias, - string $target) { + string $alias, + string $target) { parent::__construct($appId); $this->alias = $alias; $this->target = $target; diff --git a/lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php b/lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php index b6658e55239..9d166526d94 100644 --- a/lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php +++ b/lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php @@ -45,9 +45,9 @@ class ServiceFactoryRegistration extends ARegistration { private $shared; public function __construct(string $appId, - string $alias, - callable $target, - bool $shared) { + string $alias, + callable $target, + bool $shared) { parent::__construct($appId); $this->name = $alias; $this->factory = $target; diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index a012d1e8ea6..93365582864 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -345,6 +345,7 @@ class DIContainer extends SimpleContainer implements IAppContainer { $this->registerService(IAppConfig::class, function (ContainerInterface $c) { return new OC\AppFramework\Services\AppConfig( $c->get(IConfig::class), + $c->get(\OCP\IAppConfig::class), $c->get('AppName') ); }); @@ -404,33 +405,6 @@ class DIContainer extends SimpleContainer implements IAppContainer { } /** - * @deprecated use the ILogger instead - * @param string $message - * @param string $level - * @return mixed - */ - public function log($message, $level) { - switch ($level) { - case 'debug': - $level = ILogger::DEBUG; - break; - case 'info': - $level = ILogger::INFO; - break; - case 'warn': - $level = ILogger::WARN; - break; - case 'fatal': - $level = ILogger::FATAL; - break; - default: - $level = ILogger::ERROR; - break; - } - \OCP\Util::writeLog($this->getAppName(), $message, $level); - } - - /** * Register a capability * * @param string $serviceName e.g. 'OCA\Files\Capabilities' diff --git a/lib/private/AppFramework/Http/Dispatcher.php b/lib/private/AppFramework/Http/Dispatcher.php index 13b391eb287..6e946f2bfa3 100644 --- a/lib/private/AppFramework/Http/Dispatcher.php +++ b/lib/private/AppFramework/Http/Dispatcher.php @@ -38,6 +38,7 @@ use OC\AppFramework\Utility\ControllerMethodReflector; use OC\DB\ConnectionAdapter; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\ParameterOutOfRangeException; use OCP\AppFramework\Http\Response; use OCP\Diagnostics\IEventLogger; use OCP\IConfig; @@ -88,14 +89,14 @@ class Dispatcher { * @param IEventLogger $eventLogger */ public function __construct(Http $protocol, - MiddlewareDispatcher $middlewareDispatcher, - ControllerMethodReflector $reflector, - IRequest $request, - IConfig $config, - ConnectionAdapter $connection, - LoggerInterface $logger, - IEventLogger $eventLogger, - ContainerInterface $appContainer) { + MiddlewareDispatcher $middlewareDispatcher, + ControllerMethodReflector $reflector, + IRequest $request, + IConfig $config, + ConnectionAdapter $connection, + LoggerInterface $logger, + IEventLogger $eventLogger, + ContainerInterface $appContainer) { $this->protocol = $protocol; $this->middlewareDispatcher = $middlewareDispatcher; $this->reflector = $reflector; @@ -197,7 +198,7 @@ class Dispatcher { private function executeController(Controller $controller, string $methodName): Response { $arguments = []; - // valid types that will be casted + // valid types that will be cast $types = ['int', 'integer', 'bool', 'boolean', 'float', 'double']; foreach ($this->reflector->getParameters() as $param => $default) { @@ -219,6 +220,7 @@ class Dispatcher { $value = false; } elseif ($value !== null && \in_array($type, $types, true)) { settype($value, $type); + $this->ensureParameterValueSatisfiesRange($param, $value); } elseif ($value === null && $type !== null && $this->appContainer->has($type)) { $value = $this->appContainer->get($type); } @@ -250,4 +252,22 @@ class Dispatcher { return $response; } + + /** + * @psalm-param mixed $value + * @throws ParameterOutOfRangeException + */ + private function ensureParameterValueSatisfiesRange(string $param, $value): void { + $rangeInfo = $this->reflector->getRange($param); + if ($rangeInfo) { + if ($value < $rangeInfo['min'] || $value > $rangeInfo['max']) { + throw new ParameterOutOfRangeException( + $param, + $value, + $rangeInfo['min'], + $rangeInfo['max'], + ); + } + } + } } diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php index 408e88583a0..94054c3e62c 100644 --- a/lib/private/AppFramework/Http/Request.php +++ b/lib/private/AppFramework/Http/Request.php @@ -63,11 +63,12 @@ use Symfony\Component\HttpFoundation\IpUtils; * @property string method * @property mixed[] parameters * @property mixed[] server + * @template-implements \ArrayAccess<string,mixed> */ class Request implements \ArrayAccess, \Countable, IRequest { public const USER_AGENT_IE = '/(MSIE)|(Trident)/'; // Microsoft Edge User Agent from https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx - public const USER_AGENT_MS_EDGE = '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+ Edge\/[0-9.]+$/'; + public const USER_AGENT_MS_EDGE = '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+ Edge?\/[0-9.]+$/'; // Firefox User Agent from https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference public const USER_AGENT_FIREFOX = '/^Mozilla\/5\.0 \([^)]+\) Gecko\/[0-9.]+ Firefox\/[0-9.]+$/'; // Chrome User Agent from https://developer.chrome.com/multidevice/user-agent @@ -118,10 +119,10 @@ class Request implements \ArrayAccess, \Countable, IRequest { * @see https://www.php.net/manual/en/reserved.variables.php */ public function __construct(array $vars, - IRequestId $requestId, - IConfig $config, - CsrfTokenManager $csrfTokenManager = null, - string $stream = 'php://input') { + IRequestId $requestId, + IConfig $config, + CsrfTokenManager $csrfTokenManager = null, + string $stream = 'php://input') { $this->inputStream = $stream; $this->items['params'] = []; $this->requestId = $requestId; @@ -193,9 +194,7 @@ class Request implements \ArrayAccess, \Countable, IRequest { */ #[\ReturnTypeWillChange] public function offsetGet($offset) { - return isset($this->items['parameters'][$offset]) - ? $this->items['parameters'][$offset] - : null; + return $this->items['parameters'][$offset] ?? null; } /** @@ -255,9 +254,7 @@ class Request implements \ArrayAccess, \Countable, IRequest { case 'cookies': case 'urlParams': case 'method': - return isset($this->items[$name]) - ? $this->items[$name] - : null; + return $this->items[$name] ?? null; case 'parameters': case 'params': if ($this->isPutStreamContent()) { @@ -577,7 +574,14 @@ class Request implements \ArrayAccess, \Countable, IRequest { * @return boolean true if $remoteAddress matches any entry in $trustedProxies, false otherwise */ protected function isTrustedProxy($trustedProxies, $remoteAddress) { - return IpUtils::checkIp($remoteAddress, $trustedProxies); + try { + return IpUtils::checkIp($remoteAddress, $trustedProxies); + } catch (\Throwable) { + // We can not log to our log here as the logger is using `getRemoteAddress` which uses the function, so we would have a cyclic dependency + // Reaching this line means `trustedProxies` is in invalid format. + error_log('Nextcloud trustedProxies has malformed entries'); + return false; + } } /** @@ -597,14 +601,25 @@ class Request implements \ArrayAccess, \Countable, IRequest { // only have one default, so we cannot ship an insecure product out of the box ]); - foreach ($forwardedForHeaders as $header) { + // Read the x-forwarded-for headers and values in reverse order as per + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#selecting_an_ip_address + foreach (array_reverse($forwardedForHeaders) as $header) { if (isset($this->server[$header])) { - foreach (explode(',', $this->server[$header]) as $IP) { + foreach (array_reverse(explode(',', $this->server[$header])) as $IP) { $IP = trim($IP); + $colons = substr_count($IP, ':'); + if ($colons > 1) { + // Extract IP from string with brackets and optional port + if (preg_match('/^\[(.+?)\](?::\d+)?$/', $IP, $matches) && isset($matches[1])) { + $IP = $matches[1]; + } + } elseif ($colons === 1) { + // IPv4 with port + $IP = substr($IP, 0, strpos($IP, ':')); + } - // remove brackets from IPv6 addresses - if (str_starts_with($IP, '[') && str_ends_with($IP, ']')) { - $IP = substr($IP, 1, -1); + if ($this->isTrustedProxy($trustedProxies, $IP)) { + continue; } if (filter_var($IP, FILTER_VALIDATE_IP) !== false) { @@ -620,14 +635,12 @@ class Request implements \ArrayAccess, \Countable, IRequest { /** * Check overwrite condition - * @param string $type * @return bool */ - private function isOverwriteCondition(string $type = ''): bool { + private function isOverwriteCondition(): bool { $regex = '/' . $this->config->getSystemValueString('overwritecondaddr', '') . '/'; $remoteAddr = isset($this->server['REMOTE_ADDR']) ? $this->server['REMOTE_ADDR'] : ''; - return $regex === '//' || preg_match($regex, $remoteAddr) === 1 - || $type !== 'protocol'; + return $regex === '//' || preg_match($regex, $remoteAddr) === 1; } /** @@ -637,7 +650,7 @@ class Request implements \ArrayAccess, \Countable, IRequest { */ public function getServerProtocol(): string { if ($this->config->getSystemValueString('overwriteprotocol') !== '' - && $this->isOverwriteCondition('protocol')) { + && $this->isOverwriteCondition()) { return $this->config->getSystemValueString('overwriteprotocol'); } diff --git a/lib/private/AppFramework/Http/RequestId.php b/lib/private/AppFramework/Http/RequestId.php index 70032873a75..a6b24c0a2ff 100644 --- a/lib/private/AppFramework/Http/RequestId.php +++ b/lib/private/AppFramework/Http/RequestId.php @@ -31,7 +31,7 @@ class RequestId implements IRequestId { protected string $requestId; public function __construct(string $uniqueId, - ISecureRandom $secureRandom) { + ISecureRandom $secureRandom) { $this->requestId = $uniqueId; $this->secureRandom = $secureRandom; } diff --git a/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php b/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php index 35eb0098eed..e129f70aef6 100644 --- a/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php +++ b/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php @@ -40,15 +40,15 @@ use OCP\AppFramework\Middleware; */ class MiddlewareDispatcher { /** - * @var array array containing all the middlewares + * @var Middleware[] array containing all the middlewares */ - private $middlewares; + private array $middlewares; /** * @var int counter which tells us what middleware was executed once an * exception occurs */ - private $middlewareCounter; + private int $middlewareCounter; /** @@ -64,14 +64,14 @@ class MiddlewareDispatcher { * Adds a new middleware * @param Middleware $middleWare the middleware which will be added */ - public function registerMiddleware(Middleware $middleWare) { + public function registerMiddleware(Middleware $middleWare): void { $this->middlewares[] = $middleWare; } /** * returns an array with all middleware elements - * @return array the middlewares + * @return Middleware[] the middlewares */ public function getMiddlewares(): array { return $this->middlewares; @@ -86,7 +86,7 @@ class MiddlewareDispatcher { * @param string $methodName the name of the method that will be called on * the controller */ - public function beforeController(Controller $controller, string $methodName) { + public function beforeController(Controller $controller, string $methodName): void { // we need to count so that we know which middlewares we have to ask in // case there is an exception $middlewareCount = \count($this->middlewares); diff --git a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php index 8bdacf550b6..fef9632487e 100644 --- a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php @@ -38,6 +38,7 @@ use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Middleware; use OCP\IRequest; +use OCP\ISession; use OCP\Security\Bruteforce\IThrottler; use ReflectionMethod; @@ -58,9 +59,9 @@ class CORSMiddleware extends Middleware { private $throttler; public function __construct(IRequest $request, - ControllerMethodReflector $reflector, - Session $session, - IThrottler $throttler) { + ControllerMethodReflector $reflector, + Session $session, + IThrottler $throttler) { $this->request = $request; $this->reflector = $reflector; $this->session = $session; @@ -91,6 +92,10 @@ class CORSMiddleware extends Middleware { if ($this->request->passesCSRFCheck()) { return; } + // Skip CORS check for requests with AppAPI auth. + if ($this->session->getSession() instanceof ISession && $this->session->getSession()->get('app_api') === true) { + return; + } $this->session->logout(); try { if ($user === null || $pass === null || !$this->session->logClientIn($user, $pass, $this->request, $this->throttler)) { diff --git a/lib/private/AppFramework/Middleware/Security/CSPMiddleware.php b/lib/private/AppFramework/Middleware/Security/CSPMiddleware.php index ae0dc1f134e..60a7cef8fa1 100644 --- a/lib/private/AppFramework/Middleware/Security/CSPMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/CSPMiddleware.php @@ -44,8 +44,8 @@ class CSPMiddleware extends Middleware { private $csrfTokenManager; public function __construct(ContentSecurityPolicyManager $policyManager, - ContentSecurityPolicyNonceManager $cspNonceManager, - CsrfTokenManager $csrfTokenManager) { + ContentSecurityPolicyNonceManager $cspNonceManager, + CsrfTokenManager $csrfTokenManager) { $this->contentSecurityPolicyManager = $policyManager; $this->cspNonceManager = $cspNonceManager; $this->csrfTokenManager = $csrfTokenManager; diff --git a/lib/private/AppFramework/Middleware/Security/Exceptions/SecurityException.php b/lib/private/AppFramework/Middleware/Security/Exceptions/SecurityException.php index 3232980b7e5..3b2296c145f 100644 --- a/lib/private/AppFramework/Middleware/Security/Exceptions/SecurityException.php +++ b/lib/private/AppFramework/Middleware/Security/Exceptions/SecurityException.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright Copyright (c) 2016, ownCloud, Inc. * diff --git a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php index a72a7a40016..351f47ea924 100644 --- a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php @@ -55,9 +55,9 @@ class PasswordConfirmationMiddleware extends Middleware { * @param ITimeFactory $timeFactory */ public function __construct(ControllerMethodReflector $reflector, - ISession $session, - IUserSession $userSession, - ITimeFactory $timeFactory) { + ISession $session, + IUserSession $userSession, + ITimeFactory $timeFactory) { $this->reflector = $reflector; $this->session = $session; $this->userSession = $userSession; diff --git a/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php b/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php index e6d35dc66f2..870efdd44fa 100644 --- a/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php @@ -38,7 +38,7 @@ class SameSiteCookieMiddleware extends Middleware { private $reflector; public function __construct(Request $request, - ControllerMethodReflector $reflector) { + ControllerMethodReflector $reflector) { $this->request = $request; $this->reflector = $reflector; } diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php index db6c7a02c77..386075bd968 100644 --- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php @@ -104,18 +104,18 @@ class SecurityMiddleware extends Middleware { private $userSession; public function __construct(IRequest $request, - ControllerMethodReflector $reflector, - INavigationManager $navigationManager, - IURLGenerator $urlGenerator, - LoggerInterface $logger, - string $appName, - bool $isLoggedIn, - bool $isAdminUser, - bool $isSubAdmin, - IAppManager $appManager, - IL10N $l10n, - AuthorizedGroupMapper $mapper, - IUserSession $userSession + ControllerMethodReflector $reflector, + INavigationManager $navigationManager, + IURLGenerator $urlGenerator, + LoggerInterface $logger, + string $appName, + bool $isLoggedIn, + bool $isAdminUser, + bool $isSubAdmin, + IAppManager $appManager, + IL10N $l10n, + AuthorizedGroupMapper $mapper, + IUserSession $userSession ) { $this->navigationManager = $navigationManager; $this->request = $request; @@ -180,20 +180,20 @@ class SecurityMiddleware extends Middleware { } } if (!$authorized) { - throw new NotAdminException($this->l10n->t('Logged in user must be an admin, a sub admin or gotten special right to access this setting')); + throw new NotAdminException($this->l10n->t('Logged in account must be an admin, a sub admin or gotten special right to access this setting')); } } if ($this->hasAnnotationOrAttribute($reflectionMethod, 'SubAdminRequired', SubAdminRequired::class) && !$this->isSubAdmin && !$this->isAdminUser && !$authorized) { - throw new NotAdminException($this->l10n->t('Logged in user must be an admin or sub admin')); + throw new NotAdminException($this->l10n->t('Logged in account must be an admin or sub admin')); } if (!$this->hasAnnotationOrAttribute($reflectionMethod, 'SubAdminRequired', SubAdminRequired::class) && !$this->hasAnnotationOrAttribute($reflectionMethod, 'NoAdminRequired', NoAdminRequired::class) && !$this->isAdminUser && !$authorized) { - throw new NotAdminException($this->l10n->t('Logged in user must be an admin')); + throw new NotAdminException($this->l10n->t('Logged in account must be an admin')); } } diff --git a/lib/private/AppFramework/Middleware/SessionMiddleware.php b/lib/private/AppFramework/Middleware/SessionMiddleware.php index 39f85915901..0acdcf8b7ef 100644 --- a/lib/private/AppFramework/Middleware/SessionMiddleware.php +++ b/lib/private/AppFramework/Middleware/SessionMiddleware.php @@ -44,7 +44,7 @@ class SessionMiddleware extends Middleware { private $session; public function __construct(ControllerMethodReflector $reflector, - ISession $session) { + ISession $session) { $this->reflector = $reflector; $this->session = $session; } diff --git a/lib/private/AppFramework/OCS/BaseResponse.php b/lib/private/AppFramework/OCS/BaseResponse.php index 123b73d302c..78bcc5586d3 100644 --- a/lib/private/AppFramework/OCS/BaseResponse.php +++ b/lib/private/AppFramework/OCS/BaseResponse.php @@ -64,10 +64,10 @@ abstract class BaseResponse extends Response { * @param int|null $itemsPerPage */ public function __construct(DataResponse $dataResponse, - $format = 'xml', - $statusMessage = null, - $itemsCount = null, - $itemsPerPage = null) { + $format = 'xml', + $statusMessage = null, + $itemsCount = null, + $itemsPerPage = null) { parent::__construct(); $this->format = $format; @@ -159,6 +159,10 @@ abstract class BaseResponse extends Response { $writer->startElement($k); $this->toXML($v, $writer); $writer->endElement(); + } elseif ($v instanceof \JsonSerializable) { + $writer->startElement($k); + $this->toXML($v->jsonSerialize(), $writer); + $writer->endElement(); } else { $writer->writeElement($k, $v); } diff --git a/lib/private/AppFramework/Routing/RouteConfig.php b/lib/private/AppFramework/Routing/RouteConfig.php index 6e3e49e8d99..7d63e5477ce 100644 --- a/lib/private/AppFramework/Routing/RouteConfig.php +++ b/lib/private/AppFramework/Routing/RouteConfig.php @@ -136,7 +136,13 @@ class RouteConfig { $controllerName = $this->buildControllerName($controller); $actionName = $this->buildActionName($action); - $routeName = $routeNamePrefix . $this->appName . '.' . $controller . '.' . $action . $postfix; + /* + * The route name has to be lowercase, for symfony to match it correctly. + * This is required because smyfony allows mixed casing for controller names in the routes. + * To avoid breaking all the existing route names, registering and matching will only use the lowercase names. + * This is also safe on the PHP side because class and method names collide regardless of the casing. + */ + $routeName = strtolower($routeNamePrefix . $this->appName . '.' . $controller . '.' . $action . $postfix); $router = $this->router->create($routeName, $url) ->method($verb); diff --git a/lib/private/AppFramework/Routing/RouteParser.php b/lib/private/AppFramework/Routing/RouteParser.php index 1b3a6c1255a..1b05c23df9d 100644 --- a/lib/private/AppFramework/Routing/RouteParser.php +++ b/lib/private/AppFramework/Routing/RouteParser.php @@ -100,7 +100,13 @@ class RouteParser { $controllerName = $this->buildControllerName($controller); $actionName = $this->buildActionName($action); - $routeName = $routeNamePrefix . $appName . '.' . $controller . '.' . $action . $postfix; + /* + * The route name has to be lowercase, for symfony to match it correctly. + * This is required because smyfony allows mixed casing for controller names in the routes. + * To avoid breaking all the existing route names, registering and matching will only use the lowercase names. + * This is also safe on the PHP side because class and method names collide regardless of the casing. + */ + $routeName = strtolower($routeNamePrefix . $appName . '.' . $controller . '.' . $action . $postfix); $routeObject = new Route($url); $routeObject->method($verb); diff --git a/lib/private/AppFramework/ScopedPsrLogger.php b/lib/private/AppFramework/ScopedPsrLogger.php index 4ed91cdb6c0..1cb58da11ef 100644 --- a/lib/private/AppFramework/ScopedPsrLogger.php +++ b/lib/private/AppFramework/ScopedPsrLogger.php @@ -37,7 +37,7 @@ class ScopedPsrLogger implements LoggerInterface { private $appId; public function __construct(LoggerInterface $inner, - string $appId) { + string $appId) { $this->inner = $inner; $this->appId = $appId; } diff --git a/lib/private/AppFramework/Services/AppConfig.php b/lib/private/AppFramework/Services/AppConfig.php index 1fc07bc22b0..1d18baef9ed 100644 --- a/lib/private/AppFramework/Services/AppConfig.php +++ b/lib/private/AppFramework/Services/AppConfig.php @@ -26,39 +26,322 @@ declare(strict_types=1); */ namespace OC\AppFramework\Services; +use InvalidArgumentException; +use JsonException; use OCP\AppFramework\Services\IAppConfig; +use OCP\Exceptions\AppConfigTypeConflictException; +use OCP\Exceptions\AppConfigUnknownKeyException; use OCP\IConfig; class AppConfig implements IAppConfig { - /** @var IConfig */ - private $config; + public function __construct( + private IConfig $config, + /** @var \OC\AppConfig */ + private \OCP\IAppConfig $appConfig, + private string $appName, + ) { + } - /** @var string */ - private $appName; + /** + * @inheritDoc + * + * @return string[] list of stored config keys + * @since 20.0.0 + */ + public function getAppKeys(): array { + return $this->appConfig->getKeys($this->appName); + } - public function __construct(IConfig $config, string $appName) { - $this->config = $config; - $this->appName = $appName; + /** + * @inheritDoc + * + * @param string $key config key + * @param bool|null $lazy TRUE to search within lazy loaded config, NULL to search within all config + * + * @return bool TRUE if key exists + * @since 29.0.0 + */ + public function hasAppKey(string $key, ?bool $lazy = false): bool { + return $this->appConfig->hasKey($this->appName, $key, $lazy); } - public function getAppKeys(): array { - return $this->config->getAppKeys($this->appName); + /** + * @param string $key config key + * @param bool|null $lazy TRUE to search within lazy loaded config, NULL to search within all config + * + * @return bool + * @throws AppConfigUnknownKeyException if config key is not known + * @since 29.0.0 + */ + public function isSensitive(string $key, ?bool $lazy = false): bool { + return $this->appConfig->isSensitive($this->appName, $key, $lazy); + } + + /** + * @inheritDoc + * + * @param string $key config key + * + * @return bool TRUE if config is lazy loaded + * @throws AppConfigUnknownKeyException if config key is not known + * @see \OCP\IAppConfig for details about lazy loading + * @since 29.0.0 + */ + public function isLazy(string $key): bool { + return $this->appConfig->isLazy($this->appName, $key); + } + + /** + * @inheritDoc + * + * @param string $key config keys prefix to search + * @param bool $filtered TRUE to hide sensitive config values. Value are replaced by {@see IConfig::SENSITIVE_VALUE} + * + * @return array<string, string> [configKey => configValue] + * @since 29.0.0 + */ + public function getAllAppValues(string $key = '', bool $filtered = false): array { + return $this->appConfig->getAllValues($this->appName, $key, $filtered); } + /** + * @inheritDoc + * + * @param string $key the key of the value, under which will be saved + * @param string $value the value that should be stored + * @since 20.0.0 + * @deprecated 29.0.0 use {@see setAppValueString()} + */ public function setAppValue(string $key, string $value): void { - $this->config->setAppValue($this->appName, $key, $value); + /** @psalm-suppress InternalMethod */ + $this->appConfig->setValueMixed($this->appName, $key, $value); + } + + /** + * @inheritDoc + * + * @param string $key config key + * @param string $value config value + * @param bool $lazy set config as lazy loaded + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueString( + string $key, + string $value, + bool $lazy = false, + bool $sensitive = false + ): bool { + return $this->appConfig->setValueString($this->appName, $key, $value, $lazy, $sensitive); + } + + /** + * @inheritDoc + * + * @param string $key config key + * @param int $value config value + * @param bool $lazy set config as lazy loaded + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueInt( + string $key, + int $value, + bool $lazy = false, + bool $sensitive = false + ): bool { + return $this->appConfig->setValueInt($this->appName, $key, $value, $lazy, $sensitive); + } + + /** + * @inheritDoc + * + * @param string $key config key + * @param float $value config value + * @param bool $lazy set config as lazy loaded + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueFloat( + string $key, + float $value, + bool $lazy = false, + bool $sensitive = false + ): bool { + return $this->appConfig->setValueFloat($this->appName, $key, $value, $lazy, $sensitive); } + /** + * @inheritDoc + * + * @param string $key config key + * @param bool $value config value + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueBool( + string $key, + bool $value, + bool $lazy = false + ): bool { + return $this->appConfig->setValueBool($this->appName, $key, $value, $lazy); + } + + /** + * @inheritDoc + * + * @param string $key config key + * @param array $value config value + * @param bool $lazy set config as lazy loaded + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * + * @return bool TRUE if value was different, therefor updated in database + * @throws AppConfigTypeConflictException if type from database is not VALUE_MIXED and different from the requested one + * @throws JsonException + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueArray( + string $key, + array $value, + bool $lazy = false, + bool $sensitive = false + ): bool { + return $this->appConfig->setValueArray($this->appName, $key, $value, $lazy, $sensitive); + } + + /** + * @param string $key + * @param string $default + * + * @since 20.0.0 + * @deprecated 29.0.0 use {@see getAppValueString()} + * @return string + */ public function getAppValue(string $key, string $default = ''): string { - return $this->config->getAppValue($this->appName, $key, $default); + /** @psalm-suppress InternalMethod */ + /** @psalm-suppress UndefinedInterfaceMethod */ + return $this->appConfig->getValueMixed($this->appName, $key, $default); + } + + /** + * @inheritDoc + * + * @param string $key config key + * @param string $default default value + * @param bool $lazy search within lazy loaded config + * + * @return string stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueString(string $key, string $default = '', bool $lazy = false): string { + return $this->appConfig->getValueString($this->appName, $key, $default, $lazy); + } + + /** + * @inheritDoc + * + * @param string $key config key + * @param int $default default value + * @param bool $lazy search within lazy loaded config + * + * @return int stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueInt(string $key, int $default = 0, bool $lazy = false): int { + return $this->appConfig->getValueInt($this->appName, $key, $default, $lazy); + } + + /** + * @inheritDoc + * + * @param string $key config key + * @param float $default default value + * @param bool $lazy search within lazy loaded config + * + * @return float stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueFloat(string $key, float $default = 0, bool $lazy = false): float { + return $this->appConfig->getValueFloat($this->appName, $key, $default, $lazy); + } + + /** + * @inheritDoc + * + * @param string $key config key + * @param bool $default default value + * @param bool $lazy search within lazy loaded config + * + * @return bool stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueBool(string $key, bool $default = false, bool $lazy = false): bool { + return $this->appConfig->getValueBool($this->appName, $key, $default, $lazy); + } + + /** + * @inheritDoc + * + * @param string $key config key + * @param array $default default value + * @param bool $lazy search within lazy loaded config + * + * @return array stored config value or $default if not set in database + * @throws InvalidArgumentException if one of the argument format is invalid + * @throws AppConfigTypeConflictException in case of conflict with the value type set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueArray(string $key, array $default = [], bool $lazy = false): array { + return $this->appConfig->getValueArray($this->appName, $key, $default, $lazy); } + /** + * @inheritDoc + * + * @param string $key the key of the value, under which it was saved + * @since 20.0.0 + */ public function deleteAppValue(string $key): void { - $this->config->deleteAppValue($this->appName, $key); + $this->appConfig->deleteKey($this->appName, $key); } + /** + * @inheritDoc + * + * @since 20.0.0 + */ public function deleteAppValues(): void { - $this->config->deleteAppValues($this->appName); + $this->appConfig->deleteApp($this->appName); } public function setUserValue(string $userId, string $key, string $value, ?string $preCondition = null): void { diff --git a/lib/private/AppFramework/Utility/ControllerMethodReflector.php b/lib/private/AppFramework/Utility/ControllerMethodReflector.php index b76b3c33c42..bd68dd96ed4 100644 --- a/lib/private/AppFramework/Utility/ControllerMethodReflector.php +++ b/lib/private/AppFramework/Utility/ControllerMethodReflector.php @@ -42,6 +42,7 @@ class ControllerMethodReflector implements IControllerMethodReflector { public $annotations = []; private $types = []; private $parameters = []; + private array $ranges = []; /** * @param object $object an object or classname @@ -54,26 +55,38 @@ class ControllerMethodReflector implements IControllerMethodReflector { if ($docs !== false) { // extract everything prefixed by @ and first letter uppercase preg_match_all('/^\h+\*\h+@(?P<annotation>[A-Z]\w+)((?P<parameter>.*))?$/m', $docs, $matches); - foreach ($matches['annotation'] as $key => $annontation) { - $annontation = strtolower($annontation); + foreach ($matches['annotation'] as $key => $annotation) { + $annotation = strtolower($annotation); $annotationValue = $matches['parameter'][$key]; - if (isset($annotationValue[0]) && $annotationValue[0] === '(' && $annotationValue[\strlen($annotationValue) - 1] === ')') { + if (str_starts_with($annotationValue, '(') && str_ends_with($annotationValue, ')')) { $cutString = substr($annotationValue, 1, -1); $cutString = str_replace(' ', '', $cutString); - $splittedArray = explode(',', $cutString); - foreach ($splittedArray as $annotationValues) { + $splitArray = explode(',', $cutString); + foreach ($splitArray as $annotationValues) { [$key, $value] = explode('=', $annotationValues); - $this->annotations[$annontation][$key] = $value; + $this->annotations[$annotation][$key] = $value; } continue; } - $this->annotations[$annontation] = [$annotationValue]; + $this->annotations[$annotation] = [$annotationValue]; } // extract type parameter information preg_match_all('/@param\h+(?P<type>\w+)\h+\$(?P<var>\w+)/', $docs, $matches); $this->types = array_combine($matches['var'], $matches['type']); + preg_match_all('/@psalm-param\h+(?P<type>\w+)<(?P<rangeMin>(-?\d+|min)),\h*(?P<rangeMax>(-?\d+|max))>\h+\$(?P<var>\w+)/', $docs, $matches); + foreach ($matches['var'] as $index => $varName) { + if ($matches['type'][$index] !== 'int') { + // only int ranges are possible at the moment + // @see https://psalm.dev/docs/annotating_code/type_syntax/scalar_types + continue; + } + $this->ranges[$varName] = [ + 'min' => $matches['rangeMin'][$index] === 'min' ? PHP_INT_MIN : (int)$matches['rangeMin'][$index], + 'max' => $matches['rangeMax'][$index] === 'max' ? PHP_INT_MAX : (int)$matches['rangeMax'][$index], + ]; + } } foreach ($reflection->getParameters() as $param) { @@ -106,6 +119,14 @@ class ControllerMethodReflector implements IControllerMethodReflector { return null; } + public function getRange(string $parameter): ?array { + if (array_key_exists($parameter, $this->ranges)) { + return $this->ranges[$parameter]; + } + + return null; + } + /** * @return array the arguments of the method with key => default value */ diff --git a/lib/private/AppFramework/Utility/SimpleContainer.php b/lib/private/AppFramework/Utility/SimpleContainer.php index 7aa5cb83926..83aed4381b3 100644 --- a/lib/private/AppFramework/Utility/SimpleContainer.php +++ b/lib/private/AppFramework/Utility/SimpleContainer.php @@ -37,8 +37,8 @@ use Pimple\Container; use Psr\Container\ContainerInterface; use ReflectionClass; use ReflectionException; -use ReflectionParameter; use ReflectionNamedType; +use ReflectionParameter; use function class_exists; /** @@ -105,6 +105,11 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer { try { return $this->query($resolveName); } catch (QueryException $e2) { + // Pass null if typed and nullable + if ($parameter->allowsNull() && ($parameterType instanceof ReflectionNamedType)) { + return null; + } + // don't lose the error we got while trying to query by type throw new QueryException($e->getMessage(), (int) $e->getCode(), $e); } diff --git a/lib/private/AppFramework/Utility/TimeFactory.php b/lib/private/AppFramework/Utility/TimeFactory.php index 1e4655dd1cd..737777a11ac 100644 --- a/lib/private/AppFramework/Utility/TimeFactory.php +++ b/lib/private/AppFramework/Utility/TimeFactory.php @@ -34,7 +34,7 @@ use OCP\AppFramework\Utility\ITimeFactory; * Use this to get a timestamp or DateTime object in code to remain testable * * @since 8.0.0 - * @since 26.0.0 Extends the \Psr\Clock\ClockInterface interface + * @since 27.0.0 Implements the \Psr\Clock\ClockInterface interface * @ref https://www.php-fig.org/psr/psr-20/#21-clockinterface */ class TimeFactory implements ITimeFactory { @@ -73,4 +73,11 @@ class TimeFactory implements ITimeFactory { return $clone; } + + public function getTimeZone(?string $timezone = null): \DateTimeZone { + if ($timezone !== null) { + return new \DateTimeZone($timezone); + } + return $this->timezone; + } } diff --git a/lib/private/AppScriptSort.php b/lib/private/AppScriptSort.php index c42d02d485d..2e36034d04f 100644 --- a/lib/private/AppScriptSort.php +++ b/lib/private/AppScriptSort.php @@ -46,10 +46,10 @@ class AppScriptSort { * @param array $sortedScriptDeps */ private function topSortVisit( - AppScriptDependency $app, - array &$parents, - array &$scriptDeps, - array &$sortedScriptDeps): void { + AppScriptDependency $app, + array &$parents, + array &$scriptDeps, + array &$sortedScriptDeps): void { // Detect and log circular dependencies if (isset($parents[$app->getId()])) { $this->logger->error('Circular dependency in app scripts at app ' . $app->getId()); diff --git a/lib/private/Archive/TAR.php b/lib/private/Archive/TAR.php index 9dc906384e0..a6140e44eb6 100644 --- a/lib/private/Archive/TAR.php +++ b/lib/private/Archive/TAR.php @@ -197,7 +197,7 @@ class TAR extends Archive { if ($pos = strpos($result, '/')) { $result = substr($result, 0, $pos + 1); } - if (array_search($result, $folderContent) === false) { + if (!in_array($result, $folderContent)) { $folderContent[] = $result; } } @@ -269,7 +269,7 @@ class TAR extends Archive { */ public function fileExists(string $path): bool { $files = $this->getFiles(); - if ((array_search($path, $files) !== false) or (array_search($path . '/', $files) !== false)) { + if ((in_array($path, $files)) or (in_array($path . '/', $files))) { return true; } else { $folderPath = rtrim($path, '/') . '/'; diff --git a/lib/private/Authentication/Events/AppPasswordCreatedEvent.php b/lib/private/Authentication/Events/AppPasswordCreatedEvent.php index a90abd25026..068c0a73277 100644 --- a/lib/private/Authentication/Events/AppPasswordCreatedEvent.php +++ b/lib/private/Authentication/Events/AppPasswordCreatedEvent.php @@ -25,16 +25,14 @@ declare(strict_types=1); */ namespace OC\Authentication\Events; -use OC\Authentication\Token\IToken; +use OCP\Authentication\Token\IToken; use OCP\EventDispatcher\Event; class AppPasswordCreatedEvent extends Event { - /** @var IToken */ - private $token; - - public function __construct(IToken $token) { + public function __construct( + private IToken $token, + ) { parent::__construct(); - $this->token = $token; } public function getToken(): IToken { diff --git a/lib/private/Authentication/Exceptions/ExpiredTokenException.php b/lib/private/Authentication/Exceptions/ExpiredTokenException.php index 0dc92b45920..15069313712 100644 --- a/lib/private/Authentication/Exceptions/ExpiredTokenException.php +++ b/lib/private/Authentication/Exceptions/ExpiredTokenException.php @@ -27,17 +27,19 @@ namespace OC\Authentication\Exceptions; use OC\Authentication\Token\IToken; -class ExpiredTokenException extends InvalidTokenException { - /** @var IToken */ - private $token; - - public function __construct(IToken $token) { - parent::__construct(); - - $this->token = $token; +/** + * @deprecated 28.0.0 use {@see \OCP\Authentication\Exceptions\ExpiredTokenException} instead + */ +class ExpiredTokenException extends \OCP\Authentication\Exceptions\ExpiredTokenException { + public function __construct( + IToken $token, + ) { + parent::__construct($token); } public function getToken(): IToken { - return $this->token; + $token = parent::getToken(); + /** @var IToken $token We know that we passed OC interface from constructor */ + return $token; } } diff --git a/lib/private/Authentication/Exceptions/InvalidTokenException.php b/lib/private/Authentication/Exceptions/InvalidTokenException.php index acaabff6b88..7de6e1522fa 100644 --- a/lib/private/Authentication/Exceptions/InvalidTokenException.php +++ b/lib/private/Authentication/Exceptions/InvalidTokenException.php @@ -24,7 +24,8 @@ declare(strict_types=1); */ namespace OC\Authentication\Exceptions; -use Exception; - -class InvalidTokenException extends Exception { +/** + * @deprecated 28.0.0 use OCP version instead + */ +class InvalidTokenException extends \OCP\Authentication\Exceptions\InvalidTokenException { } diff --git a/lib/private/Authentication/Exceptions/WipeTokenException.php b/lib/private/Authentication/Exceptions/WipeTokenException.php index 1c60ab9da78..25b7cb74359 100644 --- a/lib/private/Authentication/Exceptions/WipeTokenException.php +++ b/lib/private/Authentication/Exceptions/WipeTokenException.php @@ -27,17 +27,19 @@ namespace OC\Authentication\Exceptions; use OC\Authentication\Token\IToken; -class WipeTokenException extends InvalidTokenException { - /** @var IToken */ - private $token; - - public function __construct(IToken $token) { - parent::__construct(); - - $this->token = $token; +/** + * @deprecated 28.0.0 use {@see \OCP\Authentication\Exceptions\WipeTokenException} instead + */ +class WipeTokenException extends \OCP\Authentication\Exceptions\WipeTokenException { + public function __construct( + IToken $token, + ) { + parent::__construct($token); } public function getToken(): IToken { - return $this->token; + $token = parent::getToken(); + /** @var IToken $token We know that we passed OC interface from constructor */ + return $token; } } diff --git a/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php b/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php index edebb2a2641..3e8348f075a 100644 --- a/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php +++ b/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php @@ -46,7 +46,7 @@ class RemoteWipeActivityListener implements IEventListener { private $logger; public function __construct(IActvityManager $activityManager, - LoggerInterface $logger) { + LoggerInterface $logger) { $this->activityManager = $activityManager; $this->logger = $logger; } diff --git a/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php b/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php index cba2b183589..fb3f771d1e4 100644 --- a/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php +++ b/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php @@ -57,9 +57,9 @@ class RemoteWipeEmailListener implements IEventListener { private $logger; public function __construct(IMailer $mailer, - IUserManager $userManager, - IL10nFactory $l10nFactory, - LoggerInterface $logger) { + IUserManager $userManager, + IL10nFactory $l10nFactory, + LoggerInterface $logger) { $this->mailer = $mailer; $this->userManager = $userManager; $this->l10n = $l10nFactory->get('core'); diff --git a/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php b/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php index 81feab32746..37732ecf5f2 100644 --- a/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php +++ b/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php @@ -45,7 +45,7 @@ class RemoteWipeNotificationsListener implements IEventListener { private $timeFactory; public function __construct(INotificationManager $notificationManager, - ITimeFactory $timeFactory) { + ITimeFactory $timeFactory) { $this->notificationManager = $notificationManager; $this->timeFactory = $timeFactory; } diff --git a/lib/private/Authentication/Listeners/UserDeletedFilesCleanupListener.php b/lib/private/Authentication/Listeners/UserDeletedFilesCleanupListener.php index 5e657be0763..a29a73ad8ad 100644 --- a/lib/private/Authentication/Listeners/UserDeletedFilesCleanupListener.php +++ b/lib/private/Authentication/Listeners/UserDeletedFilesCleanupListener.php @@ -34,6 +34,7 @@ use OCP\Files\Storage\IStorage; use OCP\User\Events\BeforeUserDeletedEvent; use OCP\User\Events\UserDeletedEvent; +/** @template-implements IEventListener<BeforeUserDeletedEvent|UserDeletedEvent> */ class UserDeletedFilesCleanupListener implements IEventListener { /** @var array<string,IStorage> */ private $homeStorageCache = []; @@ -55,7 +56,7 @@ class UserDeletedFilesCleanupListener implements IEventListener { $userHome = $this->mountProviderCollection->getHomeMountForUser($event->getUser()); $storage = $userHome->getStorage(); if (!$storage) { - throw new \Exception("User has no home storage"); + throw new \Exception("Account has no home storage"); } // remove all wrappers, so we do the delete directly on the home storage bypassing any wrapper diff --git a/lib/private/Authentication/Listeners/UserDeletedTokenCleanupListener.php b/lib/private/Authentication/Listeners/UserDeletedTokenCleanupListener.php index a09a08568d5..f4f08a50add 100644 --- a/lib/private/Authentication/Listeners/UserDeletedTokenCleanupListener.php +++ b/lib/private/Authentication/Listeners/UserDeletedTokenCleanupListener.php @@ -44,7 +44,7 @@ class UserDeletedTokenCleanupListener implements IEventListener { private $logger; public function __construct(Manager $manager, - LoggerInterface $logger) { + LoggerInterface $logger) { $this->manager = $manager; $this->logger = $logger; } diff --git a/lib/private/Authentication/Listeners/UserDeletedWebAuthnCleanupListener.php b/lib/private/Authentication/Listeners/UserDeletedWebAuthnCleanupListener.php index 4927c3ac7f9..26db8921016 100644 --- a/lib/private/Authentication/Listeners/UserDeletedWebAuthnCleanupListener.php +++ b/lib/private/Authentication/Listeners/UserDeletedWebAuthnCleanupListener.php @@ -31,6 +31,7 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\User\Events\UserDeletedEvent; +/** @template-implements IEventListener<UserDeletedEvent> */ class UserDeletedWebAuthnCleanupListener implements IEventListener { /** @var PublicKeyCredentialMapper */ private $credentialMapper; diff --git a/lib/private/Authentication/Login/Chain.php b/lib/private/Authentication/Login/Chain.php index 3c3179472c4..60ecd004388 100644 --- a/lib/private/Authentication/Login/Chain.php +++ b/lib/private/Authentication/Login/Chain.php @@ -63,17 +63,17 @@ class Chain { private $finishRememberedLoginCommand; public function __construct(PreLoginHookCommand $preLoginHookCommand, - UserDisabledCheckCommand $userDisabledCheckCommand, - UidLoginCommand $uidLoginCommand, - EmailLoginCommand $emailLoginCommand, - LoggedInCheckCommand $loggedInCheckCommand, - CompleteLoginCommand $completeLoginCommand, - CreateSessionTokenCommand $createSessionTokenCommand, - ClearLostPasswordTokensCommand $clearLostPasswordTokensCommand, - UpdateLastPasswordConfirmCommand $updateLastPasswordConfirmCommand, - SetUserTimezoneCommand $setUserTimezoneCommand, - TwoFactorCommand $twoFactorCommand, - FinishRememberedLoginCommand $finishRememberedLoginCommand + UserDisabledCheckCommand $userDisabledCheckCommand, + UidLoginCommand $uidLoginCommand, + EmailLoginCommand $emailLoginCommand, + LoggedInCheckCommand $loggedInCheckCommand, + CompleteLoginCommand $completeLoginCommand, + CreateSessionTokenCommand $createSessionTokenCommand, + ClearLostPasswordTokensCommand $clearLostPasswordTokensCommand, + UpdateLastPasswordConfirmCommand $updateLastPasswordConfirmCommand, + SetUserTimezoneCommand $setUserTimezoneCommand, + TwoFactorCommand $twoFactorCommand, + FinishRememberedLoginCommand $finishRememberedLoginCommand ) { $this->preLoginHookCommand = $preLoginHookCommand; $this->userDisabledCheckCommand = $userDisabledCheckCommand; diff --git a/lib/private/Authentication/Login/CreateSessionTokenCommand.php b/lib/private/Authentication/Login/CreateSessionTokenCommand.php index ba237dfbf20..41616e6dad3 100644 --- a/lib/private/Authentication/Login/CreateSessionTokenCommand.php +++ b/lib/private/Authentication/Login/CreateSessionTokenCommand.php @@ -39,7 +39,7 @@ class CreateSessionTokenCommand extends ALoginCommand { private $userSession; public function __construct(IConfig $config, - Session $userSession) { + Session $userSession) { $this->config = $config; $this->userSession = $userSession; } diff --git a/lib/private/Authentication/Login/LoggedInCheckCommand.php b/lib/private/Authentication/Login/LoggedInCheckCommand.php index dc1a4d2d883..6b241d79746 100644 --- a/lib/private/Authentication/Login/LoggedInCheckCommand.php +++ b/lib/private/Authentication/Login/LoggedInCheckCommand.php @@ -39,7 +39,7 @@ class LoggedInCheckCommand extends ALoginCommand { private $dispatcher; public function __construct(LoggerInterface $logger, - IEventDispatcher $dispatcher) { + IEventDispatcher $dispatcher) { $this->logger = $logger; $this->dispatcher = $dispatcher; } diff --git a/lib/private/Authentication/Login/LoginData.php b/lib/private/Authentication/Login/LoginData.php index 240a1dc6476..0ce11cf70fc 100644 --- a/lib/private/Authentication/Login/LoginData.php +++ b/lib/private/Authentication/Login/LoginData.php @@ -55,11 +55,11 @@ class LoginData { private $rememberLogin = true; public function __construct(IRequest $request, - string $username, - ?string $password, - string $redirectUrl = null, - string $timeZone = '', - string $timeZoneOffset = '') { + string $username, + ?string $password, + string $redirectUrl = null, + string $timeZone = '', + string $timeZoneOffset = '') { $this->request = $request; $this->username = $username; $this->password = $password; diff --git a/lib/private/Authentication/Login/LoginResult.php b/lib/private/Authentication/Login/LoginResult.php index dec012c2fc9..18820d98a47 100644 --- a/lib/private/Authentication/Login/LoginResult.php +++ b/lib/private/Authentication/Login/LoginResult.php @@ -25,6 +25,8 @@ declare(strict_types=1); */ namespace OC\Authentication\Login; +use OC\Core\Controller\LoginController; + class LoginResult { /** @var bool */ private $success; @@ -59,6 +61,9 @@ class LoginResult { return $result; } + /** + * @param LoginController::LOGIN_MSG_*|null $msg + */ public static function failure(LoginData $data, string $msg = null): LoginResult { $result = new static(false, $data); if ($msg !== null) { diff --git a/lib/private/Authentication/Login/SetUserTimezoneCommand.php b/lib/private/Authentication/Login/SetUserTimezoneCommand.php index f68fce1771e..881e1c451a9 100644 --- a/lib/private/Authentication/Login/SetUserTimezoneCommand.php +++ b/lib/private/Authentication/Login/SetUserTimezoneCommand.php @@ -36,7 +36,7 @@ class SetUserTimezoneCommand extends ALoginCommand { private $session; public function __construct(IConfig $config, - ISession $session) { + ISession $session) { $this->config = $config; $this->session = $session; } diff --git a/lib/private/Authentication/Login/TwoFactorCommand.php b/lib/private/Authentication/Login/TwoFactorCommand.php index 256d88ffa81..aa5a2ff96f4 100644 --- a/lib/private/Authentication/Login/TwoFactorCommand.php +++ b/lib/private/Authentication/Login/TwoFactorCommand.php @@ -26,12 +26,12 @@ declare(strict_types=1); */ namespace OC\Authentication\Login; -use function array_pop; -use function count; use OC\Authentication\TwoFactorAuth\Manager; use OC\Authentication\TwoFactorAuth\MandatoryTwoFactor; use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\IURLGenerator; +use function array_pop; +use function count; class TwoFactorCommand extends ALoginCommand { /** @var Manager */ @@ -44,8 +44,8 @@ class TwoFactorCommand extends ALoginCommand { private $urlGenerator; public function __construct(Manager $twoFactorManager, - MandatoryTwoFactor $mandatoryTwoFactor, - IURLGenerator $urlGenerator) { + MandatoryTwoFactor $mandatoryTwoFactor, + IURLGenerator $urlGenerator) { $this->twoFactorManager = $twoFactorManager; $this->mandatoryTwoFactor = $mandatoryTwoFactor; $this->urlGenerator = $urlGenerator; diff --git a/lib/private/Authentication/Login/UserDisabledCheckCommand.php b/lib/private/Authentication/Login/UserDisabledCheckCommand.php index 7cf4c7235ec..8354457b56a 100644 --- a/lib/private/Authentication/Login/UserDisabledCheckCommand.php +++ b/lib/private/Authentication/Login/UserDisabledCheckCommand.php @@ -38,7 +38,7 @@ class UserDisabledCheckCommand extends ALoginCommand { private $logger; public function __construct(IUserManager $userManager, - LoggerInterface $logger) { + LoggerInterface $logger) { $this->userManager = $userManager; $this->logger = $logger; } diff --git a/lib/private/Authentication/Login/WebAuthnChain.php b/lib/private/Authentication/Login/WebAuthnChain.php index f3ebc313a44..d0fcf691d46 100644 --- a/lib/private/Authentication/Login/WebAuthnChain.php +++ b/lib/private/Authentication/Login/WebAuthnChain.php @@ -57,15 +57,15 @@ class WebAuthnChain { private $webAuthnLoginCommand; public function __construct(UserDisabledCheckCommand $userDisabledCheckCommand, - WebAuthnLoginCommand $webAuthnLoginCommand, - LoggedInCheckCommand $loggedInCheckCommand, - CompleteLoginCommand $completeLoginCommand, - CreateSessionTokenCommand $createSessionTokenCommand, - ClearLostPasswordTokensCommand $clearLostPasswordTokensCommand, - UpdateLastPasswordConfirmCommand $updateLastPasswordConfirmCommand, - SetUserTimezoneCommand $setUserTimezoneCommand, - TwoFactorCommand $twoFactorCommand, - FinishRememberedLoginCommand $finishRememberedLoginCommand + WebAuthnLoginCommand $webAuthnLoginCommand, + LoggedInCheckCommand $loggedInCheckCommand, + CompleteLoginCommand $completeLoginCommand, + CreateSessionTokenCommand $createSessionTokenCommand, + ClearLostPasswordTokensCommand $clearLostPasswordTokensCommand, + UpdateLastPasswordConfirmCommand $updateLastPasswordConfirmCommand, + SetUserTimezoneCommand $setUserTimezoneCommand, + TwoFactorCommand $twoFactorCommand, + FinishRememberedLoginCommand $finishRememberedLoginCommand ) { $this->userDisabledCheckCommand = $userDisabledCheckCommand; $this->webAuthnLoginCommand = $webAuthnLoginCommand; diff --git a/lib/private/Authentication/LoginCredentials/Store.php b/lib/private/Authentication/LoginCredentials/Store.php index 3a09e983ee8..2e00ac211c1 100644 --- a/lib/private/Authentication/LoginCredentials/Store.php +++ b/lib/private/Authentication/LoginCredentials/Store.php @@ -26,10 +26,10 @@ declare(strict_types=1); */ namespace OC\Authentication\LoginCredentials; -use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Token\IProvider; use OCP\Authentication\Exceptions\CredentialsUnavailableException; +use OCP\Authentication\Exceptions\InvalidTokenException; use OCP\Authentication\LoginCredentials\ICredentials; use OCP\Authentication\LoginCredentials\IStore; use OCP\ISession; @@ -48,8 +48,8 @@ class Store implements IStore { private $tokenProvider; public function __construct(ISession $session, - LoggerInterface $logger, - IProvider $tokenProvider = null) { + LoggerInterface $logger, + IProvider $tokenProvider = null) { $this->session = $session; $this->logger = $logger; $this->tokenProvider = $tokenProvider; diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php index a12d3ba34d9..fcec8cecac1 100644 --- a/lib/private/Authentication/Token/IProvider.php +++ b/lib/private/Authentication/Token/IProvider.php @@ -29,10 +29,11 @@ declare(strict_types=1); */ namespace OC\Authentication\Token; -use OC\Authentication\Exceptions\ExpiredTokenException; -use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; -use OC\Authentication\Exceptions\WipeTokenException; +use OCP\Authentication\Exceptions\ExpiredTokenException; +use OCP\Authentication\Exceptions\InvalidTokenException; +use OCP\Authentication\Exceptions\WipeTokenException; +use OCP\Authentication\Token\IToken as OCPIToken; interface IProvider { /** @@ -45,16 +46,16 @@ interface IProvider { * @param string $name Name will be trimmed to 120 chars when longer * @param int $type token type * @param int $remember whether the session token should be used for remember-me - * @return IToken + * @return OCPIToken * @throws \RuntimeException when OpenSSL reports a problem */ public function generateToken(string $token, - string $uid, - string $loginName, - ?string $password, - string $name, - int $type = IToken::TEMPORARY_TOKEN, - int $remember = IToken::DO_NOT_REMEMBER): IToken; + string $uid, + string $loginName, + ?string $password, + string $name, + int $type = OCPIToken::TEMPORARY_TOKEN, + int $remember = OCPIToken::DO_NOT_REMEMBER): OCPIToken; /** * Get a token by token id @@ -63,9 +64,9 @@ interface IProvider { * @throws InvalidTokenException * @throws ExpiredTokenException * @throws WipeTokenException - * @return IToken + * @return OCPIToken */ - public function getToken(string $tokenId): IToken; + public function getToken(string $tokenId): OCPIToken; /** * Get a token by token id @@ -74,9 +75,9 @@ interface IProvider { * @throws InvalidTokenException * @throws ExpiredTokenException * @throws WipeTokenException - * @return IToken + * @return OCPIToken */ - public function getTokenById(int $tokenId): IToken; + public function getTokenById(int $tokenId): OCPIToken; /** * Duplicate an existing session token @@ -85,9 +86,9 @@ interface IProvider { * @param string $sessionId * @throws InvalidTokenException * @throws \RuntimeException when OpenSSL reports a problem - * @return IToken The new token + * @return OCPIToken The new token */ - public function renewSessionToken(string $oldSessionId, string $sessionId): IToken; + public function renewSessionToken(string $oldSessionId, string $sessionId): OCPIToken; /** * Invalidate (delete) the given session token @@ -117,16 +118,16 @@ interface IProvider { /** * Save the updated token * - * @param IToken $token + * @param OCPIToken $token */ - public function updateToken(IToken $token); + public function updateToken(OCPIToken $token); /** * Update token activity timestamp * - * @param IToken $token + * @param OCPIToken $token */ - public function updateTokenActivity(IToken $token); + public function updateTokenActivity(OCPIToken $token); /** * Get all tokens of a user @@ -135,49 +136,49 @@ interface IProvider { * where a high number of (session) tokens is generated * * @param string $uid - * @return IToken[] + * @return OCPIToken[] */ public function getTokenByUser(string $uid): array; /** * Get the (unencrypted) password of the given token * - * @param IToken $savedToken + * @param OCPIToken $savedToken * @param string $tokenId * @throws InvalidTokenException * @throws PasswordlessTokenException * @return string */ - public function getPassword(IToken $savedToken, string $tokenId): string; + public function getPassword(OCPIToken $savedToken, string $tokenId): string; /** * Encrypt and set the password of the given token * - * @param IToken $token + * @param OCPIToken $token * @param string $tokenId * @param string $password * @throws InvalidTokenException */ - public function setPassword(IToken $token, string $tokenId, string $password); + public function setPassword(OCPIToken $token, string $tokenId, string $password); /** * Rotate the token. Useful for for example oauth tokens * - * @param IToken $token + * @param OCPIToken $token * @param string $oldTokenId * @param string $newTokenId - * @return IToken + * @return OCPIToken * @throws \RuntimeException when OpenSSL reports a problem */ - public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken; + public function rotate(OCPIToken $token, string $oldTokenId, string $newTokenId): OCPIToken; /** * Marks a token as having an invalid password. * - * @param IToken $token + * @param OCPIToken $token * @param string $tokenId */ - public function markPasswordInvalid(IToken $token, string $tokenId); + public function markPasswordInvalid(OCPIToken $token, string $tokenId); /** * Update all the passwords of $uid if required diff --git a/lib/private/Authentication/Token/IToken.php b/lib/private/Authentication/Token/IToken.php index 5ca4eaea843..eb172f33396 100644 --- a/lib/private/Authentication/Token/IToken.php +++ b/lib/private/Authentication/Token/IToken.php @@ -26,109 +26,10 @@ declare(strict_types=1); */ namespace OC\Authentication\Token; -use JsonSerializable; +use OCP\Authentication\Token\IToken as OCPIToken; -interface IToken extends JsonSerializable { - public const TEMPORARY_TOKEN = 0; - public const PERMANENT_TOKEN = 1; - public const WIPE_TOKEN = 2; - public const DO_NOT_REMEMBER = 0; - public const REMEMBER = 1; - - /** - * Get the token ID - * - * @return int - */ - public function getId(): int; - - /** - * Get the user UID - * - * @return string - */ - public function getUID(): string; - - /** - * Get the login name used when generating the token - * - * @return string - */ - public function getLoginName(): string; - - /** - * Get the (encrypted) login password - * - * @return string|null - */ - public function getPassword(); - - /** - * Get the timestamp of the last password check - * - * @return int - */ - public function getLastCheck(): int; - - /** - * Set the timestamp of the last password check - * - * @param int $time - */ - public function setLastCheck(int $time); - - /** - * Get the authentication scope for this token - * - * @return string - */ - public function getScope(): string; - - /** - * Get the authentication scope for this token - * - * @return array - */ - public function getScopeAsArray(): array; - - /** - * Set the authentication scope for this token - * - * @param array $scope - */ - public function setScope($scope); - - /** - * Get the name of the token - * @return string - */ - public function getName(): string; - - /** - * Get the remember state of the token - * - * @return int - */ - public function getRemember(): int; - - /** - * Set the token - * - * @param string $token - */ - public function setToken(string $token); - - /** - * Set the password - * - * @param string $password - */ - public function setPassword(string $password); - - /** - * Set the expiration time of the token - * - * @param int|null $expires - */ - public function setExpires($expires); +/** + * @deprecated 28.0.0 use {@see \OCP\Authentication\Token\IToken} instead + */ +interface IToken extends OCPIToken { } diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php index 6a1c7d4c1e7..e0b0e2dd14b 100644 --- a/lib/private/Authentication/Token/Manager.php +++ b/lib/private/Authentication/Token/Manager.php @@ -28,11 +28,13 @@ declare(strict_types=1); namespace OC\Authentication\Token; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; -use OC\Authentication\Exceptions\ExpiredTokenException; -use OC\Authentication\Exceptions\InvalidTokenException; +use OC\Authentication\Exceptions\InvalidTokenException as OcInvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; -use OC\Authentication\Exceptions\WipeTokenException; +use OCP\Authentication\Exceptions\ExpiredTokenException; +use OCP\Authentication\Exceptions\InvalidTokenException; +use OCP\Authentication\Exceptions\WipeTokenException; use OCP\Authentication\Token\IProvider as OCPIProvider; +use OCP\Authentication\Token\IToken as OCPIToken; class Manager implements IProvider, OCPIProvider { /** @var PublicKeyTokenProvider */ @@ -52,15 +54,15 @@ class Manager implements IProvider, OCPIProvider { * @param string $name Name will be trimmed to 120 chars when longer * @param int $type token type * @param int $remember whether the session token should be used for remember-me - * @return IToken + * @return OCPIToken */ public function generateToken(string $token, - string $uid, - string $loginName, - $password, - string $name, - int $type = IToken::TEMPORARY_TOKEN, - int $remember = IToken::DO_NOT_REMEMBER): IToken { + string $uid, + string $loginName, + $password, + string $name, + int $type = OCPIToken::TEMPORARY_TOKEN, + int $remember = OCPIToken::DO_NOT_REMEMBER): OCPIToken { if (mb_strlen($name) > 128) { $name = mb_substr($name, 0, 120) . '…'; } @@ -93,10 +95,10 @@ class Manager implements IProvider, OCPIProvider { /** * Save the updated token * - * @param IToken $token + * @param OCPIToken $token * @throws InvalidTokenException */ - public function updateToken(IToken $token) { + public function updateToken(OCPIToken $token) { $provider = $this->getProvider($token); $provider->updateToken($token); } @@ -105,16 +107,16 @@ class Manager implements IProvider, OCPIProvider { * Update token activity timestamp * * @throws InvalidTokenException - * @param IToken $token + * @param OCPIToken $token */ - public function updateTokenActivity(IToken $token) { + public function updateTokenActivity(OCPIToken $token) { $provider = $this->getProvider($token); $provider->updateTokenActivity($token); } /** * @param string $uid - * @return IToken[] + * @return OCPIToken[] */ public function getTokenByUser(string $uid): array { return $this->publicKeyTokenProvider->getTokenByUser($uid); @@ -126,9 +128,9 @@ class Manager implements IProvider, OCPIProvider { * @param string $tokenId * @throws InvalidTokenException * @throws \RuntimeException when OpenSSL reports a problem - * @return IToken + * @return OCPIToken */ - public function getToken(string $tokenId): IToken { + public function getToken(string $tokenId): OCPIToken { try { return $this->publicKeyTokenProvider->getToken($tokenId); } catch (WipeTokenException $e) { @@ -145,9 +147,9 @@ class Manager implements IProvider, OCPIProvider { * * @param int $tokenId * @throws InvalidTokenException - * @return IToken + * @return OCPIToken */ - public function getTokenById(int $tokenId): IToken { + public function getTokenById(int $tokenId): OCPIToken { try { return $this->publicKeyTokenProvider->getTokenById($tokenId); } catch (ExpiredTokenException $e) { @@ -163,9 +165,9 @@ class Manager implements IProvider, OCPIProvider { * @param string $oldSessionId * @param string $sessionId * @throws InvalidTokenException - * @return IToken + * @return OCPIToken */ - public function renewSessionToken(string $oldSessionId, string $sessionId): IToken { + public function renewSessionToken(string $oldSessionId, string $sessionId): OCPIToken { try { return $this->publicKeyTokenProvider->renewSessionToken($oldSessionId, $sessionId); } catch (ExpiredTokenException $e) { @@ -176,18 +178,18 @@ class Manager implements IProvider, OCPIProvider { } /** - * @param IToken $savedToken + * @param OCPIToken $savedToken * @param string $tokenId session token * @throws InvalidTokenException * @throws PasswordlessTokenException * @return string */ - public function getPassword(IToken $savedToken, string $tokenId): string { + public function getPassword(OCPIToken $savedToken, string $tokenId): string { $provider = $this->getProvider($savedToken); return $provider->getPassword($savedToken, $tokenId); } - public function setPassword(IToken $token, string $tokenId, string $password) { + public function setPassword(OCPIToken $token, string $tokenId, string $password) { $provider = $this->getProvider($token); $provider->setPassword($token, $tokenId, $password); } @@ -209,35 +211,37 @@ class Manager implements IProvider, OCPIProvider { } /** - * @param IToken $token + * @param OCPIToken $token * @param string $oldTokenId * @param string $newTokenId - * @return IToken + * @return OCPIToken * @throws InvalidTokenException * @throws \RuntimeException when OpenSSL reports a problem */ - public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken { + public function rotate(OCPIToken $token, string $oldTokenId, string $newTokenId): OCPIToken { if ($token instanceof PublicKeyToken) { return $this->publicKeyTokenProvider->rotate($token, $oldTokenId, $newTokenId); } - throw new InvalidTokenException(); + /** @psalm-suppress DeprecatedClass We have to throw the OC version so both OC and OCP catches catch it */ + throw new OcInvalidTokenException(); } /** - * @param IToken $token + * @param OCPIToken $token * @return IProvider * @throws InvalidTokenException */ - private function getProvider(IToken $token): IProvider { + private function getProvider(OCPIToken $token): IProvider { if ($token instanceof PublicKeyToken) { return $this->publicKeyTokenProvider; } - throw new InvalidTokenException(); + /** @psalm-suppress DeprecatedClass We have to throw the OC version so both OC and OCP catches catch it */ + throw new OcInvalidTokenException(); } - public function markPasswordInvalid(IToken $token, string $tokenId) { + public function markPasswordInvalid(OCPIToken $token, string $tokenId) { $this->getProvider($token)->markPasswordInvalid($token, $tokenId); } diff --git a/lib/private/Authentication/Token/PublicKeyToken.php b/lib/private/Authentication/Token/PublicKeyToken.php index 45335e17c31..b77a856589d 100644 --- a/lib/private/Authentication/Token/PublicKeyToken.php +++ b/lib/private/Authentication/Token/PublicKeyToken.php @@ -137,10 +137,8 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken { /** * Get the (encrypted) login password - * - * @return string|null */ - public function getPassword() { + public function getPassword(): ?string { return parent::getPassword(); } @@ -165,10 +163,8 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken { /** * Get the timestamp of the last password check - * - * @param int $time */ - public function setLastCheck(int $time) { + public function setLastCheck(int $time): void { parent::setLastCheck($time); } @@ -191,7 +187,7 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken { return $scope; } - public function setScope($scope) { + public function setScope(array|string|null $scope): void { if (is_array($scope)) { parent::setScope(json_encode($scope)); } else { @@ -211,15 +207,15 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken { return parent::getRemember(); } - public function setToken(string $token) { + public function setToken(string $token): void { parent::setToken($token); } - public function setPassword(string $password = null) { + public function setPassword(string $password = null): void { parent::setPassword($password); } - public function setExpires($expires) { + public function setExpires($expires): void { parent::setExpires($expires); } diff --git a/lib/private/Authentication/Token/PublicKeyTokenMapper.php b/lib/private/Authentication/Token/PublicKeyTokenMapper.php index 855639dd907..8f3f54075ae 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenMapper.php +++ b/lib/private/Authentication/Token/PublicKeyTokenMapper.php @@ -29,6 +29,7 @@ namespace OC\Authentication\Token; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\QBMapper; +use OCP\Authentication\Token\IToken; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; @@ -42,8 +43,6 @@ class PublicKeyTokenMapper extends QBMapper { /** * Invalidate (delete) a given token - * - * @param string $token */ public function invalidate(string $token) { /* @var $qb IQueryBuilder */ @@ -150,14 +149,15 @@ class PublicKeyTokenMapper extends QBMapper { return $entities; } - public function deleteById(string $uid, int $id) { + public function getTokenByUserAndId(string $uid, int $id): ?string { /* @var $qb IQueryBuilder */ $qb = $this->db->getQueryBuilder(); - $qb->delete($this->tableName) + $qb->select('token') + ->from($this->tableName) ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid))) ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT))); - $qb->execute(); + return $qb->executeQuery()->fetchOne() ?: null; } /** diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 3fb11611076..6fd2bebc195 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -31,13 +31,15 @@ namespace OC\Authentication\Token; use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; -use OC\Authentication\Exceptions\TokenPasswordExpiredException; use OC\Authentication\Exceptions\PasswordlessTokenException; +use OC\Authentication\Exceptions\TokenPasswordExpiredException; use OC\Authentication\Exceptions\WipeTokenException; -use OCP\AppFramework\Db\TTransactional; -use OCP\Cache\CappedMemoryCache; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\TTransactional; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Authentication\Token\IToken as OCPIToken; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IConfig; use OCP\IDBConnection; use OCP\IUserManager; @@ -47,6 +49,8 @@ use Psr\Log\LoggerInterface; class PublicKeyTokenProvider implements IProvider { public const TOKEN_MIN_LENGTH = 22; + /** Token cache TTL in seconds */ + private const TOKEN_CACHE_TTL = 10; use TTransactional; @@ -67,18 +71,20 @@ class PublicKeyTokenProvider implements IProvider { /** @var ITimeFactory */ private $time; - /** @var CappedMemoryCache */ + /** @var ICache */ private $cache; - private IHasher $hasher; + /** @var IHasher */ + private $hasher; public function __construct(PublicKeyTokenMapper $mapper, - ICrypto $crypto, - IConfig $config, - IDBConnection $db, - LoggerInterface $logger, - ITimeFactory $time, - IHasher $hasher) { + ICrypto $crypto, + IConfig $config, + IDBConnection $db, + LoggerInterface $logger, + ITimeFactory $time, + IHasher $hasher, + ICacheFactory $cacheFactory) { $this->mapper = $mapper; $this->crypto = $crypto; $this->config = $config; @@ -86,7 +92,9 @@ class PublicKeyTokenProvider implements IProvider { $this->logger = $logger; $this->time = $time; - $this->cache = new CappedMemoryCache(); + $this->cache = $cacheFactory->isLocalCacheAvailable() + ? $cacheFactory->createLocal('authtoken_') + : $cacheFactory->createInMemory(); $this->hasher = $hasher; } @@ -94,12 +102,12 @@ class PublicKeyTokenProvider implements IProvider { * {@inheritDoc} */ public function generateToken(string $token, - string $uid, - string $loginName, - ?string $password, - string $name, - int $type = IToken::TEMPORARY_TOKEN, - int $remember = IToken::DO_NOT_REMEMBER): IToken { + string $uid, + string $loginName, + ?string $password, + string $name, + int $type = OCPIToken::TEMPORARY_TOKEN, + int $remember = OCPIToken::DO_NOT_REMEMBER): OCPIToken { if (strlen($token) < self::TOKEN_MIN_LENGTH) { $exception = new InvalidTokenException('Token is too short, minimum of ' . self::TOKEN_MIN_LENGTH . ' characters is required, ' . strlen($token) . ' characters given'); $this->logger->error('Invalid token provided when generating new token', ['exception' => $exception]); @@ -128,12 +136,12 @@ class PublicKeyTokenProvider implements IProvider { } // Add the token to the cache - $this->cache[$dbToken->getToken()] = $dbToken; + $this->cacheToken($dbToken); return $dbToken; } - public function getToken(string $tokenId): IToken { + public function getToken(string $tokenId): OCPIToken { /** * Token length: 72 * @see \OC\Core\Controller\ClientFlowLoginController::generateAppPassword @@ -156,57 +164,76 @@ class PublicKeyTokenProvider implements IProvider { } $tokenHash = $this->hashToken($tokenId); + if ($token = $this->getTokenFromCache($tokenHash)) { + $this->checkToken($token); + return $token; + } - if (isset($this->cache[$tokenHash])) { - if ($this->cache[$tokenHash] instanceof DoesNotExistException) { - $ex = $this->cache[$tokenHash]; - throw new InvalidTokenException("Token does not exist: " . $ex->getMessage(), 0, $ex); - } - $token = $this->cache[$tokenHash]; - } else { + try { + $token = $this->mapper->getToken($tokenHash); + $this->cacheToken($token); + } catch (DoesNotExistException $ex) { try { - $token = $this->mapper->getToken($tokenHash); - $this->cache[$token->getToken()] = $token; - } catch (DoesNotExistException $ex) { - try { - $token = $this->mapper->getToken($this->hashTokenWithEmptySecret($tokenId)); - $this->cache[$token->getToken()] = $token; - $this->rotate($token, $tokenId, $tokenId); - } catch (DoesNotExistException $ex2) { - $this->cache[$tokenHash] = $ex2; - throw new InvalidTokenException("Token does not exist: " . $ex->getMessage(), 0, $ex); - } + $token = $this->mapper->getToken($this->hashTokenWithEmptySecret($tokenId)); + $this->rotate($token, $tokenId, $tokenId); + } catch (DoesNotExistException) { + $this->cacheInvalidHash($tokenHash); + throw new InvalidTokenException("Token does not exist: " . $ex->getMessage(), 0, $ex); } } - if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) { - throw new ExpiredTokenException($token); - } + $this->checkToken($token); - if ($token->getType() === IToken::WIPE_TOKEN) { - throw new WipeTokenException($token); - } + return $token; + } - if ($token->getPasswordInvalid() === true) { - //The password is invalid we should throw an TokenPasswordExpiredException - throw new TokenPasswordExpiredException($token); + /** + * @throws InvalidTokenException when token doesn't exist + */ + private function getTokenFromCache(string $tokenHash): ?PublicKeyToken { + $serializedToken = $this->cache->get($tokenHash); + if (null === $serializedToken) { + if ($this->cache->hasKey($tokenHash)) { + throw new InvalidTokenException('Token does not exist: ' . $tokenHash); + } + + return null; } - return $token; + $token = unserialize($serializedToken, [ + 'allowed_classes' => [PublicKeyToken::class], + ]); + + return $token instanceof PublicKeyToken ? $token : null; + } + + private function cacheToken(PublicKeyToken $token): void { + $this->cache->set($token->getToken(), serialize($token), self::TOKEN_CACHE_TTL); + } + + private function cacheInvalidHash(string $tokenHash) { + // Invalid entries can be kept longer in cache since it’s unlikely to reuse them + $this->cache->set($tokenHash, null, self::TOKEN_CACHE_TTL * 2); } - public function getTokenById(int $tokenId): IToken { + public function getTokenById(int $tokenId): OCPIToken { try { $token = $this->mapper->getTokenById($tokenId); } catch (DoesNotExistException $ex) { throw new InvalidTokenException("Token with ID $tokenId does not exist: " . $ex->getMessage(), 0, $ex); } + $this->checkToken($token); + + return $token; + } + + private function checkToken($token): void { if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) { throw new ExpiredTokenException($token); } - if ($token->getType() === IToken::WIPE_TOKEN) { + if ($token->getType() === OCPIToken::WIPE_TOKEN) { throw new WipeTokenException($token); } @@ -214,13 +241,9 @@ class PublicKeyTokenProvider implements IProvider { //The password is invalid we should throw an TokenPasswordExpiredException throw new TokenPasswordExpiredException($token); } - - return $token; } - public function renewSessionToken(string $oldSessionId, string $sessionId): IToken { - $this->cache->clear(); - + public function renewSessionToken(string $oldSessionId, string $sessionId): OCPIToken { return $this->atomic(function () use ($oldSessionId, $sessionId) { $token = $this->getToken($oldSessionId); @@ -239,10 +262,12 @@ class PublicKeyTokenProvider implements IProvider { $token->getLoginName(), $password, $token->getName(), - IToken::TEMPORARY_TOKEN, + OCPIToken::TEMPORARY_TOKEN, $token->getRemember() ); + $this->cacheToken($newToken); + $this->cacheInvalidHash($token->getToken()); $this->mapper->delete($token); return $newToken; @@ -250,47 +275,44 @@ class PublicKeyTokenProvider implements IProvider { } public function invalidateToken(string $token) { - $this->cache->clear(); - + $tokenHash = $this->hashToken($token); $this->mapper->invalidate($this->hashToken($token)); $this->mapper->invalidate($this->hashTokenWithEmptySecret($token)); + $this->cacheInvalidHash($tokenHash); } public function invalidateTokenById(string $uid, int $id) { - $this->cache->clear(); + $token = $this->mapper->getTokenById($id); + if ($token->getUID() !== $uid) { + return; + } + $this->mapper->invalidate($token->getToken()); + $this->cacheInvalidHash($token->getToken()); - $this->mapper->deleteById($uid, $id); } public function invalidateOldTokens() { - $this->cache->clear(); - $olderThan = $this->time->getTime() - $this->config->getSystemValueInt('session_lifetime', 60 * 60 * 24); $this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']); - $this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER); + $this->mapper->invalidateOld($olderThan, OCPIToken::DO_NOT_REMEMBER); $rememberThreshold = $this->time->getTime() - $this->config->getSystemValueInt('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); $this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']); - $this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER); + $this->mapper->invalidateOld($rememberThreshold, OCPIToken::REMEMBER); } public function invalidateLastUsedBefore(string $uid, int $before): void { - $this->cache->clear(); - $this->mapper->invalidateLastUsedBefore($uid, $before); } - public function updateToken(IToken $token) { - $this->cache->clear(); - + public function updateToken(OCPIToken $token) { if (!($token instanceof PublicKeyToken)) { throw new InvalidTokenException("Invalid token type"); } $this->mapper->update($token); + $this->cacheToken($token); } - public function updateTokenActivity(IToken $token) { - $this->cache->clear(); - + public function updateTokenActivity(OCPIToken $token) { if (!($token instanceof PublicKeyToken)) { throw new InvalidTokenException("Invalid token type"); } @@ -303,6 +325,7 @@ class PublicKeyTokenProvider implements IProvider { if ($token->getLastActivity() < ($now - $activityInterval)) { $token->setLastActivity($now); $this->mapper->updateActivity($token, $now); + $this->cacheToken($token); } } @@ -310,7 +333,7 @@ class PublicKeyTokenProvider implements IProvider { return $this->mapper->getTokenByUser($uid); } - public function getPassword(IToken $savedToken, string $tokenId): string { + public function getPassword(OCPIToken $savedToken, string $tokenId): string { if (!($savedToken instanceof PublicKeyToken)) { throw new InvalidTokenException("Invalid token type"); } @@ -326,9 +349,7 @@ class PublicKeyTokenProvider implements IProvider { return $this->decryptPassword($savedToken->getPassword(), $privateKey); } - public function setPassword(IToken $token, string $tokenId, string $password) { - $this->cache->clear(); - + public function setPassword(OCPIToken $token, string $tokenId, string $password) { if (!($token instanceof PublicKeyToken)) { throw new InvalidTokenException("Invalid token type"); } @@ -353,9 +374,7 @@ class PublicKeyTokenProvider implements IProvider { return $this->hasher->hash(sha1($password) . $password); } - public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken { - $this->cache->clear(); - + public function rotate(OCPIToken $token, string $oldTokenId, string $newTokenId): OCPIToken { if (!($token instanceof PublicKeyToken)) { throw new InvalidTokenException("Invalid token type"); } @@ -425,12 +444,12 @@ class PublicKeyTokenProvider implements IProvider { * @throws \RuntimeException when OpenSSL reports a problem */ private function newToken(string $token, - string $uid, - string $loginName, - $password, - string $name, - int $type, - int $remember): PublicKeyToken { + string $uid, + string $loginName, + $password, + string $name, + int $type, + int $remember): PublicKeyToken { $dbToken = new PublicKeyToken(); $dbToken->setUid($uid); $dbToken->setLoginName($loginName); @@ -478,20 +497,17 @@ class PublicKeyTokenProvider implements IProvider { return $dbToken; } - public function markPasswordInvalid(IToken $token, string $tokenId) { - $this->cache->clear(); - + public function markPasswordInvalid(OCPIToken $token, string $tokenId) { if (!($token instanceof PublicKeyToken)) { throw new InvalidTokenException("Invalid token type"); } $token->setPasswordInvalid(true); $this->mapper->update($token); + $this->cacheToken($token); } public function updatePasswords(string $uid, string $password) { - $this->cache->clear(); - // prevent setting an empty pw as result of pw-less-login if ($password === '' || !$this->config->getSystemValueBool('auth.storeCryptedPassword', true)) { return; diff --git a/lib/private/Authentication/Token/RemoteWipe.php b/lib/private/Authentication/Token/RemoteWipe.php index 5fd01cfbe87..f5267764e24 100644 --- a/lib/private/Authentication/Token/RemoteWipe.php +++ b/lib/private/Authentication/Token/RemoteWipe.php @@ -27,14 +27,14 @@ declare(strict_types=1); */ namespace OC\Authentication\Token; -use Psr\Log\LoggerInterface; -use function array_filter; use OC\Authentication\Events\RemoteWipeFinished; use OC\Authentication\Events\RemoteWipeStarted; -use OC\Authentication\Exceptions\InvalidTokenException; -use OC\Authentication\Exceptions\WipeTokenException; +use OCP\Authentication\Exceptions\InvalidTokenException; +use OCP\Authentication\Exceptions\WipeTokenException; use OCP\EventDispatcher\IEventDispatcher; use OCP\IUser; +use Psr\Log\LoggerInterface; +use function array_filter; class RemoteWipe { /** @var IProvider */ @@ -47,8 +47,8 @@ class RemoteWipe { private $logger; public function __construct(IProvider $tokenProvider, - IEventDispatcher $eventDispatcher, - LoggerInterface $logger) { + IEventDispatcher $eventDispatcher, + LoggerInterface $logger) { $this->tokenProvider = $tokenProvider; $this->eventDispatcher = $eventDispatcher; $this->logger = $logger; diff --git a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php index 4817c6b8de0..97d6a02b4c4 100644 --- a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php +++ b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php @@ -25,8 +25,6 @@ declare(strict_types=1); */ namespace OC\Authentication\TwoFactorAuth\Db; -use Doctrine\DBAL\Exception\UniqueConstraintViolationException; -use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use function array_map; @@ -70,25 +68,24 @@ class ProviderUserAssignmentDao { * Persist a new/updated (provider_id, uid, enabled) tuple */ public function persist(string $providerId, string $uid, int $enabled): void { - $qb = $this->conn->getQueryBuilder(); - - try { - // Insert a new entry - $insertQuery = $qb->insert(self::TABLE_NAME)->values([ - 'provider_id' => $qb->createNamedParameter($providerId), - 'uid' => $qb->createNamedParameter($uid), - 'enabled' => $qb->createNamedParameter($enabled, IQueryBuilder::PARAM_INT), - ]); - - $insertQuery->execute(); - } catch (UniqueConstraintViolationException $ex) { - // There is already an entry -> update it - $updateQuery = $qb->update(self::TABLE_NAME) - ->set('enabled', $qb->createNamedParameter($enabled)) - ->where($qb->expr()->eq('provider_id', $qb->createNamedParameter($providerId))) - ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid))); - $updateQuery->execute(); + $conn = $this->conn; + + // Insert a new entry + if ($conn->insertIgnoreConflict(self::TABLE_NAME, [ + 'provider_id' => $providerId, + 'uid' => $uid, + 'enabled' => $enabled, + ])) { + return; } + + // There is already an entry -> update it + $qb = $conn->getQueryBuilder(); + $updateQuery = $qb->update(self::TABLE_NAME) + ->set('enabled', $qb->createNamedParameter($enabled)) + ->where($qb->expr()->eq('provider_id', $qb->createNamedParameter($providerId))) + ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid))); + $updateQuery->executeStatement(); } /** diff --git a/lib/private/Authentication/TwoFactorAuth/EnforcementState.php b/lib/private/Authentication/TwoFactorAuth/EnforcementState.php index b95128c1e0f..91f133d6ad0 100644 --- a/lib/private/Authentication/TwoFactorAuth/EnforcementState.php +++ b/lib/private/Authentication/TwoFactorAuth/EnforcementState.php @@ -45,8 +45,8 @@ class EnforcementState implements JsonSerializable { * @param string[] $excludedGroups */ public function __construct(bool $enforced, - array $enforcedGroups = [], - array $excludedGroups = []) { + array $enforcedGroups = [], + array $excludedGroups = []) { $this->enforced = $enforced; $this->enforcedGroups = $enforcedGroups; $this->excludedGroups = $excludedGroups; diff --git a/lib/private/Authentication/TwoFactorAuth/Manager.php b/lib/private/Authentication/TwoFactorAuth/Manager.php index ff0c33445a2..3870c797f8d 100644 --- a/lib/private/Authentication/TwoFactorAuth/Manager.php +++ b/lib/private/Authentication/TwoFactorAuth/Manager.php @@ -29,10 +29,10 @@ namespace OC\Authentication\TwoFactorAuth; use BadMethodCallException; use Exception; -use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Token\IProvider as TokenProvider; use OCP\Activity\IManager; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Authentication\Exceptions\InvalidTokenException; use OCP\Authentication\TwoFactorAuth\IActivatableAtLogin; use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\Authentication\TwoFactorAuth\IRegistry; @@ -89,15 +89,15 @@ class Manager { private $userIsTwoFactorAuthenticated = []; public function __construct(ProviderLoader $providerLoader, - IRegistry $providerRegistry, - MandatoryTwoFactor $mandatoryTwoFactor, - ISession $session, - IConfig $config, - IManager $activityManager, - LoggerInterface $logger, - TokenProvider $tokenProvider, - ITimeFactory $timeFactory, - IEventDispatcher $eventDispatcher) { + IRegistry $providerRegistry, + MandatoryTwoFactor $mandatoryTwoFactor, + ISession $session, + IConfig $config, + IManager $activityManager, + LoggerInterface $logger, + TokenProvider $tokenProvider, + ITimeFactory $timeFactory, + IEventDispatcher $eventDispatcher) { $this->providerLoader = $providerLoader; $this->providerRegistry = $providerRegistry; $this->mandatoryTwoFactor = $mandatoryTwoFactor; @@ -318,8 +318,8 @@ class Manager { return false; } - // If we are authenticated using an app password skip all this - if ($this->session->exists('app_password')) { + // If we are authenticated using an app password or AppAPI Auth, skip all this + if ($this->session->exists('app_password') || $this->session->get('app_api') === true) { return false; } diff --git a/lib/private/Authentication/TwoFactorAuth/ProviderSet.php b/lib/private/Authentication/TwoFactorAuth/ProviderSet.php index af270fb83c8..4d39fd82bc6 100644 --- a/lib/private/Authentication/TwoFactorAuth/ProviderSet.php +++ b/lib/private/Authentication/TwoFactorAuth/ProviderSet.php @@ -25,9 +25,9 @@ declare(strict_types=1); */ namespace OC\Authentication\TwoFactorAuth; -use function array_filter; use OCA\TwoFactorBackupCodes\Provider\BackupCodesProvider; use OCP\Authentication\TwoFactorAuth\IProvider; +use function array_filter; /** * Contains all two-factor provider information for the two-factor login challenge diff --git a/lib/private/Authentication/TwoFactorAuth/Registry.php b/lib/private/Authentication/TwoFactorAuth/Registry.php index 482c025e144..db772265583 100644 --- a/lib/private/Authentication/TwoFactorAuth/Registry.php +++ b/lib/private/Authentication/TwoFactorAuth/Registry.php @@ -45,7 +45,7 @@ class Registry implements IRegistry { private $dispatcher; public function __construct(ProviderUserAssignmentDao $assignmentDao, - IEventDispatcher $dispatcher) { + IEventDispatcher $dispatcher) { $this->assignmentDao = $assignmentDao; $this->dispatcher = $dispatcher; } diff --git a/lib/private/Authentication/WebAuthn/Manager.php b/lib/private/Authentication/WebAuthn/Manager.php index 744a3fa354a..5a97a573b99 100644 --- a/lib/private/Authentication/WebAuthn/Manager.php +++ b/lib/private/Authentication/WebAuthn/Manager.php @@ -91,7 +91,7 @@ class Manager { $user->getUID(), //Name $user->getUID(), //ID $user->getDisplayName() //Display name -// 'https://foo.example.co/avatar/123e4567-e89b-12d3-a456-426655440000' //Icon + // 'https://foo.example.co/avatar/123e4567-e89b-12d3-a456-426655440000' //Icon ); $challenge = random_bytes(32); diff --git a/lib/private/Avatar/AvatarManager.php b/lib/private/Avatar/AvatarManager.php index 4125c8eb0a8..e88feb37ecd 100644 --- a/lib/private/Avatar/AvatarManager.php +++ b/lib/private/Avatar/AvatarManager.php @@ -55,59 +55,26 @@ use Psr\Log\LoggerInterface; * This class implements methods to access Avatar functionality */ class AvatarManager implements IAvatarManager { - /** @var IUserSession */ - private $userSession; - - /** @var Manager */ - private $userManager; - - /** @var IAppData */ - private $appData; - - /** @var IL10N */ - private $l; - - /** @var LoggerInterface */ - private $logger; - - /** @var IConfig */ - private $config; - - /** @var IAccountManager */ - private $accountManager; - - /** @var KnownUserService */ - private $knownUserService; - public function __construct( - IUserSession $userSession, - Manager $userManager, - IAppData $appData, - IL10N $l, - LoggerInterface $logger, - IConfig $config, - IAccountManager $accountManager, - KnownUserService $knownUserService + private IUserSession $userSession, + private Manager $userManager, + private IAppData $appData, + private IL10N $l, + private LoggerInterface $logger, + private IConfig $config, + private IAccountManager $accountManager, + private KnownUserService $knownUserService, ) { - $this->userSession = $userSession; - $this->userManager = $userManager; - $this->appData = $appData; - $this->l = $l; - $this->logger = $logger; - $this->config = $config; - $this->accountManager = $accountManager; - $this->knownUserService = $knownUserService; } /** * return a user specific instance of \OCP\IAvatar * @see \OCP\IAvatar * @param string $userId the ownCloud user id - * @return \OCP\IAvatar * @throws \Exception In case the username is potentially dangerous * @throws NotFoundException In case there is no user folder yet */ - public function getAvatar(string $userId) : IAvatar { + public function getAvatar(string $userId): IAvatar { $user = $this->userManager->get($userId); if ($user === null) { throw new \Exception('user does not exist'); @@ -116,10 +83,7 @@ class AvatarManager implements IAvatarManager { // sanitize userID - fixes casing issue (needed for the filesystem stuff that is done below) $userId = $user->getUID(); - $requestingUser = null; - if ($this->userSession !== null) { - $requestingUser = $this->userSession->getUser(); - } + $requestingUser = $this->userSession->getUser(); try { $folder = $this->appData->getFolder($userId); @@ -157,7 +121,7 @@ class AvatarManager implements IAvatarManager { /** * Clear generated avatars */ - public function clearCachedAvatars() { + public function clearCachedAvatars(): void { $users = $this->config->getUsersForUserValue('avatar', 'generated', 'true'); foreach ($users as $userId) { // This also bumps the avatar version leading to cache invalidation in browsers @@ -174,7 +138,7 @@ class AvatarManager implements IAvatarManager { } catch (NotPermittedException | StorageNotAvailableException $e) { $this->logger->error("Unable to delete user avatars for $userId. gnoring avatar deletion"); } catch (NoUserException $e) { - $this->logger->debug("User $userId not found. gnoring avatar deletion"); + $this->logger->debug("Account $userId not found. Ignoring avatar deletion"); } $this->config->deleteUserValue($userId, 'avatar', 'generated'); } @@ -183,7 +147,6 @@ class AvatarManager implements IAvatarManager { * Returns a GuestAvatar. * * @param string $name The guest name, e.g. "Albert". - * @return IAvatar */ public function getGuestAvatar(string $name): IAvatar { return new GuestAvatar($name, $this->logger); diff --git a/lib/private/Avatar/GuestAvatar.php b/lib/private/Avatar/GuestAvatar.php index 083deb4108f..106e159d192 100644 --- a/lib/private/Avatar/GuestAvatar.php +++ b/lib/private/Avatar/GuestAvatar.php @@ -26,8 +26,8 @@ declare(strict_types=1); */ namespace OC\Avatar; -use OCP\Files\SimpleFS\ISimpleFile; use OCP\Files\SimpleFS\InMemoryFile; +use OCP\Files\SimpleFS\ISimpleFile; use Psr\Log\LoggerInterface; /** @@ -35,18 +35,15 @@ use Psr\Log\LoggerInterface; */ class GuestAvatar extends Avatar { /** - * Holds the guest user display name. - */ - private string $userDisplayName; - - /** * GuestAvatar constructor. * * @param string $userDisplayName The guest user display name */ - public function __construct(string $userDisplayName, LoggerInterface $logger) { + public function __construct( + private string $userDisplayName, + LoggerInterface $logger, + ) { parent::__construct($logger); - $this->userDisplayName = $userDisplayName; } /** @@ -68,7 +65,6 @@ class GuestAvatar extends Avatar { * Setting avatars isn't implemented for guests. * * @param \OCP\IImage|resource|string $data - * @return void */ public function set($data): void { // unimplemented for guest user avatars diff --git a/lib/private/Avatar/PlaceholderAvatar.php b/lib/private/Avatar/PlaceholderAvatar.php index e7ca89f4d30..d420ebe574a 100644 --- a/lib/private/Avatar/PlaceholderAvatar.php +++ b/lib/private/Avatar/PlaceholderAvatar.php @@ -32,9 +32,7 @@ use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\Files\SimpleFS\ISimpleFile; use OCP\Files\SimpleFS\ISimpleFolder; -use OCP\IConfig; use OCP\IImage; -use OCP\IL10N; use Psr\Log\LoggerInterface; /** @@ -44,26 +42,12 @@ use Psr\Log\LoggerInterface; * for faster retrieval, unlike the GuestAvatar. */ class PlaceholderAvatar extends Avatar { - private ISimpleFolder $folder; - private User $user; - - /** - * UserAvatar constructor. - * - * @param IConfig $config The configuration - * @param ISimpleFolder $folder The avatar files folder - * @param IL10N $l The localization helper - * @param User $user The user this class manages the avatar for - * @param LoggerInterface $logger The logger - */ public function __construct( - ISimpleFolder $folder, - $user, - LoggerInterface $logger) { + private ISimpleFolder $folder, + private User $user, + LoggerInterface $logger, + ) { parent::__construct($logger); - - $this->folder = $folder; - $this->user = $user; } /** @@ -80,7 +64,6 @@ class PlaceholderAvatar extends Avatar { * @throws \Exception if the provided file is not a jpg or png image * @throws \Exception if the provided image is not valid * @throws NotSquareException if the image is not square - * @return void */ public function set($data): void { // unimplemented for placeholder avatars @@ -102,8 +85,6 @@ class PlaceholderAvatar extends Avatar { * * If there is no avatar file yet, one is generated. * - * @param int $size - * @return ISimpleFile * @throws NotFoundException * @throws \OCP\Files\NotPermittedException * @throws \OCP\PreConditionNotMetException diff --git a/lib/private/Avatar/UserAvatar.php b/lib/private/Avatar/UserAvatar.php index 6d39d5f067d..f96259641f3 100644 --- a/lib/private/Avatar/UserAvatar.php +++ b/lib/private/Avatar/UserAvatar.php @@ -44,31 +44,14 @@ use Psr\Log\LoggerInterface; * This class represents a registered user's avatar. */ class UserAvatar extends Avatar { - private IConfig $config; - private ISimpleFolder $folder; - private IL10N $l; - private User $user; - - /** - * UserAvatar constructor. - * - * @param IConfig $config The configuration - * @param ISimpleFolder $folder The avatar files folder - * @param IL10N $l The localization helper - * @param User $user The user this class manages the avatar for - * @param LoggerInterface $logger The logger - */ public function __construct( - ISimpleFolder $folder, - IL10N $l, - User $user, + private ISimpleFolder $folder, + private IL10N $l, + private User $user, LoggerInterface $logger, - IConfig $config) { + private IConfig $config, + ) { parent::__construct($logger); - $this->folder = $folder; - $this->l = $l; - $this->user = $user; - $this->config = $config; } /** @@ -85,7 +68,6 @@ class UserAvatar extends Avatar { * @throws \Exception if the provided file is not a jpg or png image * @throws \Exception if the provided image is not valid * @throws NotSquareException if the image is not square - * @return void */ public function set($data): void { $img = $this->getAvatarImage($data); @@ -113,7 +95,6 @@ class UserAvatar extends Avatar { * Returns an image from several sources. * * @param IImage|resource|string|\GdImage $data An image object, imagedata or path to the avatar - * @return IImage */ private function getAvatarImage($data): IImage { if ($data instanceof IImage) { @@ -229,8 +210,6 @@ class UserAvatar extends Avatar { * * If there is no avatar file yet, one is generated. * - * @param int $size - * @return ISimpleFile * @throws NotFoundException * @throws \OCP\Files\NotPermittedException * @throws \OCP\PreConditionNotMetException diff --git a/lib/private/BackgroundJob/Job.php b/lib/private/BackgroundJob/Job.php deleted file mode 100644 index ffcaaf8c36d..00000000000 --- a/lib/private/BackgroundJob/Job.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Noveen Sachdeva <noveen.sachdeva@research.iiit.ac.in> - * @author Robin Appelman <robin@icewind.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ -namespace OC\BackgroundJob; - -use OCP\BackgroundJob\IJob; -use OCP\BackgroundJob\IJobList; -use OCP\ILogger; - -/** - * @deprecated internal class, use \OCP\BackgroundJob\Job - */ -abstract class Job implements IJob { - /** @var int */ - protected $id; - - /** @var int */ - protected $lastRun; - - /** @var mixed */ - protected $argument; - - public function execute(IJobList $jobList, ILogger $logger = null) { - $jobList->setLastRun($this); - if ($logger === null) { - $logger = \OC::$server->getLogger(); - } - - try { - $jobStartTime = time(); - $logger->debug('Run ' . get_class($this) . ' job with ID ' . $this->getId(), ['app' => 'cron']); - $this->run($this->argument); - $timeTaken = time() - $jobStartTime; - - $logger->debug('Finished ' . get_class($this) . ' job with ID ' . $this->getId() . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']); - $jobList->setExecutionTime($this, $timeTaken); - } catch (\Throwable $e) { - if ($logger) { - $logger->logException($e, [ - 'app' => 'core', - 'message' => 'Error while running background job (class: ' . get_class($this) . ', arguments: ' . print_r($this->argument, true) . ')' - ]); - } - } - } - - public function start(IJobList $jobList): void { - $this->execute($jobList); - } - - abstract protected function run($argument); - - public function setId(int $id) { - $this->id = $id; - } - - public function setLastRun(int $lastRun) { - $this->lastRun = $lastRun; - } - - public function setArgument($argument) { - $this->argument = $argument; - } - - public function getId() { - return $this->id; - } - - public function getLastRun() { - return $this->lastRun; - } - - public function getArgument() { - return $this->argument; - } -} diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php index 36cccbd4eab..93d5cf74a20 100644 --- a/lib/private/BackgroundJob/JobList.php +++ b/lib/private/BackgroundJob/JobList.php @@ -41,6 +41,10 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IConfig; use OCP\IDBConnection; use Psr\Log\LoggerInterface; +use function get_class; +use function json_encode; +use function md5; +use function strlen; class JobList implements IJobList { protected IDBConnection $connection; @@ -55,11 +59,10 @@ class JobList implements IJobList { $this->logger = $logger; } - /** - * @param IJob|class-string<IJob> $job - * @param mixed $argument - */ - public function add($job, $argument = null): void { + public function add($job, $argument = null, int $firstCheck = null): void { + if ($firstCheck === null) { + $firstCheck = $this->timeFactory->getTime(); + } if ($job instanceof IJob) { $class = get_class($job); } else { @@ -79,18 +82,23 @@ class JobList implements IJobList { 'argument' => $query->createNamedParameter($argumentJson), 'argument_hash' => $query->createNamedParameter(md5($argumentJson)), 'last_run' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT), - 'last_checked' => $query->createNamedParameter($this->timeFactory->getTime(), IQueryBuilder::PARAM_INT), + 'last_checked' => $query->createNamedParameter($firstCheck, IQueryBuilder::PARAM_INT), ]); } else { $query->update('jobs') ->set('reserved_at', $query->expr()->literal(0, IQueryBuilder::PARAM_INT)) - ->set('last_checked', $query->createNamedParameter($this->timeFactory->getTime(), IQueryBuilder::PARAM_INT)) + ->set('last_checked', $query->createNamedParameter($firstCheck, IQueryBuilder::PARAM_INT)) + ->set('last_run', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT)) ->where($query->expr()->eq('class', $query->createNamedParameter($class))) ->andWhere($query->expr()->eq('argument_hash', $query->createNamedParameter(md5($argumentJson)))); } $query->executeStatement(); } + public function scheduleAfter(string $job, int $runAfter, $argument = null): void { + $this->add($job, $argument, $runAfter); + } + /** * @param IJob|string $job * @param mixed $argument @@ -384,6 +392,7 @@ class JobList implements IJobList { $query = $this->connection->getQueryBuilder(); $query->update('jobs') ->set('execution_duration', $query->createNamedParameter($timeTaken, IQueryBuilder::PARAM_INT)) + ->set('reserved_at', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT)) ->where($query->expr()->eq('id', $query->createNamedParameter($job->getId(), IQueryBuilder::PARAM_INT))); $query->executeStatement(); } @@ -406,7 +415,7 @@ class JobList implements IJobList { $query = $this->connection->getQueryBuilder(); $query->select('*') ->from('jobs') - ->where($query->expr()->neq('reserved_at', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT))) + ->where($query->expr()->gt('reserved_at', $query->createNamedParameter($this->timeFactory->getTime() - 6 * 3600, IQueryBuilder::PARAM_INT))) ->setMaxResults(1); if ($className !== null) { diff --git a/lib/private/BackgroundJob/TimedJob.php b/lib/private/BackgroundJob/TimedJob.php deleted file mode 100644 index 0f0951e1aec..00000000000 --- a/lib/private/BackgroundJob/TimedJob.php +++ /dev/null @@ -1,63 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ -namespace OC\BackgroundJob; - -use OCP\BackgroundJob\IJobList; -use OCP\ILogger; - -/** - * Class QueuedJob - * - * create a background job that is to be executed at an interval - * - * @package OC\BackgroundJob - * - * @deprecated internal class, use \OCP\BackgroundJob\TimedJob - */ -abstract class TimedJob extends Job { - protected $interval = 0; - - /** - * set the interval for the job - * - * @param int $interval - */ - public function setInterval($interval) { - $this->interval = $interval; - } - - /** - * run the job if - * - * @param IJobList $jobList - * @param ILogger|null $logger - */ - public function execute($jobList, ILogger $logger = null) { - if ((time() - $this->lastRun) > $this->interval) { - parent::execute($jobList, $logger); - } - } -} diff --git a/lib/private/BinaryFinder.php b/lib/private/BinaryFinder.php index a7ef55237db..17427e92619 100644 --- a/lib/private/BinaryFinder.php +++ b/lib/private/BinaryFinder.php @@ -22,9 +22,9 @@ declare(strict_types = 1); namespace OC; +use OCP\IBinaryFinder; use OCP\ICache; use OCP\ICacheFactory; -use OCP\IBinaryFinder; use Symfony\Component\Process\ExecutableFinder; /** diff --git a/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php b/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php new file mode 100644 index 00000000000..b57dfa317e4 --- /dev/null +++ b/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php @@ -0,0 +1,170 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2024 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Blurhash\Listener; + +use GdImage; +use kornrunner\Blurhash\Blurhash; +use OC\Files\Node\File; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\EventDispatcher\IEventListener; +use OCP\Files\GenericFileException; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; +use OCP\FilesMetadata\AMetadataEvent; +use OCP\FilesMetadata\Event\MetadataBackgroundEvent; +use OCP\FilesMetadata\Event\MetadataLiveEvent; +use OCP\IPreview; +use OCP\Lock\LockedException; + +/** + * Generate a Blurhash string as metadata when image file is uploaded/edited. + * + * @template-implements IEventListener<AMetadataEvent> + */ +class GenerateBlurhashMetadata implements IEventListener { + private const RESIZE_BOXSIZE = 300; + + private const COMPONENTS_X = 4; + private const COMPONENTS_Y = 3; + + public function __construct( + private IPreview $preview, + ) { + } + + /** + * @throws NotPermittedException + * @throws GenericFileException + * @throws LockedException + */ + public function handle(Event $event): void { + if (!($event instanceof MetadataLiveEvent) + && !($event instanceof MetadataBackgroundEvent)) { + return; + } + + $file = $event->getNode(); + if (!($file instanceof File)) { + return; + } + + $currentEtag = $file->getEtag(); + $metadata = $event->getMetadata(); + if ($metadata->getEtag('blurhash') === $currentEtag) { + return; + } + + // too heavy to run on the live thread, request a rerun as a background job + if ($event instanceof MetadataLiveEvent) { + $event->requestBackgroundJob(); + return; + } + + $image = false; + try { + // using preview image to generate the blurhash + $preview = $this->preview->getPreview($file, 256, 256); + $image = imagecreatefromstring($preview->getContent()); + } catch (NotFoundException $e) { + // https://github.com/nextcloud/server/blob/9d70fd3e64b60a316a03fb2b237891380c310c58/lib/private/legacy/OC_Image.php#L668 + // The preview system can fail on huge picture, in that case we use our own image resizer. + if (str_starts_with($file->getMimetype(), 'image/')) { + $image = $this->resizedImageFromFile($file); + } + } + + if ($image === false) { + return; + } + + $metadata->setString('blurhash', $this->generateBlurHash($image)) + ->setEtag('blurhash', $currentEtag); + } + + /** + * @param File $file + * + * @return GdImage|false + * @throws GenericFileException + * @throws NotPermittedException + * @throws LockedException + */ + private function resizedImageFromFile(File $file): GdImage|false { + $image = imagecreatefromstring($file->getContent()); + if ($image === false) { + return false; + } + + $currX = imagesx($image); + $currY = imagesy($image); + + if ($currX > $currY) { + $newX = self::RESIZE_BOXSIZE; + $newY = intval($currY * $newX / $currX); + } else { + $newY = self::RESIZE_BOXSIZE; + $newX = intval($currX * $newY / $currY); + } + + $newImage = imagescale($image, $newX, $newY); + return ($newImage !== false) ? $newImage : $image; + } + + /** + * @param GdImage $image + * + * @return string + */ + public function generateBlurHash(GdImage $image): string { + $width = imagesx($image); + $height = imagesy($image); + + $pixels = []; + for ($y = 0; $y < $height; ++$y) { + $row = []; + for ($x = 0; $x < $width; ++$x) { + $index = imagecolorat($image, $x, $y); + $colors = imagecolorsforindex($image, $index); + $row[] = [$colors['red'], $colors['green'], $colors['blue']]; + } + + $pixels[] = $row; + } + + return Blurhash::encode($pixels, self::COMPONENTS_X, self::COMPONENTS_Y); + } + + /** + * @param IEventDispatcher $eventDispatcher + * + * @return void + */ + public static function loadListeners(IEventDispatcher $eventDispatcher): void { + $eventDispatcher->addServiceListener(MetadataLiveEvent::class, self::class); + $eventDispatcher->addServiceListener(MetadataBackgroundEvent::class, self::class); + } +} diff --git a/lib/private/Cache/File.php b/lib/private/Cache/File.php index 72fc95a802b..74e795cc377 100644 --- a/lib/private/Cache/File.php +++ b/lib/private/Cache/File.php @@ -60,7 +60,7 @@ class File implements ICache { $this->storage = new View('/' . $user->getUID() . '/cache'); return $this->storage; } else { - \OC::$server->get(LoggerInterface::class)->error('Can\'t get cache storage, user not logged in', ['app' => 'core']); + \OCP\Server::get(LoggerInterface::class)->error('Can\'t get cache storage, user not logged in', ['app' => 'core']); throw new \OC\ForbiddenException('Can\t get cache storage, user not logged in'); } } @@ -192,11 +192,11 @@ class File implements ICache { } } catch (\OCP\Lock\LockedException $e) { // ignore locked chunks - \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', ['app' => 'core']); + \OCP\Server::get(LoggerInterface::class)->debug('Could not cleanup locked chunk "' . $file . '"', ['app' => 'core']); } catch (\OCP\Files\ForbiddenException $e) { - \OC::$server->getLogger()->debug('Could not cleanup forbidden chunk "' . $file . '"', ['app' => 'core']); + \OCP\Server::get(LoggerInterface::class)->debug('Could not cleanup forbidden chunk "' . $file . '"', ['app' => 'core']); } catch (\OCP\Files\LockNotAcquiredException $e) { - \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', ['app' => 'core']); + \OCP\Server::get(LoggerInterface::class)->debug('Could not cleanup locked chunk "' . $file . '"', ['app' => 'core']); } } } diff --git a/lib/private/CapabilitiesManager.php b/lib/private/CapabilitiesManager.php index 7885a98869d..6b34b50cb98 100644 --- a/lib/private/CapabilitiesManager.php +++ b/lib/private/CapabilitiesManager.php @@ -30,8 +30,8 @@ namespace OC; use OCP\AppFramework\QueryException; use OCP\Capabilities\ICapability; -use OCP\Capabilities\IPublicCapability; use OCP\Capabilities\IInitialStateExcludedCapability; +use OCP\Capabilities\IPublicCapability; use Psr\Log\LoggerInterface; class CapabilitiesManager { diff --git a/lib/private/Collaboration/AutoComplete/Manager.php b/lib/private/Collaboration/AutoComplete/Manager.php index cab15baf535..7b40165d4d8 100644 --- a/lib/private/Collaboration/AutoComplete/Manager.php +++ b/lib/private/Collaboration/AutoComplete/Manager.php @@ -29,47 +29,46 @@ use OCP\IServerContainer; class Manager implements IManager { /** @var string[] */ - protected $sorters = []; + protected array $sorters = []; /** @var ISorter[] */ - protected $sorterInstances = []; - /** @var IServerContainer */ - private $c; + protected array $sorterInstances = []; - public function __construct(IServerContainer $container) { - $this->c = $container; + public function __construct( + private IServerContainer $container, + ) { } - public function runSorters(array $sorters, array &$sortArray, array $context) { + public function runSorters(array $sorters, array &$sortArray, array $context): void { $sorterInstances = $this->getSorters(); while ($sorter = array_shift($sorters)) { if (isset($sorterInstances[$sorter])) { $sorterInstances[$sorter]->sort($sortArray, $context); } else { - $this->c->getLogger()->warning('No sorter for ID "{id}", skipping', [ + $this->container->getLogger()->warning('No sorter for ID "{id}", skipping', [ 'app' => 'core', 'id' => $sorter ]); } } } - public function registerSorter($className) { + public function registerSorter($className): void { $this->sorters[] = $className; } - protected function getSorters() { + protected function getSorters(): array { if (count($this->sorterInstances) === 0) { foreach ($this->sorters as $sorter) { /** @var ISorter $instance */ - $instance = $this->c->resolve($sorter); + $instance = $this->container->resolve($sorter); if (!$instance instanceof ISorter) { - $this->c->getLogger()->notice('Skipping sorter which is not an instance of ISorter. Class name: {class}', + $this->container->getLogger()->notice('Skipping sorter which is not an instance of ISorter. Class name: {class}', ['app' => 'core', 'class' => $sorter]); continue; } $sorterId = trim($instance->getId()); if (trim($sorterId) === '') { - $this->c->getLogger()->notice('Skipping sorter with empty ID. Class name: {class}', + $this->container->getLogger()->notice('Skipping sorter with empty ID. Class name: {class}', ['app' => 'core', 'class' => $sorter]); continue; } diff --git a/lib/private/Collaboration/Collaborators/GroupPlugin.php b/lib/private/Collaboration/Collaborators/GroupPlugin.php index 75e52c19e0b..91e665db783 100644 --- a/lib/private/Collaboration/Collaborators/GroupPlugin.php +++ b/lib/private/Collaboration/Collaborators/GroupPlugin.php @@ -37,34 +37,31 @@ use OCP\IUserSession; use OCP\Share\IShare; class GroupPlugin implements ISearchPlugin { - /** @var bool */ - protected $shareeEnumeration; - /** @var bool */ - protected $shareWithGroupOnly; - /** @var bool */ - protected $shareeEnumerationInGroupOnly; - /** @var bool */ - protected $groupSharingDisabled; - - /** @var IGroupManager */ - private $groupManager; - /** @var IConfig */ - private $config; - /** @var IUserSession */ - private $userSession; - - public function __construct(IConfig $config, IGroupManager $groupManager, IUserSession $userSession) { - $this->groupManager = $groupManager; - $this->config = $config; - $this->userSession = $userSession; + protected bool $shareeEnumeration; + protected bool $shareWithGroupOnly; + + protected bool $shareeEnumerationInGroupOnly; + + protected bool $groupSharingDisabled; + + public function __construct( + private IConfig $config, + private IGroupManager $groupManager, + private IUserSession $userSession, + private mixed $shareWithGroupOnlyExcludeGroupsList = [], + ) { $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes'; $this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes'; $this->groupSharingDisabled = $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'no'; + + if ($this->shareWithGroupOnly) { + $this->shareWithGroupOnlyExcludeGroupsList = json_decode($this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', ''), true) ?? []; + } } - public function search($search, $limit, $offset, ISearchResult $searchResult) { + public function search($search, $limit, $offset, ISearchResult $searchResult): bool { if ($this->groupSharingDisabled) { return false; } @@ -89,6 +86,9 @@ class GroupPlugin implements ISearchPlugin { return $group->getGID(); }, $userGroups); $groupIds = array_intersect($groupIds, $userGroups); + + // ShareWithGroupOnly filtering + $groupIds = array_diff($groupIds, $this->shareWithGroupOnlyExcludeGroupsList); } $lowerSearch = strtolower($search); diff --git a/lib/private/Collaboration/Collaborators/LookupPlugin.php b/lib/private/Collaboration/Collaborators/LookupPlugin.php index 86ac70ab970..5a03e4f8673 100644 --- a/lib/private/Collaboration/Collaborators/LookupPlugin.php +++ b/lib/private/Collaboration/Collaborators/LookupPlugin.php @@ -38,31 +38,21 @@ use OCP\Share\IShare; use Psr\Log\LoggerInterface; class LookupPlugin implements ISearchPlugin { - /** @var IConfig */ - private $config; - /** @var IClientService */ - private $clientService; /** @var string remote part of the current user's cloud id */ - private $currentUserRemote; - /** @var ICloudIdManager */ - private $cloudIdManager; - /** @var LoggerInterface */ - private $logger; + private string $currentUserRemote; - public function __construct(IConfig $config, - IClientService $clientService, - IUserSession $userSession, - ICloudIdManager $cloudIdManager, - LoggerInterface $logger) { - $this->config = $config; - $this->clientService = $clientService; - $this->cloudIdManager = $cloudIdManager; + public function __construct( + private IConfig $config, + private IClientService $clientService, + IUserSession $userSession, + private ICloudIdManager $cloudIdManager, + private LoggerInterface $logger, + ) { $currentUserCloudId = $userSession->getUser()->getCloudId(); $this->currentUserRemote = $cloudIdManager->resolveCloudId($currentUserCloudId)->getRemote(); - $this->logger = $logger; } - public function search($search, $limit, $offset, ISearchResult $searchResult) { + public function search($search, $limit, $offset, ISearchResult $searchResult): bool { $isGlobalScaleEnabled = $this->config->getSystemValueBool('gs.enabled', false); $isLookupServerEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes'; $hasInternetConnection = $this->config->getSystemValueBool('has_internet_connection', true); @@ -103,7 +93,7 @@ class LookupPlugin implements ISearchPlugin { if ($this->currentUserRemote === $remote) { continue; } - $name = isset($lookup['name']['value']) ? $lookup['name']['value'] : ''; + $name = $lookup['name']['value'] ?? ''; $label = empty($name) ? $lookup['federationId'] : $name . ' (' . $lookup['federationId'] . ')'; $result[] = [ 'label' => $label, diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index aa317ec1720..1529f78f045 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -37,66 +37,48 @@ use OCP\IConfig; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserSession; -use OCP\Share\IShare; use OCP\Mail\IMailer; +use OCP\Share\IShare; class MailPlugin implements ISearchPlugin { - /* @var bool */ - protected $shareWithGroupOnly; - /* @var bool */ - protected $shareeEnumeration; - /* @var bool */ - protected $shareeEnumerationInGroupOnly; - /* @var bool */ - protected $shareeEnumerationPhone; - /* @var bool */ - protected $shareeEnumerationFullMatch; - /* @var bool */ - protected $shareeEnumerationFullMatchEmail; + protected bool $shareWithGroupOnly; + + protected bool $shareeEnumeration; + + protected bool $shareeEnumerationInGroupOnly; - /** @var IManager */ - private $contactsManager; - /** @var ICloudIdManager */ - private $cloudIdManager; - /** @var IConfig */ - private $config; + protected bool $shareeEnumerationPhone; - /** @var IGroupManager */ - private $groupManager; - /** @var KnownUserService */ - private $knownUserService; - /** @var IUserSession */ - private $userSession; - /** @var IMailer */ - private $mailer; + protected bool $shareeEnumerationFullMatch; - public function __construct(IManager $contactsManager, - ICloudIdManager $cloudIdManager, - IConfig $config, - IGroupManager $groupManager, - KnownUserService $knownUserService, - IUserSession $userSession, - IMailer $mailer) { - $this->contactsManager = $contactsManager; - $this->cloudIdManager = $cloudIdManager; - $this->config = $config; - $this->groupManager = $groupManager; - $this->knownUserService = $knownUserService; - $this->userSession = $userSession; - $this->mailer = $mailer; + protected bool $shareeEnumerationFullMatchEmail; + public function __construct( + private IManager $contactsManager, + private ICloudIdManager $cloudIdManager, + private IConfig $config, + private IGroupManager $groupManager, + private KnownUserService $knownUserService, + private IUserSession $userSession, + private IMailer $mailer, + private mixed $shareWithGroupOnlyExcludeGroupsList = [], + ) { $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes'; $this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes'; $this->shareeEnumerationPhone = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes'; $this->shareeEnumerationFullMatch = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes'; $this->shareeEnumerationFullMatchEmail = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_email', 'yes') === 'yes'; + + if ($this->shareWithGroupOnly) { + $this->shareWithGroupOnlyExcludeGroupsList = json_decode($this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', ''), true) ?? []; + } } /** * {@inheritdoc} */ - public function search($search, $limit, $offset, ISearchResult $searchResult) { + public function search($search, $limit, $offset, ISearchResult $searchResult): bool { if ($this->shareeEnumerationFullMatch && !$this->shareeEnumerationFullMatchEmail) { return false; } @@ -120,8 +102,8 @@ class MailPlugin implements ISearchPlugin { [ 'limit' => $limit, 'offset' => $offset, - 'enumeration' => (bool) $this->shareeEnumeration, - 'fullmatch' => (bool) $this->shareeEnumerationFullMatch, + 'enumeration' => $this->shareeEnumeration, + 'fullmatch' => $this->shareeEnumerationFullMatch, ] ); $lowerSearch = strtolower($search); @@ -150,6 +132,10 @@ class MailPlugin implements ISearchPlugin { * Check if the user may share with the user associated with the e-mail of the just found contact */ $userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser()); + + // ShareWithGroupOnly filtering + $userGroups = array_diff($userGroups, $this->shareWithGroupOnlyExcludeGroupsList); + $found = false; foreach ($userGroups as $userGroup) { if ($this->groupManager->isInGroup($contact['UID'], $userGroup)) { @@ -163,7 +149,7 @@ class MailPlugin implements ISearchPlugin { } if ($exactEmailMatch && $this->shareeEnumerationFullMatch) { try { - $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]); + $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0] ?? ''); } catch (\InvalidArgumentException $e) { continue; } @@ -188,7 +174,7 @@ class MailPlugin implements ISearchPlugin { if ($this->shareeEnumeration) { try { - $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]); + $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0] ?? ''); } catch (\InvalidArgumentException $e) { continue; } @@ -286,6 +272,6 @@ class MailPlugin implements ISearchPlugin { public function isCurrentUser(ICloudId $cloud): bool { $currentUser = $this->userSession->getUser(); - return $currentUser instanceof IUser ? $currentUser->getUID() === $cloud->getUser() : false; + return $currentUser instanceof IUser && $currentUser->getUID() === $cloud->getUser(); } } diff --git a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php index 413799e52c6..01f25b3d43d 100644 --- a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php +++ b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php @@ -33,14 +33,12 @@ use OCP\Share; use OCP\Share\IShare; class RemoteGroupPlugin implements ISearchPlugin { - protected $shareeEnumeration; + private bool $enabled = false; - /** @var ICloudIdManager */ - private $cloudIdManager; - /** @var bool */ - private $enabled = false; - - public function __construct(ICloudFederationProviderManager $cloudFederationProviderManager, ICloudIdManager $cloudIdManager) { + public function __construct( + ICloudFederationProviderManager $cloudFederationProviderManager, + private ICloudIdManager $cloudIdManager, + ) { try { $fileSharingProvider = $cloudFederationProviderManager->getCloudFederationProvider('file'); $supportedShareTypes = $fileSharingProvider->getSupportedShareTypes(); @@ -50,10 +48,9 @@ class RemoteGroupPlugin implements ISearchPlugin { } catch (\Exception $e) { // do nothing, just don't enable federated group shares } - $this->cloudIdManager = $cloudIdManager; } - public function search($search, $limit, $offset, ISearchResult $searchResult) { + public function search($search, $limit, $offset, ISearchResult $searchResult): bool { $result = ['wide' => [], 'exact' => []]; $resultType = new SearchResultType('remote_groups'); @@ -83,7 +80,7 @@ class RemoteGroupPlugin implements ISearchPlugin { * @return array [user, remoteURL] * @throws \InvalidArgumentException */ - public function splitGroupRemote($address) { + public function splitGroupRemote($address): array { try { $cloudId = $this->cloudIdManager->resolveCloudId($address); return [$cloudId->getUser(), $cloudId->getRemote()]; diff --git a/lib/private/Collaboration/Collaborators/RemotePlugin.php b/lib/private/Collaboration/Collaborators/RemotePlugin.php index 7d7a013a38c..a0868796689 100644 --- a/lib/private/Collaboration/Collaborators/RemotePlugin.php +++ b/lib/private/Collaboration/Collaborators/RemotePlugin.php @@ -37,32 +37,22 @@ use OCP\IUserSession; use OCP\Share\IShare; class RemotePlugin implements ISearchPlugin { - protected $shareeEnumeration; + protected bool $shareeEnumeration; - /** @var IManager */ - private $contactsManager; - /** @var ICloudIdManager */ - private $cloudIdManager; - /** @var IConfig */ - private $config; - /** @var IUserManager */ - private $userManager; - /** @var string */ - private $userId = ''; + private string $userId; - public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) { - $this->contactsManager = $contactsManager; - $this->cloudIdManager = $cloudIdManager; - $this->config = $config; - $this->userManager = $userManager; - $user = $userSession->getUser(); - if ($user !== null) { - $this->userId = $user->getUID(); - } + public function __construct( + private IManager $contactsManager, + private ICloudIdManager $cloudIdManager, + private IConfig $config, + private IUserManager $userManager, + IUserSession $userSession, + ) { + $this->userId = $userSession->getUser()?->getUID() ?? ''; $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; } - public function search($search, $limit, $offset, ISearchResult $searchResult) { + public function search($search, $limit, $offset, ISearchResult $searchResult): bool { $result = ['wide' => [], 'exact' => []]; $resultType = new SearchResultType('remotes'); @@ -185,7 +175,7 @@ class RemotePlugin implements ISearchPlugin { * @return array [user, remoteURL] * @throws \InvalidArgumentException */ - public function splitUserRemote($address) { + public function splitUserRemote(string $address): array { try { $cloudId = $this->cloudIdManager->resolveCloudId($address); return [$cloudId->getUser(), $cloudId->getRemote()]; diff --git a/lib/private/Collaboration/Collaborators/Search.php b/lib/private/Collaboration/Collaborators/Search.php index 8d99ed42fcd..6b05d7e674b 100644 --- a/lib/private/Collaboration/Collaborators/Search.php +++ b/lib/private/Collaboration/Collaborators/Search.php @@ -35,32 +35,28 @@ use OCP\IContainer; use OCP\Share; class Search implements ISearch { - /** @var IContainer */ - private $c; + protected array $pluginList = []; - protected $pluginList = []; - - public function __construct(IContainer $c) { - $this->c = $c; + public function __construct( + private IContainer $container, + ) { } /** * @param string $search - * @param array $shareTypes * @param bool $lookup * @param int|null $limit * @param int|null $offset - * @return array * @throws \OCP\AppFramework\QueryException */ - public function search($search, array $shareTypes, $lookup, $limit, $offset) { + public function search($search, array $shareTypes, $lookup, $limit, $offset): array { $hasMoreResults = false; // Trim leading and trailing whitespace characters, e.g. when query is copy-pasted $search = trim($search); /** @var ISearchResult $searchResult */ - $searchResult = $this->c->resolve(SearchResult::class); + $searchResult = $this->container->resolve(SearchResult::class); foreach ($shareTypes as $type) { if (!isset($this->pluginList[$type])) { @@ -68,14 +64,14 @@ class Search implements ISearch { } foreach ($this->pluginList[$type] as $plugin) { /** @var ISearchPlugin $searchPlugin */ - $searchPlugin = $this->c->resolve($plugin); + $searchPlugin = $this->container->resolve($plugin); $hasMoreResults = $searchPlugin->search($search, $limit, $offset, $searchResult) || $hasMoreResults; } } // Get from lookup server, not a separate share type if ($lookup) { - $searchPlugin = $this->c->resolve(LookupPlugin::class); + $searchPlugin = $this->container->resolve(LookupPlugin::class); $hasMoreResults = $searchPlugin->search($search, $limit, $offset, $searchResult) || $hasMoreResults; } @@ -105,7 +101,7 @@ class Search implements ISearch { return [$searchResult->asArray(), $hasMoreResults]; } - public function registerPlugin(array $pluginInfo) { + public function registerPlugin(array $pluginInfo): void { $shareType = constant(Share::class . '::' . $pluginInfo['shareType']); if ($shareType === null) { throw new \InvalidArgumentException('Provided ShareType is invalid'); diff --git a/lib/private/Collaboration/Collaborators/SearchResult.php b/lib/private/Collaboration/Collaborators/SearchResult.php index 76d78c9c231..524ffba4b9e 100644 --- a/lib/private/Collaboration/Collaborators/SearchResult.php +++ b/lib/private/Collaboration/Collaborators/SearchResult.php @@ -28,13 +28,13 @@ use OCP\Collaboration\Collaborators\ISearchResult; use OCP\Collaboration\Collaborators\SearchResultType; class SearchResult implements ISearchResult { - protected $result = [ + protected array $result = [ 'exact' => [], ]; - protected $exactIdMatches = []; + protected array $exactIdMatches = []; - public function addResultSet(SearchResultType $type, array $matches, array $exactMatches = null) { + public function addResultSet(SearchResultType $type, array $matches, array $exactMatches = null): void { $type = $type->getLabel(); if (!isset($this->result[$type])) { $this->result[$type] = []; @@ -47,15 +47,15 @@ class SearchResult implements ISearchResult { } } - public function markExactIdMatch(SearchResultType $type) { + public function markExactIdMatch(SearchResultType $type): void { $this->exactIdMatches[$type->getLabel()] = 1; } - public function hasExactIdMatch(SearchResultType $type) { + public function hasExactIdMatch(SearchResultType $type): bool { return isset($this->exactIdMatches[$type->getLabel()]); } - public function hasResult(SearchResultType $type, $collaboratorId) { + public function hasResult(SearchResultType $type, $collaboratorId): bool { $type = $type->getLabel(); if (!isset($this->result[$type])) { return false; @@ -73,11 +73,11 @@ class SearchResult implements ISearchResult { return false; } - public function asArray() { + public function asArray(): array { return $this->result; } - public function unsetResult(SearchResultType $type) { + public function unsetResult(SearchResultType $type): void { $type = $type->getLabel(); $this->result[$type] = []; if (isset($this->result['exact'][$type])) { diff --git a/lib/private/Collaboration/Collaborators/UserPlugin.php b/lib/private/Collaboration/Collaborators/UserPlugin.php index 9beecdaa6cb..005b0d05812 100644 --- a/lib/private/Collaboration/Collaborators/UserPlugin.php +++ b/lib/private/Collaboration/Collaborators/UserPlugin.php @@ -44,50 +44,31 @@ use OCP\Share\IShare; use OCP\UserStatus\IManager as IUserStatusManager; class UserPlugin implements ISearchPlugin { - /* @var bool */ - protected $shareWithGroupOnly; - /* @var bool */ - protected $shareeEnumeration; - /* @var bool */ - protected $shareeEnumerationInGroupOnly; - /* @var bool */ - protected $shareeEnumerationPhone; - /* @var bool */ - protected $shareeEnumerationFullMatch; - /* @var bool */ - protected $shareeEnumerationFullMatchUserId; - /* @var bool */ - protected $shareeEnumerationFullMatchEmail; - /* @var bool */ - protected $shareeEnumerationFullMatchIgnoreSecondDisplayName; - - /** @var IConfig */ - private $config; - /** @var IGroupManager */ - private $groupManager; - /** @var IUserSession */ - private $userSession; - /** @var IUserManager */ - private $userManager; - /** @var KnownUserService */ - private $knownUserService; - /** @var IUserStatusManager */ - private $userStatusManager; - - public function __construct(IConfig $config, - IUserManager $userManager, - IGroupManager $groupManager, - IUserSession $userSession, - KnownUserService $knownUserService, - IUserStatusManager $userStatusManager) { - $this->config = $config; - - $this->groupManager = $groupManager; - $this->userSession = $userSession; - $this->userManager = $userManager; - $this->knownUserService = $knownUserService; - $this->userStatusManager = $userStatusManager; + protected bool $shareWithGroupOnly; + protected bool $shareeEnumeration; + + protected bool $shareeEnumerationInGroupOnly; + + protected bool $shareeEnumerationPhone; + + protected bool $shareeEnumerationFullMatch; + + protected bool $shareeEnumerationFullMatchUserId; + + protected bool $shareeEnumerationFullMatchEmail; + + protected bool $shareeEnumerationFullMatchIgnoreSecondDisplayName; + + public function __construct( + private IConfig $config, + private IUserManager $userManager, + private IGroupManager $groupManager, + private IUserSession $userSession, + private KnownUserService $knownUserService, + private IUserStatusManager $userStatusManager, + private mixed $shareWithGroupOnlyExcludeGroupsList = [], + ) { $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes'; $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; $this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes'; @@ -96,15 +77,23 @@ class UserPlugin implements ISearchPlugin { $this->shareeEnumerationFullMatchUserId = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_userid', 'yes') === 'yes'; $this->shareeEnumerationFullMatchEmail = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_email', 'yes') === 'yes'; $this->shareeEnumerationFullMatchIgnoreSecondDisplayName = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_ignore_second_dn', 'no') === 'yes'; + + if ($this->shareWithGroupOnly) { + $this->shareWithGroupOnlyExcludeGroupsList = json_decode($this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', ''), true) ?? []; + } } - public function search($search, $limit, $offset, ISearchResult $searchResult) { + public function search($search, $limit, $offset, ISearchResult $searchResult): bool { $result = ['wide' => [], 'exact' => []]; $users = []; $hasMoreResults = false; $currentUserId = $this->userSession->getUser()->getUID(); $currentUserGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser()); + + // ShareWithGroupOnly filtering + $currentUserGroups = array_diff($currentUserGroups, $this->shareWithGroupOnlyExcludeGroupsList); + if ($this->shareWithGroupOnly || $this->shareeEnumerationInGroupOnly) { // Search in all the groups this user is part of foreach ($currentUserGroups as $userGroupId) { @@ -282,8 +271,6 @@ class UserPlugin implements ISearchPlugin { } } - - $type = new SearchResultType('users'); $searchResult->addResultSet($type, $result['wide'], $result['exact']); if (count($result['exact'])) { @@ -293,7 +280,7 @@ class UserPlugin implements ISearchPlugin { return $hasMoreResults; } - public function takeOutCurrentUser(array &$users) { + public function takeOutCurrentUser(array &$users): void { $currentUser = $this->userSession->getUser(); if (!is_null($currentUser)) { if (isset($users[$currentUser->getUID()])) { diff --git a/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php b/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php index 1dbe8e3bc35..4277b3837d2 100644 --- a/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php +++ b/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php @@ -36,10 +36,9 @@ use OCP\Share\Events\ShareDeletedEvent; /** @template-implements IEventListener<Event|NodeDeletedEvent|ShareDeletedEvent|ShareCreatedEvent> */ class FileReferenceEventListener implements IEventListener { - private IReferenceManager $manager; - - public function __construct(IReferenceManager $manager) { - $this->manager = $manager; + public function __construct( + private IReferenceManager $manager, + ) { } public static function register(IEventDispatcher $eventDispatcher): void { diff --git a/lib/private/Collaboration/Reference/File/FileReferenceProvider.php b/lib/private/Collaboration/Reference/File/FileReferenceProvider.php index d423a830495..125649246df 100644 --- a/lib/private/Collaboration/Reference/File/FileReferenceProvider.php +++ b/lib/private/Collaboration/Reference/File/FileReferenceProvider.php @@ -31,7 +31,6 @@ use OCP\Collaboration\Reference\Reference; use OCP\Files\IMimeTypeDetector; use OCP\Files\InvalidPathException; use OCP\Files\IRootFolder; -use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\IL10N; @@ -41,26 +40,18 @@ use OCP\IUserSession; use OCP\L10N\IFactory; class FileReferenceProvider extends ADiscoverableReferenceProvider { - private IURLGenerator $urlGenerator; - private IRootFolder $rootFolder; private ?string $userId; - private IPreview $previewManager; - private IMimeTypeDetector $mimeTypeDetector; private IL10N $l10n; public function __construct( - IURLGenerator $urlGenerator, - IRootFolder $rootFolder, + private IURLGenerator $urlGenerator, + private IRootFolder $rootFolder, IUserSession $userSession, - IMimeTypeDetector $mimeTypeDetector, - IPreview $previewManager, - IFactory $l10n + private IMimeTypeDetector $mimeTypeDetector, + private IPreview $previewManager, + IFactory $l10n, ) { - $this->urlGenerator = $urlGenerator; - $this->rootFolder = $rootFolder; - $this->userId = $userSession->getUser() ? $userSession->getUser()->getUID() : null; - $this->previewManager = $previewManager; - $this->mimeTypeDetector = $mimeTypeDetector; + $this->userId = $userSession->getUser()?->getUID(); $this->l10n = $l10n->get('files'); } @@ -129,15 +120,12 @@ class FileReferenceProvider extends ADiscoverableReferenceProvider { try { $userFolder = $this->rootFolder->getUserFolder($this->userId); - $files = $userFolder->getById($fileId); + $file = $userFolder->getFirstNodeById($fileId); - if (empty($files)) { + if (!$file) { throw new NotFoundException(); } - /** @var Node $file */ - $file = array_shift($files); - $reference->setTitle($file->getName()); $reference->setDescription($file->getMimetype()); $reference->setUrl($this->urlGenerator->getAbsoluteURL('/index.php/f/' . $fileId)); diff --git a/lib/private/Collaboration/Reference/LinkReferenceProvider.php b/lib/private/Collaboration/Reference/LinkReferenceProvider.php index dbdab75abcb..08b388b47a4 100644 --- a/lib/private/Collaboration/Reference/LinkReferenceProvider.php +++ b/lib/private/Collaboration/Reference/LinkReferenceProvider.php @@ -5,6 +5,7 @@ declare(strict_types=1); * @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> * * @author Julius Härtl <jus@bitgrid.net> + * @author Anupam Kumar <kyteinsky@gmail.com> * * @license GNU AGPL version 3 or any later version * @@ -24,168 +25,8 @@ declare(strict_types=1); namespace OC\Collaboration\Reference; -use Fusonic\OpenGraph\Consumer; -use GuzzleHttp\Exception\GuzzleException; -use GuzzleHttp\Psr7\LimitStream; -use GuzzleHttp\Psr7\Utils; -use OC\Security\RateLimiting\Exception\RateLimitExceededException; -use OC\Security\RateLimiting\Limiter; -use OC\SystemConfig; -use OCP\Collaboration\Reference\IReference; -use OCP\Collaboration\Reference\IReferenceProvider; -use OCP\Collaboration\Reference\Reference; -use OCP\Files\AppData\IAppDataFactory; -use OCP\Files\NotFoundException; -use OCP\Http\Client\IClientService; -use OCP\IRequest; -use OCP\IURLGenerator; -use OCP\IUserSession; -use Psr\Log\LoggerInterface; +use OCP\Collaboration\Reference\LinkReferenceProvider as OCPLinkReferenceProvider; -class LinkReferenceProvider implements IReferenceProvider { - public const MAX_PREVIEW_SIZE = 1024 * 1024; - - public const ALLOWED_CONTENT_TYPES = [ - 'image/png', - 'image/jpg', - 'image/jpeg', - 'image/gif', - 'image/svg+xml', - 'image/webp' - ]; - - private IClientService $clientService; - private LoggerInterface $logger; - private SystemConfig $systemConfig; - private IAppDataFactory $appDataFactory; - private IURLGenerator $urlGenerator; - private Limiter $limiter; - private IUserSession $userSession; - private IRequest $request; - - public function __construct(IClientService $clientService, LoggerInterface $logger, SystemConfig $systemConfig, IAppDataFactory $appDataFactory, IURLGenerator $urlGenerator, Limiter $limiter, IUserSession $userSession, IRequest $request) { - $this->clientService = $clientService; - $this->logger = $logger; - $this->systemConfig = $systemConfig; - $this->appDataFactory = $appDataFactory; - $this->urlGenerator = $urlGenerator; - $this->limiter = $limiter; - $this->userSession = $userSession; - $this->request = $request; - } - - public function matchReference(string $referenceText): bool { - if ($this->systemConfig->getValue('reference_opengraph', true) !== true) { - return false; - } - - return (bool)preg_match(IURLGenerator::URL_REGEX, $referenceText); - } - - public function resolveReference(string $referenceText): ?IReference { - if ($this->matchReference($referenceText)) { - $reference = new Reference($referenceText); - $this->fetchReference($reference); - return $reference; - } - - return null; - } - - private function fetchReference(Reference $reference): void { - try { - $user = $this->userSession->getUser(); - if ($user) { - $this->limiter->registerUserRequest('opengraph', 10, 120, $user); - } else { - $this->limiter->registerAnonRequest('opengraph', 10, 120, $this->request->getRemoteAddress()); - } - } catch (RateLimitExceededException $e) { - return; - } - - $client = $this->clientService->newClient(); - try { - $headResponse = $client->head($reference->getId(), [ 'timeout' => 10 ]); - } catch (\Exception $e) { - $this->logger->debug('Failed to perform HEAD request to get target metadata', ['exception' => $e]); - return; - } - $linkContentLength = $headResponse->getHeader('Content-Length'); - if (is_numeric($linkContentLength) && (int) $linkContentLength > 5 * 1024 * 1024) { - $this->logger->debug('Skip resolving links pointing to content length > 5 MB'); - return; - } - $linkContentType = $headResponse->getHeader('Content-Type'); - $expectedContentType = 'text/html'; - $suffixedExpectedContentType = $expectedContentType . ';'; - $startsWithSuffixed = substr($linkContentType, 0, strlen($suffixedExpectedContentType)) === $suffixedExpectedContentType; - // check the header begins with the expected content type - if ($linkContentType !== $expectedContentType && !$startsWithSuffixed) { - $this->logger->debug('Skip resolving links pointing to content type that is not "text/html"'); - return; - } - try { - $response = $client->get($reference->getId(), [ 'timeout' => 10 ]); - } catch (\Exception $e) { - $this->logger->debug('Failed to fetch link for obtaining open graph data', ['exception' => $e]); - return; - } - - $responseBody = (string)$response->getBody(); - - // OpenGraph handling - $consumer = new Consumer(); - $consumer->useFallbackMode = true; - $object = $consumer->loadHtml($responseBody); - - $reference->setUrl($reference->getId()); - - if ($object->title) { - $reference->setTitle($object->title); - } - - if ($object->description) { - $reference->setDescription($object->description); - } - - if ($object->images) { - try { - $host = parse_url($object->images[0]->url, PHP_URL_HOST); - if ($host === false || $host === null) { - $this->logger->warning('Could not detect host of open graph image URI for ' . $reference->getId()); - } else { - $appData = $this->appDataFactory->get('core'); - try { - $folder = $appData->getFolder('opengraph'); - } catch (NotFoundException $e) { - $folder = $appData->newFolder('opengraph'); - } - $response = $client->get($object->images[0]->url, ['timeout' => 10]); - $contentType = $response->getHeader('Content-Type'); - $contentLength = $response->getHeader('Content-Length'); - - if (in_array($contentType, self::ALLOWED_CONTENT_TYPES, true) && $contentLength < self::MAX_PREVIEW_SIZE) { - $stream = Utils::streamFor($response->getBody()); - $bodyStream = new LimitStream($stream, self::MAX_PREVIEW_SIZE, 0); - $reference->setImageContentType($contentType); - $folder->newFile(md5($reference->getId()), $bodyStream->getContents()); - $reference->setImageUrl($this->urlGenerator->linkToRouteAbsolute('core.Reference.preview', ['referenceId' => md5($reference->getId())])); - } - } - } catch (GuzzleException $e) { - $this->logger->info('Failed to fetch and store the open graph image for ' . $reference->getId(), ['exception' => $e]); - } catch (\Throwable $e) { - $this->logger->error('Failed to fetch and store the open graph image for ' . $reference->getId(), ['exception' => $e]); - } - } - } - - public function getCachePrefix(string $referenceId): string { - return $referenceId; - } - - public function getCacheKey(string $referenceId): ?string { - return null; - } +/** @deprecated 29.0.0 Use OCP\Collaboration\Reference\LinkReferenceProvider instead */ +class LinkReferenceProvider extends OCPLinkReferenceProvider { } diff --git a/lib/private/Collaboration/Reference/ReferenceManager.php b/lib/private/Collaboration/Reference/ReferenceManager.php index 2897410f5d6..a837651f1fe 100644 --- a/lib/private/Collaboration/Reference/ReferenceManager.php +++ b/lib/private/Collaboration/Reference/ReferenceManager.php @@ -46,33 +46,22 @@ class ReferenceManager implements IReferenceManager { /** @var IReferenceProvider[]|null */ private ?array $providers = null; private ICache $cache; - private Coordinator $coordinator; - private ContainerInterface $container; - private LinkReferenceProvider $linkReferenceProvider; - private LoggerInterface $logger; - private IConfig $config; - private IUserSession $userSession; - - public function __construct(LinkReferenceProvider $linkReferenceProvider, - ICacheFactory $cacheFactory, - Coordinator $coordinator, - ContainerInterface $container, - LoggerInterface $logger, - IConfig $config, - IUserSession $userSession) { - $this->linkReferenceProvider = $linkReferenceProvider; + + public function __construct( + private LinkReferenceProvider $linkReferenceProvider, + ICacheFactory $cacheFactory, + private Coordinator $coordinator, + private ContainerInterface $container, + private LoggerInterface $logger, + private IConfig $config, + private IUserSession $userSession, + ) { $this->cache = $cacheFactory->createDistributed('reference'); - $this->coordinator = $coordinator; - $this->container = $container; - $this->logger = $logger; - $this->config = $config; - $this->userSession = $userSession; } /** * Extract a list of URLs from a text * - * @param string $text * @return string[] */ public function extractReferences(string $text): array { @@ -85,9 +74,6 @@ class ReferenceManager implements IReferenceManager { /** * Try to get a cached reference object from a reference string - * - * @param string $referenceId - * @return IReference|null */ public function getReferenceFromCache(string $referenceId): ?IReference { $matchedProvider = $this->getMatchedProvider($referenceId); @@ -102,9 +88,6 @@ class ReferenceManager implements IReferenceManager { /** * Try to get a cached reference object from a full cache key - * - * @param string $cacheKey - * @return IReference|null */ public function getReferenceByCacheKey(string $cacheKey): ?IReference { $cached = $this->cache->get($cacheKey); @@ -118,9 +101,6 @@ class ReferenceManager implements IReferenceManager { /** * Get a reference object from a reference string with a matching provider * Use a cached reference if possible - * - * @param string $referenceId - * @return IReference|null */ public function resolveReference(string $referenceId): ?IReference { $matchedProvider = $this->getMatchedProvider($referenceId); @@ -137,6 +117,11 @@ class ReferenceManager implements IReferenceManager { $reference = $matchedProvider->resolveReference($referenceId); if ($reference) { + $cachePrefix = $matchedProvider->getCachePrefix($referenceId); + if ($cachePrefix !== '') { + // If a prefix is used we set an additional key to know when we need to delete by prefix during invalidateCache() + $this->cache->set('hasPrefix-' . md5($cachePrefix), true, self::CACHE_TTL); + } $this->cache->set($cacheKey, Reference::toCache($reference), self::CACHE_TTL); return $reference; } @@ -148,7 +133,6 @@ class ReferenceManager implements IReferenceManager { * Try to match a reference string with all the registered providers * Fallback to the link reference provider (using OpenGraph) * - * @param string $referenceId * @return IReferenceProvider|null the first matching provider */ private function getMatchedProvider(string $referenceId): ?IReferenceProvider { @@ -169,10 +153,6 @@ class ReferenceManager implements IReferenceManager { /** * Get a hashed full cache key from a key and prefix given by a provider - * - * @param IReferenceProvider $provider - * @param string $referenceId - * @return string */ private function getFullCacheKey(IReferenceProvider $provider, string $referenceId): string { $cacheKey = $provider->getCacheKey($referenceId); @@ -183,14 +163,14 @@ class ReferenceManager implements IReferenceManager { /** * Remove a specific cache entry from its key+prefix - * - * @param string $cachePrefix - * @param string|null $cacheKey - * @return void */ public function invalidateCache(string $cachePrefix, ?string $cacheKey = null): void { if ($cacheKey === null) { - $this->cache->clear(md5($cachePrefix)); + // clear might be a heavy operation, so we only do it if there have actually been keys set + if ($this->cache->remove('hasPrefix-' . md5($cachePrefix))) { + $this->cache->clear(md5($cachePrefix)); + } + return; } diff --git a/lib/private/Collaboration/Reference/RenderReferenceEventListener.php b/lib/private/Collaboration/Reference/RenderReferenceEventListener.php index dc2c5612666..ab9b8fd1b63 100644 --- a/lib/private/Collaboration/Reference/RenderReferenceEventListener.php +++ b/lib/private/Collaboration/Reference/RenderReferenceEventListener.php @@ -34,12 +34,10 @@ use OCP\IInitialStateService; /** @template-implements IEventListener<Event|RenderReferenceEvent> */ class RenderReferenceEventListener implements IEventListener { - private IReferenceManager $manager; - private IInitialStateService $initialStateService; - - public function __construct(IReferenceManager $manager, IInitialStateService $initialStateService) { - $this->manager = $manager; - $this->initialStateService = $initialStateService; + public function __construct( + private IReferenceManager $manager, + private IInitialStateService $initialStateService, + ) { } public static function register(IEventDispatcher $eventDispatcher): void { diff --git a/lib/private/Collaboration/Resources/Collection.php b/lib/private/Collaboration/Resources/Collection.php index e34c38a80cd..3a09fe60051 100644 --- a/lib/private/Collaboration/Resources/Collection.php +++ b/lib/private/Collaboration/Resources/Collection.php @@ -37,46 +37,21 @@ use OCP\IDBConnection; use OCP\IUser; class Collection implements ICollection { - /** @var Manager */ - protected $manager; - - /** @var IDBConnection */ - protected $connection; - - /** @var int */ - protected $id; - - /** @var string */ - protected $name; - - /** @var IUser|null */ - protected $userForAccess; - - /** @var bool|null */ - protected $access; - /** @var IResource[] */ - protected $resources; + protected array $resources = []; public function __construct( - IManager $manager, - IDBConnection $connection, - int $id, - string $name, - ?IUser $userForAccess = null, - ?bool $access = null + /** @var Manager $manager */ + protected IManager $manager, + protected IDBConnection $connection, + protected int $id, + protected string $name, + protected ?IUser $userForAccess = null, + protected ?bool $access = null ) { - $this->manager = $manager; - $this->connection = $connection; - $this->id = $id; - $this->name = $name; - $this->userForAccess = $userForAccess; - $this->access = $access; - $this->resources = []; } /** - * @return int * @since 16.0.0 */ public function getId(): int { @@ -84,7 +59,6 @@ class Collection implements ICollection { } /** - * @return string * @since 16.0.0 */ public function getName(): string { @@ -92,7 +66,6 @@ class Collection implements ICollection { } /** - * @param string $name * @since 16.0.0 */ public function setName(string $name): void { @@ -120,7 +93,6 @@ class Collection implements ICollection { /** * Adds a resource to a collection * - * @param IResource $resource * @throws ResourceException when the resource is already part of the collection * @since 16.0.0 */ @@ -153,7 +125,6 @@ class Collection implements ICollection { /** * Removes a resource from a collection * - * @param IResource $resource * @since 16.0.0 */ public function removeResource(IResource $resource): void { @@ -178,8 +149,6 @@ class Collection implements ICollection { /** * Can a user/guest access the collection * - * @param IUser|null $user - * @return bool * @since 16.0.0 */ public function canAccess(?IUser $user): bool { diff --git a/lib/private/Collaboration/Resources/Manager.php b/lib/private/Collaboration/Resources/Manager.php index fc8804e69b4..0f4dbd7cbb7 100644 --- a/lib/private/Collaboration/Resources/Manager.php +++ b/lib/private/Collaboration/Resources/Manager.php @@ -45,26 +45,17 @@ class Manager implements IManager { public const TABLE_RESOURCES = 'collres_resources'; public const TABLE_ACCESS_CACHE = 'collres_accesscache'; - /** @var IDBConnection */ - protected $connection; - /** @var IProviderManager */ - protected $providerManager; - /** @var LoggerInterface */ - protected $logger; - /** @var string[] */ - protected $providers = []; - + protected array $providers = []; - public function __construct(IDBConnection $connection, IProviderManager $providerManager, LoggerInterface $logger) { - $this->connection = $connection; - $this->providerManager = $providerManager; - $this->logger = $logger; + public function __construct( + protected IDBConnection $connection, + protected IProviderManager $providerManager, + protected LoggerInterface $logger, + ) { } /** - * @param int $id - * @return ICollection * @throws CollectionException when the collection could not be found * @since 16.0.0 */ @@ -85,9 +76,6 @@ class Manager implements IManager { } /** - * @param int $id - * @param IUser|null $user - * @return ICollection * @throws CollectionException when the collection could not be found * @since 16.0.0 */ @@ -122,10 +110,6 @@ class Manager implements IManager { } /** - * @param IUser $user - * @param string $filter - * @param int $limit - * @param int $start * @return ICollection[] * @since 16.0.0 */ @@ -173,8 +157,6 @@ class Manager implements IManager { } /** - * @param string $name - * @return ICollection * @since 16.0.0 */ public function newCollection(string $name): ICollection { @@ -189,9 +171,6 @@ class Manager implements IManager { } /** - * @param string $type - * @param string $id - * @return IResource * @since 16.0.0 */ public function createResource(string $type, string $id): IResource { @@ -199,10 +178,6 @@ class Manager implements IManager { } /** - * @param string $type - * @param string $id - * @param IUser|null $user - * @return IResource * @throws ResourceException * @since 16.0.0 */ @@ -239,8 +214,6 @@ class Manager implements IManager { } /** - * @param ICollection $collection - * @param IUser|null $user * @return IResource[] * @since 16.0.0 */ @@ -274,8 +247,6 @@ class Manager implements IManager { /** * Get the rich object data of a resource * - * @param IResource $resource - * @return array * @since 16.0.0 */ public function getResourceRichObject(IResource $resource): array { @@ -294,9 +265,6 @@ class Manager implements IManager { /** * Can a user/guest access the collection * - * @param IResource $resource - * @param IUser|null $user - * @return bool * @since 16.0.0 */ public function canAccessResource(IResource $resource, ?IUser $user): bool { @@ -325,9 +293,6 @@ class Manager implements IManager { /** * Can a user/guest access the collection * - * @param ICollection $collection - * @param IUser|null $user - * @return bool * @since 16.0.0 */ public function canAccessCollection(ICollection $collection, ?IUser $user): bool { @@ -505,9 +470,6 @@ class Manager implements IManager { $query->execute(); } - /** - * @param string $provider - */ public function registerResourceProvider(string $provider): void { $this->logger->debug('\OC\Collaboration\Resources\Manager::registerResourceProvider is deprecated', ['provider' => $provider]); $this->providerManager->registerResourceProvider($provider); @@ -516,7 +478,6 @@ class Manager implements IManager { /** * Get the resource type of the provider * - * @return string * @since 16.0.0 */ public function getType(): string { diff --git a/lib/private/Collaboration/Resources/ProviderManager.php b/lib/private/Collaboration/Resources/ProviderManager.php index 4f5ed53b162..823d6764f58 100644 --- a/lib/private/Collaboration/Resources/ProviderManager.php +++ b/lib/private/Collaboration/Resources/ProviderManager.php @@ -34,20 +34,15 @@ use Psr\Log\LoggerInterface; class ProviderManager implements IProviderManager { /** @var string[] */ - protected $providers = []; + protected array $providers = []; /** @var IProvider[] */ - protected $providerInstances = []; + protected array $providerInstances = []; - /** @var IServerContainer */ - protected $serverContainer; - - /** @var LoggerInterface */ - protected $logger; - - public function __construct(IServerContainer $serverContainer, LoggerInterface $logger) { - $this->serverContainer = $serverContainer; - $this->logger = $logger; + public function __construct( + protected IServerContainer $serverContainer, + protected LoggerInterface $logger, + ) { } public function getResourceProviders(): array { diff --git a/lib/private/Collaboration/Resources/Resource.php b/lib/private/Collaboration/Resources/Resource.php index b5e0215cb39..059b1802128 100644 --- a/lib/private/Collaboration/Resources/Resource.php +++ b/lib/private/Collaboration/Resources/Resource.php @@ -33,45 +33,19 @@ use OCP\IDBConnection; use OCP\IUser; class Resource implements IResource { - /** @var IManager */ - protected $manager; - - /** @var IDBConnection */ - protected $connection; - - /** @var string */ - protected $type; - - /** @var string */ - protected $id; - - /** @var IUser|null */ - protected $userForAccess; - - /** @var bool|null */ - protected $access; - - /** @var array|null */ - protected $data; + protected ?array $data = null; public function __construct( - IManager $manager, - IDBConnection $connection, - string $type, - string $id, - ?IUser $userForAccess = null, - ?bool $access = null + protected IManager $manager, + protected IDBConnection $connection, + protected string $type, + protected string $id, + protected ?IUser $userForAccess = null, + protected ?bool $access = null ) { - $this->manager = $manager; - $this->connection = $connection; - $this->type = $type; - $this->id = $id; - $this->userForAccess = $userForAccess; - $this->access = $access; } /** - * @return string * @since 16.0.0 */ public function getType(): string { @@ -79,7 +53,6 @@ class Resource implements IResource { } /** - * @return string * @since 16.0.0 */ public function getId(): string { @@ -87,7 +60,6 @@ class Resource implements IResource { } /** - * @return array * @since 16.0.0 */ public function getRichObject(): array { @@ -101,8 +73,6 @@ class Resource implements IResource { /** * Can a user/guest access the resource * - * @param IUser|null $user - * @return bool * @since 16.0.0 */ public function canAccess(?IUser $user): bool { diff --git a/lib/private/Command/AsyncBus.php b/lib/private/Command/AsyncBus.php index ec6fbc91f68..c65e6cad78e 100644 --- a/lib/private/Command/AsyncBus.php +++ b/lib/private/Command/AsyncBus.php @@ -82,7 +82,7 @@ abstract class AsyncBus implements IBus { private function canRunAsync($command) { $traits = $this->getTraits($command); foreach ($traits as $trait) { - if (array_search($trait, $this->syncTraits) !== false) { + if (in_array($trait, $this->syncTraits)) { return false; } } diff --git a/lib/private/Command/CallableJob.php b/lib/private/Command/CallableJob.php index 8bb3c76c9af..7f515660955 100644 --- a/lib/private/Command/CallableJob.php +++ b/lib/private/Command/CallableJob.php @@ -21,7 +21,7 @@ */ namespace OC\Command; -use OC\BackgroundJob\QueuedJob; +use OCP\BackgroundJob\QueuedJob; class CallableJob extends QueuedJob { protected function run($serializedCallable) { diff --git a/lib/private/Command/ClosureJob.php b/lib/private/Command/ClosureJob.php index 5639852e4db..3e0fe73b029 100644 --- a/lib/private/Command/ClosureJob.php +++ b/lib/private/Command/ClosureJob.php @@ -22,13 +22,12 @@ */ namespace OC\Command; -use OC\BackgroundJob\QueuedJob; use Laravel\SerializableClosure\SerializableClosure as LaravelClosure; -use Opis\Closure\SerializableClosure as OpisClosure; +use OCP\BackgroundJob\QueuedJob; class ClosureJob extends QueuedJob { - protected function run($serializedCallable) { - $callable = unserialize($serializedCallable, [LaravelClosure::class, OpisClosure::class]); + protected function run($argument) { + $callable = unserialize($argument, [LaravelClosure::class]); $callable = $callable->getClosure(); if (is_callable($callable)) { $callable(); diff --git a/lib/private/Command/CommandJob.php b/lib/private/Command/CommandJob.php index 5b267162c81..368d264f3bb 100644 --- a/lib/private/Command/CommandJob.php +++ b/lib/private/Command/CommandJob.php @@ -22,15 +22,15 @@ */ namespace OC\Command; -use OC\BackgroundJob\QueuedJob; +use OCP\BackgroundJob\QueuedJob; use OCP\Command\ICommand; /** * Wrap a command in the background job interface */ class CommandJob extends QueuedJob { - protected function run($serializedCommand) { - $command = unserialize($serializedCommand); + protected function run($argument) { + $command = unserialize($argument); if ($command instanceof ICommand) { $command->handle(); } else { diff --git a/lib/private/Command/CronBus.php b/lib/private/Command/CronBus.php index 8749ad0bff5..495cd011db1 100644 --- a/lib/private/Command/CronBus.php +++ b/lib/private/Command/CronBus.php @@ -25,32 +25,26 @@ */ namespace OC\Command; -use OCP\Command\ICommand; use Laravel\SerializableClosure\SerializableClosure; +use OCP\BackgroundJob\IJob; +use OCP\BackgroundJob\IJobList; +use OCP\Command\ICommand; class CronBus extends AsyncBus { - /** - * @var \OCP\BackgroundJob\IJobList - */ - private $jobList; - - - /** - * @param \OCP\BackgroundJob\IJobList $jobList - */ - public function __construct($jobList) { - $this->jobList = $jobList; + public function __construct( + private IJobList $jobList, + ) { } - protected function queueCommand($command) { + protected function queueCommand($command): void { $this->jobList->add($this->getJobClass($command), $this->serializeCommand($command)); } /** - * @param \OCP\Command\ICommand | callable $command - * @return string + * @param ICommand|callable $command + * @return class-string<IJob> */ - private function getJobClass($command) { + private function getJobClass($command): string { if ($command instanceof \Closure) { return ClosureJob::class; } elseif (is_callable($command)) { @@ -63,10 +57,10 @@ class CronBus extends AsyncBus { } /** - * @param \OCP\Command\ICommand | callable $command + * @param ICommand|callable $command * @return string */ - private function serializeCommand($command) { + private function serializeCommand($command): string { if ($command instanceof \Closure) { return serialize(new SerializableClosure($command)); } elseif (is_callable($command) or $command instanceof ICommand) { diff --git a/lib/private/Comments/Comment.php b/lib/private/Comments/Comment.php index 35e88c74438..58a3ac96b1d 100644 --- a/lib/private/Comments/Comment.php +++ b/lib/private/Comments/Comment.php @@ -42,6 +42,7 @@ class Comment implements IComment { 'objectType' => '', 'objectId' => '', 'referenceId' => null, + 'metaData' => null, 'creationDT' => null, 'latestChildDT' => null, 'reactions' => null, @@ -219,7 +220,7 @@ class Comment implements IComment { * */ public function getMentions(): array { - $ok = preg_match_all("/\B(?<![^a-z0-9_\-@\.\'\s])@(\"guest\/[a-f0-9]+\"|\"group\/[a-z0-9_\-@\.\' ]+\"|\"[a-z0-9_\-@\.\' ]+\"|[a-z0-9_\-@\.\']+)/i", $this->getMessage(), $mentions); + $ok = preg_match_all("/\B(?<![^a-z0-9_\-@\.\'\s])@(\"guest\/[a-f0-9]+\"|\"(?:federated_)?(?:group|team|user){1}\/[a-z0-9_\-@\.\' \/:]+\"|\"[a-z0-9_\-@\.\' ]+\"|[a-z0-9_\-@\.\']+)/i", $this->getMessage(), $mentions); if (!$ok || !isset($mentions[0])) { return []; } @@ -229,11 +230,21 @@ class Comment implements IComment { }); $result = []; foreach ($mentionIds as $mentionId) { + // Cut-off the @ and remove wrapping double-quotes $cleanId = trim(substr($mentionId, 1), '"'); + if (str_starts_with($cleanId, 'guest/')) { $result[] = ['type' => 'guest', 'id' => $cleanId]; + } elseif (str_starts_with($cleanId, 'federated_group/')) { + $result[] = ['type' => 'federated_group', 'id' => substr($cleanId, 16)]; } elseif (str_starts_with($cleanId, 'group/')) { $result[] = ['type' => 'group', 'id' => substr($cleanId, 6)]; + } elseif (str_starts_with($cleanId, 'federated_team/')) { + $result[] = ['type' => 'federated_team', 'id' => substr($cleanId, 15)]; + } elseif (str_starts_with($cleanId, 'team/')) { + $result[] = ['type' => 'team', 'id' => substr($cleanId, 5)]; + } elseif (str_starts_with($cleanId, 'federated_user/')) { + $result[] = ['type' => 'federated_user', 'id' => substr($cleanId, 15)]; } else { $result[] = ['type' => 'user', 'id' => $cleanId]; } @@ -403,6 +414,34 @@ class Comment implements IComment { /** * @inheritDoc */ + public function getMetaData(): ?array { + if ($this->data['metaData'] === null) { + return null; + } + + try { + $metaData = json_decode($this->data['metaData'], true, flags: JSON_THROW_ON_ERROR); + } catch (\JsonException $e) { + return null; + } + return is_array($metaData) ? $metaData : null; + } + + /** + * @inheritDoc + */ + public function setMetaData(?array $metaData): IComment { + if ($metaData === null) { + $this->data['metaData'] = null; + } else { + $this->data['metaData'] = json_encode($metaData, JSON_THROW_ON_ERROR); + } + return $this; + } + + /** + * @inheritDoc + */ public function getReactions(): array { return $this->data['reactions'] ?? []; } diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php index af4fda277d6..49b319038cb 100644 --- a/lib/private/Comments/Manager.php +++ b/lib/private/Comments/Manager.php @@ -29,7 +29,7 @@ namespace OC\Comments; use Doctrine\DBAL\Exception\DriverException; -use Doctrine\DBAL\Exception\InvalidFieldNameException; +use OCA\DAV\Connector\Sabre\File; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Comments\CommentsEvent; use OCP\Comments\IComment; @@ -37,22 +37,19 @@ use OCP\Comments\ICommentsEventHandler; use OCP\Comments\ICommentsManager; use OCP\Comments\NotFoundException; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\FileInfo; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; use OCP\IConfig; use OCP\IDBConnection; use OCP\IEmojiHelper; -use OCP\IUser; use OCP\IInitialStateService; +use OCP\IUser; use OCP\PreConditionNotMetException; use OCP\Util; use Psr\Log\LoggerInterface; class Manager implements ICommentsManager { - protected IDBConnection $dbConn; - protected LoggerInterface $logger; - protected IConfig $config; - protected ITimeFactory $timeFactory; - protected IEmojiHelper $emojiHelper; - protected IInitialStateService $initialStateService; /** @var IComment[] */ protected array $commentsCache = []; @@ -65,18 +62,15 @@ class Manager implements ICommentsManager { /** @var \Closure[] */ protected array $displayNameResolvers = []; - public function __construct(IDBConnection $dbConn, - LoggerInterface $logger, - IConfig $config, - ITimeFactory $timeFactory, - IEmojiHelper $emojiHelper, - IInitialStateService $initialStateService) { - $this->dbConn = $dbConn; - $this->logger = $logger; - $this->config = $config; - $this->timeFactory = $timeFactory; - $this->emojiHelper = $emojiHelper; - $this->initialStateService = $initialStateService; + public function __construct( + protected IDBConnection $dbConn, + protected LoggerInterface $logger, + protected IConfig $config, + protected ITimeFactory $timeFactory, + protected IEmojiHelper $emojiHelper, + protected IInitialStateService $initialStateService, + protected IRootFolder $rootFolder, + ) { } /** @@ -97,7 +91,8 @@ class Manager implements ICommentsManager { $data['expire_date'] = new \DateTime($data['expire_date']); } $data['children_count'] = (int)$data['children_count']; - $data['reference_id'] = $data['reference_id'] ?? null; + $data['reference_id'] = $data['reference_id']; + $data['meta_data'] = json_decode($data['meta_data'], true); if ($this->supportReactions()) { if ($data['reactions'] !== null) { $list = json_decode($data['reactions'], true); @@ -501,6 +496,22 @@ class Manager implements ICommentsManager { ) ); } + } elseif ($lastKnownCommentId > 0) { + // We didn't find the "$lastKnownComment" but we still use the ID as an offset. + // This is required as a fall-back for expired messages in talk and deleted comments in other apps. + if ($sortDirection === 'desc') { + if ($includeLastKnown) { + $query->andWhere($query->expr()->lte('id', $query->createNamedParameter($lastKnownCommentId))); + } else { + $query->andWhere($query->expr()->lt('id', $query->createNamedParameter($lastKnownCommentId))); + } + } else { + if ($includeLastKnown) { + $query->andWhere($query->expr()->gte('id', $query->createNamedParameter($lastKnownCommentId))); + } else { + $query->andWhere($query->expr()->gt('id', $query->createNamedParameter($lastKnownCommentId))); + } + } } $resultStatement = $query->execute(); @@ -520,8 +531,8 @@ class Manager implements ICommentsManager { * @param int $id the comment to look for */ protected function getLastKnownComment(string $objectType, - string $objectId, - int $id): ?IComment { + string $objectId, + int $id): ?IComment { $query = $this->dbConn->getQueryBuilder(); $query->select('*') ->from('comments') @@ -804,54 +815,25 @@ class Manager implements ICommentsManager { /** * Get the number of unread comments for all files in a folder * + * This is unused since 8bd39fccf411195839f2dadee085fad18ec52c23 + * * @param int $folderId * @param IUser $user * @return array [$fileId => $unreadCount] */ public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) { - $qb = $this->dbConn->getQueryBuilder(); - - $query = $qb->select('f.fileid') - ->addSelect($qb->func()->count('c.id', 'num_ids')) - ->from('filecache', 'f') - ->leftJoin('f', 'comments', 'c', $qb->expr()->andX( - $qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)), - $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')) - )) - ->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX( - $qb->expr()->eq('c.object_id', 'm.object_id'), - $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')) - )) - ->where( - $qb->expr()->andX( - $qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId)), - $qb->expr()->orX( - $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')), - $qb->expr()->isNull('c.object_type') - ), - $qb->expr()->orX( - $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')), - $qb->expr()->isNull('m.object_type') - ), - $qb->expr()->orX( - $qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())), - $qb->expr()->isNull('m.user_id') - ), - $qb->expr()->orX( - $qb->expr()->gt('c.creation_timestamp', 'm.marker_datetime'), - $qb->expr()->isNull('m.marker_datetime') - ) - ) - )->groupBy('f.fileid'); - - $resultStatement = $query->execute(); - - $results = []; - while ($row = $resultStatement->fetch()) { - $results[$row['fileid']] = (int) $row['num_ids']; + $directory = $this->rootFolder->getFirstNodeById($folderId); + if (!$directory instanceof Folder) { + return []; } - $resultStatement->closeCursor(); - return $results; + $children = $directory->getDirectoryListing(); + $ids = array_map(fn (FileInfo $child) => (string) $child->getId(), $children); + + $ids[] = (string) $directory->getId(); + $counts = $this->getNumberOfUnreadCommentsForObjects('files', $ids, $user); + return array_filter($counts, function (int $count) { + return $count > 0; + }); } /** @@ -1134,22 +1116,6 @@ class Manager implements ICommentsManager { * @return bool */ protected function insert(IComment $comment): bool { - try { - $result = $this->insertQuery($comment, true); - } catch (InvalidFieldNameException $e) { - // The reference id field was only added in Nextcloud 19. - // In order to not cause too long waiting times on the update, - // it was decided to only add it lazy, as it is also not a critical - // feature, but only helps to have a better experience while commenting. - // So in case the reference_id field is missing, - // we simply save the comment without that field. - $result = $this->insertQuery($comment, false); - } - - return $result; - } - - protected function insertQuery(IComment $comment, bool $tryWritingReferenceId): bool { $qb = $this->dbConn->getQueryBuilder(); $values = [ @@ -1165,12 +1131,10 @@ class Manager implements ICommentsManager { 'object_type' => $qb->createNamedParameter($comment->getObjectType()), 'object_id' => $qb->createNamedParameter($comment->getObjectId()), 'expire_date' => $qb->createNamedParameter($comment->getExpireDate(), 'datetime'), + 'reference_id' => $qb->createNamedParameter($comment->getReferenceId()), + 'meta_data' => $qb->createNamedParameter(json_encode($comment->getMetaData())), ]; - if ($tryWritingReferenceId) { - $values['reference_id'] = $qb->createNamedParameter($comment->getReferenceId()); - } - $affectedRows = $qb->insert('comments') ->values($values) ->execute(); @@ -1273,12 +1237,7 @@ class Manager implements ICommentsManager { $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId())); $this->uncache($comment->getId()); - try { - $result = $this->updateQuery($comment, true); - } catch (InvalidFieldNameException $e) { - // See function insert() for explanation - $result = $this->updateQuery($comment, false); - } + $result = $this->updateQuery($comment); if ($comment->getVerb() === 'reaction_deleted') { $this->deleteReaction($comment); @@ -1289,7 +1248,7 @@ class Manager implements ICommentsManager { return $result; } - protected function updateQuery(IComment $comment, bool $tryWritingReferenceId): bool { + protected function updateQuery(IComment $comment): bool { $qb = $this->dbConn->getQueryBuilder(); $qb ->update('comments') @@ -1304,14 +1263,11 @@ class Manager implements ICommentsManager { ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime')) ->set('object_type', $qb->createNamedParameter($comment->getObjectType())) ->set('object_id', $qb->createNamedParameter($comment->getObjectId())) - ->set('expire_date', $qb->createNamedParameter($comment->getExpireDate(), 'datetime')); - - if ($tryWritingReferenceId) { - $qb->set('reference_id', $qb->createNamedParameter($comment->getReferenceId())); - } - - $affectedRows = $qb->where($qb->expr()->eq('id', $qb->createNamedParameter($comment->getId()))) - ->execute(); + ->set('expire_date', $qb->createNamedParameter($comment->getExpireDate(), 'datetime')) + ->set('reference_id', $qb->createNamedParameter($comment->getReferenceId())) + ->set('meta_data', $qb->createNamedParameter(json_encode($comment->getMetaData()))) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($comment->getId()))); + $affectedRows = $qb->executeStatement(); if ($affectedRows === 0) { throw new NotFoundException('Comment to update does ceased to exist'); diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php index 113f0507ef5..44f64e09e94 100644 --- a/lib/private/Console/Application.php +++ b/lib/private/Console/Application.php @@ -47,23 +47,18 @@ use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; class Application { - /** @var IConfig */ - private $config; + private IConfig $config; private SymfonyApplication $application; - /** @var IEventDispatcher */ - private $dispatcher; - /** @var IRequest */ - private $request; - /** @var LoggerInterface */ - private $logger; - /** @var MemoryInfo */ - private $memoryInfo; + private IEventDispatcher $dispatcher; + private IRequest $request; + private LoggerInterface $logger; + private MemoryInfo $memoryInfo; public function __construct(IConfig $config, - IEventDispatcher $dispatcher, - IRequest $request, - LoggerInterface $logger, - MemoryInfo $memoryInfo) { + IEventDispatcher $dispatcher, + IRequest $request, + LoggerInterface $logger, + MemoryInfo $memoryInfo) { $defaults = \OC::$server->getThemingDefaults(); $this->config = $config; $this->application = new SymfonyApplication($defaults->getName(), \OC_Util::getVersionString()); @@ -74,8 +69,6 @@ class Application { } /** - * @param InputInterface $input - * @param ConsoleOutputInterface $output * @throws \Exception */ public function loadCommands( @@ -128,7 +121,14 @@ class Application { // load commands using info.xml $info = $appManager->getAppInfo($app); if (isset($info['commands'])) { - $this->loadCommandsFromInfoXml($info['commands']); + try { + $this->loadCommandsFromInfoXml($info['commands']); + } catch (\Throwable $e) { + $output->writeln("<error>" . $e->getMessage() . "</error>"); + $this->logger->error($e->getMessage(), [ + 'exception' => $e, + ]); + } } // load from register_command.php \OC_App::registerAutoloading($app, $appPath); diff --git a/lib/private/Console/TimestampFormatter.php b/lib/private/Console/TimestampFormatter.php index 8d74c28e94f..afb1f67c37f 100644 --- a/lib/private/Console/TimestampFormatter.php +++ b/lib/private/Console/TimestampFormatter.php @@ -27,17 +27,17 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface; use Symfony\Component\Console\Formatter\OutputFormatterStyleInterface; class TimestampFormatter implements OutputFormatterInterface { - /** @var IConfig */ + /** @var ?IConfig */ protected $config; /** @var OutputFormatterInterface */ protected $formatter; /** - * @param IConfig $config + * @param ?IConfig $config * @param OutputFormatterInterface $formatter */ - public function __construct(IConfig $config, OutputFormatterInterface $formatter) { + public function __construct(?IConfig $config, OutputFormatterInterface $formatter) { $this->config = $config; $this->formatter = $formatter; } @@ -104,11 +104,16 @@ class TimestampFormatter implements OutputFormatterInterface { return $this->formatter->format($message); } - $timeZone = $this->config->getSystemValue('logtimezone', 'UTC'); - $timeZone = $timeZone !== null ? new \DateTimeZone($timeZone) : null; + if ($this->config instanceof IConfig) { + $timeZone = $this->config->getSystemValue('logtimezone', 'UTC'); + $timeZone = $timeZone !== null ? new \DateTimeZone($timeZone) : null; - $time = new \DateTime('now', $timeZone); - $timestampInfo = $time->format($this->config->getSystemValue('logdateformat', \DateTimeInterface::ATOM)); + $time = new \DateTime('now', $timeZone); + $timestampInfo = $time->format($this->config->getSystemValue('logdateformat', \DateTimeInterface::ATOM)); + } else { + $time = new \DateTime('now'); + $timestampInfo = $time->format(\DateTimeInterface::ATOM); + } return $timestampInfo . ' ' . $this->formatter->format($message); } diff --git a/lib/private/Contacts/ContactsMenu/ActionProviderStore.php b/lib/private/Contacts/ContactsMenu/ActionProviderStore.php index 7ba5db4bb33..67354a5fb2d 100644 --- a/lib/private/Contacts/ContactsMenu/ActionProviderStore.php +++ b/lib/private/Contacts/ContactsMenu/ActionProviderStore.php @@ -33,6 +33,7 @@ use OC\Contacts\ContactsMenu\Providers\EMailProvider; use OC\Contacts\ContactsMenu\Providers\LocalTimeProvider; use OC\Contacts\ContactsMenu\Providers\ProfileProvider; use OCP\AppFramework\QueryException; +use OCP\Contacts\ContactsMenu\IBulkProvider; use OCP\Contacts\ContactsMenu\IProvider; use OCP\IServerContainer; use OCP\IUser; @@ -47,18 +48,26 @@ class ActionProviderStore { } /** - * @return IProvider[] + * @return list<IProvider|IBulkProvider> * @throws Exception */ public function getProviders(IUser $user): array { $appClasses = $this->getAppProviderClasses($user); $providerClasses = $this->getServerProviderClasses(); $allClasses = array_merge($providerClasses, $appClasses); + /** @var list<IProvider|IBulkProvider> $providers */ $providers = []; foreach ($allClasses as $class) { try { - $providers[] = $this->serverContainer->get($class); + $provider = $this->serverContainer->get($class); + if ($provider instanceof IProvider || $provider instanceof IBulkProvider) { + $providers[] = $provider; + } else { + $this->logger->warning('Ignoring invalid contacts menu provider', [ + 'class' => $class, + ]); + } } catch (QueryException $ex) { $this->logger->error( 'Could not load contacts menu action provider ' . $class, diff --git a/lib/private/Contacts/ContactsMenu/ContactsStore.php b/lib/private/Contacts/ContactsMenu/ContactsStore.php index c692b486ae4..2f141cbc0ab 100644 --- a/lib/private/Contacts/ContactsMenu/ContactsStore.php +++ b/lib/private/Contacts/ContactsMenu/ContactsStore.php @@ -33,6 +33,8 @@ namespace OC\Contacts\ContactsMenu; use OC\KnownUser\KnownUserService; use OC\Profile\ProfileManager; +use OCA\UserStatus\Db\UserStatus; +use OCA\UserStatus\Service\StatusService; use OCP\Contacts\ContactsMenu\IContactsStore; use OCP\Contacts\ContactsMenu\IEntry; use OCP\Contacts\IManager; @@ -42,10 +44,17 @@ use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; use OCP\L10N\IFactory as IL10NFactory; +use function array_column; +use function array_fill_keys; +use function array_filter; +use function array_key_exists; +use function array_merge; +use function count; class ContactsStore implements IContactsStore { public function __construct( private IManager $contactsManager, + private ?StatusService $userStatusService, private IConfig $config, private ProfileManager $profileManager, private IUserManager $userManager, @@ -70,15 +79,75 @@ class ContactsStore implements IContactsStore { if ($offset !== null) { $options['offset'] = $offset; } + // Status integration only works without pagination and filters + if ($offset === null && ($filter === null || $filter === '')) { + $recentStatuses = $this->userStatusService?->findAllRecentStatusChanges($limit, $offset) ?? []; + } else { + $recentStatuses = []; + } - $allContacts = $this->contactsManager->search( - $filter ?? '', - [ - 'FN', - 'EMAIL' - ], - $options - ); + // Search by status if there is no filter and statuses are available + if (!empty($recentStatuses)) { + $allContacts = array_filter(array_map(function (UserStatus $userStatus) use ($options) { + // UID is ambiguous with federation. We have to use the federated cloud ID to an exact match of + // A local user + $user = $this->userManager->get($userStatus->getUserId()); + if ($user === null) { + return null; + } + + $contact = $this->contactsManager->search( + $user->getCloudId(), + [ + 'CLOUD', + ], + array_merge( + $options, + [ + 'limit' => 1, + 'offset' => 0, + ], + ), + )[0] ?? null; + if ($contact !== null) { + $contact[Entry::PROPERTY_STATUS_MESSAGE_TIMESTAMP] = $userStatus->getStatusMessageTimestamp(); + } + return $contact; + }, $recentStatuses)); + if ($limit !== null && count($allContacts) < $limit) { + // More contacts were requested + $fromContacts = $this->contactsManager->search( + $filter ?? '', + [ + 'FN', + 'EMAIL' + ], + array_merge( + $options, + [ + 'limit' => $limit - count($allContacts), + ], + ), + ); + + // Create hash map of all status contacts + $existing = array_fill_keys(array_column($allContacts, 'URI'), null); + // Append the ones that are new + $allContacts = array_merge( + $allContacts, + array_filter($fromContacts, fn (array $contact): bool => !array_key_exists($contact['URI'], $existing)) + ); + } + } else { + $allContacts = $this->contactsManager->search( + $filter ?? '', + [ + 'FN', + 'EMAIL' + ], + $options + ); + } $userId = $user->getUID(); $contacts = array_filter($allContacts, function ($contact) use ($userId) { @@ -108,6 +177,9 @@ class ContactsStore implements IContactsStore { * 3. if the `shareapi_only_share_with_group_members` config option is * enabled it will filter all users which doesn't have a common group * with the current user. + * If enabled, the 'shareapi_only_share_with_group_members_exclude_group_list' + * config option may specify some groups excluded from the principle of + * belonging to the same group. * * @param Entry[] $entries * @return Entry[] the filtered contacts @@ -141,6 +213,13 @@ class ContactsStore implements IContactsStore { } } + // ownGroupsOnly : some groups may be excluded + if ($ownGroupsOnly) { + $excludeGroupsFromOwnGroups = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', ''); + $excludeGroupsFromOwnGroupsList = json_decode($excludeGroupsFromOwnGroups, true) ?? []; + $selfGroups = array_diff($selfGroups, $excludeGroupsFromOwnGroupsList); + } + $selfUID = $self->getUID(); return array_values(array_filter($entries, function (IEntry $entry) use ($skipLocal, $ownGroupsOnly, $selfGroups, $selfUID, $disallowEnumeration, $restrictEnumerationGroup, $restrictEnumerationPhone, $allowEnumerationFullMatch, $filter) { @@ -265,36 +344,39 @@ class ContactsStore implements IContactsStore { private function contactArrayToEntry(array $contact): Entry { $entry = new Entry(); - if (isset($contact['UID'])) { + if (!empty($contact['UID'])) { $uid = $contact['UID']; $entry->setId($uid); + $entry->setProperty('isUser', false); + // overloaded usage so leaving as-is for now if (isset($contact['isLocalSystemBook'])) { $avatar = $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $uid, 'size' => 64]); - } elseif (isset($contact['FN'])) { - $avatar = $this->urlGenerator->linkToRouteAbsolute('core.GuestAvatar.getAvatar', ['guestName' => $contact['FN'], 'size' => 64]); + $entry->setProperty('isUser', true); + } elseif (!empty($contact['FN'])) { + $avatar = $this->urlGenerator->linkToRouteAbsolute('core.GuestAvatar.getAvatar', ['guestName' => str_replace('/', ' ', $contact['FN']), 'size' => 64]); } else { - $avatar = $this->urlGenerator->linkToRouteAbsolute('core.GuestAvatar.getAvatar', ['guestName' => $uid, 'size' => 64]); + $avatar = $this->urlGenerator->linkToRouteAbsolute('core.GuestAvatar.getAvatar', ['guestName' => str_replace('/', ' ', $uid), 'size' => 64]); } $entry->setAvatar($avatar); } - if (isset($contact['FN'])) { + if (!empty($contact['FN'])) { $entry->setFullName($contact['FN']); } $avatarPrefix = "VALUE=uri:"; - if (isset($contact['PHOTO']) && str_starts_with($contact['PHOTO'], $avatarPrefix)) { + if (!empty($contact['PHOTO']) && str_starts_with($contact['PHOTO'], $avatarPrefix)) { $entry->setAvatar(substr($contact['PHOTO'], strlen($avatarPrefix))); } - if (isset($contact['EMAIL'])) { + if (!empty($contact['EMAIL'])) { foreach ($contact['EMAIL'] as $email) { $entry->addEMailAddress($email); } } // Provide profile parameters for core/src/OC/contactsmenu/contact.handlebars template - if (isset($contact['UID']) && isset($contact['FN'])) { + if (!empty($contact['UID']) && !empty($contact['FN'])) { $targetUserId = $contact['UID']; $targetUser = $this->userManager->get($targetUserId); if (!empty($targetUser)) { diff --git a/lib/private/Contacts/ContactsMenu/Entry.php b/lib/private/Contacts/ContactsMenu/Entry.php index f1cb4f9c52f..954f46e1296 100644 --- a/lib/private/Contacts/ContactsMenu/Entry.php +++ b/lib/private/Contacts/ContactsMenu/Entry.php @@ -29,8 +29,11 @@ namespace OC\Contacts\ContactsMenu; use OCP\Contacts\ContactsMenu\IAction; use OCP\Contacts\ContactsMenu\IEntry; +use function array_merge; class Entry implements IEntry { + public const PROPERTY_STATUS_MESSAGE_TIMESTAMP = 'statusMessageTimestamp'; + /** @var string|int|null */ private $id = null; @@ -50,6 +53,11 @@ class Entry implements IEntry { private array $properties = []; + private ?string $status = null; + private ?string $statusMessage = null; + private ?int $statusMessageTimestamp = null; + private ?string $statusIcon = null; + public function setId(string $id): void { $this->id = $id; } @@ -102,6 +110,16 @@ class Entry implements IEntry { $this->sortActions(); } + public function setStatus(string $status, + string $statusMessage = null, + int $statusMessageTimestamp = null, + string $icon = null): void { + $this->status = $status; + $this->statusMessage = $statusMessage; + $this->statusMessageTimestamp = $statusMessageTimestamp; + $this->statusIcon = $icon; + } + /** * @return IAction[] */ @@ -127,11 +145,15 @@ class Entry implements IEntry { }); } + public function setProperty(string $propertyName, mixed $value) { + $this->properties[$propertyName] = $value; + } + /** - * @param array $contact key-value array containing additional properties + * @param array $properties key-value array containing additional properties */ - public function setProperties(array $contact): void { - $this->properties = $contact; + public function setProperties(array $properties): void { + $this->properties = array_merge($this->properties, $properties); } public function getProperty(string $key): mixed { @@ -142,7 +164,7 @@ class Entry implements IEntry { } /** - * @return array{id: int|string|null, fullName: string, avatar: string|null, topAction: mixed, actions: array, lastMessage: '', emailAddresses: string[], profileTitle: string|null, profileUrl: string|null} + * @return array{id: int|string|null, fullName: string, avatar: string|null, topAction: mixed, actions: array, lastMessage: '', emailAddresses: string[], profileTitle: string|null, profileUrl: string|null, status: string|null, statusMessage: null|string, statusMessageTimestamp: null|int, statusIcon: null|string, isUser: bool, uid: mixed} */ public function jsonSerialize(): array { $topAction = !empty($this->actions) ? $this->actions[0]->jsonSerialize() : null; @@ -160,6 +182,20 @@ class Entry implements IEntry { 'emailAddresses' => $this->getEMailAddresses(), 'profileTitle' => $this->profileTitle, 'profileUrl' => $this->profileUrl, + 'status' => $this->status, + 'statusMessage' => $this->statusMessage, + 'statusMessageTimestamp' => $this->statusMessageTimestamp, + 'statusIcon' => $this->statusIcon, + 'isUser' => $this->getProperty('isUser') === true, + 'uid' => $this->getProperty('UID'), ]; } + + public function getStatusMessage(): ?string { + return $this->statusMessage; + } + + public function getStatusMessageTimestamp(): ?int { + return $this->statusMessageTimestamp; + } } diff --git a/lib/private/Contacts/ContactsMenu/Manager.php b/lib/private/Contacts/ContactsMenu/Manager.php index 490cf602283..5cf9a07c8e3 100644 --- a/lib/private/Contacts/ContactsMenu/Manager.php +++ b/lib/private/Contacts/ContactsMenu/Manager.php @@ -28,7 +28,9 @@ namespace OC\Contacts\ContactsMenu; use Exception; use OCP\App\IAppManager; use OCP\Constants; +use OCP\Contacts\ContactsMenu\IBulkProvider; use OCP\Contacts\ContactsMenu\IEntry; +use OCP\Contacts\ContactsMenu\IProvider; use OCP\IConfig; use OCP\IUser; @@ -80,8 +82,19 @@ class Manager { * @return IEntry[] */ private function sortEntries(array $entries): array { - usort($entries, function (IEntry $entryA, IEntry $entryB) { - return strcasecmp($entryA->getFullName(), $entryB->getFullName()); + usort($entries, function (Entry $entryA, Entry $entryB) { + $aStatusTimestamp = $entryA->getProperty(Entry::PROPERTY_STATUS_MESSAGE_TIMESTAMP); + $bStatusTimestamp = $entryB->getProperty(Entry::PROPERTY_STATUS_MESSAGE_TIMESTAMP); + if (!$aStatusTimestamp && !$bStatusTimestamp) { + return strcasecmp($entryA->getFullName(), $entryB->getFullName()); + } + if ($aStatusTimestamp === null) { + return 1; + } + if ($bStatusTimestamp === null) { + return -1; + } + return $bStatusTimestamp - $aStatusTimestamp; }); return $entries; } @@ -92,9 +105,14 @@ class Manager { */ private function processEntries(array $entries, IUser $user): void { $providers = $this->actionProviderStore->getProviders($user); - foreach ($entries as $entry) { - foreach ($providers as $provider) { - $provider->process($entry); + + foreach ($providers as $provider) { + if ($provider instanceof IBulkProvider && !($provider instanceof IProvider)) { + $provider->process($entries); + } elseif ($provider instanceof IProvider && !($provider instanceof IBulkProvider)) { + foreach ($entries as $entry) { + $provider->process($entry); + } } } } diff --git a/lib/private/ContactsManager.php b/lib/private/ContactsManager.php index c39f7c715cc..cfbd4305cd8 100644 --- a/lib/private/ContactsManager.php +++ b/lib/private/ContactsManager.php @@ -91,20 +91,20 @@ class ContactsManager implements IManager { * This function can be used to delete the contact identified by the given id * * @param int $id the unique identifier to a contact - * @param string $address_book_key identifier of the address book in which the contact shall be deleted + * @param string $addressBookKey identifier of the address book in which the contact shall be deleted * @return bool successful or not */ - public function delete($id, $address_book_key) { - $addressBook = $this->getAddressBook($address_book_key); + public function delete($id, $addressBookKey) { + $addressBook = $this->getAddressBook($addressBookKey); if (!$addressBook) { - return null; + return false; } if ($addressBook->getPermissions() & Constants::PERMISSION_DELETE) { return $addressBook->delete($id); } - return null; + return false; } /** @@ -112,11 +112,11 @@ class ContactsManager implements IManager { * Otherwise the contact will be updated by replacing the entire data set. * * @param array $properties this array if key-value-pairs defines a contact - * @param string $address_book_key identifier of the address book in which the contact shall be created or updated - * @return array representing the contact just created or updated + * @param string $addressBookKey identifier of the address book in which the contact shall be created or updated + * @return ?array representing the contact just created or updated */ - public function createOrUpdate($properties, $address_book_key) { - $addressBook = $this->getAddressBook($address_book_key); + public function createOrUpdate($properties, $addressBookKey) { + $addressBook = $this->getAddressBook($addressBookKey); if (!$addressBook) { return null; } @@ -133,7 +133,7 @@ class ContactsManager implements IManager { * * @return bool true if enabled, false if not */ - public function isEnabled() { + public function isEnabled(): bool { return !empty($this->addressBooks) || !empty($this->addressBookLoaders); } @@ -192,11 +192,8 @@ class ContactsManager implements IManager { /** * Get (and load when needed) the address book for $key - * - * @param string $addressBookKey - * @return IAddressBook */ - protected function getAddressBook($addressBookKey) { + protected function getAddressBook(string $addressBookKey): ?IAddressBook { $this->loadAddressBooks(); if (!array_key_exists($addressBookKey, $this->addressBooks)) { return null; diff --git a/lib/private/DB/Adapter.php b/lib/private/DB/Adapter.php index acaa529c0e2..ad232aaabd1 100644 --- a/lib/private/DB/Adapter.php +++ b/lib/private/DB/Adapter.php @@ -30,6 +30,7 @@ namespace OC\DB; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; +use OC\DB\Exceptions\DbalException; /** * This handles the way we use to write queries, into something that can be @@ -142,9 +143,12 @@ class Adapter { foreach ($values as $key => $value) { $builder->setValue($key, $builder->createNamedParameter($value)); } - return $builder->execute(); - } catch (UniqueConstraintViolationException $e) { - return 0; + return $builder->executeStatement(); + } catch (DbalException $e) { + if ($e->getReason() === \OCP\DB\Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + return 0; + } + throw $e; } } } diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php index 85c6a72dfdb..a8838bbae2c 100644 --- a/lib/private/DB/Connection.php +++ b/lib/private/DB/Connection.php @@ -38,25 +38,28 @@ namespace OC\DB; use Doctrine\Common\EventManager; use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Configuration; +use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection; use Doctrine\DBAL\Driver; use Doctrine\DBAL\Exception; +use Doctrine\DBAL\Exception\ConnectionLost; use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Platforms\OraclePlatform; -use Doctrine\DBAL\Platforms\PostgreSQL94Platform; use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Result; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Statement; +use OC\DB\QueryBuilder\QueryBuilder; +use OC\SystemConfig; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Diagnostics\IEventLogger; use OCP\IRequestId; use OCP\PreConditionNotMetException; use OCP\Profiler\IProfiler; -use OC\DB\QueryBuilder\QueryBuilder; -use OC\SystemConfig; +use Psr\Clock\ClockInterface; use Psr\Log\LoggerInterface; +use function in_array; -class Connection extends \Doctrine\DBAL\Connection { +class Connection extends PrimaryReadReplicaConnection { /** @var string */ protected $tablePrefix; @@ -66,6 +69,8 @@ class Connection extends \Doctrine\DBAL\Connection { /** @var SystemConfig */ private $systemConfig; + private ClockInterface $clock; + private LoggerInterface $logger; protected $lockedTable = null; @@ -78,6 +83,12 @@ class Connection extends \Doctrine\DBAL\Connection { /** @var DbDataCollector|null */ protected $dbDataCollector = null; + private array $lastConnectionCheck = []; + + protected ?float $transactionActiveSince = null; + + /** @var array<string, int> */ + protected $tableDirtyWrites = []; /** * Initializes a new instance of the Connection class. @@ -104,6 +115,7 @@ class Connection extends \Doctrine\DBAL\Connection { $this->tablePrefix = $params['tablePrefix']; $this->systemConfig = \OC::$server->getSystemConfig(); + $this->clock = \OCP\Server::get(ClockInterface::class); $this->logger = \OC::$server->get(LoggerInterface::class); /** @var \OCP\Profiler\IProfiler */ @@ -120,13 +132,16 @@ class Connection extends \Doctrine\DBAL\Connection { /** * @throws Exception */ - public function connect() { + public function connect($connectionName = null) { try { if ($this->_conn) { + $this->reconnectIfNeeded(); /** @psalm-suppress InternalMethod */ return parent::connect(); } + $this->lastConnectionCheck[$this->getConnectionName()] = time(); + // Only trigger the event logger for the initial connect call $eventLogger = \OC::$server->get(IEventLogger::class); $eventLogger->start('connect:db', 'db connection opened'); @@ -220,7 +235,7 @@ class Connection extends \Doctrine\DBAL\Connection { * @return Statement The prepared statement. * @throws Exception */ - public function prepare($statement, $limit = null, $offset = null): Statement { + public function prepare($sql, $limit = null, $offset = null): Statement { if ($limit === -1 || $limit === null) { $limit = null; } else { @@ -231,9 +246,9 @@ class Connection extends \Doctrine\DBAL\Connection { } if (!is_null($limit)) { $platform = $this->getDatabasePlatform(); - $statement = $platform->modifyLimitQuery($statement, $limit, $offset); + $sql = $platform->modifyLimitQuery($sql, $limit, $offset); } - $statement = $this->replaceTablePrefix($statement); + $statement = $this->replaceTablePrefix($sql); $statement = $this->adapter->fixupStatement($statement); return parent::prepare($statement); @@ -255,6 +270,42 @@ class Connection extends \Doctrine\DBAL\Connection { * @throws \Doctrine\DBAL\Exception */ public function executeQuery(string $sql, array $params = [], $types = [], QueryCacheProfile $qcp = null): Result { + $tables = $this->getQueriedTables($sql); + $now = $this->clock->now()->getTimestamp(); + $dirtyTableWrites = []; + foreach ($tables as $table) { + $lastAccess = $this->tableDirtyWrites[$table] ?? 0; + // Only very recent writes are considered dirty + if ($lastAccess >= ($now - 3)) { + $dirtyTableWrites[] = $table; + } + } + if ($this->isTransactionActive()) { + // Transacted queries go to the primary. The consistency of the primary guarantees that we can not run + // into a dirty read. + } elseif (count($dirtyTableWrites) === 0) { + // No tables read that could have been written already in the same request and no transaction active + // so we can switch back to the replica for reading as long as no writes happen that switch back to the primary + // We cannot log here as this would log too early in the server boot process + $this->ensureConnectedToReplica(); + } else { + // Read to a table that has been written to previously + // While this might not necessarily mean that we did a read after write it is an indication for a code path to check + $this->logger->log( + (int) ($this->systemConfig->getValue('loglevel_dirty_database_queries', null) ?? 0), + 'dirty table reads: ' . $sql, + [ + 'tables' => array_keys($this->tableDirtyWrites), + 'reads' => $tables, + 'exception' => new \Exception('dirty table reads: ' . $sql), + ], + ); + // To prevent a dirty read on a replica that is slightly out of sync, we + // switch back to the primary. This is detrimental for performance but + // safer for consistency. + $this->ensureConnectedToPrimary(); + } + $sql = $this->replaceTablePrefix($sql); $sql = $this->adapter->fixupStatement($sql); $this->queriesExecuted++; @@ -263,6 +314,16 @@ class Connection extends \Doctrine\DBAL\Connection { } /** + * Helper function to get the list of tables affected by a given query + * used to track dirty tables that received a write with the current request + */ + private function getQueriedTables(string $sql): array { + $re = '/(\*PREFIX\*\w+)/mi'; + preg_match_all($re, $sql, $matches); + return array_map([$this, 'replaceTablePrefix'], $matches[0] ?? []); + } + + /** * @throws Exception */ public function executeUpdate(string $sql, array $params = [], array $types = []): int { @@ -288,6 +349,10 @@ class Connection extends \Doctrine\DBAL\Connection { * @throws \Doctrine\DBAL\Exception */ public function executeStatement($sql, array $params = [], array $types = []): int { + $tables = $this->getQueriedTables($sql); + foreach ($tables as $table) { + $this->tableDirtyWrites[$table] = $this->clock->now()->getTimestamp(); + } $sql = $this->replaceTablePrefix($sql); $sql = $this->adapter->fixupStatement($sql); $this->queriesExecuted++; @@ -303,6 +368,11 @@ class Connection extends \Doctrine\DBAL\Connection { $prefix .= \OC::$server->get(IRequestId::class)->getId() . "\t"; } + // FIXME: Improve to log the actual target db host + $isPrimary = $this->connections['primary'] === $this->_conn; + $prefix .= ' ' . ($isPrimary === true ? 'primary' : 'replica') . ' '; + $prefix .= ' ' . $this->getTransactionNestingLevel() . ' '; + file_put_contents( $this->systemConfig->getValue('query_log_file', ''), $prefix . $sql . "\n", @@ -321,14 +391,14 @@ class Connection extends \Doctrine\DBAL\Connection { * * @param string $seqName Name of the sequence object from which the ID should be returned. * - * @return string the last inserted ID. + * @return int the last inserted ID. * @throws Exception */ - public function lastInsertId($seqName = null) { - if ($seqName) { - $seqName = $this->replaceTablePrefix($seqName); + public function lastInsertId($name = null): int { + if ($name) { + $name = $this->replaceTablePrefix($name); } - return $this->adapter->lastInsertId($seqName); + return $this->adapter->lastInsertId($name); } /** @@ -600,12 +670,61 @@ class Connection extends \Doctrine\DBAL\Connection { return new SQLiteMigrator($this, $config, $dispatcher); } elseif ($platform instanceof OraclePlatform) { return new OracleMigrator($this, $config, $dispatcher); - } elseif ($platform instanceof MySQLPlatform) { - return new MySQLMigrator($this, $config, $dispatcher); - } elseif ($platform instanceof PostgreSQL94Platform) { - return new PostgreSqlMigrator($this, $config, $dispatcher); } else { return new Migrator($this, $config, $dispatcher); } } + + public function beginTransaction() { + if (!$this->inTransaction()) { + $this->transactionActiveSince = microtime(true); + } + return parent::beginTransaction(); + } + + public function commit() { + $result = parent::commit(); + if ($this->getTransactionNestingLevel() === 0) { + $timeTook = microtime(true) - $this->transactionActiveSince; + $this->transactionActiveSince = null; + if ($timeTook > 1) { + $this->logger->warning('Transaction took ' . $timeTook . 's', ['exception' => new \Exception('Transaction took ' . $timeTook . 's')]); + } + } + return $result; + } + + public function rollBack() { + $result = parent::rollBack(); + if ($this->getTransactionNestingLevel() === 0) { + $timeTook = microtime(true) - $this->transactionActiveSince; + $this->transactionActiveSince = null; + if ($timeTook > 1) { + $this->logger->warning('Transaction rollback took longer than 1s: ' . $timeTook, ['exception' => new \Exception('Long running transaction rollback')]); + } + } + return $result; + } + + private function reconnectIfNeeded(): void { + if ( + !isset($this->lastConnectionCheck[$this->getConnectionName()]) || + $this->lastConnectionCheck[$this->getConnectionName()] + 30 >= time() || + $this->isTransactionActive() + ) { + return; + } + + try { + $this->_conn->query($this->getDriver()->getDatabasePlatform()->getDummySelectSQL()); + $this->lastConnectionCheck[$this->getConnectionName()] = time(); + } catch (ConnectionLost|\Exception $e) { + $this->logger->warning('Exception during connectivity check, closing and reconnecting', ['exception' => $e]); + $this->close(); + } + } + + private function getConnectionName(): string { + return $this->isConnectedToPrimary() ? 'primary' : 'replica'; + } } diff --git a/lib/private/DB/ConnectionAdapter.php b/lib/private/DB/ConnectionAdapter.php index a53c7ecd994..e27c98194fb 100644 --- a/lib/private/DB/ConnectionAdapter.php +++ b/lib/private/DB/ConnectionAdapter.php @@ -27,6 +27,10 @@ namespace OC\DB; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Platforms\MySQLPlatform; +use Doctrine\DBAL\Platforms\OraclePlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Schema\Schema; use OC\DB\Exceptions\DbalException; use OCP\DB\IPreparedStatement; @@ -87,7 +91,7 @@ class ConnectionAdapter implements IDBConnection { public function lastInsertId(string $table): int { try { - return (int)$this->inner->lastInsertId($table); + return $this->inner->lastInsertId($table); } catch (Exception $e) { throw DbalException::wrap($e); } @@ -242,4 +246,19 @@ class ConnectionAdapter implements IDBConnection { public function getInner(): Connection { return $this->inner; } + + public function getDatabaseProvider(): string { + $platform = $this->inner->getDatabasePlatform(); + if ($platform instanceof MySQLPlatform) { + return IDBConnection::PLATFORM_MYSQL; + } elseif ($platform instanceof OraclePlatform) { + return IDBConnection::PLATFORM_ORACLE; + } elseif ($platform instanceof PostgreSQLPlatform) { + return IDBConnection::PLATFORM_POSTGRES; + } elseif ($platform instanceof SqlitePlatform) { + return IDBConnection::PLATFORM_SQLITE; + } else { + throw new \Exception('Database ' . $platform::class . ' not supported'); + } + } } diff --git a/lib/private/DB/ConnectionFactory.php b/lib/private/DB/ConnectionFactory.php index 1b0ac436364..e868f18ec34 100644 --- a/lib/private/DB/ConnectionFactory.php +++ b/lib/private/DB/ConnectionFactory.php @@ -32,7 +32,6 @@ use Doctrine\Common\EventManager; use Doctrine\DBAL\Configuration; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Event\Listeners\OracleSessionInit; -use Doctrine\DBAL\Event\Listeners\SQLSessionInit; use OC\SystemConfig; /** @@ -127,11 +126,8 @@ class ConnectionFactory { $normalizedType = $this->normalizeType($type); $eventManager = new EventManager(); $eventManager->addEventSubscriber(new SetTransactionIsolationLevel()); + $additionalConnectionParams = array_merge($this->createConnectionParams(), $additionalConnectionParams); switch ($normalizedType) { - case 'mysql': - $eventManager->addEventSubscriber( - new SQLSessionInit("SET SESSION AUTOCOMMIT=1")); - break; case 'oci': $eventManager->addEventSubscriber(new OracleSessionInit); // the driverOptions are unused in dbal and need to be mapped to the parameters @@ -139,7 +135,7 @@ class ConnectionFactory { $additionalConnectionParams = array_merge($additionalConnectionParams, $additionalConnectionParams['driverOptions']); } $host = $additionalConnectionParams['host']; - $port = isset($additionalConnectionParams['port']) ? $additionalConnectionParams['port'] : null; + $port = $additionalConnectionParams['port'] ?? null; $dbName = $additionalConnectionParams['dbname']; // we set the connect string as dbname and unset the host to coerce doctrine into using it as connect string @@ -159,7 +155,7 @@ class ConnectionFactory { } /** @var Connection $connection */ $connection = DriverManager::getConnection( - array_merge($this->getDefaultConnectionParams($type), $additionalConnectionParams), + $additionalConnectionParams, new Configuration(), $eventManager ); @@ -195,10 +191,10 @@ class ConnectionFactory { public function createConnectionParams(string $configPrefix = '') { $type = $this->config->getValue('dbtype', 'sqlite'); - $connectionParams = [ + $connectionParams = array_merge($this->getDefaultConnectionParams($type), [ 'user' => $this->config->getValue($configPrefix . 'dbuser', $this->config->getValue('dbuser', '')), 'password' => $this->config->getValue($configPrefix . 'dbpassword', $this->config->getValue('dbpassword', '')), - ]; + ]); $name = $this->config->getValue($configPrefix . 'dbname', $this->config->getValue('dbname', self::DEFAULT_DBNAME)); if ($this->normalizeType($type) === 'sqlite3') { @@ -237,7 +233,11 @@ class ConnectionFactory { $connectionParams['persistent'] = true; } - return $connectionParams; + $replica = $this->config->getValue('dbreplica', []) ?: [$connectionParams]; + return array_merge($connectionParams, [ + 'primary' => $connectionParams, + 'replica' => $replica, + ]); } /** diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php index 71d7b51d149..f885422c928 100644 --- a/lib/private/DB/MigrationService.php +++ b/lib/private/DB/MigrationService.php @@ -43,6 +43,7 @@ use OCP\AppFramework\QueryException; use OCP\DB\ISchemaWrapper; use OCP\Migration\IMigrationStep; use OCP\Migration\IOutput; +use OCP\Server; use Psr\Log\LoggerInterface; class MigrationService { @@ -51,6 +52,7 @@ class MigrationService { private string $migrationsPath; private string $migrationsNamespace; private IOutput $output; + private LoggerInterface $logger; private Connection $connection; private string $appName; private bool $checkOracle; @@ -58,11 +60,16 @@ class MigrationService { /** * @throws \Exception */ - public function __construct($appName, Connection $connection, ?IOutput $output = null, ?AppLocator $appLocator = null) { + public function __construct(string $appName, Connection $connection, ?IOutput $output = null, ?AppLocator $appLocator = null, ?LoggerInterface $logger = null) { $this->appName = $appName; $this->connection = $connection; + if ($logger === null) { + $this->logger = Server::get(LoggerInterface::class); + } else { + $this->logger = $logger; + } if ($output === null) { - $this->output = new SimpleOutput(\OC::$server->get(LoggerInterface::class), $appName); + $this->output = new SimpleOutput($this->logger, $appName); } else { $this->output = $output; } @@ -100,18 +107,15 @@ class MigrationService { /** * Returns the name of the app for which this migration is executed - * - * @return string */ - public function getApp() { + public function getApp(): string { return $this->appName; } /** - * @return bool * @codeCoverageIgnore - this will implicitly tested on installation */ - private function createMigrationTable() { + private function createMigrationTable(): bool { if ($this->migrationTableCreated) { return false; } @@ -188,7 +192,7 @@ class MigrationService { ->where($qb->expr()->eq('app', $qb->createNamedParameter($this->getApp()))) ->orderBy('version'); - $result = $qb->execute(); + $result = $qb->executeQuery(); $rows = $result->fetchAll(\PDO::FETCH_COLUMN); $result->closeCursor(); @@ -197,15 +201,17 @@ class MigrationService { /** * Returns all versions which are available in the migration folder - * - * @return array + * @return list<string> */ - public function getAvailableVersions() { + public function getAvailableVersions(): array { $this->ensureMigrationsAreLoaded(); return array_map('strval', array_keys($this->migrations)); } - protected function findMigrations() { + /** + * @return array<string, string> + */ + protected function findMigrations(): array { $directory = realpath($this->migrationsPath); if ($directory === false || !file_exists($directory) || !is_dir($directory)) { return []; @@ -322,10 +328,9 @@ class MigrationService { /** * Return the explicit version for the aliases; current, next, prev, latest * - * @param string $alias * @return mixed|null|string */ - public function getMigration($alias) { + public function getMigration(string $alias) { switch ($alias) { case 'current': return $this->getCurrentVersion(); @@ -342,29 +347,22 @@ class MigrationService { return '0'; } - /** - * @param string $version - * @param int $delta - * @return null|string - */ - private function getRelativeVersion($version, $delta) { + private function getRelativeVersion(string $version, int $delta): ?string { $this->ensureMigrationsAreLoaded(); $versions = $this->getAvailableVersions(); - array_unshift($versions, 0); + array_unshift($versions, '0'); + /** @var int $offset */ $offset = array_search($version, $versions, true); if ($offset === false || !isset($versions[$offset + $delta])) { // Unknown version or delta out of bounds. return null; } - return (string) $versions[$offset + $delta]; + return (string)$versions[$offset + $delta]; } - /** - * @return string - */ - private function getCurrentVersion() { + private function getCurrentVersion(): string { $m = $this->getMigratedVersions(); if (count($m) === 0) { return '0'; @@ -374,11 +372,9 @@ class MigrationService { } /** - * @param string $version - * @return string * @throws \InvalidArgumentException */ - private function getClass($version) { + private function getClass(string $version): string { $this->ensureMigrationsAreLoaded(); if (isset($this->migrations[$version])) { @@ -390,22 +386,18 @@ class MigrationService { /** * Allows to set an IOutput implementation which is used for logging progress and messages - * - * @param IOutput $output */ - public function setOutput(IOutput $output) { + public function setOutput(IOutput $output): void { $this->output = $output; } /** * Applies all not yet applied versions up to $to - * - * @param string $to - * @param bool $schemaOnly * @throws \InvalidArgumentException */ - public function migrate($to = 'latest', $schemaOnly = false) { + public function migrate(string $to = 'latest', bool $schemaOnly = false): void { if ($schemaOnly) { + $this->output->debug('Migrating schema only'); $this->migrateSchemaOnly($to); return; } @@ -425,11 +417,9 @@ class MigrationService { /** * Applies all not yet applied versions up to $to - * - * @param string $to * @throws \InvalidArgumentException */ - public function migrateSchemaOnly($to = 'latest') { + public function migrateSchemaOnly(string $to = 'latest'): void { // read known migrations $toBeExecuted = $this->getMigrationsToExecute($to); @@ -439,6 +429,7 @@ class MigrationService { $toSchema = null; foreach ($toBeExecuted as $version) { + $this->output->debug('- Reading ' . $version); $instance = $this->createInstance($version); $toSchema = $instance->changeSchema($this->output, function () use ($toSchema): ISchemaWrapper { @@ -447,16 +438,20 @@ class MigrationService { } if ($toSchema instanceof SchemaWrapper) { + $this->output->debug('- Checking target database schema'); $targetSchema = $toSchema->getWrappedSchema(); - $this->ensureUniqueNamesConstraints($targetSchema); + $this->ensureUniqueNamesConstraints($targetSchema, true); if ($this->checkOracle) { $beforeSchema = $this->connection->createSchema(); $this->ensureOracleConstraints($beforeSchema, $targetSchema, strlen($this->connection->getPrefix())); } + + $this->output->debug('- Migrate database schema'); $this->connection->migrateToSchema($targetSchema); $toSchema->performDropTableCalls(); } + $this->output->debug('- Mark migrations as executed'); foreach ($toBeExecuted as $version) { $this->markAsExecuted($version); } @@ -526,7 +521,7 @@ class MigrationService { if ($toSchema instanceof SchemaWrapper) { $targetSchema = $toSchema->getWrappedSchema(); - $this->ensureUniqueNamesConstraints($targetSchema); + $this->ensureUniqueNamesConstraints($targetSchema, $schemaOnly); if ($this->checkOracle) { $sourceSchema = $this->connection->createSchema(); $this->ensureOracleConstraints($sourceSchema, $targetSchema, strlen($this->connection->getPrefix())); @@ -662,14 +657,26 @@ class MigrationService { } /** + * Ensure naming constraints + * * Naming constraints: * - Index, sequence and primary key names must be unique within a Postgres Schema * + * Only on installation we want to break hard, so that all developers notice + * the bugs when installing the app on any database or CI, and can work on + * fixing their migrations before releasing a version incompatible with Postgres. + * + * In case of updates we might be running on production instances and the + * administrators being faced with the error would not know how to resolve it + * anyway. This can also happen with instances, that had the issue before the + * current update, so we don't want to make their life more complicated + * than needed. + * * @param Schema $targetSchema + * @param bool $isInstalling */ - public function ensureUniqueNamesConstraints(Schema $targetSchema): void { + public function ensureUniqueNamesConstraints(Schema $targetSchema, bool $isInstalling): void { $constraintNames = []; - $sequences = $targetSchema->getSequences(); foreach ($targetSchema->getTables() as $table) { @@ -680,14 +687,20 @@ class MigrationService { } if (isset($constraintNames[$thing->getName()])) { - throw new \InvalidArgumentException('Index name "' . $thing->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); + if ($isInstalling) { + throw new \InvalidArgumentException('Index name "' . $thing->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); + } + $this->logErrorOrWarning('Index name "' . $thing->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); } $constraintNames[$thing->getName()] = $table->getName(); } foreach ($table->getForeignKeys() as $thing) { if (isset($constraintNames[$thing->getName()])) { - throw new \InvalidArgumentException('Foreign key name "' . $thing->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); + if ($isInstalling) { + throw new \InvalidArgumentException('Foreign key name "' . $thing->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); + } + $this->logErrorOrWarning('Foreign key name "' . $thing->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); } $constraintNames[$thing->getName()] = $table->getName(); } @@ -700,7 +713,10 @@ class MigrationService { } if (isset($constraintNames[$indexName])) { - throw new \InvalidArgumentException('Primary index name "' . $indexName . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); + if ($isInstalling) { + throw new \InvalidArgumentException('Primary index name "' . $indexName . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); + } + $this->logErrorOrWarning('Primary index name "' . $indexName . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); } $constraintNames[$indexName] = $table->getName(); } @@ -708,12 +724,23 @@ class MigrationService { foreach ($sequences as $sequence) { if (isset($constraintNames[$sequence->getName()])) { - throw new \InvalidArgumentException('Sequence name "' . $sequence->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); + if ($isInstalling) { + throw new \InvalidArgumentException('Sequence name "' . $sequence->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); + } + $this->logErrorOrWarning('Sequence name "' . $sequence->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".'); } $constraintNames[$sequence->getName()] = 'sequence'; } } + protected function logErrorOrWarning(string $log): void { + if ($this->output instanceof SimpleOutput) { + $this->output->warning($log); + } else { + $this->logger->error($log); + } + } + private function ensureMigrationsAreLoaded() { if (empty($this->migrations)) { $this->migrations = $this->findMigrations(); diff --git a/lib/private/DB/Migrator.php b/lib/private/DB/Migrator.php index 74e5a285351..7cf95b04000 100644 --- a/lib/private/DB/Migrator.php +++ b/lib/private/DB/Migrator.php @@ -31,14 +31,13 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Schema\AbstractAsset; -use Doctrine\DBAL\Schema\Comparator; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\SchemaDiff; use Doctrine\DBAL\Types\StringType; use Doctrine\DBAL\Types\Type; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use function preg_match; -use OCP\EventDispatcher\IEventDispatcher; class Migrator { /** @var Connection */ @@ -53,8 +52,8 @@ class Migrator { private $noEmit = false; public function __construct(Connection $connection, - IConfig $config, - ?IEventDispatcher $dispatcher = null) { + IConfig $config, + ?IEventDispatcher $dispatcher = null) { $this->connection = $connection; $this->config = $config; $this->dispatcher = $dispatcher; @@ -75,7 +74,7 @@ class Migrator { $schemaDiff = $this->getDiff($targetSchema, $this->connection); $script = ''; - $sqls = $schemaDiff->toSql($this->connection->getDatabasePlatform()); + $sqls = $this->connection->getDatabasePlatform()->getAlterSchemaSQL($schemaDiff); foreach ($sqls as $sql) { $script .= $this->convertStatementToScript($sql); } @@ -95,18 +94,20 @@ class Migrator { } return preg_match($filterExpression, $asset) === 1; }); - return $this->connection->getSchemaManager()->createSchema(); + return $this->connection->createSchemaManager()->introspectSchema(); } /** * @return SchemaDiff */ protected function getDiff(Schema $targetSchema, Connection $connection) { - // adjust varchar columns with a length higher then getVarcharMaxLength to clob + // Adjust STRING columns with a length higher than 4000 to TEXT (clob) + // for consistency between the supported databases and + // old vs. new installations. foreach ($targetSchema->getTables() as $table) { foreach ($table->getColumns() as $column) { if ($column->getType() instanceof StringType) { - if ($column->getLength() > $connection->getDatabasePlatform()->getVarcharMaxLength()) { + if ($column->getLength() > 4000) { $column->setType(Type::getType('text')); $column->setLength(null); } @@ -122,7 +123,7 @@ class Migrator { } return preg_match($filterExpression, $asset) === 1; }); - $sourceSchema = $connection->getSchemaManager()->createSchema(); + $sourceSchema = $connection->createSchemaManager()->introspectSchema(); // remove tables we don't know about foreach ($sourceSchema->getTables() as $table) { @@ -137,9 +138,8 @@ class Migrator { } } - /** @psalm-suppress InternalMethod */ - $comparator = new Comparator(); - return $comparator->compare($sourceSchema, $targetSchema); + $comparator = $connection->createSchemaManager()->createComparator(); + return $comparator->compareSchemas($sourceSchema, $targetSchema); } /** @@ -155,11 +155,11 @@ class Migrator { if (!$connection->getDatabasePlatform() instanceof MySQLPlatform) { $connection->beginTransaction(); } - $sqls = $schemaDiff->toSql($connection->getDatabasePlatform()); + $sqls = $connection->getDatabasePlatform()->getAlterSchemaSQL($schemaDiff); $step = 0; foreach ($sqls as $sql) { $this->emit($sql, $step++, count($sqls)); - $connection->query($sql); + $connection->executeQuery($sql); } if (!$connection->getDatabasePlatform() instanceof MySQLPlatform) { $connection->commit(); @@ -178,7 +178,7 @@ class Migrator { } protected function getFilterExpression() { - return '/^' . preg_quote($this->config->getSystemValueString('dbtableprefix', 'oc_')) . '/'; + return '/^' . preg_quote($this->config->getSystemValueString('dbtableprefix', 'oc_'), '/') . '/'; } protected function emit(string $sql, int $step, int $max): void { diff --git a/lib/private/DB/MissingColumnInformation.php b/lib/private/DB/MissingColumnInformation.php index f651546b4b3..919f8923a26 100644 --- a/lib/private/DB/MissingColumnInformation.php +++ b/lib/private/DB/MissingColumnInformation.php @@ -26,7 +26,7 @@ declare(strict_types=1); namespace OC\DB; class MissingColumnInformation { - private $listOfMissingColumns = []; + private array $listOfMissingColumns = []; public function addHintForMissingColumn(string $tableName, string $columnName): void { $this->listOfMissingColumns[] = [ diff --git a/lib/private/DB/MissingIndexInformation.php b/lib/private/DB/MissingIndexInformation.php index 74498668349..4fc3a52d3a4 100644 --- a/lib/private/DB/MissingIndexInformation.php +++ b/lib/private/DB/MissingIndexInformation.php @@ -27,16 +27,16 @@ declare(strict_types=1); namespace OC\DB; class MissingIndexInformation { - private $listOfMissingIndexes = []; + private array $listOfMissingIndices = []; - public function addHintForMissingSubject(string $tableName, string $indexName) { - $this->listOfMissingIndexes[] = [ + public function addHintForMissingIndex(string $tableName, string $indexName): void { + $this->listOfMissingIndices[] = [ 'tableName' => $tableName, 'indexName' => $indexName ]; } - public function getListOfMissingIndexes(): array { - return $this->listOfMissingIndexes; + public function getListOfMissingIndices(): array { + return $this->listOfMissingIndices; } } diff --git a/lib/private/DB/MissingPrimaryKeyInformation.php b/lib/private/DB/MissingPrimaryKeyInformation.php index f28c8cfb352..42e5584291c 100644 --- a/lib/private/DB/MissingPrimaryKeyInformation.php +++ b/lib/private/DB/MissingPrimaryKeyInformation.php @@ -26,9 +26,9 @@ declare(strict_types=1); namespace OC\DB; class MissingPrimaryKeyInformation { - private $listOfMissingPrimaryKeys = []; + private array $listOfMissingPrimaryKeys = []; - public function addHintForMissingSubject(string $tableName) { + public function addHintForMissingPrimaryKey(string $tableName): void { $this->listOfMissingPrimaryKeys[] = [ 'tableName' => $tableName, ]; diff --git a/lib/private/DB/MySQLMigrator.php b/lib/private/DB/MySQLMigrator.php deleted file mode 100644 index 0f8cbb309f3..00000000000 --- a/lib/private/DB/MySQLMigrator.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Robin Appelman <robin@icewind.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ -namespace OC\DB; - -use Doctrine\DBAL\Schema\Schema; - -class MySQLMigrator extends Migrator { - /** - * @param Schema $targetSchema - * @param \Doctrine\DBAL\Connection $connection - * @return \Doctrine\DBAL\Schema\SchemaDiff - */ - protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { - $platform = $connection->getDatabasePlatform(); - $platform->registerDoctrineTypeMapping('enum', 'string'); - $platform->registerDoctrineTypeMapping('bit', 'string'); - - $schemaDiff = parent::getDiff($targetSchema, $connection); - - // identifiers need to be quoted for mysql - foreach ($schemaDiff->changedTables as $tableDiff) { - $tableDiff->name = $this->connection->quoteIdentifier($tableDiff->name); - foreach ($tableDiff->changedColumns as $column) { - $column->oldColumnName = $this->connection->quoteIdentifier($column->oldColumnName); - } - } - - return $schemaDiff; - } -} diff --git a/lib/private/DB/OracleConnection.php b/lib/private/DB/OracleConnection.php index b7e040965ee..1112d5c450a 100644 --- a/lib/private/DB/OracleConnection.php +++ b/lib/private/DB/OracleConnection.php @@ -29,6 +29,8 @@ namespace OC\DB; class OracleConnection extends Connection { /** * Quote the keys of the array + * @param array<string, string> $data + * @return array<string, string> */ private function quoteKeys(array $data) { $return = []; diff --git a/lib/private/DB/OracleMigrator.php b/lib/private/DB/OracleMigrator.php index 18deb97ec26..5abab1a34e2 100644 --- a/lib/private/DB/OracleMigrator.php +++ b/lib/private/DB/OracleMigrator.php @@ -1,5 +1,8 @@ <?php + +declare(strict_types=1); /** + * @copyright Copyright (c) 2023, Joas Schilling <coding@schilljs.com> * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Christoph Wurst <christoph@winzerhof-wurst.at> @@ -29,176 +32,114 @@ namespace OC\DB; use Doctrine\DBAL\Exception; -use Doctrine\DBAL\Schema\Column; -use Doctrine\DBAL\Schema\ColumnDiff; -use Doctrine\DBAL\Schema\ForeignKeyConstraint; -use Doctrine\DBAL\Schema\Index; use Doctrine\DBAL\Schema\Schema; -use Doctrine\DBAL\Schema\Table; class OracleMigrator extends Migrator { /** - * Quote a column's name but changing the name requires recreating - * the column instance and copying over all properties. - * - * @param Column $column old column - * @return Column new column instance with new name - */ - protected function quoteColumn(Column $column) { - $newColumn = new Column( - $this->connection->quoteIdentifier($column->getName()), - $column->getType() - ); - $newColumn->setAutoincrement($column->getAutoincrement()); - $newColumn->setColumnDefinition($column->getColumnDefinition()); - $newColumn->setComment($column->getComment()); - $newColumn->setDefault($column->getDefault()); - $newColumn->setFixed($column->getFixed()); - $newColumn->setLength($column->getLength()); - $newColumn->setNotnull($column->getNotnull()); - $newColumn->setPrecision($column->getPrecision()); - $newColumn->setScale($column->getScale()); - $newColumn->setUnsigned($column->getUnsigned()); - $newColumn->setPlatformOptions($column->getPlatformOptions()); - $newColumn->setCustomSchemaOptions($column->getPlatformOptions()); - return $newColumn; - } - - /** - * Quote an index's name but changing the name requires recreating - * the index instance and copying over all properties. - * - * @param Index $index old index - * @return Index new index instance with new name - */ - protected function quoteIndex($index) { - return new Index( - //TODO migrate existing uppercase indexes, then $this->connection->quoteIdentifier($index->getName()), - $index->getName(), - array_map(function ($columnName) { - return $this->connection->quoteIdentifier($columnName); - }, $index->getColumns()), - $index->isUnique(), - $index->isPrimary(), - $index->getFlags(), - $index->getOptions() - ); - } - - /** - * Quote an ForeignKeyConstraint's name but changing the name requires recreating - * the ForeignKeyConstraint instance and copying over all properties. - * - * @param ForeignKeyConstraint $fkc old fkc - * @return ForeignKeyConstraint new fkc instance with new name - */ - protected function quoteForeignKeyConstraint($fkc) { - return new ForeignKeyConstraint( - array_map(function ($columnName) { - return $this->connection->quoteIdentifier($columnName); - }, $fkc->getLocalColumns()), - $this->connection->quoteIdentifier($fkc->getForeignTableName()), - array_map(function ($columnName) { - return $this->connection->quoteIdentifier($columnName); - }, $fkc->getForeignColumns()), - $fkc->getName(), - $fkc->getOptions() - ); - } - - /** * @param Schema $targetSchema * @param \Doctrine\DBAL\Connection $connection * @return \Doctrine\DBAL\Schema\SchemaDiff * @throws Exception */ - protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { - $schemaDiff = parent::getDiff($targetSchema, $connection); - + protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection): \Doctrine\DBAL\Schema\SchemaDiff { // oracle forces us to quote the identifiers - $schemaDiff->newTables = array_map(function (Table $table) { - return new Table( + $quotedSchema = new Schema(); + foreach ($targetSchema->getTables() as $table) { + $quotedTable = $quotedSchema->createTable( $this->connection->quoteIdentifier($table->getName()), - array_map(function (Column $column) { - return $this->quoteColumn($column); - }, $table->getColumns()), - array_map(function (Index $index) { - return $this->quoteIndex($index); - }, $table->getIndexes()), - [], - array_map(function (ForeignKeyConstraint $fck) { - return $this->quoteForeignKeyConstraint($fck); - }, $table->getForeignKeys()), - $table->getOptions() ); - }, $schemaDiff->newTables); - $schemaDiff->removedTables = array_map(function (Table $table) { - return new Table( - $this->connection->quoteIdentifier($table->getName()), - $table->getColumns(), - $table->getIndexes(), - [], - $table->getForeignKeys(), - $table->getOptions() - ); - }, $schemaDiff->removedTables); - - foreach ($schemaDiff->changedTables as $tableDiff) { - $tableDiff->name = $this->connection->quoteIdentifier($tableDiff->name); - - $tableDiff->addedColumns = array_map(function (Column $column) { - return $this->quoteColumn($column); - }, $tableDiff->addedColumns); - - foreach ($tableDiff->changedColumns as $column) { - $column->oldColumnName = $this->connection->quoteIdentifier($column->oldColumnName); - // auto increment is not relevant for oracle and can anyhow not be applied on change - $column->changedProperties = array_diff($column->changedProperties, ['autoincrement', 'unsigned']); + foreach ($table->getColumns() as $column) { + $newColumn = $quotedTable->addColumn( + $this->connection->quoteIdentifier($column->getName()), + $column->getType()->getTypeRegistry()->lookupName($column->getType()), + ); + $newColumn->setAutoincrement($column->getAutoincrement()); + $newColumn->setColumnDefinition($column->getColumnDefinition()); + $newColumn->setComment($column->getComment()); + $newColumn->setDefault($column->getDefault()); + $newColumn->setFixed($column->getFixed()); + $newColumn->setLength($column->getLength()); + $newColumn->setNotnull($column->getNotnull()); + $newColumn->setPrecision($column->getPrecision()); + $newColumn->setScale($column->getScale()); + $newColumn->setUnsigned($column->getUnsigned()); + $newColumn->setPlatformOptions($column->getPlatformOptions()); } - // remove columns that no longer have changed (because autoincrement and unsigned are not supported) - $tableDiff->changedColumns = array_filter($tableDiff->changedColumns, function (ColumnDiff $column) { - return count($column->changedProperties) > 0; - }); - - $tableDiff->removedColumns = array_map(function (Column $column) { - return $this->quoteColumn($column); - }, $tableDiff->removedColumns); - - $tableDiff->renamedColumns = array_map(function (Column $column) { - return $this->quoteColumn($column); - }, $tableDiff->renamedColumns); - - $tableDiff->addedIndexes = array_map(function (Index $index) { - return $this->quoteIndex($index); - }, $tableDiff->addedIndexes); - $tableDiff->changedIndexes = array_map(function (Index $index) { - return $this->quoteIndex($index); - }, $tableDiff->changedIndexes); - - $tableDiff->removedIndexes = array_map(function (Index $index) { - return $this->quoteIndex($index); - }, $tableDiff->removedIndexes); + foreach ($table->getIndexes() as $index) { + if ($index->isPrimary()) { + $quotedTable->setPrimaryKey( + array_map(function ($columnName) { + return $this->connection->quoteIdentifier($columnName); + }, $index->getColumns()), + //TODO migrate existing uppercase indexes, then $this->connection->quoteIdentifier($index->getName()), + $index->getName(), + ); + } elseif ($index->isUnique()) { + $quotedTable->addUniqueIndex( + array_map(function ($columnName) { + return $this->connection->quoteIdentifier($columnName); + }, $index->getColumns()), + //TODO migrate existing uppercase indexes, then $this->connection->quoteIdentifier($index->getName()), + $index->getName(), + $index->getOptions(), + ); + } else { + $quotedTable->addIndex( + array_map(function ($columnName) { + return $this->connection->quoteIdentifier($columnName); + }, $index->getColumns()), + //TODO migrate existing uppercase indexes, then $this->connection->quoteIdentifier($index->getName()), + $index->getName(), + $index->getFlags(), + $index->getOptions(), + ); + } + } - $tableDiff->renamedIndexes = array_map(function (Index $index) { - return $this->quoteIndex($index); - }, $tableDiff->renamedIndexes); + foreach ($table->getUniqueConstraints() as $constraint) { + $quotedTable->addUniqueConstraint( + array_map(function ($columnName) { + return $this->connection->quoteIdentifier($columnName); + }, $constraint->getColumns()), + $this->connection->quoteIdentifier($constraint->getName()), + $constraint->getFlags(), + $constraint->getOptions(), + ); + } - $tableDiff->addedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) { - return $this->quoteForeignKeyConstraint($fkc); - }, $tableDiff->addedForeignKeys); + foreach ($table->getForeignKeys() as $foreignKey) { + $quotedTable->addForeignKeyConstraint( + $this->connection->quoteIdentifier($foreignKey->getForeignTableName()), + array_map(function ($columnName) { + return $this->connection->quoteIdentifier($columnName); + }, $foreignKey->getLocalColumns()), + array_map(function ($columnName) { + return $this->connection->quoteIdentifier($columnName); + }, $foreignKey->getForeignColumns()), + $foreignKey->getOptions(), + $this->connection->quoteIdentifier($foreignKey->getName()), + ); + } - $tableDiff->changedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) { - return $this->quoteForeignKeyConstraint($fkc); - }, $tableDiff->changedForeignKeys); + foreach ($table->getOptions() as $option => $value) { + $quotedTable->addOption( + $option, + $value, + ); + } + } - $tableDiff->removedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) { - return $this->quoteForeignKeyConstraint($fkc); - }, $tableDiff->removedForeignKeys); + foreach ($targetSchema->getSequences() as $sequence) { + $quotedSchema->createSequence( + $sequence->getName(), + $sequence->getAllocationSize(), + $sequence->getInitialValue(), + ); } - return $schemaDiff; + return parent::getDiff($quotedSchema, $connection); } /** @@ -206,7 +147,7 @@ class OracleMigrator extends Migrator { * @return string */ protected function convertStatementToScript($statement) { - if (substr($statement, -1) === ';') { + if (str_ends_with($statement, ';')) { return $statement . PHP_EOL . '/' . PHP_EOL; } $script = $statement . ';'; diff --git a/lib/private/DB/PostgreSqlMigrator.php b/lib/private/DB/PostgreSqlMigrator.php deleted file mode 100644 index 92a0842e1a7..00000000000 --- a/lib/private/DB/PostgreSqlMigrator.php +++ /dev/null @@ -1,55 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ -namespace OC\DB; - -use Doctrine\DBAL\Schema\Schema; - -class PostgreSqlMigrator extends Migrator { - /** - * @param Schema $targetSchema - * @param \Doctrine\DBAL\Connection $connection - * @return \Doctrine\DBAL\Schema\SchemaDiff - */ - protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { - $schemaDiff = parent::getDiff($targetSchema, $connection); - - foreach ($schemaDiff->changedTables as $tableDiff) { - // fix default value in brackets - pg 9.4 is returning a negative default value in () - // see https://github.com/doctrine/dbal/issues/2427 - foreach ($tableDiff->changedColumns as $column) { - $column->changedProperties = array_filter($column->changedProperties, function ($changedProperties) use ($column) { - if ($changedProperties !== 'default') { - return true; - } - $fromDefault = $column->fromColumn->getDefault(); - $toDefault = $column->column->getDefault(); - $fromDefault = trim((string) $fromDefault, '()'); - - // by intention usage of != - return $fromDefault != $toDefault; - }); - } - } - - return $schemaDiff; - } -} diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php index ae4f19f5d18..ad45f77e5ea 100644 --- a/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php +++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php @@ -117,8 +117,8 @@ class ExpressionBuilder implements IExpressionBuilder { * @return string */ public function comparison($x, string $operator, $y, $type = null): string { - $x = $this->helper->quoteColumnName($x); - $y = $this->helper->quoteColumnName($y); + $x = $this->prepareColumn($x, $type); + $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->comparison($x, $operator, $y); } @@ -140,8 +140,8 @@ class ExpressionBuilder implements IExpressionBuilder { * @return string */ public function eq($x, $y, $type = null): string { - $x = $this->helper->quoteColumnName($x); - $y = $this->helper->quoteColumnName($y); + $x = $this->prepareColumn($x, $type); + $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->eq($x, $y); } @@ -162,8 +162,8 @@ class ExpressionBuilder implements IExpressionBuilder { * @return string */ public function neq($x, $y, $type = null): string { - $x = $this->helper->quoteColumnName($x); - $y = $this->helper->quoteColumnName($y); + $x = $this->prepareColumn($x, $type); + $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->neq($x, $y); } @@ -184,8 +184,8 @@ class ExpressionBuilder implements IExpressionBuilder { * @return string */ public function lt($x, $y, $type = null): string { - $x = $this->helper->quoteColumnName($x); - $y = $this->helper->quoteColumnName($y); + $x = $this->prepareColumn($x, $type); + $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->lt($x, $y); } @@ -206,8 +206,8 @@ class ExpressionBuilder implements IExpressionBuilder { * @return string */ public function lte($x, $y, $type = null): string { - $x = $this->helper->quoteColumnName($x); - $y = $this->helper->quoteColumnName($y); + $x = $this->prepareColumn($x, $type); + $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->lte($x, $y); } @@ -228,8 +228,8 @@ class ExpressionBuilder implements IExpressionBuilder { * @return string */ public function gt($x, $y, $type = null): string { - $x = $this->helper->quoteColumnName($x); - $y = $this->helper->quoteColumnName($y); + $x = $this->prepareColumn($x, $type); + $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->gt($x, $y); } @@ -250,8 +250,8 @@ class ExpressionBuilder implements IExpressionBuilder { * @return string */ public function gte($x, $y, $type = null): string { - $x = $this->helper->quoteColumnName($x); - $y = $this->helper->quoteColumnName($y); + $x = $this->prepareColumn($x, $type); + $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->gte($x, $y); } @@ -435,4 +435,13 @@ class ExpressionBuilder implements IExpressionBuilder { $this->helper->quoteColumnName($column) ); } + + /** + * @param mixed $column + * @param mixed|null $type + * @return array|IQueryFunction|string + */ + protected function prepareColumn($column, $type) { + return $this->helper->quoteColumnNames($column); + } } diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php index caeb8009885..8184e369317 100644 --- a/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php +++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php @@ -39,80 +39,9 @@ class OCIExpressionBuilder extends ExpressionBuilder { protected function prepareColumn($column, $type) { if ($type === IQueryBuilder::PARAM_STR && !is_array($column) && !($column instanceof IParameter) && !($column instanceof ILiteral)) { $column = $this->castColumn($column, $type); - } else { - $column = $this->helper->quoteColumnNames($column); } - return $column; - } - - /** - * @inheritdoc - */ - public function comparison($x, string $operator, $y, $type = null): string { - $x = $this->prepareColumn($x, $type); - $y = $this->prepareColumn($y, $type); - - return $this->expressionBuilder->comparison($x, $operator, $y); - } - - /** - * @inheritdoc - */ - public function eq($x, $y, $type = null): string { - $x = $this->prepareColumn($x, $type); - $y = $this->prepareColumn($y, $type); - - return $this->expressionBuilder->eq($x, $y); - } - - /** - * @inheritdoc - */ - public function neq($x, $y, $type = null): string { - $x = $this->prepareColumn($x, $type); - $y = $this->prepareColumn($y, $type); - - return $this->expressionBuilder->neq($x, $y); - } - - /** - * @inheritdoc - */ - public function lt($x, $y, $type = null): string { - $x = $this->prepareColumn($x, $type); - $y = $this->prepareColumn($y, $type); - - return $this->expressionBuilder->lt($x, $y); - } - - /** - * @inheritdoc - */ - public function lte($x, $y, $type = null): string { - $x = $this->prepareColumn($x, $type); - $y = $this->prepareColumn($y, $type); - - return $this->expressionBuilder->lte($x, $y); - } - - /** - * @inheritdoc - */ - public function gt($x, $y, $type = null): string { - $x = $this->prepareColumn($x, $type); - $y = $this->prepareColumn($y, $type); - - return $this->expressionBuilder->gt($x, $y); - } - - /** - * @inheritdoc - */ - public function gte($x, $y, $type = null): string { - $x = $this->prepareColumn($x, $type); - $y = $this->prepareColumn($y, $type); - return $this->expressionBuilder->gte($x, $y); + return parent::prepareColumn($column, $type); } /** diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php index 289aa09b003..4e2797761d6 100644 --- a/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php +++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php @@ -23,6 +23,12 @@ */ namespace OC\DB\QueryBuilder\ExpressionBuilder; +use OC\DB\QueryBuilder\QueryFunction; +use OCP\DB\QueryBuilder\ILiteral; +use OCP\DB\QueryBuilder\IParameter; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\DB\QueryBuilder\IQueryFunction; + class SqliteExpressionBuilder extends ExpressionBuilder { /** * @inheritdoc @@ -34,4 +40,33 @@ class SqliteExpressionBuilder extends ExpressionBuilder { public function iLike($x, $y, $type = null): string { return $this->like($this->functionBuilder->lower($x), $this->functionBuilder->lower($y), $type); } + + /** + * @param mixed $column + * @param mixed|null $type + * @return array|IQueryFunction|string + */ + protected function prepareColumn($column, $type) { + if ($type === IQueryBuilder::PARAM_DATE && !is_array($column) && !($column instanceof IParameter) && !($column instanceof ILiteral)) { + return $this->castColumn($column, $type); + } + + return parent::prepareColumn($column, $type); + } + + /** + * Returns a IQueryFunction that casts the column to the given type + * + * @param string $column + * @param mixed $type One of IQueryBuilder::PARAM_* + * @return IQueryFunction + */ + public function castColumn($column, $type): IQueryFunction { + if ($type === IQueryBuilder::PARAM_DATE) { + $column = $this->helper->quoteColumnName($column); + return new QueryFunction('DATETIME(' . $column . ')'); + } + + return parent::castColumn($column, $type); + } } diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php index 2f97b4a146c..c2818911ccf 100644 --- a/lib/private/DB/QueryBuilder/QueryBuilder.php +++ b/lib/private/DB/QueryBuilder/QueryBuilder.php @@ -866,7 +866,7 @@ class QueryBuilder implements IQueryBuilder { public function where(...$predicates) { if ($this->getQueryPart('where') !== null && $this->systemConfig->getValue('debug', false)) { // Only logging a warning, not throwing for now. - $e = new QueryException('Using where() on non-empty WHERE part, please verify it is intentional to not call whereAnd() or whereOr() instead. Otherwise consider creating a new query builder object or call resetQueryPart(\'where\') first.'); + $e = new QueryException('Using where() on non-empty WHERE part, please verify it is intentional to not call andWhere() or orWhere() instead. Otherwise consider creating a new query builder object or call resetQueryPart(\'where\') first.'); $this->logger->warning($e->getMessage(), ['exception' => $e]); } @@ -1202,7 +1202,7 @@ class QueryBuilder implements IQueryBuilder { * @link http://www.zetacomponents.org * * @param mixed $value - * @param mixed $type + * @param IQueryBuilder::PARAM_* $type * @param string $placeHolder The name to bind with. The string must start with a colon ':'. * * @return IParameter the placeholder name used. @@ -1229,7 +1229,7 @@ class QueryBuilder implements IQueryBuilder { * </code> * * @param mixed $value - * @param integer $type + * @param IQueryBuilder::PARAM_* $type * * @return IParameter */ diff --git a/lib/private/DB/SQLiteMigrator.php b/lib/private/DB/SQLiteMigrator.php index cbb39070a48..e0102e105b2 100644 --- a/lib/private/DB/SQLiteMigrator.php +++ b/lib/private/DB/SQLiteMigrator.php @@ -24,8 +24,6 @@ namespace OC\DB; use Doctrine\DBAL\Schema\Schema; -use Doctrine\DBAL\Types\BigIntType; -use Doctrine\DBAL\Types\Type; class SQLiteMigrator extends Migrator { /** @@ -34,21 +32,12 @@ class SQLiteMigrator extends Migrator { * @return \Doctrine\DBAL\Schema\SchemaDiff */ protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { - $platform = $connection->getDatabasePlatform(); - $platform->registerDoctrineTypeMapping('tinyint unsigned', 'integer'); - $platform->registerDoctrineTypeMapping('smallint unsigned', 'integer'); - $platform->registerDoctrineTypeMapping('varchar ', 'string'); - foreach ($targetSchema->getTables() as $table) { foreach ($table->getColumns() as $column) { // column comments are not supported on SQLite if ($column->getComment() !== null) { $column->setComment(null); } - // with sqlite autoincrement columns is of type integer - if ($column->getType() instanceof BigIntType && $column->getAutoincrement()) { - $column->setType(Type::getType('integer')); - } } } diff --git a/lib/private/DB/SetTransactionIsolationLevel.php b/lib/private/DB/SetTransactionIsolationLevel.php index b067edde441..9d9323664c8 100644 --- a/lib/private/DB/SetTransactionIsolationLevel.php +++ b/lib/private/DB/SetTransactionIsolationLevel.php @@ -26,8 +26,10 @@ declare(strict_types=1); namespace OC\DB; use Doctrine\Common\EventSubscriber; +use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection; use Doctrine\DBAL\Event\ConnectionEventArgs; use Doctrine\DBAL\Events; +use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\TransactionIsolationLevel; class SetTransactionIsolationLevel implements EventSubscriber { @@ -36,7 +38,13 @@ class SetTransactionIsolationLevel implements EventSubscriber { * @return void */ public function postConnect(ConnectionEventArgs $args) { - $args->getConnection()->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED); + $connection = $args->getConnection(); + if ($connection instanceof PrimaryReadReplicaConnection && $connection->isConnectedToPrimary()) { + $connection->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED); + if ($connection->getDatabasePlatform() instanceof MySQLPlatform) { + $connection->executeStatement('SET SESSION AUTOCOMMIT=1'); + } + } } public function getSubscribedEvents() { diff --git a/lib/private/Dashboard/Manager.php b/lib/private/Dashboard/Manager.php index 18a66499167..25a2df5d9da 100644 --- a/lib/private/Dashboard/Manager.php +++ b/lib/private/Dashboard/Manager.php @@ -33,15 +33,15 @@ use OCP\Dashboard\IManager; use OCP\Dashboard\IWidget; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; -use Throwable; use Psr\Log\LoggerInterface; +use Throwable; class Manager implements IManager { /** @var array */ private $lazyWidgets = []; - /** @var IWidget[] */ - private $widgets = []; + /** @var array<string, IWidget> */ + private array $widgets = []; private ContainerInterface $serverContainer; private ?IAppManager $appManager = null; @@ -115,7 +115,7 @@ class Manager implements IManager { $endTime = microtime(true); $duration = $endTime - $startTime; if ($duration > 1) { - \OC::$server->get(LoggerInterface::class)->error( + \OC::$server->get(LoggerInterface::class)->info( 'Dashboard widget {widget} took {duration} seconds to load.', [ 'widget' => $widget->getId(), @@ -134,6 +134,9 @@ class Manager implements IManager { $this->lazyWidgets = []; } + /** + * @return array<string, IWidget> + */ public function getWidgets(): array { $this->loadLazyPanels(); return $this->widgets; diff --git a/lib/private/DateTimeFormatter.php b/lib/private/DateTimeFormatter.php index 1c8b4f6d3ab..57c4833a4e3 100644 --- a/lib/private/DateTimeFormatter.php +++ b/lib/private/DateTimeFormatter.php @@ -125,7 +125,7 @@ class DateTimeFormatter implements \OCP\IDateTimeFormatter { * @return string Formatted relative date string */ public function formatDateRelativeDay($timestamp, $format = 'long', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null) { - if (substr($format, -1) !== '*' && substr($format, -1) !== '*') { + if (!str_ends_with($format, '^') && !str_ends_with($format, '*')) { $format .= '^'; } @@ -289,7 +289,7 @@ class DateTimeFormatter implements \OCP\IDateTimeFormatter { * @return string Formatted relative date and time string */ public function formatDateTimeRelativeDay($timestamp, $formatDate = 'long', $formatTime = 'medium', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null) { - if (substr($formatDate, -1) !== '^' && substr($formatDate, -1) !== '*') { + if (!str_ends_with($formatDate, '^') && !str_ends_with($formatDate, '*')) { $formatDate .= '^'; } diff --git a/lib/private/DirectEditing/Manager.php b/lib/private/DirectEditing/Manager.php index 2dd2abe5408..da4811589da 100644 --- a/lib/private/DirectEditing/Manager.php +++ b/lib/private/DirectEditing/Manager.php @@ -25,8 +25,9 @@ */ namespace OC\DirectEditing; -use Doctrine\DBAL\FetchMode; +use \OCP\DirectEditing\IManager; use \OCP\Files\Folder; +use Doctrine\DBAL\FetchMode; use OCP\AppFramework\Http\NotFoundResponse; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\TemplateResponse; @@ -34,7 +35,6 @@ use OCP\Constants; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DirectEditing\ACreateFromTemplate; use OCP\DirectEditing\IEditor; -use \OCP\DirectEditing\IManager; use OCP\DirectEditing\IToken; use OCP\Encryption\IManager as EncryptionManager; use OCP\Files\File; @@ -310,11 +310,11 @@ class Manager implements IManager { if ($filePath !== null) { return $userFolder->get($filePath); } - $files = $userFolder->getById($fileId); - if (count($files) === 0) { + $file = $userFolder->getFirstNodeById($fileId); + if (!$file) { throw new NotFoundException('File nound found by id ' . $fileId); } - return $files[0]; + return $file; } public function isEnabled(): bool { diff --git a/lib/private/Encryption/DecryptAll.php b/lib/private/Encryption/DecryptAll.php index 7bf4ce62d28..98ea35c62e0 100644 --- a/lib/private/Encryption/DecryptAll.php +++ b/lib/private/Encryption/DecryptAll.php @@ -31,6 +31,7 @@ namespace OC\Encryption; use OC\Encryption\Exceptions\DecryptionFailedException; use OC\Files\View; use OCP\Encryption\IEncryptionModule; +use OCP\Encryption\IManager; use OCP\IUserManager; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; @@ -43,31 +44,14 @@ class DecryptAll { /** @var InputInterface */ protected $input; - /** @var Manager */ - protected $encryptionManager; - - /** @var IUserManager */ - protected $userManager; - - /** @var View */ - protected $rootView; - /** @var array files which couldn't be decrypted */ protected $failed; - /** - * @param Manager $encryptionManager - * @param IUserManager $userManager - * @param View $rootView - */ public function __construct( - Manager $encryptionManager, - IUserManager $userManager, - View $rootView + protected IManager $encryptionManager, + protected IUserManager $userManager, + protected View $rootView ) { - $this->encryptionManager = $encryptionManager; - $this->userManager = $userManager; - $this->rootView = $rootView; $this->failed = []; } diff --git a/lib/private/Encryption/EncryptionWrapper.php b/lib/private/Encryption/EncryptionWrapper.php index 37264e81823..a6bc72ef18f 100644 --- a/lib/private/Encryption/EncryptionWrapper.php +++ b/lib/private/Encryption/EncryptionWrapper.php @@ -29,7 +29,8 @@ use OC\Files\Storage\Wrapper\Encryption; use OC\Files\View; use OC\Memcache\ArrayCache; use OCP\Files\Mount\IMountPoint; -use OCP\Files\Storage; +use OCP\Files\Storage\IDisableEncryptionStorage; +use OCP\Files\Storage\IStorage; use Psr\Log\LoggerInterface; /** @@ -52,8 +53,8 @@ class EncryptionWrapper { * EncryptionWrapper constructor. */ public function __construct(ArrayCache $arrayCache, - Manager $manager, - LoggerInterface $logger + Manager $manager, + LoggerInterface $logger ) { $this->arrayCache = $arrayCache; $this->manager = $manager; @@ -64,18 +65,19 @@ class EncryptionWrapper { * Wraps the given storage when it is not a shared storage * * @param string $mountPoint - * @param Storage $storage + * @param IStorage $storage * @param IMountPoint $mount - * @return Encryption|Storage + * @param bool $force apply the wrapper even if the storage normally has encryption disabled, helpful for repair steps + * @return Encryption|IStorage */ - public function wrapStorage($mountPoint, Storage $storage, IMountPoint $mount) { + public function wrapStorage(string $mountPoint, IStorage $storage, IMountPoint $mount, bool $force = false) { $parameters = [ 'storage' => $storage, 'mountPoint' => $mountPoint, 'mount' => $mount ]; - if (!$storage->instanceOfStorage(Storage\IDisableEncryptionStorage::class) && $mountPoint !== '/') { + if ($force || (!$storage->instanceOfStorage(IDisableEncryptionStorage::class) && $mountPoint !== '/')) { $user = \OC::$server->getUserSession()->getUser(); $mountManager = Filesystem::getMountManager(); $uid = $user ? $user->getUID() : null; diff --git a/lib/private/Encryption/File.php b/lib/private/Encryption/File.php index daab097ce7c..f2b1de23234 100644 --- a/lib/private/Encryption/File.php +++ b/lib/private/Encryption/File.php @@ -27,9 +27,9 @@ */ namespace OC\Encryption; -use OCP\Cache\CappedMemoryCache; use OCA\Files_External\Service\GlobalStoragesService; use OCP\App\IAppManager; +use OCP\Cache\CappedMemoryCache; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Share\IManager; @@ -47,8 +47,8 @@ class File implements \OCP\Encryption\IFile { private ?IAppManager $appManager = null; public function __construct(Util $util, - IRootFolder $rootFolder, - IManager $shareManager) { + IRootFolder $rootFolder, + IManager $shareManager) { $this->util = $util; $this->cache = new CappedMemoryCache(); $this->rootFolder = $rootFolder; diff --git a/lib/private/Encryption/HookManager.php b/lib/private/Encryption/HookManager.php index 5081bcccf94..afcb7ce3763 100644 --- a/lib/private/Encryption/HookManager.php +++ b/lib/private/Encryption/HookManager.php @@ -24,8 +24,8 @@ namespace OC\Encryption; use OC\Files\Filesystem; -use OC\Files\View; use OC\Files\SetupManager; +use OC\Files\View; use Psr\Log\LoggerInterface; class HookManager { diff --git a/lib/private/Encryption/Keys/Storage.php b/lib/private/Encryption/Keys/Storage.php index e88c305eeec..cc7ed2f1f7b 100644 --- a/lib/private/Encryption/Keys/Storage.php +++ b/lib/private/Encryption/Keys/Storage.php @@ -98,14 +98,14 @@ class Storage implements IStorage { */ public function getFileKey($path, $keyId, $encryptionModuleId) { $realFile = $this->util->stripPartialFileExtension($path); - $keyDir = $this->getFileKeyDir($encryptionModuleId, $realFile); + $keyDir = $this->util->getFileKeyDir($encryptionModuleId, $realFile); $key = $this->getKey($keyDir . $keyId)['key']; if ($key === '' && $realFile !== $path) { // Check if the part file has keys and use them, if no normal keys // exist. This is required to fix copyBetweenStorage() when we // rename a .part file over storage borders. - $keyDir = $this->getFileKeyDir($encryptionModuleId, $path); + $keyDir = $this->util->getFileKeyDir($encryptionModuleId, $path); $key = $this->getKey($keyDir . $keyId)['key']; } @@ -135,7 +135,7 @@ class Storage implements IStorage { * @inheritdoc */ public function setFileKey($path, $keyId, $key, $encryptionModuleId) { - $keyDir = $this->getFileKeyDir($encryptionModuleId, $path); + $keyDir = $this->util->getFileKeyDir($encryptionModuleId, $path); return $this->setKey($keyDir . $keyId, [ 'key' => base64_encode($key), ]); @@ -177,7 +177,7 @@ class Storage implements IStorage { * @inheritdoc */ public function deleteFileKey($path, $keyId, $encryptionModuleId) { - $keyDir = $this->getFileKeyDir($encryptionModuleId, $path); + $keyDir = $this->util->getFileKeyDir($encryptionModuleId, $path); return !$this->view->file_exists($keyDir . $keyId) || $this->view->unlink($keyDir . $keyId); } @@ -185,7 +185,7 @@ class Storage implements IStorage { * @inheritdoc */ public function deleteAllFileKeys($path) { - $keyDir = $this->getFileKeyDir('', $path); + $keyDir = $this->util->getFileKeyDir('', $path); return !$this->view->file_exists($keyDir) || $this->view->deleteAll($keyDir); } @@ -356,26 +356,6 @@ class Storage implements IStorage { } /** - * get path to key folder for a given file - * - * @param string $encryptionModuleId - * @param string $path path to the file, relative to data/ - * @return string - */ - private function getFileKeyDir($encryptionModuleId, $path) { - [$owner, $filename] = $this->util->getUidAndFilename($path); - - // in case of system wide mount points the keys are stored directly in the data directory - if ($this->util->isSystemWideMountPoint($filename, $owner)) { - $keyPath = $this->root_dir . '/' . $this->keys_base_dir . $filename . '/'; - } else { - $keyPath = $this->root_dir . '/' . $owner . $this->keys_base_dir . $filename . '/'; - } - - return Filesystem::normalizePath($keyPath . $encryptionModuleId . '/', false); - } - - /** * move keys if a file was renamed * * @param string $source diff --git a/lib/private/Encryption/Manager.php b/lib/private/Encryption/Manager.php index f751bd94b28..f48d259eea0 100644 --- a/lib/private/Encryption/Manager.php +++ b/lib/private/Encryption/Manager.php @@ -32,39 +32,24 @@ use OC\Memcache\ArrayCache; use OC\ServiceUnavailableException; use OCP\Encryption\IEncryptionModule; use OCP\Encryption\IManager; +use OCP\Files\Mount\IMountPoint; +use OCP\Files\Storage\IStorage; use OCP\IConfig; use OCP\IL10N; use Psr\Log\LoggerInterface; class Manager implements IManager { - /** @var array */ - protected $encryptionModules; - - /** @var IConfig */ - protected $config; - - protected LoggerInterface $logger; - - /** @var Il10n */ - protected $l; - - /** @var View */ - protected $rootView; - - /** @var Util */ - protected $util; - - /** @var ArrayCache */ - protected $arrayCache; - - public function __construct(IConfig $config, LoggerInterface $logger, IL10N $l10n, View $rootView, Util $util, ArrayCache $arrayCache) { + protected array $encryptionModules; + + public function __construct( + protected IConfig $config, + protected LoggerInterface $logger, + protected IL10N $l, + protected View $rootView, + protected Util $util, + protected ArrayCache $arrayCache, + ) { $this->encryptionModules = []; - $this->config = $config; - $this->logger = $logger; - $this->l = $l10n; - $this->rootView = $rootView; - $this->util = $util; - $this->arrayCache = $arrayCache; } /** @@ -234,6 +219,11 @@ class Manager implements IManager { } } + public function forceWrapStorage(IMountPoint $mountPoint, IStorage $storage) { + $encryptionWrapper = new EncryptionWrapper($this->arrayCache, $this, $this->logger); + return $encryptionWrapper->wrapStorage($mountPoint->getMountPoint(), $storage, $mountPoint, true); + } + /** * check if key storage is ready diff --git a/lib/private/Encryption/Update.php b/lib/private/Encryption/Update.php index 2e390177baf..1d9ec8510d0 100644 --- a/lib/private/Encryption/Update.php +++ b/lib/private/Encryption/Update.php @@ -62,14 +62,14 @@ class Update { * @param string $uid */ public function __construct( - View $view, - Util $util, - Mount\Manager $mountManager, - Manager $encryptionManager, - File $file, - LoggerInterface $logger, - $uid - ) { + View $view, + Util $util, + Mount\Manager $mountManager, + Manager $encryptionManager, + File $file, + LoggerInterface $logger, + $uid + ) { $this->view = $view; $this->util = $util; $this->mountManager = $mountManager; diff --git a/lib/private/Encryption/Util.php b/lib/private/Encryption/Util.php index a468908ffc8..bd27d71c40e 100644 --- a/lib/private/Encryption/Util.php +++ b/lib/private/Encryption/Util.php @@ -357,4 +357,53 @@ class Util { public function getKeyStorageRoot(): string { return $this->config->getAppValue('core', 'encryption_key_storage_root', ''); } + + /** + * parse raw header to array + * + * @param string $rawHeader + * @return array + */ + public function parseRawHeader(string $rawHeader) { + $result = []; + if (str_starts_with($rawHeader, Util::HEADER_START)) { + $header = $rawHeader; + $endAt = strpos($header, Util::HEADER_END); + if ($endAt !== false) { + $header = substr($header, 0, $endAt + strlen(Util::HEADER_END)); + + // +1 to not start with an ':' which would result in empty element at the beginning + $exploded = explode(':', substr($header, strlen(Util::HEADER_START) + 1)); + + $element = array_shift($exploded); + while ($element !== Util::HEADER_END && $element !== null) { + $result[$element] = array_shift($exploded); + $element = array_shift($exploded); + } + } + } + + return $result; + } + + /** + * get path to key folder for a given file + * + * @param string $encryptionModuleId + * @param string $path path to the file, relative to data/ + * @return string + */ + public function getFileKeyDir(string $encryptionModuleId, string $path): string { + [$owner, $filename] = $this->getUidAndFilename($path); + $root = $this->getKeyStorageRoot(); + + // in case of system-wide mount points the keys are stored directly in the data directory + if ($this->isSystemWideMountPoint($filename, $owner)) { + $keyPath = $root . '/' . '/files_encryption/keys' . $filename . '/'; + } else { + $keyPath = $root . '/' . $owner . '/files_encryption/keys' . $filename . '/'; + } + + return Filesystem::normalizePath($keyPath . $encryptionModuleId . '/', false); + } } diff --git a/lib/private/EventDispatcher/EventDispatcher.php b/lib/private/EventDispatcher/EventDispatcher.php index 88c6b2cf32c..39bf2a6afa9 100644 --- a/lib/private/EventDispatcher/EventDispatcher.php +++ b/lib/private/EventDispatcher/EventDispatcher.php @@ -27,35 +27,23 @@ declare(strict_types=1); */ namespace OC\EventDispatcher; -use OC\Log; -use Psr\Log\LoggerInterface; -use function get_class; use OC\Broadcast\Events\BroadcastEvent; +use OC\Log; use OCP\Broadcast\Events\IBroadcastEvent; use OCP\EventDispatcher\ABroadcastedEvent; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventDispatcher; -use OCP\IContainer; use OCP\IServerContainer; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyDispatcher; +use function get_class; class EventDispatcher implements IEventDispatcher { - /** @var SymfonyDispatcher */ - private $dispatcher; - - /** @var IContainer */ - private $container; - - /** @var LoggerInterface */ - private $logger; - - public function __construct(SymfonyDispatcher $dispatcher, - IServerContainer $container, - LoggerInterface $logger) { - $this->dispatcher = $dispatcher; - $this->container = $container; - $this->logger = $logger; - + public function __construct( + private SymfonyDispatcher $dispatcher, + private IServerContainer $container, + private LoggerInterface $logger, + ) { // inject the event dispatcher into the logger // this is done here because there is a cyclic dependency between the event dispatcher and logger if ($this->logger instanceof Log || $this->logger instanceof Log\PsrLoggerAdapter) { @@ -64,19 +52,19 @@ class EventDispatcher implements IEventDispatcher { } public function addListener(string $eventName, - callable $listener, - int $priority = 0): void { + callable $listener, + int $priority = 0): void { $this->dispatcher->addListener($eventName, $listener, $priority); } public function removeListener(string $eventName, - callable $listener): void { + callable $listener): void { $this->dispatcher->removeListener($eventName, $listener); } public function addServiceListener(string $eventName, - string $className, - int $priority = 0): void { + string $className, + int $priority = 0): void { $listener = new ServiceEventListener( $this->container, $className, @@ -86,11 +74,15 @@ class EventDispatcher implements IEventDispatcher { $this->addListener($eventName, $listener, $priority); } + public function hasListeners(string $eventName): bool { + return $this->dispatcher->hasListeners($eventName); + } + /** * @deprecated */ public function dispatch(string $eventName, - Event $event): void { + Event $event): void { $this->dispatcher->dispatch($event, $eventName); if ($event instanceof ABroadcastedEvent && !$event->isPropagationStopped()) { diff --git a/lib/private/EventDispatcher/ServiceEventListener.php b/lib/private/EventDispatcher/ServiceEventListener.php index 21cdf7f8cc2..a7bbbcd82aa 100644 --- a/lib/private/EventDispatcher/ServiceEventListener.php +++ b/lib/private/EventDispatcher/ServiceEventListener.php @@ -54,8 +54,8 @@ final class ServiceEventListener { private $service; public function __construct(IServerContainer $container, - string $class, - LoggerInterface $logger) { + string $class, + LoggerInterface $logger) { $this->container = $container; $this->class = $class; $this->logger = $logger; diff --git a/lib/private/Federation/CloudFederationProviderManager.php b/lib/private/Federation/CloudFederationProviderManager.php index b11c4060ab4..07df3e7a209 100644 --- a/lib/private/Federation/CloudFederationProviderManager.php +++ b/lib/private/Federation/CloudFederationProviderManager.php @@ -1,9 +1,13 @@ <?php + +declare(strict_types=1); + /** * @copyright Copyright (c) 2018 Bjoern Schiessle <bjoern@schiessle.org> * * @author Bjoern Schiessle <bjoern@schiessle.org> * @author Christoph Wurst <christoph@winzerhof-wurst.at> + * @author Maxence Lange <maxence@artificial-owl.com> * * @license GNU AGPL version 3 or any later version * @@ -32,6 +36,10 @@ use OCP\Federation\ICloudFederationProviderManager; use OCP\Federation\ICloudFederationShare; use OCP\Federation\ICloudIdManager; use OCP\Http\Client\IClientService; +use OCP\Http\Client\IResponse; +use OCP\IConfig; +use OCP\OCM\Exceptions\OCMProviderException; +use OCP\OCM\IOCMDiscoveryService; use Psr\Log\LoggerInterface; /** @@ -43,40 +51,16 @@ use Psr\Log\LoggerInterface; */ class CloudFederationProviderManager implements ICloudFederationProviderManager { /** @var array list of available cloud federation providers */ - private $cloudFederationProvider; - - /** @var IAppManager */ - private $appManager; - - /** @var IClientService */ - private $httpClientService; - - /** @var ICloudIdManager */ - private $cloudIdManager; - - private LoggerInterface $logger; - - /** @var array cache OCM end-points */ - private $ocmEndPoints = []; - - private $supportedAPIVersion = '1.0-proposal1'; - - /** - * CloudFederationProviderManager constructor. - * - * @param IAppManager $appManager - * @param IClientService $httpClientService - * @param ICloudIdManager $cloudIdManager - */ - public function __construct(IAppManager $appManager, - IClientService $httpClientService, - ICloudIdManager $cloudIdManager, - LoggerInterface $logger) { - $this->cloudFederationProvider = []; - $this->appManager = $appManager; - $this->httpClientService = $httpClientService; - $this->cloudIdManager = $cloudIdManager; - $this->logger = $logger; + private array $cloudFederationProvider = []; + + public function __construct( + private IConfig $config, + private IAppManager $appManager, + private IClientService $httpClientService, + private ICloudIdManager $cloudIdManager, + private IOCMDiscoveryService $discoveryService, + private LoggerInterface $logger + ) { } @@ -128,18 +112,23 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager } } + /** + * @deprecated 29.0.0 - Use {@see sendCloudShare()} instead and handle errors manually + */ public function sendShare(ICloudFederationShare $share) { $cloudID = $this->cloudIdManager->resolveCloudId($share->getShareWith()); - $ocmEndPoint = $this->getOCMEndPoint($cloudID->getRemote()); - if (empty($ocmEndPoint)) { + try { + $ocmProvider = $this->discoveryService->discover($cloudID->getRemote()); + } catch (OCMProviderException $e) { return false; } $client = $this->httpClientService->newClient(); try { - $response = $client->post($ocmEndPoint . '/shares', [ + $response = $client->post($ocmProvider->getEndPoint() . '/shares', [ 'body' => json_encode($share->getShare()), 'headers' => ['content-type' => 'application/json'], + 'verify' => !$this->config->getSystemValueBool('sharing.federation.allowSelfSignedCertificates', false), 'timeout' => 10, 'connect_timeout' => 10, ]); @@ -163,22 +152,52 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager } /** + * @param ICloudFederationShare $share + * @return IResponse + * @throws OCMProviderException + */ + public function sendCloudShare(ICloudFederationShare $share): IResponse { + $cloudID = $this->cloudIdManager->resolveCloudId($share->getShareWith()); + $ocmProvider = $this->discoveryService->discover($cloudID->getRemote()); + + $client = $this->httpClientService->newClient(); + try { + return $client->post($ocmProvider->getEndPoint() . '/shares', [ + 'body' => json_encode($share->getShare()), + 'headers' => ['content-type' => 'application/json'], + 'verify' => !$this->config->getSystemValueBool('sharing.federation.allowSelfSignedCertificates', false), + 'timeout' => 10, + 'connect_timeout' => 10, + ]); + } catch (\Throwable $e) { + $this->logger->error('Error while sending share to federation server: ' . $e->getMessage(), ['exception' => $e]); + try { + return $client->getResponseFromThrowable($e); + } catch (\Throwable $e) { + throw new OCMProviderException($e->getMessage(), $e->getCode(), $e); + } + } + } + + /** * @param string $url * @param ICloudFederationNotification $notification * @return array|false + * @deprecated 29.0.0 - Use {@see sendCloudNotification()} instead and handle errors manually */ public function sendNotification($url, ICloudFederationNotification $notification) { - $ocmEndPoint = $this->getOCMEndPoint($url); - - if (empty($ocmEndPoint)) { + try { + $ocmProvider = $this->discoveryService->discover($url); + } catch (OCMProviderException $e) { return false; } $client = $this->httpClientService->newClient(); try { - $response = $client->post($ocmEndPoint . '/notifications', [ + $response = $client->post($ocmProvider->getEndPoint() . '/notifications', [ 'body' => json_encode($notification->getMessage()), 'headers' => ['content-type' => 'application/json'], + 'verify' => !$this->config->getSystemValueBool('sharing.federation.allowSelfSignedCertificates', false), 'timeout' => 10, 'connect_timeout' => 10, ]); @@ -195,43 +214,39 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager } /** - * check if the new cloud federation API is ready to be used - * - * @return bool - */ - public function isReady() { - return $this->appManager->isEnabledForUser('cloud_federation_api'); - } - /** - * check if server supports the new OCM api and ask for the correct end-point - * - * @param string $url full base URL of the cloud server - * @return string + * @param string $url + * @param ICloudFederationNotification $notification + * @return IResponse + * @throws OCMProviderException */ - protected function getOCMEndPoint($url) { - if (isset($this->ocmEndPoints[$url])) { - return $this->ocmEndPoints[$url]; - } + public function sendCloudNotification(string $url, ICloudFederationNotification $notification): IResponse { + $ocmProvider = $this->discoveryService->discover($url); $client = $this->httpClientService->newClient(); try { - $response = $client->get($url . '/ocm-provider/', ['timeout' => 10, 'connect_timeout' => 10]); - } catch (\Exception $e) { - $this->ocmEndPoints[$url] = ''; - return ''; - } - - $result = $response->getBody(); - $result = json_decode($result, true); - - $supportedVersion = isset($result['apiVersion']) && $result['apiVersion'] === $this->supportedAPIVersion; - - if (isset($result['endPoint']) && $supportedVersion) { - $this->ocmEndPoints[$url] = $result['endPoint']; - return $result['endPoint']; + return $client->post($ocmProvider->getEndPoint() . '/notifications', [ + 'body' => json_encode($notification->getMessage()), + 'headers' => ['content-type' => 'application/json'], + 'verify' => !$this->config->getSystemValueBool('sharing.federation.allowSelfSignedCertificates', false), + 'timeout' => 10, + 'connect_timeout' => 10, + ]); + } catch (\Throwable $e) { + $this->logger->error('Error while sending notification to federation server: ' . $e->getMessage(), ['exception' => $e]); + try { + return $client->getResponseFromThrowable($e); + } catch (\Throwable $e) { + throw new OCMProviderException($e->getMessage(), $e->getCode(), $e); + } } + } - $this->ocmEndPoints[$url] = ''; - return ''; + /** + * check if the new cloud federation API is ready to be used + * + * @return bool + */ + public function isReady() { + return $this->appManager->isEnabledForUser('cloud_federation_api'); } } diff --git a/lib/private/Federation/CloudFederationShare.php b/lib/private/Federation/CloudFederationShare.php index 0f79ba521ea..4b741b28bee 100644 --- a/lib/private/Federation/CloudFederationShare.php +++ b/lib/private/Federation/CloudFederationShare.php @@ -57,16 +57,16 @@ class CloudFederationShare implements ICloudFederationShare { * @param string $sharedSecret */ public function __construct($shareWith = '', - $name = '', - $description = '', - $providerId = '', - $owner = '', - $ownerDisplayName = '', - $sharedBy = '', - $sharedByDisplayName = '', - $shareType = '', - $resourceType = '', - $sharedSecret = '' + $name = '', + $description = '', + $providerId = '', + $owner = '', + $ownerDisplayName = '', + $sharedBy = '', + $sharedByDisplayName = '', + $shareType = '', + $resourceType = '', + $sharedSecret = '' ) { $this->setShareWith($shareWith); $this->setResourceName($name); diff --git a/lib/private/Files/AppData/AppData.php b/lib/private/Files/AppData/AppData.php index 237fcb42e03..1c632c3062f 100644 --- a/lib/private/Files/AppData/AppData.php +++ b/lib/private/Files/AppData/AppData.php @@ -26,9 +26,9 @@ declare(strict_types=1); */ namespace OC\Files\AppData; -use OCP\Cache\CappedMemoryCache; use OC\Files\SimpleFS\SimpleFolder; use OC\SystemConfig; +use OCP\Cache\CappedMemoryCache; use OCP\Files\Folder; use OCP\Files\IAppData; use OCP\Files\IRootFolder; @@ -53,8 +53,8 @@ class AppData implements IAppData { * @param string $appId */ public function __construct(IRootFolder $rootFolder, - SystemConfig $systemConfig, - string $appId) { + SystemConfig $systemConfig, + string $appId) { $this->rootFolder = $rootFolder; $this->config = $systemConfig; $this->appId = $appId; diff --git a/lib/private/Files/AppData/Factory.php b/lib/private/Files/AppData/Factory.php index 03f8fdedcbd..a16c3df327d 100644 --- a/lib/private/Files/AppData/Factory.php +++ b/lib/private/Files/AppData/Factory.php @@ -39,7 +39,7 @@ class Factory implements IAppDataFactory { private array $folders = []; public function __construct(IRootFolder $rootFolder, - SystemConfig $systemConfig) { + SystemConfig $systemConfig) { $this->rootFolder = $rootFolder; $this->config = $systemConfig; } diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index 67d01bb6999..2c53706189a 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -44,12 +44,13 @@ use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchQuery; use OC\Files\Storage\Wrapper\Encryption; +use OC\SystemConfig; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Cache\CacheEntryInsertedEvent; +use OCP\Files\Cache\CacheEntryRemovedEvent; use OCP\Files\Cache\CacheEntryUpdatedEvent; use OCP\Files\Cache\CacheInsertEvent; -use OCP\Files\Cache\CacheEntryRemovedEvent; use OCP\Files\Cache\CacheUpdateEvent; use OCP\Files\Cache\ICache; use OCP\Files\Cache\ICacheEntry; @@ -59,6 +60,7 @@ use OCP\Files\Search\ISearchComparison; use OCP\Files\Search\ISearchOperator; use OCP\Files\Search\ISearchQuery; use OCP\Files\Storage\IStorage; +use OCP\FilesMetadata\IFilesMetadataManager; use OCP\IDBConnection; use OCP\Util; use Psr\Log\LoggerInterface; @@ -81,61 +83,53 @@ class Cache implements ICache { /** * @var array partial data for the cache */ - protected $partial = []; - - /** - * @var string - */ - protected $storageId; - - private $storage; - - /** - * @var Storage $storageCache - */ - protected $storageCache; - - /** @var IMimeTypeLoader */ - protected $mimetypeLoader; - - /** - * @var IDBConnection - */ - protected $connection; - - /** - * @var IEventDispatcher - */ - protected $eventDispatcher; - - /** @var QuerySearchHelper */ - protected $querySearchHelper; - - /** - * @param IStorage $storage - */ - public function __construct(IStorage $storage) { + protected array $partial = []; + protected string $storageId; + protected Storage $storageCache; + protected IMimeTypeLoader$mimetypeLoader; + protected IDBConnection $connection; + protected SystemConfig $systemConfig; + protected LoggerInterface $logger; + protected QuerySearchHelper $querySearchHelper; + protected IEventDispatcher $eventDispatcher; + protected IFilesMetadataManager $metadataManager; + + public function __construct( + private IStorage $storage, + // this constructor is used in to many pleases to easily do proper di + // so instead we group it all together + CacheDependencies $dependencies = null, + ) { $this->storageId = $storage->getId(); - $this->storage = $storage; if (strlen($this->storageId) > 64) { $this->storageId = md5($this->storageId); } - - $this->storageCache = new Storage($storage); - $this->mimetypeLoader = \OC::$server->getMimeTypeLoader(); - $this->connection = \OC::$server->getDatabaseConnection(); - $this->eventDispatcher = \OC::$server->get(IEventDispatcher::class); - $this->querySearchHelper = \OCP\Server::get(QuerySearchHelper::class); + if (!$dependencies) { + $dependencies = \OC::$server->get(CacheDependencies::class); + } + $this->storageCache = new Storage($this->storage, true, $dependencies->getConnection()); + $this->mimetypeLoader = $dependencies->getMimeTypeLoader(); + $this->connection = $dependencies->getConnection(); + $this->systemConfig = $dependencies->getSystemConfig(); + $this->logger = $dependencies->getLogger(); + $this->querySearchHelper = $dependencies->getQuerySearchHelper(); + $this->eventDispatcher = $dependencies->getEventDispatcher(); + $this->metadataManager = $dependencies->getMetadataManager(); } protected function getQueryBuilder() { return new CacheQueryBuilder( $this->connection, - \OC::$server->getSystemConfig(), - \OC::$server->get(LoggerInterface::class) + $this->systemConfig, + $this->logger, + $this->metadataManager, ); } + public function getStorageCache(): Storage { + return $this->storageCache; + } + /** * Get the numeric storage id for this cache's storage * @@ -154,6 +148,7 @@ class Cache implements ICache { public function get($file) { $query = $this->getQueryBuilder(); $query->selectFileCache(); + $metadataQuery = $query->selectMetadata(); if (is_string($file) || $file == '') { // normalize file @@ -175,6 +170,7 @@ class Cache implements ICache { } elseif (!$data) { return $data; } else { + $data['metadata'] = $metadataQuery?->extractMetadata($data)->asArray() ?? []; return self::cacheEntryFromData($data, $this->mimetypeLoader); } } @@ -239,11 +235,14 @@ class Cache implements ICache { ->whereParent($fileId) ->orderBy('name', 'ASC'); + $metadataQuery = $query->selectMetadata(); + $result = $query->execute(); $files = $result->fetchAll(); $result->closeCursor(); - return array_map(function (array $data) { + return array_map(function (array $data) use ($metadataQuery) { + $data['metadata'] = $metadataQuery?->extractMetadata($data)->asArray() ?? []; return self::cacheEntryFromData($data, $this->mimetypeLoader); }, $files); } @@ -447,7 +446,7 @@ class Cache implements ICache { $params = []; $extensionParams = []; foreach ($data as $name => $value) { - if (array_search($name, $fields) !== false) { + if (in_array($name, $fields)) { if ($name === 'path') { $params['path_hash'] = md5($value); } elseif ($name === 'mimetype') { @@ -467,7 +466,7 @@ class Cache implements ICache { } $params[$name] = $value; } - if (array_search($name, $extensionFields) !== false) { + if (in_array($name, $extensionFields)) { $extensionParams[$name] = $value; } } @@ -586,8 +585,13 @@ class Cache implements ICache { return $cacheEntry->getPath(); }, $children); - $deletedIds = array_merge($deletedIds, $childIds); - $deletedPaths = array_merge($deletedPaths, $childPaths); + foreach ($childIds as $childId) { + $deletedIds[] = $childId; + } + + foreach ($childPaths as $childPath) { + $deletedPaths[] = $childPath; + } $query = $this->getQueryBuilder(); $query->delete('filecache_extended') @@ -599,9 +603,12 @@ class Cache implements ICache { } /** @var ICacheEntry[] $childFolders */ - $childFolders = array_filter($children, function ($child) { - return $child->getMimeType() == FileInfo::MIMETYPE_FOLDER; - }); + $childFolders = []; + foreach ($children as $child) { + if ($child->getMimeType() == FileInfo::MIMETYPE_FOLDER) { + $childFolders[] = $child; + } + } foreach ($childFolders as $folder) { $parentIds[] = $folder->getId(); $queue[] = $folder->getId(); diff --git a/lib/private/Files/Cache/CacheDependencies.php b/lib/private/Files/Cache/CacheDependencies.php new file mode 100644 index 00000000000..7c51f3ff884 --- /dev/null +++ b/lib/private/Files/Cache/CacheDependencies.php @@ -0,0 +1,57 @@ +<?php + +namespace OC\Files\Cache; + +use OC\SystemConfig; +use OC\User\DisplayNameCache; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\IMimeTypeLoader; +use OCP\FilesMetadata\IFilesMetadataManager; +use OCP\IDBConnection; +use Psr\Log\LoggerInterface; + +class CacheDependencies { + public function __construct( + private IMimeTypeLoader $mimeTypeLoader, + private IDBConnection $connection, + private IEventDispatcher $eventDispatcher, + private QuerySearchHelper $querySearchHelper, + private SystemConfig $systemConfig, + private LoggerInterface $logger, + private IFilesMetadataManager $metadataManager, + private DisplayNameCache $displayNameCache, + ) { + } + + public function getMimeTypeLoader(): IMimeTypeLoader { + return $this->mimeTypeLoader; + } + + public function getConnection(): IDBConnection { + return $this->connection; + } + + public function getEventDispatcher(): IEventDispatcher { + return $this->eventDispatcher; + } + + public function getQuerySearchHelper(): QuerySearchHelper { + return $this->querySearchHelper; + } + + public function getSystemConfig(): SystemConfig { + return $this->systemConfig; + } + + public function getLogger(): LoggerInterface { + return $this->logger; + } + + public function getDisplayNameCache(): DisplayNameCache { + return $this->displayNameCache; + } + + public function getMetadataManager(): IFilesMetadataManager { + return $this->metadataManager; + } +} diff --git a/lib/private/Files/Cache/CacheEntry.php b/lib/private/Files/Cache/CacheEntry.php index ce9df2823c8..d1a64552fd1 100644 --- a/lib/private/Files/Cache/CacheEntry.php +++ b/lib/private/Files/Cache/CacheEntry.php @@ -134,7 +134,7 @@ class CacheEntry implements ICacheEntry { } public function getUnencryptedSize(): int { - if (isset($this->data['unencrypted_size']) && $this->data['unencrypted_size'] > 0) { + if ($this->data['encrypted'] && isset($this->data['unencrypted_size']) && $this->data['unencrypted_size'] > 0) { return $this->data['unencrypted_size']; } else { return $this->data['size'] ?? 0; diff --git a/lib/private/Files/Cache/CacheQueryBuilder.php b/lib/private/Files/Cache/CacheQueryBuilder.php index 34d2177b84e..365d28fc8c5 100644 --- a/lib/private/Files/Cache/CacheQueryBuilder.php +++ b/lib/private/Files/Cache/CacheQueryBuilder.php @@ -5,6 +5,7 @@ declare(strict_types=1); /** * @copyright Copyright (c) 2019 Robin Appelman <robin@icewind.nl> * + * @author Maxence Lange <maxence@artificial-owl.com> * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version @@ -28,6 +29,8 @@ namespace OC\Files\Cache; use OC\DB\QueryBuilder\QueryBuilder; use OC\SystemConfig; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\FilesMetadata\IFilesMetadataManager; +use OCP\FilesMetadata\IMetadataQuery; use OCP\IDBConnection; use Psr\Log\LoggerInterface; @@ -35,9 +38,14 @@ use Psr\Log\LoggerInterface; * Query builder with commonly used helpers for filecache queries */ class CacheQueryBuilder extends QueryBuilder { - private $alias = null; - - public function __construct(IDBConnection $connection, SystemConfig $systemConfig, LoggerInterface $logger) { + private ?string $alias = null; + + public function __construct( + IDBConnection $connection, + SystemConfig $systemConfig, + LoggerInterface $logger, + private IFilesMetadataManager $filesMetadataManager, + ) { parent::__construct($connection, $systemConfig, $logger); } @@ -63,7 +71,7 @@ class CacheQueryBuilder extends QueryBuilder { public function selectFileCache(string $alias = null, bool $joinExtendedCache = true) { $name = $alias ?: 'filecache'; $this->select("$name.fileid", 'storage', 'path', 'path_hash', "$name.parent", "$name.name", 'mimetype', 'mimepart', 'size', 'mtime', - 'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum', 'unencrypted_size') + 'storage_mtime', 'encrypted', 'etag', "$name.permissions", 'checksum', 'unencrypted_size') ->from('filecache', $name); if ($joinExtendedCache) { @@ -126,4 +134,15 @@ class CacheQueryBuilder extends QueryBuilder { return $this; } + + /** + * join metadata to current query builder and returns an helper + * + * @return IMetadataQuery|null NULL if no metadata have never been generated + */ + public function selectMetadata(): ?IMetadataQuery { + $metadataQuery = $this->filesMetadataManager->getMetadataQuery($this, $this->alias, 'fileid'); + $metadataQuery?->retrieveMetadata(); + return $metadataQuery; + } } diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php index 15c089a0f11..d8c5e66e129 100644 --- a/lib/private/Files/Cache/QuerySearchHelper.php +++ b/lib/private/Files/Cache/QuerySearchHelper.php @@ -3,6 +3,7 @@ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> * * @author Christoph Wurst <christoph@winzerhof-wurst.at> + * @author Maxence Lange <maxence@artificial-owl.com> * @author Robin Appelman <robin@icewind.nl> * @author Roeland Jago Douma <roeland@famdouma.nl> * @author Tobias Kaminsky <tobias@kaminsky.me> @@ -37,52 +38,47 @@ use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountPoint; use OCP\Files\Search\ISearchBinaryOperator; use OCP\Files\Search\ISearchQuery; +use OCP\FilesMetadata\IFilesMetadataManager; +use OCP\FilesMetadata\IMetadataQuery; use OCP\IDBConnection; use OCP\IGroupManager; use OCP\IUser; use Psr\Log\LoggerInterface; class QuerySearchHelper { - /** @var IMimeTypeLoader */ - private $mimetypeLoader; - /** @var IDBConnection */ - private $connection; - /** @var SystemConfig */ - private $systemConfig; - private LoggerInterface $logger; - /** @var SearchBuilder */ - private $searchBuilder; - /** @var QueryOptimizer */ - private $queryOptimizer; - private IGroupManager $groupManager; - public function __construct( - IMimeTypeLoader $mimetypeLoader, - IDBConnection $connection, - SystemConfig $systemConfig, - LoggerInterface $logger, - SearchBuilder $searchBuilder, - QueryOptimizer $queryOptimizer, - IGroupManager $groupManager, + private IMimeTypeLoader $mimetypeLoader, + private IDBConnection $connection, + private SystemConfig $systemConfig, + private LoggerInterface $logger, + private SearchBuilder $searchBuilder, + private QueryOptimizer $queryOptimizer, + private IGroupManager $groupManager, + private IFilesMetadataManager $filesMetadataManager, ) { - $this->mimetypeLoader = $mimetypeLoader; - $this->connection = $connection; - $this->systemConfig = $systemConfig; - $this->logger = $logger; - $this->searchBuilder = $searchBuilder; - $this->queryOptimizer = $queryOptimizer; - $this->groupManager = $groupManager; } protected function getQueryBuilder() { return new CacheQueryBuilder( $this->connection, $this->systemConfig, - $this->logger + $this->logger, + $this->filesMetadataManager, ); } - protected function applySearchConstraints(CacheQueryBuilder $query, ISearchQuery $searchQuery, array $caches): void { + /** + * @param CacheQueryBuilder $query + * @param ISearchQuery $searchQuery + * @param array $caches + * @param IMetadataQuery|null $metadataQuery + */ + protected function applySearchConstraints( + CacheQueryBuilder $query, + ISearchQuery $searchQuery, + array $caches, + ?IMetadataQuery $metadataQuery = null + ): void { $storageFilters = array_values(array_map(function (ICache $cache) { return $cache->getQueryFilterForStorage(); }, $caches)); @@ -90,12 +86,12 @@ class QuerySearchHelper { $filter = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [$searchQuery->getSearchOperation(), $storageFilter]); $this->queryOptimizer->processOperator($filter); - $searchExpr = $this->searchBuilder->searchOperatorToDBExpr($query, $filter); + $searchExpr = $this->searchBuilder->searchOperatorToDBExpr($query, $filter, $metadataQuery); if ($searchExpr) { $query->andWhere($searchExpr); } - $this->searchBuilder->addSearchOrdersToQuery($query, $searchQuery->getOrder()); + $this->searchBuilder->addSearchOrdersToQuery($query, $searchQuery->getOrder(), $metadataQuery); if ($searchQuery->getLimit()) { $query->setMaxResults($searchQuery->getLimit()); @@ -144,6 +140,11 @@ class QuerySearchHelper { )); } + + protected function equipQueryForShares(CacheQueryBuilder $query): void { + $query->join('file', 'share', 's', $query->expr()->eq('file.fileid', 's.file_source')); + } + /** * Perform a file system search in multiple caches * @@ -175,19 +176,31 @@ class QuerySearchHelper { $query = $builder->selectFileCache('file', false); $requestedFields = $this->searchBuilder->extractRequestedFields($searchQuery->getSearchOperation()); + if (in_array('systemtag', $requestedFields)) { $this->equipQueryForSystemTags($query, $this->requireUser($searchQuery)); } if (in_array('tagname', $requestedFields) || in_array('favorite', $requestedFields)) { $this->equipQueryForDavTags($query, $this->requireUser($searchQuery)); } + if (in_array('owner', $requestedFields) || in_array('share_with', $requestedFields) || in_array('share_type', $requestedFields)) { + $this->equipQueryForShares($query); + } - $this->applySearchConstraints($query, $searchQuery, $caches); + $metadataQuery = $query->selectMetadata(); + + $this->applySearchConstraints($query, $searchQuery, $caches, $metadataQuery); $result = $query->execute(); $files = $result->fetchAll(); - $rawEntries = array_map(function (array $data) { + $rawEntries = array_map(function (array $data) use ($metadataQuery) { + // migrate to null safe ... + if ($metadataQuery === null) { + $data['metadata'] = []; + } else { + $data['metadata'] = $metadataQuery->extractMetadata($data)->asArray(); + } return Cache::cacheEntryFromData($data, $this->mimetypeLoader); }, $files); diff --git a/lib/private/Files/Cache/Scanner.php b/lib/private/Files/Cache/Scanner.php index 52268032409..0c82e21e30d 100644 --- a/lib/private/Files/Cache/Scanner.php +++ b/lib/private/Files/Cache/Scanner.php @@ -37,14 +37,14 @@ namespace OC\Files\Cache; use Doctrine\DBAL\Exception; use OC\Files\Storage\Wrapper\Encryption; +use OC\Files\Storage\Wrapper\Jail; +use OC\Hooks\BasicEmitter; use OCP\Files\Cache\IScanner; use OCP\Files\ForbiddenException; use OCP\Files\NotFoundException; use OCP\Files\Storage\IReliableEtagStorage; use OCP\IDBConnection; use OCP\Lock\ILockingProvider; -use OC\Files\Storage\Wrapper\Jail; -use OC\Hooks\BasicEmitter; use Psr\Log\LoggerInterface; /** @@ -203,7 +203,9 @@ class Scanner extends BasicEmitter implements IScanner { $fileId = $cacheData['fileid']; $data['fileid'] = $fileId; // only reuse data if the file hasn't explicitly changed - if (isset($data['storage_mtime']) && isset($cacheData['storage_mtime']) && $data['storage_mtime'] === $cacheData['storage_mtime']) { + $mtimeUnchanged = isset($data['storage_mtime']) && isset($cacheData['storage_mtime']) && $data['storage_mtime'] === $cacheData['storage_mtime']; + // if the folder is marked as unscanned, never reuse etags + if ($mtimeUnchanged && $cacheData['size'] !== -1) { $data['mtime'] = $cacheData['mtime']; if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) { $data['size'] = $cacheData['size']; @@ -220,6 +222,11 @@ class Scanner extends BasicEmitter implements IScanner { // Only update metadata that has changed $newData = array_diff_assoc($data, $cacheData->getData()); + + // make it known to the caller that etag has been changed and needs propagation + if (isset($newData['etag'])) { + $data['etag_changed'] = true; + } } else { // we only updated unencrypted_size if it's already set unset($data['unencrypted_size']); @@ -385,19 +392,23 @@ class Scanner extends BasicEmitter implements IScanner { * @param int $reuse a combination of self::REUSE_* * @param int $folderId id for the folder to be scanned * @param bool $lock set to false to disable getting an additional read lock during scanning - * @param int $oldSize the size of the folder before (re)scanning the children + * @param int|float $oldSize the size of the folder before (re)scanning the children * @return int|float the size of the scanned folder or -1 if the size is unknown at this stage */ - protected function scanChildren(string $path, $recursive, int $reuse, int $folderId, bool $lock, int $oldSize) { + protected function scanChildren(string $path, $recursive, int $reuse, int $folderId, bool $lock, int|float $oldSize, &$etagChanged = false) { if ($reuse === -1) { $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG; } $this->emit('\OC\Files\Cache\Scanner', 'scanFolder', [$path, $this->storageId]); $size = 0; - $childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size); + $childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size, $etagChanged); foreach ($childQueue as $child => [$childId, $childSize]) { - $childSize = $this->scanChildren($child, $recursive, $reuse, $childId, $lock, $childSize); + // "etag changed" propagates up, but not down, so we pass `false` to the children even if we already know that the etag of the current folder changed + $childEtagChanged = false; + $childSize = $this->scanChildren($child, $recursive, $reuse, $childId, $lock, $childSize, $childEtagChanged); + $etagChanged |= $childEtagChanged; + if ($childSize === -1) { $size = -1; } elseif ($size !== -1) { @@ -410,15 +421,27 @@ class Scanner extends BasicEmitter implements IScanner { if ($this->storage->instanceOfStorage(Encryption::class)) { $this->cache->calculateFolderSize($path); } else { - if ($this->cacheActive && $oldSize !== $size) { - $this->cache->update($folderId, ['size' => $size]); + if ($this->cacheActive) { + $updatedData = []; + if ($oldSize !== $size) { + $updatedData['size'] = $size; + } + if ($etagChanged) { + $updatedData['etag'] = uniqid(); + } + if ($updatedData) { + $this->cache->update($folderId, $updatedData); + } } } $this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', [$path, $this->storageId]); return $size; } - private function handleChildren($path, $recursive, $reuse, $folderId, $lock, &$size) { + /** + * @param bool|IScanner::SCAN_RECURSIVE_INCOMPLETE $recursive + */ + private function handleChildren(string $path, $recursive, int $reuse, int $folderId, bool $lock, int|float &$size, bool &$etagChanged): array { // we put this in it's own function so it cleans up the memory before we start recursing $existingChildren = $this->getExistingChildren($folderId); $newChildren = iterator_to_array($this->storage->getDirectoryContent($path)); @@ -436,7 +459,7 @@ class Scanner extends BasicEmitter implements IScanner { $childQueue = []; $newChildNames = []; foreach ($newChildren as $fileMeta) { - $permissions = isset($fileMeta['scan_permissions']) ? $fileMeta['scan_permissions'] : $fileMeta['permissions']; + $permissions = $fileMeta['scan_permissions'] ?? $fileMeta['permissions']; if ($permissions === 0) { continue; } @@ -453,7 +476,7 @@ class Scanner extends BasicEmitter implements IScanner { $newChildNames[] = $file; $child = $path ? $path . '/' . $file : $file; try { - $existingData = isset($existingChildren[$file]) ? $existingChildren[$file] : false; + $existingData = $existingChildren[$file] ?? false; $data = $this->scanFile($child, $reuse, $folderId, $existingData, $lock, $fileMeta); if ($data) { if ($data['mimetype'] === 'httpd/unix-directory' && $recursive === self::SCAN_RECURSIVE) { @@ -466,6 +489,10 @@ class Scanner extends BasicEmitter implements IScanner { } elseif ($size !== -1) { $size += $data['size']; } + + if (isset($data['etag_changed']) && $data['etag_changed']) { + $etagChanged = true; + } } } catch (Exception $ex) { // might happen if inserting duplicate while a scanning diff --git a/lib/private/Files/Cache/SearchBuilder.php b/lib/private/Files/Cache/SearchBuilder.php index b9a70bbd39b..e8063b77aa5 100644 --- a/lib/private/Files/Cache/SearchBuilder.php +++ b/lib/private/Files/Cache/SearchBuilder.php @@ -3,6 +3,7 @@ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> * * @author Christoph Wurst <christoph@winzerhof-wurst.at> + * @author Maxence Lange <maxence@artificial-owl.com> * @author Robin Appelman <robin@icewind.nl> * @author Roeland Jago Douma <roeland@famdouma.nl> * @author Tobias Kaminsky <tobias@kaminsky.me> @@ -32,11 +33,16 @@ use OCP\Files\Search\ISearchBinaryOperator; use OCP\Files\Search\ISearchComparison; use OCP\Files\Search\ISearchOperator; use OCP\Files\Search\ISearchOrder; +use OCP\FilesMetadata\IMetadataQuery; /** * Tools for transforming search queries into database queries + * + * @psalm-import-type ParamSingleValue from ISearchComparison + * @psalm-import-type ParamValue from ISearchComparison */ class SearchBuilder { + /** @var array<string, string> */ protected static $searchOperatorMap = [ ISearchComparison::COMPARE_LIKE => 'iLike', ISearchComparison::COMPARE_LIKE_CASE_SENSITIVE => 'like', @@ -45,8 +51,11 @@ class SearchBuilder { ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'gte', ISearchComparison::COMPARE_LESS_THAN => 'lt', ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lte', + ISearchComparison::COMPARE_DEFINED => 'isNotNull', + ISearchComparison::COMPARE_IN => 'in', ]; + /** @var array<string, string> */ protected static $searchOperatorNegativeMap = [ ISearchComparison::COMPARE_LIKE => 'notLike', ISearchComparison::COMPARE_LIKE_CASE_SENSITIVE => 'notLike', @@ -55,6 +64,39 @@ class SearchBuilder { ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'lt', ISearchComparison::COMPARE_LESS_THAN => 'gte', ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'gt', + ISearchComparison::COMPARE_DEFINED => 'isNull', + ISearchComparison::COMPARE_IN => 'notIn', + ]; + + /** @var array<string, string> */ + protected static $fieldTypes = [ + 'mimetype' => 'string', + 'mtime' => 'integer', + 'name' => 'string', + 'path' => 'string', + 'size' => 'integer', + 'tagname' => 'string', + 'systemtag' => 'string', + 'favorite' => 'boolean', + 'fileid' => 'integer', + 'storage' => 'integer', + 'share_with' => 'string', + 'share_type' => 'integer', + 'owner' => 'string', + ]; + + /** @var array<string, int> */ + protected static $paramTypeMap = [ + 'string' => IQueryBuilder::PARAM_STR, + 'integer' => IQueryBuilder::PARAM_INT, + 'boolean' => IQueryBuilder::PARAM_BOOL, + ]; + + /** @var array<string, int> */ + protected static $paramArrayTypeMap = [ + 'string' => IQueryBuilder::PARAM_STR_ARRAY, + 'integer' => IQueryBuilder::PARAM_INT_ARRAY, + 'boolean' => IQueryBuilder::PARAM_INT_ARRAY, ]; public const TAG_FAVORITE = '_$!<Favorite>!$_'; @@ -76,7 +118,7 @@ class SearchBuilder { return array_reduce($operator->getArguments(), function (array $fields, ISearchOperator $operator) { return array_unique(array_merge($fields, $this->extractRequestedFields($operator))); }, []); - } elseif ($operator instanceof ISearchComparison) { + } elseif ($operator instanceof ISearchComparison && !$operator->getExtra()) { return [$operator->getField()]; } return []; @@ -86,13 +128,21 @@ class SearchBuilder { * @param IQueryBuilder $builder * @param ISearchOperator[] $operators */ - public function searchOperatorArrayToDBExprArray(IQueryBuilder $builder, array $operators) { - return array_filter(array_map(function ($operator) use ($builder) { - return $this->searchOperatorToDBExpr($builder, $operator); + public function searchOperatorArrayToDBExprArray( + IQueryBuilder $builder, + array $operators, + ?IMetadataQuery $metadataQuery = null + ) { + return array_filter(array_map(function ($operator) use ($builder, $metadataQuery) { + return $this->searchOperatorToDBExpr($builder, $operator, $metadataQuery); }, $operators)); } - public function searchOperatorToDBExpr(IQueryBuilder $builder, ISearchOperator $operator) { + public function searchOperatorToDBExpr( + IQueryBuilder $builder, + ISearchOperator $operator, + ?IMetadataQuery $metadataQuery = null + ) { $expr = $builder->expr(); if ($operator instanceof ISearchBinaryOperator) { @@ -104,62 +154,99 @@ class SearchBuilder { case ISearchBinaryOperator::OPERATOR_NOT: $negativeOperator = $operator->getArguments()[0]; if ($negativeOperator instanceof ISearchComparison) { - return $this->searchComparisonToDBExpr($builder, $negativeOperator, self::$searchOperatorNegativeMap); + return $this->searchComparisonToDBExpr($builder, $negativeOperator, self::$searchOperatorNegativeMap, $metadataQuery); } else { throw new \InvalidArgumentException('Binary operators inside "not" is not supported'); } // no break case ISearchBinaryOperator::OPERATOR_AND: - return call_user_func_array([$expr, 'andX'], $this->searchOperatorArrayToDBExprArray($builder, $operator->getArguments())); + return call_user_func_array([$expr, 'andX'], $this->searchOperatorArrayToDBExprArray($builder, $operator->getArguments(), $metadataQuery)); case ISearchBinaryOperator::OPERATOR_OR: - return call_user_func_array([$expr, 'orX'], $this->searchOperatorArrayToDBExprArray($builder, $operator->getArguments())); + return call_user_func_array([$expr, 'orX'], $this->searchOperatorArrayToDBExprArray($builder, $operator->getArguments(), $metadataQuery)); default: throw new \InvalidArgumentException('Invalid operator type: ' . $operator->getType()); } } elseif ($operator instanceof ISearchComparison) { - return $this->searchComparisonToDBExpr($builder, $operator, self::$searchOperatorMap); + return $this->searchComparisonToDBExpr($builder, $operator, self::$searchOperatorMap, $metadataQuery); } else { throw new \InvalidArgumentException('Invalid operator type: ' . get_class($operator)); } } - private function searchComparisonToDBExpr(IQueryBuilder $builder, ISearchComparison $comparison, array $operatorMap) { - $this->validateComparison($comparison); + private function searchComparisonToDBExpr( + IQueryBuilder $builder, + ISearchComparison $comparison, + array $operatorMap, + ?IMetadataQuery $metadataQuery = null + ) { + if ($comparison->getExtra()) { + [$field, $value, $type, $paramType] = $this->getExtraOperatorField($comparison, $metadataQuery); + } else { + [$field, $value, $type, $paramType] = $this->getOperatorFieldAndValue($comparison); + } - [$field, $value, $type] = $this->getOperatorFieldAndValue($comparison); if (isset($operatorMap[$type])) { $queryOperator = $operatorMap[$type]; - return $builder->expr()->$queryOperator($field, $this->getParameterForValue($builder, $value)); + return $builder->expr()->$queryOperator($field, $this->getParameterForValue($builder, $value, $paramType)); } else { throw new \InvalidArgumentException('Invalid operator type: ' . $comparison->getType()); } } - private function getOperatorFieldAndValue(ISearchComparison $operator) { + /** + * @param ISearchComparison $operator + * @return list{string, ParamValue, string, string} + */ + private function getOperatorFieldAndValue(ISearchComparison $operator): array { + $this->validateComparison($operator); $field = $operator->getField(); $value = $operator->getValue(); $type = $operator->getType(); + $pathEqHash = $operator->getQueryHint(ISearchComparison::HINT_PATH_EQ_HASH, true); + return $this->getOperatorFieldAndValueInner($field, $value, $type, $pathEqHash); + } + + /** + * @param string $field + * @param ParamValue $value + * @param string $type + * @return list{string, ParamValue, string, string} + */ + private function getOperatorFieldAndValueInner(string $field, mixed $value, string $type, bool $pathEqHash): array { + $paramType = self::$fieldTypes[$field]; + if ($type === ISearchComparison::COMPARE_IN) { + $resultField = $field; + $values = []; + foreach ($value as $arrayValue) { + /** @var ParamSingleValue $arrayValue */ + [$arrayField, $arrayValue] = $this->getOperatorFieldAndValueInner($field, $arrayValue, ISearchComparison::COMPARE_EQUAL, $pathEqHash); + $resultField = $arrayField; + $values[] = $arrayValue; + } + return [$resultField, $values, ISearchComparison::COMPARE_IN, $paramType]; + } if ($field === 'mimetype') { $value = (string)$value; - if ($operator->getType() === ISearchComparison::COMPARE_EQUAL) { - $value = (int)$this->mimetypeLoader->getId($value); - } elseif ($operator->getType() === ISearchComparison::COMPARE_LIKE) { + if ($type === ISearchComparison::COMPARE_EQUAL) { + $value = $this->mimetypeLoader->getId($value); + } elseif ($type === ISearchComparison::COMPARE_LIKE) { // transform "mimetype='foo/%'" to "mimepart='foo'" if (preg_match('|(.+)/%|', $value, $matches)) { $field = 'mimepart'; - $value = (int)$this->mimetypeLoader->getId($matches[1]); + $value = $this->mimetypeLoader->getId($matches[1]); $type = ISearchComparison::COMPARE_EQUAL; } elseif (str_contains($value, '%')) { throw new \InvalidArgumentException('Unsupported query value for mimetype: ' . $value . ', only values in the format "mime/type" or "mime/%" are supported'); } else { $field = 'mimetype'; - $value = (int)$this->mimetypeLoader->getId($value); + $value = $this->mimetypeLoader->getId($value); $type = ISearchComparison::COMPARE_EQUAL; } } } elseif ($field === 'favorite') { $field = 'tag.category'; $value = self::TAG_FAVORITE; + $paramType = 'string'; } elseif ($field === 'name') { $field = 'file.name'; } elseif ($field === 'tagname') { @@ -168,59 +255,82 @@ class SearchBuilder { $field = 'systemtag.name'; } elseif ($field === 'fileid') { $field = 'file.fileid'; - } elseif ($field === 'path' && $type === ISearchComparison::COMPARE_EQUAL && $operator->getQueryHint(ISearchComparison::HINT_PATH_EQ_HASH, true)) { + } elseif ($field === 'path' && $type === ISearchComparison::COMPARE_EQUAL && $pathEqHash) { $field = 'path_hash'; $value = md5((string)$value); + } elseif ($field === 'owner') { + $field = 'uid_owner'; } - return [$field, $value, $type]; + return [$field, $value, $type, $paramType]; } private function validateComparison(ISearchComparison $operator) { - $types = [ - 'mimetype' => 'string', - 'mtime' => 'integer', - 'name' => 'string', - 'path' => 'string', - 'size' => 'integer', - 'tagname' => 'string', - 'systemtag' => 'string', - 'favorite' => 'boolean', - 'fileid' => 'integer', - 'storage' => 'integer', - ]; $comparisons = [ - 'mimetype' => ['eq', 'like'], + 'mimetype' => ['eq', 'like', 'in'], 'mtime' => ['eq', 'gt', 'lt', 'gte', 'lte'], - 'name' => ['eq', 'like', 'clike'], - 'path' => ['eq', 'like', 'clike'], + 'name' => ['eq', 'like', 'clike', 'in'], + 'path' => ['eq', 'like', 'clike', 'in'], 'size' => ['eq', 'gt', 'lt', 'gte', 'lte'], 'tagname' => ['eq', 'like'], 'systemtag' => ['eq', 'like'], 'favorite' => ['eq'], - 'fileid' => ['eq'], - 'storage' => ['eq'], + 'fileid' => ['eq', 'in'], + 'storage' => ['eq', 'in'], + 'share_with' => ['eq'], + 'share_type' => ['eq'], + 'owner' => ['eq'], ]; - if (!isset($types[$operator->getField()])) { + if (!isset(self::$fieldTypes[$operator->getField()])) { throw new \InvalidArgumentException('Unsupported comparison field ' . $operator->getField()); } - $type = $types[$operator->getField()]; - if (gettype($operator->getValue()) !== $type) { - throw new \InvalidArgumentException('Invalid type for field ' . $operator->getField()); + $type = self::$fieldTypes[$operator->getField()]; + if ($operator->getType() === ISearchComparison::COMPARE_IN) { + if (!is_array($operator->getValue())) { + throw new \InvalidArgumentException('Invalid type for field ' . $operator->getField()); + } + foreach ($operator->getValue() as $arrayValue) { + if (gettype($arrayValue) !== $type) { + throw new \InvalidArgumentException('Invalid type in array for field ' . $operator->getField()); + } + } + } else { + if (gettype($operator->getValue()) !== $type) { + throw new \InvalidArgumentException('Invalid type for field ' . $operator->getField()); + } } if (!in_array($operator->getType(), $comparisons[$operator->getField()])) { throw new \InvalidArgumentException('Unsupported comparison for field ' . $operator->getField() . ': ' . $operator->getType()); } } - private function getParameterForValue(IQueryBuilder $builder, $value) { + + private function getExtraOperatorField(ISearchComparison $operator, IMetadataQuery $metadataQuery): array { + $paramType = self::$fieldTypes[$operator->getField()]; + $field = $operator->getField(); + $value = $operator->getValue(); + $type = $operator->getType(); + + switch($operator->getExtra()) { + case IMetadataQuery::EXTRA: + $metadataQuery->joinIndex($field); // join index table if not joined yet + $field = $metadataQuery->getMetadataValueField($field); + break; + default: + throw new \InvalidArgumentException('Invalid extra type: ' . $operator->getExtra()); + } + + return [$field, $value, $type, $paramType]; + } + + private function getParameterForValue(IQueryBuilder $builder, $value, string $paramType) { if ($value instanceof \DateTime) { $value = $value->getTimestamp(); } - if (is_numeric($value)) { - $type = IQueryBuilder::PARAM_INT; + if (is_array($value)) { + $type = self::$paramArrayTypeMap[$paramType]; } else { - $type = IQueryBuilder::PARAM_STR; + $type = self::$paramTypeMap[$paramType]; } return $builder->createNamedParameter($value, $type); } @@ -228,24 +338,32 @@ class SearchBuilder { /** * @param IQueryBuilder $query * @param ISearchOrder[] $orders + * @param IMetadataQuery|null $metadataQuery */ - public function addSearchOrdersToQuery(IQueryBuilder $query, array $orders) { + public function addSearchOrdersToQuery(IQueryBuilder $query, array $orders, ?IMetadataQuery $metadataQuery = null): void { foreach ($orders as $order) { $field = $order->getField(); - if ($field === 'fileid') { - $field = 'file.fileid'; - } + switch ($order->getExtra()) { + case IMetadataQuery::EXTRA: + $metadataQuery->joinIndex($field); // join index table if not joined yet + $field = $metadataQuery->getMetadataValueField($order->getField()); + break; - // Mysql really likes to pick an index for sorting if it can't fully satisfy the where - // filter with an index, since search queries pretty much never are fully filtered by index - // mysql often picks an index for sorting instead of the much more useful index for filtering. - // - // By changing the order by to an expression, mysql isn't smart enough to see that it could still - // use the index, so it instead picks an index for the filtering - if ($field === 'mtime') { - $field = $query->func()->add($field, $query->createNamedParameter(0)); - } + default: + if ($field === 'fileid') { + $field = 'file.fileid'; + } + // Mysql really likes to pick an index for sorting if it can't fully satisfy the where + // filter with an index, since search queries pretty much never are fully filtered by index + // mysql often picks an index for sorting instead of the much more useful index for filtering. + // + // By changing the order by to an expression, mysql isn't smart enough to see that it could still + // use the index, so it instead picks an index for the filtering + if ($field === 'mtime') { + $field = $query->func()->add($field, $query->createNamedParameter(0)); + } + } $query->addOrderBy($field, $order->getDirection()); } } diff --git a/lib/private/Files/Cache/Storage.php b/lib/private/Files/Cache/Storage.php index 01fc638cef8..ba0f98f42f4 100644 --- a/lib/private/Files/Cache/Storage.php +++ b/lib/private/Files/Cache/Storage.php @@ -31,6 +31,7 @@ namespace OC\Files\Cache; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Files\Storage\IStorage; +use OCP\IDBConnection; use Psr\Log\LoggerInterface; /** @@ -65,7 +66,7 @@ class Storage { * @param bool $isAvailable * @throws \RuntimeException */ - public function __construct($storage, $isAvailable = true) { + public function __construct($storage, $isAvailable, IDBConnection $connection) { if ($storage instanceof IStorage) { $this->storageId = $storage->getId(); } else { @@ -76,7 +77,6 @@ class Storage { if ($row = self::getStorageById($this->storageId)) { $this->numericId = (int)$row['numeric_id']; } else { - $connection = \OC::$server->getDatabaseConnection(); $available = $isAvailable ? 1 : 0; if ($connection->insertIfNotExist('*PREFIX*storages', ['id' => $this->storageId, 'available' => $available])) { $this->numericId = $connection->lastInsertId('*PREFIX*storages'); diff --git a/lib/private/Files/Cache/Updater.php b/lib/private/Files/Cache/Updater.php index 457dd207e9d..a6f2f3375a4 100644 --- a/lib/private/Files/Cache/Updater.php +++ b/lib/private/Files/Cache/Updater.php @@ -119,7 +119,7 @@ class Updater implements IUpdater { * @param string $path * @param int $time */ - public function update($path, $time = null) { + public function update($path, $time = null, ?int $sizeDifference = null) { if (!$this->enabled or Scanner::isPartialFile($path)) { return; } @@ -128,20 +128,22 @@ class Updater implements IUpdater { } $data = $this->scanner->scan($path, Scanner::SCAN_SHALLOW, -1, false); - if ( - isset($data['oldSize']) && isset($data['size']) && - !$data['encrypted'] // encryption is a pita and touches the cache itself - ) { + + if (isset($data['oldSize']) && isset($data['size'])) { $sizeDifference = $data['size'] - $data['oldSize']; - } else { - // scanner didn't provide size info, fallback to full size calculation - $sizeDifference = 0; - if ($this->cache instanceof Cache) { - $this->cache->correctFolderSize($path, $data); - } + } + + // encryption is a pita and touches the cache itself + if (isset($data['encrypted']) && !!$data['encrypted']) { + $sizeDifference = null; + } + + // scanner didn't provide size info, fallback to full size calculation + if ($this->cache instanceof Cache && $sizeDifference === null) { + $this->cache->correctFolderSize($path, $data); } $this->correctParentStorageMtime($path); - $this->propagator->propagateChange($path, $time, $sizeDifference); + $this->propagator->propagateChange($path, $time, $sizeDifference ?? 0); } /** diff --git a/lib/private/Files/Cache/Watcher.php b/lib/private/Files/Cache/Watcher.php index acc76f263dc..61ea5b2f848 100644 --- a/lib/private/Files/Cache/Watcher.php +++ b/lib/private/Files/Cache/Watcher.php @@ -129,7 +129,7 @@ class Watcher implements IWatcher { * @return bool */ public function needsUpdate($path, $cachedData) { - if ($this->watchPolicy === self::CHECK_ALWAYS or ($this->watchPolicy === self::CHECK_ONCE and array_search($path, $this->checkedPaths) === false)) { + if ($this->watchPolicy === self::CHECK_ALWAYS or ($this->watchPolicy === self::CHECK_ONCE and !in_array($path, $this->checkedPaths))) { $this->checkedPaths[] = $path; return $this->storage->hasUpdated($path, $cachedData['storage_mtime']); } diff --git a/lib/private/Files/Cache/Wrapper/CacheJail.php b/lib/private/Files/Cache/Wrapper/CacheJail.php index d8cf3eb61d7..f9754e433df 100644 --- a/lib/private/Files/Cache/Wrapper/CacheJail.php +++ b/lib/private/Files/Cache/Wrapper/CacheJail.php @@ -28,8 +28,10 @@ namespace OC\Files\Cache\Wrapper; use OC\Files\Cache\Cache; +use OC\Files\Cache\CacheDependencies; use OC\Files\Search\SearchBinaryOperator; use OC\Files\Search\SearchComparison; +use OCP\Files\Cache\ICache; use OCP\Files\Cache\ICacheEntry; use OCP\Files\Search\ISearchBinaryOperator; use OCP\Files\Search\ISearchComparison; @@ -45,15 +47,13 @@ class CacheJail extends CacheWrapper { protected $root; protected $unjailedRoot; - /** - * @param ?\OCP\Files\Cache\ICache $cache - * @param string $root - */ - public function __construct($cache, $root) { - parent::__construct($cache); + public function __construct( + ?ICache $cache, + string $root, + CacheDependencies $dependencies = null, + ) { + parent::__construct($cache, $dependencies); $this->root = $root; - $this->connection = \OC::$server->getDatabaseConnection(); - $this->mimetypeLoader = \OC::$server->getMimeTypeLoader(); if ($cache instanceof CacheJail) { $this->unjailedRoot = $cache->getSourcePath($root); diff --git a/lib/private/Files/Cache/Wrapper/CacheWrapper.php b/lib/private/Files/Cache/Wrapper/CacheWrapper.php index 39a78f31343..31410eea798 100644 --- a/lib/private/Files/Cache/Wrapper/CacheWrapper.php +++ b/lib/private/Files/Cache/Wrapper/CacheWrapper.php @@ -30,33 +30,32 @@ namespace OC\Files\Cache\Wrapper; use OC\Files\Cache\Cache; -use OC\Files\Cache\QuerySearchHelper; +use OC\Files\Cache\CacheDependencies; use OCP\Files\Cache\ICache; use OCP\Files\Cache\ICacheEntry; -use OCP\Files\IMimeTypeLoader; use OCP\Files\Search\ISearchOperator; use OCP\Files\Search\ISearchQuery; -use OCP\IDBConnection; +use OCP\Server; class CacheWrapper extends Cache { /** - * @var \OCP\Files\Cache\ICache + * @var ?ICache */ protected $cache; - /** - * @param \OCP\Files\Cache\ICache $cache - */ - public function __construct($cache) { + public function __construct(?ICache $cache, CacheDependencies $dependencies = null) { $this->cache = $cache; - if ($cache instanceof Cache) { + if (!$dependencies && $cache instanceof Cache) { $this->mimetypeLoader = $cache->mimetypeLoader; $this->connection = $cache->connection; $this->querySearchHelper = $cache->querySearchHelper; } else { - $this->mimetypeLoader = \OC::$server->get(IMimeTypeLoader::class); - $this->connection = \OC::$server->get(IDBConnection::class); - $this->querySearchHelper = \OC::$server->get(QuerySearchHelper::class); + if (!$dependencies) { + $dependencies = Server::get(CacheDependencies::class); + } + $this->mimetypeLoader = $dependencies->getMimeTypeLoader(); + $this->connection = $dependencies->getConnection(); + $this->querySearchHelper = $dependencies->getQuerySearchHelper(); } } @@ -91,7 +90,7 @@ class CacheWrapper extends Cache { */ public function get($file) { $result = $this->getCache()->get($file); - if ($result) { + if ($result instanceof ICacheEntry) { $result = $this->formatCacheEntry($result); } return $result; diff --git a/lib/private/Files/Config/CachedMountInfo.php b/lib/private/Files/Config/CachedMountInfo.php index 43c9fae63ec..19fa87aa090 100644 --- a/lib/private/Files/Config/CachedMountInfo.php +++ b/lib/private/Files/Config/CachedMountInfo.php @@ -35,6 +35,7 @@ class CachedMountInfo implements ICachedMountInfo { protected ?int $mountId; protected string $rootInternalPath; protected string $mountProvider; + protected string $key; /** * CachedMountInfo constructor. @@ -65,6 +66,7 @@ class CachedMountInfo implements ICachedMountInfo { throw new \Exception("Mount provider $mountProvider name exceeds the limit of 128 characters"); } $this->mountProvider = $mountProvider; + $this->key = $rootId . '::' . $mountPoint; } /** @@ -95,12 +97,7 @@ class CachedMountInfo implements ICachedMountInfo { // TODO injection etc Filesystem::initMountPoints($this->getUser()->getUID()); $userNode = \OC::$server->getUserFolder($this->getUser()->getUID()); - $nodes = $userNode->getParent()->getById($this->getRootId()); - if (count($nodes) > 0) { - return $nodes[0]; - } else { - return null; - } + return $userNode->getParent()->getFirstNodeById($this->getRootId()); } /** @@ -132,4 +129,8 @@ class CachedMountInfo implements ICachedMountInfo { public function getMountProvider(): string { return $this->mountProvider; } + + public function getKey(): string { + return $this->key; + } } diff --git a/lib/private/Files/Config/LazyPathCachedMountInfo.php b/lib/private/Files/Config/LazyPathCachedMountInfo.php new file mode 100644 index 00000000000..d42052c5f83 --- /dev/null +++ b/lib/private/Files/Config/LazyPathCachedMountInfo.php @@ -0,0 +1,63 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OC\Files\Config; + +use OCP\IUser; + +class LazyPathCachedMountInfo extends CachedMountInfo { + // we don't allow \ in paths so it makes a great placeholder + private const PATH_PLACEHOLDER = '\\PLACEHOLDER\\'; + + /** @var callable(CachedMountInfo): string */ + protected $rootInternalPathCallback; + + /** + * @param IUser $user + * @param int $storageId + * @param int $rootId + * @param string $mountPoint + * @param string $mountProvider + * @param int|null $mountId + * @param callable(CachedMountInfo): string $rootInternalPathCallback + * @throws \Exception + */ + public function __construct( + IUser $user, + int $storageId, + int $rootId, + string $mountPoint, + string $mountProvider, + int $mountId = null, + callable $rootInternalPathCallback, + ) { + parent::__construct($user, $storageId, $rootId, $mountPoint, $mountProvider, $mountId, self::PATH_PLACEHOLDER); + $this->rootInternalPathCallback = $rootInternalPathCallback; + } + + public function getRootInternalPath(): string { + if ($this->rootInternalPath === self::PATH_PLACEHOLDER) { + $this->rootInternalPath = ($this->rootInternalPathCallback)($this); + } + return $this->rootInternalPath; + } +} diff --git a/lib/private/Files/Config/LazyStorageMountInfo.php b/lib/private/Files/Config/LazyStorageMountInfo.php index 78055a2cdb8..7e4acb2e129 100644 --- a/lib/private/Files/Config/LazyStorageMountInfo.php +++ b/lib/private/Files/Config/LazyStorageMountInfo.php @@ -39,6 +39,7 @@ class LazyStorageMountInfo extends CachedMountInfo { $this->rootId = 0; $this->storageId = 0; $this->mountPoint = ''; + $this->key = ''; } /** @@ -87,4 +88,11 @@ class LazyStorageMountInfo extends CachedMountInfo { public function getMountProvider(): string { return $this->mount->getMountProvider(); } + + public function getKey(): string { + if (!$this->key) { + $this->key = $this->getRootId() . '::' . $this->getMountPoint(); + } + return $this->key; + } } diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php index ae6481e45bb..d251199fd43 100644 --- a/lib/private/Files/Config/MountProviderCollection.php +++ b/lib/private/Files/Config/MountProviderCollection.php @@ -238,6 +238,11 @@ class MountProviderCollection implements IMountProviderCollection, Emitter { $mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) { return array_merge($mounts, $providerMounts); }, []); + + if (count($mounts) === 0) { + throw new \Exception("No root mounts provided by any provider"); + } + return $mounts; } diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index 90f94b6598e..8275eee7b9f 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -28,14 +28,13 @@ */ namespace OC\Files\Config; +use OC\User\LazyUser; use OCP\Cache\CappedMemoryCache; -use OCA\Files_Sharing\SharedMount; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Diagnostics\IEventLogger; use OCP\Files\Config\ICachedMountFileInfo; use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Config\IUserMountCache; -use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; use OCP\IDBConnection; use OCP\IUser; @@ -54,6 +53,11 @@ class UserMountCache implements IUserMountCache { * @var CappedMemoryCache<ICachedMountInfo[]> **/ private CappedMemoryCache $mountsForUsers; + /** + * fileid => internal path mapping for cached mount info. + * @var CappedMemoryCache<string> + **/ + private CappedMemoryCache $internalPathCache; private LoggerInterface $logger; /** @var CappedMemoryCache<array> */ private CappedMemoryCache $cacheInfoCache; @@ -73,46 +77,33 @@ class UserMountCache implements IUserMountCache { $this->logger = $logger; $this->eventLogger = $eventLogger; $this->cacheInfoCache = new CappedMemoryCache(); + $this->internalPathCache = new CappedMemoryCache(); $this->mountsForUsers = new CappedMemoryCache(); } public function registerMounts(IUser $user, array $mounts, array $mountProviderClasses = null) { $this->eventLogger->start('fs:setup:user:register', 'Registering mounts for user'); - // filter out non-proper storages coming from unit tests - $mounts = array_filter($mounts, function (IMountPoint $mount) { - return $mount instanceof SharedMount || ($mount->getStorage() && $mount->getStorage()->getCache()); - }); - /** @var ICachedMountInfo[] $newMounts */ - $newMounts = array_map(function (IMountPoint $mount) use ($user) { + /** @var array<string, ICachedMountInfo> $newMounts */ + $newMounts = []; + foreach ($mounts as $mount) { // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet) - if ($mount->getStorageRootId() === -1) { - return null; - } else { - return new LazyStorageMountInfo($user, $mount); + if ($mount->getStorageRootId() !== -1) { + $mountInfo = new LazyStorageMountInfo($user, $mount); + $newMounts[$mountInfo->getKey()] = $mountInfo; } - }, $mounts); - $newMounts = array_values(array_filter($newMounts)); - $newMountKeys = array_map(function (ICachedMountInfo $mount) { - return $mount->getRootId() . '::' . $mount->getMountPoint(); - }, $newMounts); - $newMounts = array_combine($newMountKeys, $newMounts); + } $cachedMounts = $this->getMountsForUser($user); if (is_array($mountProviderClasses)) { $cachedMounts = array_filter($cachedMounts, function (ICachedMountInfo $mountInfo) use ($mountProviderClasses, $newMounts) { // for existing mounts that didn't have a mount provider set // we still want the ones that map to new mounts - $mountKey = $mountInfo->getRootId() . '::' . $mountInfo->getMountPoint(); - if ($mountInfo->getMountProvider() === '' && isset($newMounts[$mountKey])) { + if ($mountInfo->getMountProvider() === '' && isset($newMounts[$mountInfo->getKey()])) { return true; } return in_array($mountInfo->getMountProvider(), $mountProviderClasses); }); } - $cachedRootKeys = array_map(function (ICachedMountInfo $mount) { - return $mount->getRootId() . '::' . $mount->getMountPoint(); - }, $cachedMounts); - $cachedMounts = array_combine($cachedRootKeys, $cachedMounts); $addedMounts = []; $removedMounts = []; @@ -131,46 +122,44 @@ class UserMountCache implements IUserMountCache { $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts); - $this->connection->beginTransaction(); - try { - foreach ($addedMounts as $mount) { - $this->addToCache($mount); - /** @psalm-suppress InvalidArgument */ - $this->mountsForUsers[$user->getUID()][] = $mount; - } - foreach ($removedMounts as $mount) { - $this->removeFromCache($mount); - $index = array_search($mount, $this->mountsForUsers[$user->getUID()]); - unset($this->mountsForUsers[$user->getUID()][$index]); - } - foreach ($changedMounts as $mount) { - $this->updateCachedMount($mount); + if ($addedMounts || $removedMounts || $changedMounts) { + $this->connection->beginTransaction(); + $userUID = $user->getUID(); + try { + foreach ($addedMounts as $mount) { + $this->addToCache($mount); + /** @psalm-suppress InvalidArgument */ + $this->mountsForUsers[$userUID][$mount->getKey()] = $mount; + } + foreach ($removedMounts as $mount) { + $this->removeFromCache($mount); + unset($this->mountsForUsers[$userUID][$mount->getKey()]); + } + foreach ($changedMounts as $mount) { + $this->updateCachedMount($mount); + /** @psalm-suppress InvalidArgument */ + $this->mountsForUsers[$userUID][$mount->getKey()] = $mount; + } + $this->connection->commit(); + } catch (\Throwable $e) { + $this->connection->rollBack(); + throw $e; } - $this->connection->commit(); - } catch (\Throwable $e) { - $this->connection->rollBack(); - throw $e; } $this->eventLogger->end('fs:setup:user:register'); } /** - * @param ICachedMountInfo[] $newMounts - * @param ICachedMountInfo[] $cachedMounts + * @param array<string, ICachedMountInfo> $newMounts + * @param array<string, ICachedMountInfo> $cachedMounts * @return ICachedMountInfo[] */ private function findChangedMounts(array $newMounts, array $cachedMounts) { - $new = []; - foreach ($newMounts as $mount) { - $new[$mount->getRootId() . '::' . $mount->getMountPoint()] = $mount; - } $changed = []; - foreach ($cachedMounts as $cachedMount) { - $key = $cachedMount->getRootId() . '::' . $cachedMount->getMountPoint(); - if (isset($new[$key])) { - $newMount = $new[$key]; + foreach ($cachedMounts as $key => $cachedMount) { + if (isset($newMounts[$key])) { + $newMount = $newMounts[$key]; if ( - $newMount->getMountPoint() !== $cachedMount->getMountPoint() || $newMount->getStorageId() !== $cachedMount->getStorageId() || $newMount->getMountId() !== $cachedMount->getMountId() || $newMount->getMountProvider() !== $cachedMount->getMountProvider() @@ -222,24 +211,38 @@ class UserMountCache implements IUserMountCache { $query->execute(); } - private function dbRowToMountInfo(array $row) { - $user = $this->userManager->get($row['user_id']); - if (is_null($user)) { - return null; - } + /** + * @param array $row + * @param (callable(CachedMountInfo): string)|null $pathCallback + * @return CachedMountInfo + */ + private function dbRowToMountInfo(array $row, ?callable $pathCallback = null): ICachedMountInfo { + $user = new LazyUser($row['user_id'], $this->userManager); $mount_id = $row['mount_id']; if (!is_null($mount_id)) { $mount_id = (int)$mount_id; } - return new CachedMountInfo( - $user, - (int)$row['storage_id'], - (int)$row['root_id'], - $row['mount_point'], - $row['mount_provider_class'] ?? '', - $mount_id, - isset($row['path']) ? $row['path'] : '', - ); + if ($pathCallback) { + return new LazyPathCachedMountInfo( + $user, + (int)$row['storage_id'], + (int)$row['root_id'], + $row['mount_point'], + $row['mount_provider_class'] ?? '', + $mount_id, + $pathCallback, + ); + } else { + return new CachedMountInfo( + $user, + (int)$row['storage_id'], + (int)$row['root_id'], + $row['mount_point'], + $row['mount_provider_class'] ?? '', + $mount_id, + $row['path'] ?? '', + ); + } } /** @@ -247,20 +250,43 @@ class UserMountCache implements IUserMountCache { * @return ICachedMountInfo[] */ public function getMountsForUser(IUser $user) { - if (!isset($this->mountsForUsers[$user->getUID()])) { + $userUID = $user->getUID(); + if (!$this->userManager->userExists($userUID)) { + return []; + } + if (!isset($this->mountsForUsers[$userUID])) { $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class') + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'mount_provider_class') ->from('mounts', 'm') - ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) - ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID()))); + ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($userUID))); $result = $query->execute(); $rows = $result->fetchAll(); $result->closeCursor(); - $this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows)); + /** @var array<string, ICachedMountInfo> $mounts */ + $mounts = []; + foreach ($rows as $row) { + $mount = $this->dbRowToMountInfo($row, [$this, 'getInternalPathForMountInfo']); + if ($mount !== null) { + $mounts[$mount->getKey()] = $mount; + } + } + $this->mountsForUsers[$userUID] = $mounts; } - return $this->mountsForUsers[$user->getUID()]; + return $this->mountsForUsers[$userUID]; + } + + public function getInternalPathForMountInfo(CachedMountInfo $info): string { + $cached = $this->internalPathCache->get($info->getRootId()); + if ($cached !== null) { + return $cached; + } + $builder = $this->connection->getQueryBuilder(); + $query = $builder->select('path') + ->from('filecache') + ->where($builder->expr()->eq('fileid', $builder->createPositionalParameter($info->getRootId()))); + return $query->executeQuery()->fetchOne() ?: ''; } /** @@ -345,30 +371,22 @@ class UserMountCache implements IUserMountCache { } catch (NotFoundException $e) { return []; } - $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class') - ->from('mounts', 'm') - ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) - ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($storageId, IQueryBuilder::PARAM_INT))); - - if ($user) { - $query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user))); - } + $mountsForStorage = $this->getMountsForStorageId($storageId, $user); - $result = $query->execute(); - $rows = $result->fetchAll(); - $result->closeCursor(); - // filter mounts that are from the same storage but a different directory - $filteredMounts = array_filter($rows, function (array $row) use ($internalPath, $fileId) { - if ($fileId === (int)$row['root_id']) { + // filter mounts that are from the same storage but not a parent of the file we care about + $filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) { + if ($fileId === $mount->getRootId()) { return true; } - $internalMountPath = $row['path'] ?? ''; + $internalMountPath = $mount->getRootInternalPath(); + + return $internalMountPath === '' || str_starts_with($internalPath, $internalMountPath . '/'); + }); - return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/'; + $filteredMounts = array_filter($filteredMounts, function (ICachedMountInfo $mount) { + return $this->userManager->userExists($mount->getUser()->getUID()); }); - $filteredMounts = array_filter(array_map([$this, 'dbRowToMountInfo'], $filteredMounts)); return array_map(function (ICachedMountInfo $mount) use ($internalPath) { return new CachedMountFileInfo( $mount->getUser(), @@ -463,7 +481,7 @@ class UserMountCache implements IUserMountCache { }, $mounts); $mounts = array_combine($mountPoints, $mounts); - $current = $path; + $current = rtrim($path, '/'); // walk up the directory tree until we find a path that has a mountpoint set // the loop will return if a mountpoint is found or break if none are found while (true) { diff --git a/lib/private/Files/FileInfo.php b/lib/private/Files/FileInfo.php index 3937ee16a7c..81a283e365b 100644 --- a/lib/private/Files/FileInfo.php +++ b/lib/private/Files/FileInfo.php @@ -6,6 +6,7 @@ * @author Joas Schilling <coding@schilljs.com> * @author Julius Härtl <jus@bitgrid.net> * @author Lukas Reschke <lukas@statuscode.ch> + * @author Maxence Lange <maxence@artificial-owl.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Piotr M <mrow4a@yahoo.com> * @author Robin Appelman <robin@icewind.nl> @@ -32,12 +33,16 @@ */ namespace OC\Files; -use OCA\Files_Sharing\ISharedStorage; +use OC\Files\Mount\HomeMountPoint; +use OCA\Files_Sharing\External\Mount; +use OCA\Files_Sharing\ISharedMountPoint; use OCP\Files\Cache\ICacheEntry; -use OCP\Files\IHomeStorage; use OCP\Files\Mount\IMountPoint; use OCP\IUser; +/** + * @template-implements \ArrayAccess<string,mixed> + */ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { private array|ICacheEntry $data; /** @@ -121,21 +126,14 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { */ #[\ReturnTypeWillChange] public function offsetGet($offset) { - if ($offset === 'type') { - return $this->getType(); - } elseif ($offset === 'etag') { - return $this->getEtag(); - } elseif ($offset === 'size') { - return $this->getSize(); - } elseif ($offset === 'mtime') { - return $this->getMTime(); - } elseif ($offset === 'permissions') { - return $this->getPermissions(); - } elseif (isset($this->data[$offset])) { - return $this->data[$offset]; - } else { - return null; - } + return match ($offset) { + 'type' => $this->getType(), + 'etag' => $this->getEtag(), + 'size' => $this->getSize(), + 'mtime' => $this->getMTime(), + 'permissions' => $this->getPermissions(), + default => $this->data[$offset] ?? null, + }; } /** @@ -183,7 +181,9 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @return string */ public function getName() { - return isset($this->data['name']) ? $this->data['name'] : basename($this->getPath()); + return empty($this->data['name']) + ? basename($this->getPath()) + : $this->data['name']; } /** @@ -207,7 +207,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { if ($includeMounts) { $this->updateEntryfromSubMounts(); - if (isset($this->data['unencrypted_size']) && $this->data['unencrypted_size'] > 0) { + if ($this->isEncrypted() && isset($this->data['unencrypted_size']) && $this->data['unencrypted_size'] > 0) { return $this->data['unencrypted_size']; } else { return isset($this->data['size']) ? 0 + $this->data['size'] : 0; @@ -229,11 +229,11 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @return bool */ public function isEncrypted() { - return $this->data['encrypted']; + return $this->data['encrypted'] ?? false; } /** - * Return the currently version used for the HMAC in the encryption app + * Return the current version used for the HMAC in the encryption app */ public function getEncryptedVersion(): int { return isset($this->data['encryptedVersion']) ? (int) $this->data['encryptedVersion'] : 1; @@ -243,11 +243,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @return int */ public function getPermissions() { - $perms = (int) $this->data['permissions']; - if (\OCP\Util::isSharingDisabledForUser() || ($this->isShared() && !\OC\Share\Share::isResharingAllowed())) { - $perms = $perms & ~\OCP\Constants::PERMISSION_SHARE; - } - return $perms; + return (int) $this->data['permissions']; } /** @@ -315,13 +311,12 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @return bool */ public function isShared() { - $storage = $this->getStorage(); - return $storage->instanceOfStorage(ISharedStorage::class); + return $this->mount instanceof ISharedMountPoint; } public function isMounted() { - $storage = $this->getStorage(); - return !($storage->instanceOfStorage(IHomeStorage::class) || $storage->instanceOfStorage(ISharedStorage::class)); + $isHome = $this->mount instanceof HomeMountPoint; + return !$isHome && !$this->isShared(); } /** @@ -416,4 +411,16 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { public function getUploadTime(): int { return (int) $this->data['upload_time']; } + + public function getParentId(): int { + return $this->data['parent'] ?? -1; + } + + /** + * @inheritDoc + * @return array<string, int|string|bool|float|string[]|int[]> + */ + public function getMetadata(): array { + return $this->data['metadata'] ?? []; + } } diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php index 5f7c0c403db..c6a5513d5b7 100644 --- a/lib/private/Files/Filesystem.php +++ b/lib/private/Files/Filesystem.php @@ -37,9 +37,9 @@ */ namespace OC\Files; -use OCP\Cache\CappedMemoryCache; use OC\Files\Mount\MountPoint; use OC\User\NoUserException; +use OCP\Cache\CappedMemoryCache; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Events\Node\FilesystemTornDownEvent; use OCP\Files\Mount\IMountManager; @@ -48,6 +48,7 @@ use OCP\Files\Storage\IStorageFactory; use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; +use Psr\Log\LoggerInterface; class Filesystem { private static ?Mount\Manager $mounts = null; @@ -200,7 +201,7 @@ class Filesystem { */ public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) { if (self::$logWarningWhenAddingStorageWrapper) { - \OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [ + \OCP\Server::get(LoggerInterface::class)->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [ 'wrapper' => $wrapperName, 'app' => 'filesystem', ]); diff --git a/lib/private/Files/Mount/HomeMountPoint.php b/lib/private/Files/Mount/HomeMountPoint.php new file mode 100644 index 00000000000..0bec12af5c2 --- /dev/null +++ b/lib/private/Files/Mount/HomeMountPoint.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2023 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Files\Mount; + +use OCP\Files\Storage\IStorageFactory; +use OCP\IUser; + +class HomeMountPoint extends MountPoint { + private IUser $user; + + public function __construct( + IUser $user, + $storage, + string $mountpoint, + array $arguments = null, + IStorageFactory $loader = null, + array $mountOptions = null, + int $mountId = null, + string $mountProvider = null + ) { + parent::__construct($storage, $mountpoint, $arguments, $loader, $mountOptions, $mountId, $mountProvider); + $this->user = $user; + } + + public function getUser(): IUser { + return $this->user; + } +} diff --git a/lib/private/Files/Mount/LocalHomeMountProvider.php b/lib/private/Files/Mount/LocalHomeMountProvider.php index 25a67fc1574..964b607d152 100644 --- a/lib/private/Files/Mount/LocalHomeMountProvider.php +++ b/lib/private/Files/Mount/LocalHomeMountProvider.php @@ -38,6 +38,6 @@ class LocalHomeMountProvider implements IHomeMountProvider { */ public function getHomeMountForUser(IUser $user, IStorageFactory $loader) { $arguments = ['user' => $user]; - return new MountPoint('\OC\Files\Storage\Home', '/' . $user->getUID(), $arguments, $loader, null, null, self::class); + return new HomeMountPoint($user, '\OC\Files\Storage\Home', '/' . $user->getUID(), $arguments, $loader, null, null, self::class); } } diff --git a/lib/private/Files/Mount/Manager.php b/lib/private/Files/Mount/Manager.php index 805cce658a6..2b2de1fbff1 100644 --- a/lib/private/Files/Mount/Manager.php +++ b/lib/private/Files/Mount/Manager.php @@ -10,6 +10,7 @@ declare(strict_types=1); * @author Robin Appelman <robin@icewind.nl> * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Roeland Jago Douma <roeland@famdouma.nl> + * @author Jonas <jonas@freesources.org> * * @license AGPL-3.0 * @@ -29,10 +30,11 @@ declare(strict_types=1); namespace OC\Files\Mount; -use OCP\Cache\CappedMemoryCache; use OC\Files\Filesystem; use OC\Files\SetupManager; use OC\Files\SetupManagerFactory; +use OCP\Cache\CappedMemoryCache; +use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Mount\IMountManager; use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; @@ -99,6 +101,15 @@ class Manager implements IMountManager { return $this->pathCache[$path]; } + + + if (count($this->mounts) === 0) { + $this->setupManager->setupRoot(); + if (count($this->mounts) === 0) { + throw new \Exception("No mounts even after explicitly setting up the root mounts"); + } + } + $current = $path; while (true) { $mountPoint = $current . '/'; @@ -115,7 +126,7 @@ class Manager implements IMountManager { } } - throw new NotFoundException("No mount for path " . $path . " existing mounts: " . implode(",", array_keys($this->mounts))); + throw new NotFoundException("No mount for path " . $path . " existing mounts (" . count($this->mounts) ."): " . implode(",", array_keys($this->mounts))); } /** @@ -226,4 +237,21 @@ class Manager implements IMountManager { }); } } + + /** + * Return the mount matching a cached mount info (or mount file info) + * + * @param ICachedMountInfo $info + * + * @return IMountPoint|null + */ + public function getMountFromMountInfo(ICachedMountInfo $info): ?IMountPoint { + $this->setupManager->setupForPath($info->getMountPoint()); + foreach ($this->mounts as $mount) { + if ($mount->getMountPoint() === $info->getMountPoint()) { + return $mount; + } + } + return null; + } } diff --git a/lib/private/Files/Mount/MountPoint.php b/lib/private/Files/Mount/MountPoint.php index f526928cc15..fe6358b32f1 100644 --- a/lib/private/Files/Mount/MountPoint.php +++ b/lib/private/Files/Mount/MountPoint.php @@ -272,7 +272,7 @@ class MountPoint implements IMountPoint { * @return mixed */ public function getOption($name, $default) { - return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default; + return $this->mountOptions[$name] ?? $default; } /** diff --git a/lib/private/Files/Mount/ObjectHomeMountProvider.php b/lib/private/Files/Mount/ObjectHomeMountProvider.php index 77912adfd34..3593a95c311 100644 --- a/lib/private/Files/Mount/ObjectHomeMountProvider.php +++ b/lib/private/Files/Mount/ObjectHomeMountProvider.php @@ -65,7 +65,7 @@ class ObjectHomeMountProvider implements IHomeMountProvider { return null; } - return new MountPoint('\OC\Files\ObjectStore\HomeObjectStoreStorage', '/' . $user->getUID(), $config['arguments'], $loader, null, null, self::class); + return new HomeMountPoint($user, '\OC\Files\ObjectStore\HomeObjectStoreStorage', '/' . $user->getUID(), $config['arguments'], $loader, null, null, self::class); } /** @@ -122,7 +122,7 @@ class ObjectHomeMountProvider implements IHomeMountProvider { $config['arguments']['bucket'] = ''; } $mapper = new \OC\Files\ObjectStore\Mapper($user, $this->config); - $numBuckets = isset($config['arguments']['num_buckets']) ? $config['arguments']['num_buckets'] : 64; + $numBuckets = $config['arguments']['num_buckets'] ?? 64; $config['arguments']['bucket'] .= $mapper->getBucket($numBuckets); $this->config->setUserValue($user->getUID(), 'homeobjectstore', 'bucket', $config['arguments']['bucket']); diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index ccd10da9d0c..014b66fdf63 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -177,7 +177,7 @@ class Folder extends Node implements \OCP\Files\Folder { * @throws \OCP\Files\NotPermittedException */ public function newFile($path, $content = null) { - if (empty($path)) { + if ($path === '') { throw new NotPermittedException('Could not create as provided path is empty'); } if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) { @@ -307,12 +307,16 @@ class Folder extends Node implements \OCP\Files\Folder { /** * @param int $id - * @return \OC\Files\Node\Node[] + * @return \OCP\Files\Node[] */ public function getById($id) { return $this->root->getByIdInPath((int)$id, $this->getPath()); } + public function getFirstNodeById(int $id): ?\OCP\Files\Node { + return current($this->getById($id)) ?: null; + } + protected function getAppDataDirectoryName(): string { $instanceId = \OC::$server->getConfig()->getSystemValueString('instanceid'); return 'appdata_' . $instanceId; diff --git a/lib/private/Files/Node/HookConnector.php b/lib/private/Files/Node/HookConnector.php index a8e76d95c22..d66c7a60664 100644 --- a/lib/private/Files/Node/HookConnector.php +++ b/lib/private/Files/Node/HookConnector.php @@ -6,6 +6,7 @@ declare(strict_types=1); * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Arthur Schiwon <blizzz@arthur-schiwon.de> + * @author Maxence Lange <maxence@artificial-owl.com> * @author Robin Appelman <robin@icewind.nl> * @author Roeland Jago Douma <roeland@famdouma.nl> * @@ -30,6 +31,7 @@ use OC\Files\Filesystem; use OC\Files\View; use OCP\EventDispatcher\GenericEvent; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Exceptions\AbortedEventException; use OCP\Files\Events\Node\BeforeNodeCopiedEvent; use OCP\Files\Events\Node\BeforeNodeCreatedEvent; use OCP\Files\Events\Node\BeforeNodeDeletedEvent; @@ -46,27 +48,18 @@ use OCP\Files\Events\Node\NodeWrittenEvent; use OCP\Files\FileInfo; use OCP\Files\IRootFolder; use OCP\Util; +use Psr\Log\LoggerInterface; class HookConnector { - /** @var IRootFolder */ - private $root; - - /** @var View */ - private $view; - /** @var FileInfo[] */ - private $deleteMetaCache = []; - - /** @var IEventDispatcher */ - private $dispatcher; + private array $deleteMetaCache = []; public function __construct( - IRootFolder $root, - View $view, - IEventDispatcher $dispatcher) { - $this->root = $root; - $this->view = $view; - $this->dispatcher = $dispatcher; + private IRootFolder $root, + private View $view, + private IEventDispatcher $dispatcher, + private LoggerInterface $logger + ) { } public function viewToNode() { @@ -134,7 +127,12 @@ class HookConnector { $this->dispatcher->dispatch('\OCP\Files::preDelete', new GenericEvent($node)); $event = new BeforeNodeDeletedEvent($node); - $this->dispatcher->dispatchTyped($event); + try { + $this->dispatcher->dispatchTyped($event); + } catch (AbortedEventException $e) { + $arguments['run'] = false; + $this->logger->warning('delete process aborted', ['exception' => $e]); + } } public function postDelete($arguments) { @@ -172,7 +170,12 @@ class HookConnector { $this->dispatcher->dispatch('\OCP\Files::preRename', new GenericEvent([$source, $target])); $event = new BeforeNodeRenamedEvent($source, $target); - $this->dispatcher->dispatchTyped($event); + try { + $this->dispatcher->dispatchTyped($event); + } catch (AbortedEventException $e) { + $arguments['run'] = false; + $this->logger->warning('rename process aborted', ['exception' => $e]); + } } public function postRename($arguments) { @@ -192,7 +195,12 @@ class HookConnector { $this->dispatcher->dispatch('\OCP\Files::preCopy', new GenericEvent([$source, $target])); $event = new BeforeNodeCopiedEvent($source, $target); - $this->dispatcher->dispatchTyped($event); + try { + $this->dispatcher->dispatchTyped($event); + } catch (AbortedEventException $e) { + $arguments['run'] = false; + $this->logger->warning('copy process aborted', ['exception' => $e]); + } } public function postCopy($arguments) { diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php index d495d6f4c57..4aae5cf9804 100644 --- a/lib/private/Files/Node/LazyFolder.php +++ b/lib/private/Files/Node/LazyFolder.php @@ -5,6 +5,7 @@ declare(strict_types=1); /** * @copyright Copyright (c) 2020 Robin Appelman <robin@icewind.nl> * + * @author Maxence Lange <maxence@artificial-owl.com> * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version @@ -26,10 +27,13 @@ declare(strict_types=1); namespace OC\Files\Node; +use OC\Files\Filesystem; use OC\Files\Utils\PathHelper; -use OCP\Files\Folder; use OCP\Constants; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountPoint; +use OCP\Files\NotPermittedException; /** * Class LazyFolder @@ -41,23 +45,33 @@ use OCP\Files\Mount\IMountPoint; */ class LazyFolder implements Folder { /** @var \Closure(): Folder */ - private $folderClosure; - - /** @var LazyFolder | null */ - protected $folder = null; - + private \Closure $folderClosure; + protected ?Folder $folder = null; + protected IRootFolder $rootFolder; protected array $data; /** - * LazyFolder constructor. - * + * @param IRootFolder $rootFolder * @param \Closure(): Folder $folderClosure + * @param array $data */ - public function __construct(\Closure $folderClosure, array $data = []) { + public function __construct(IRootFolder $rootFolder, \Closure $folderClosure, array $data = []) { + $this->rootFolder = $rootFolder; $this->folderClosure = $folderClosure; $this->data = $data; } + protected function getRootFolder(): IRootFolder { + return $this->rootFolder; + } + + protected function getRealFolder(): Folder { + if ($this->folder === null) { + $this->folder = call_user_func($this->folderClosure); + } + return $this->folder; + } + /** * Magic method to first get the real rootFolder and then * call $method with $args on it @@ -67,11 +81,7 @@ class LazyFolder implements Folder { * @return mixed */ public function __call($method, $args) { - if ($this->folder === null) { - $this->folder = call_user_func($this->folderClosure); - } - - return call_user_func_array([$this->folder, $method], $args); + return call_user_func_array([$this->getRealFolder(), $method], $args); } /** @@ -148,7 +158,7 @@ class LazyFolder implements Folder { * @inheritDoc */ public function get($path) { - return $this->__call(__FUNCTION__, func_get_args()); + return $this->getRootFolder()->get($this->getFullPath($path)); } /** @@ -207,6 +217,9 @@ class LazyFolder implements Folder { * @inheritDoc */ public function getId() { + if (isset($this->data['fileid'])) { + return $this->data['fileid']; + } return $this->__call(__FUNCTION__, func_get_args()); } @@ -221,6 +234,9 @@ class LazyFolder implements Folder { * @inheritDoc */ public function getMTime() { + if (isset($this->data['mtime'])) { + return $this->data['mtime']; + } return $this->__call(__FUNCTION__, func_get_args()); } @@ -228,6 +244,9 @@ class LazyFolder implements Folder { * @inheritDoc */ public function getSize($includeMounts = true): int|float { + if (isset($this->data['size'])) { + return $this->data['size']; + } return $this->__call(__FUNCTION__, func_get_args()); } @@ -235,6 +254,9 @@ class LazyFolder implements Folder { * @inheritDoc */ public function getEtag() { + if (isset($this->data['etag'])) { + return $this->data['etag']; + } return $this->__call(__FUNCTION__, func_get_args()); } @@ -299,6 +321,12 @@ class LazyFolder implements Folder { * @inheritDoc */ public function getName() { + if (isset($this->data['path'])) { + return basename($this->data['path']); + } + if (isset($this->data['name'])) { + return $this->data['name']; + } return $this->__call(__FUNCTION__, func_get_args()); } @@ -390,6 +418,13 @@ class LazyFolder implements Folder { * @inheritDoc */ public function getFullPath($path) { + if (isset($this->data['path'])) { + $path = PathHelper::normalizePath($path); + if (!Filesystem::isValidPath($path)) { + throw new NotPermittedException('Invalid path "' . $path . '"'); + } + return $this->data['path'] . $path; + } return $this->__call(__FUNCTION__, func_get_args()); } @@ -457,7 +492,11 @@ class LazyFolder implements Folder { * @inheritDoc */ public function getById($id) { - return $this->__call(__FUNCTION__, func_get_args()); + return $this->getRootFolder()->getByIdInPath((int)$id, $this->getPath()); + } + + public function getFirstNodeById(int $id): ?\OCP\Files\Node { + return $this->getRootFolder()->getFirstNodeByIdInPath($id, $this->getPath()); } /** @@ -533,4 +572,19 @@ class LazyFolder implements Folder { public function getRelativePath($path) { return PathHelper::getRelativePath($this->getPath(), $path); } + + public function getParentId(): int { + if (isset($this->data['parent'])) { + return $this->data['parent']; + } + return $this->__call(__FUNCTION__, func_get_args()); + } + + /** + * @inheritDoc + * @return array<string, int|string|bool|float|string[]|int[]> + */ + public function getMetadata(): array { + return $this->data['metadata'] ?? $this->__call(__FUNCTION__, func_get_args()); + } } diff --git a/lib/private/Files/Node/LazyRoot.php b/lib/private/Files/Node/LazyRoot.php index c01b9fdbb83..dd1596319fa 100644 --- a/lib/private/Files/Node/LazyRoot.php +++ b/lib/private/Files/Node/LazyRoot.php @@ -22,7 +22,11 @@ */ namespace OC\Files\Node; +use OCP\Files\Cache\ICacheEntry; use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountPoint; +use OCP\Files\Node; +use OCP\Files\Node as INode; /** * Class LazyRoot @@ -33,9 +37,18 @@ use OCP\Files\IRootFolder; * @package OC\Files\Node */ class LazyRoot extends LazyFolder implements IRootFolder { - /** - * @inheritDoc - */ + public function __construct(\Closure $folderClosure, array $data = []) { + parent::__construct($this, $folderClosure, $data); + } + + protected function getRootFolder(): IRootFolder { + $folder = $this->getRealFolder(); + if (!$folder instanceof IRootFolder) { + throw new \Exception('Lazy root folder closure didn\'t return a root folder'); + } + return $folder; + } + public function getUserFolder($userId) { return $this->__call(__FUNCTION__, func_get_args()); } @@ -43,4 +56,12 @@ class LazyRoot extends LazyFolder implements IRootFolder { public function getByIdInPath(int $id, string $path) { return $this->__call(__FUNCTION__, func_get_args()); } + + public function getFirstNodeByIdInPath(int $id, string $path): ?Node { + return $this->__call(__FUNCTION__, func_get_args()); + } + + public function getNodeFromCacheEntryAndMount(ICacheEntry $cacheEntry, IMountPoint $mountPoint): INode { + return $this->getRootFolder()->getNodeFromCacheEntryAndMount($cacheEntry, $mountPoint); + } } diff --git a/lib/private/Files/Node/LazyUserFolder.php b/lib/private/Files/Node/LazyUserFolder.php index 8fbdec4b49d..3cb840ccb6d 100644 --- a/lib/private/Files/Node/LazyUserFolder.php +++ b/lib/private/Files/Node/LazyUserFolder.php @@ -23,30 +23,28 @@ declare(strict_types=1); namespace OC\Files\Node; -use OCP\Files\FileInfo; use OCP\Constants; +use OCP\Files\File; +use OCP\Files\FileInfo; +use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountManager; use OCP\Files\NotFoundException; -use OCP\Files\Folder; -use OCP\Files\File; use OCP\IUser; use Psr\Log\LoggerInterface; class LazyUserFolder extends LazyFolder { - private IRootFolder $root; private IUser $user; private string $path; private IMountManager $mountManager; public function __construct(IRootFolder $rootFolder, IUser $user, IMountManager $mountManager) { - $this->root = $rootFolder; $this->user = $user; $this->mountManager = $mountManager; $this->path = '/' . $user->getUID() . '/files'; - parent::__construct(function () use ($user): Folder { + parent::__construct($rootFolder, function () use ($user): Folder { try { - $node = $this->root->get($this->path); + $node = $this->getRootFolder()->get($this->path); if ($node instanceof File) { $e = new \RuntimeException(); \OCP\Server::get(LoggerInterface::class)->error('User root storage is not a folder: ' . $this->path, [ @@ -56,31 +54,20 @@ class LazyUserFolder extends LazyFolder { } return $node; } catch (NotFoundException $e) { - if (!$this->root->nodeExists('/' . $user->getUID())) { - $this->root->newFolder('/' . $user->getUID()); + if (!$this->getRootFolder()->nodeExists('/' . $user->getUID())) { + $this->getRootFolder()->newFolder('/' . $user->getUID()); } - return $this->root->newFolder($this->path); + return $this->getRootFolder()->newFolder($this->path); } }, [ 'path' => $this->path, - 'permissions' => Constants::PERMISSION_ALL, + // Sharing user root folder is not allowed + 'permissions' => Constants::PERMISSION_ALL ^ Constants::PERMISSION_SHARE, 'type' => FileInfo::TYPE_FOLDER, 'mimetype' => FileInfo::MIMETYPE_FOLDER, ]); } - public function get($path) { - return $this->root->get('/' . $this->user->getUID() . '/files/' . ltrim($path, '/')); - } - - /** - * @param int $id - * @return \OCP\Files\Node[] - */ - public function getById($id) { - return $this->root->getByIdInPath((int)$id, $this->getPath()); - } - public function getMountPoint() { if ($this->folder !== null) { return $this->folder->getMountPoint(); diff --git a/lib/private/Files/Node/Node.php b/lib/private/Files/Node/Node.php index 61ae762638f..acd91c56d3f 100644 --- a/lib/private/Files/Node/Node.php +++ b/lib/private/Files/Node/Node.php @@ -7,6 +7,7 @@ * @author Christoph Wurst <christoph@winzerhof-wurst.at> * @author Joas Schilling <coding@schilljs.com> * @author Julius Härtl <jus@bitgrid.net> + * @author Maxence Lange <maxence@artificial-owl.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Roeland Jago Douma <roeland@famdouma.nl> @@ -43,7 +44,7 @@ use OCP\Files\NotPermittedException; use OCP\Lock\LockedException; use OCP\PreConditionNotMetException; -// FIXME: this class really should be abstract +// FIXME: this class really should be abstract (+1) class Node implements INode { /** * @var \OC\Files\View $view @@ -59,10 +60,7 @@ class Node implements INode { protected ?FileInfo $fileInfo; - /** - * @var Node|null - */ - protected $parent; + protected ?INode $parent; private bool $infoHasSubMountsIncluded; @@ -72,7 +70,7 @@ class Node implements INode { * @param string $path * @param FileInfo $fileInfo */ - public function __construct(IRootFolder $root, $view, $path, $fileInfo = null, ?Node $parent = null, bool $infoHasSubMountsIncluded = true) { + public function __construct(IRootFolder $root, $view, $path, $fileInfo = null, ?INode $parent = null, bool $infoHasSubMountsIncluded = true) { if (Filesystem::normalizePath($view->getRoot()) !== '/') { throw new PreConditionNotMetException('The view passed to the node should not have any fake root set'); } @@ -134,7 +132,14 @@ class Node implements INode { if (method_exists($this->root, 'emit')) { $this->root->emit('\OC\Files', $hook, $args); } - $dispatcher->dispatch('\OCP\Files::' . $hook, new GenericEvent($args)); + + if (in_array($hook, ['preWrite', 'postWrite', 'preCreate', 'postCreate', 'preTouch', 'postTouch', 'preDelete', 'postDelete'], true)) { + $event = new GenericEvent($args[0]); + } else { + $event = new GenericEvent($args); + } + + $dispatcher->dispatch('\OCP\Files::' . $hook, $event); } } @@ -300,7 +305,25 @@ class Node implements INode { return $this->root; } - $this->parent = $this->root->get($newPath); + // Manually fetch the parent if the current node doesn't have a file info yet + try { + $fileInfo = $this->getFileInfo(); + } catch (NotFoundException) { + $this->parent = $this->root->get($newPath); + /** @var \OCP\Files\Folder $this->parent */ + return $this->parent; + } + + // gather the metadata we already know about our parent + $parentData = [ + 'path' => $newPath, + 'fileid' => $fileInfo->getParentId(), + ]; + + // and create lazy folder with it instead of always querying + $this->parent = new LazyFolder($this->root, function () use ($newPath) { + return $this->root->get($newPath); + }, $parentData); } return $this->parent; @@ -328,13 +351,7 @@ class Node implements INode { * @return bool */ public function isValidPath($path) { - if (!$path || $path[0] !== '/') { - $path = '/' . $path; - } - if (strstr($path, '/../') || strrchr($path, '/') === '/..') { - return false; - } - return true; + return Filesystem::isValidPath($path); } public function isMounted() { @@ -477,4 +494,16 @@ class Node implements INode { public function getUploadTime(): int { return $this->getFileInfo()->getUploadTime(); } + + public function getParentId(): int { + return $this->fileInfo->getParentId(); + } + + /** + * @inheritDoc + * @return array<string, int|string|bool|float|string[]|int[]> + */ + public function getMetadata(): array { + return $this->fileInfo->getMetadata(); + } } diff --git a/lib/private/Files/Node/NonExistingFolder.php b/lib/private/Files/Node/NonExistingFolder.php index 34621b18f19..af0ad002f24 100644 --- a/lib/private/Files/Node/NonExistingFolder.php +++ b/lib/private/Files/Node/NonExistingFolder.php @@ -162,6 +162,10 @@ class NonExistingFolder extends Folder { throw new NotFoundException(); } + public function getFirstNodeById(int $id): ?\OCP\Files\Node { + throw new NotFoundException(); + } + public function getFreeSpace() { throw new NotFoundException(); } diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php index 7bd88981ff2..71bc7a6da6b 100644 --- a/lib/private/Files/Node/Root.php +++ b/lib/private/Files/Node/Root.php @@ -32,7 +32,6 @@ namespace OC\Files\Node; -use OCP\Cache\CappedMemoryCache; use OC\Files\FileInfo; use OC\Files\Mount\Manager; use OC\Files\Mount\MountPoint; @@ -40,7 +39,9 @@ use OC\Files\Utils\PathHelper; use OC\Files\View; use OC\Hooks\PublicEmitter; use OC\User\NoUserException; +use OCP\Cache\CappedMemoryCache; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Cache\ICacheEntry; use OCP\Files\Config\IUserMountCache; use OCP\Files\Events\Node\FilesystemTornDownEvent; use OCP\Files\IRootFolder; @@ -48,6 +49,8 @@ use OCP\Files\Mount\IMountPoint; use OCP\Files\Node as INode; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IUser; use OCP\IUserManager; use Psr\Log\LoggerInterface; @@ -80,6 +83,7 @@ class Root extends Folder implements IRootFolder { private LoggerInterface $logger; private IUserManager $userManager; private IEventDispatcher $eventDispatcher; + private ICache $pathByIdCache; /** * @param Manager $manager @@ -93,7 +97,8 @@ class Root extends Folder implements IRootFolder { IUserMountCache $userMountCache, LoggerInterface $logger, IUserManager $userManager, - IEventDispatcher $eventDispatcher + IEventDispatcher $eventDispatcher, + ICacheFactory $cacheFactory, ) { parent::__construct($this, $view, ''); $this->mountManager = $manager; @@ -106,6 +111,7 @@ class Root extends Folder implements IRootFolder { $eventDispatcher->addListener(FilesystemTornDownEvent::class, function () { $this->userFolderCache = new CappedMemoryCache(); }); + $this->pathByIdCache = $cacheFactory->createLocal('path-by-id'); } /** @@ -382,7 +388,7 @@ class Root extends Folder implements IRootFolder { try { $folder = $this->get('/' . $userId . '/files'); if (!$folder instanceof \OCP\Files\Folder) { - throw new \Exception("User folder for $userId exists as a file"); + throw new \Exception("Account folder for \"$userId\" exists as a file"); } } catch (NotFoundException $e) { if (!$this->nodeExists('/' . $userId)) { @@ -404,6 +410,31 @@ class Root extends Folder implements IRootFolder { return $this->userMountCache; } + public function getFirstNodeByIdInPath(int $id, string $path): ?INode { + // scope the cache by user, so we don't return nodes for different users + if ($this->user) { + $cachedPath = $this->pathByIdCache->get($this->user->getUID() . '::' . $id); + if ($cachedPath && str_starts_with($path, $cachedPath)) { + // getting the node by path is significantly cheaper than finding it by id + $node = $this->get($cachedPath); + // by validating that the cached path still has the requested fileid we can work around the need to invalidate the cached path + // if the cached path is invalid or a different file now we fall back to the uncached logic + if ($node && $node->getId() === $id) { + return $node; + } + } + } + $node = current($this->getByIdInPath($id, $path)); + if (!$node) { + return null; + } + + if ($this->user) { + $this->pathByIdCache->set($this->user->getUID() . '::' . $id, $node->getPath()); + } + return $node; + } + /** * @param int $id * @return Node[] @@ -487,4 +518,29 @@ class Root extends Folder implements IRootFolder { }); return $folders; } + + public function getNodeFromCacheEntryAndMount(ICacheEntry $cacheEntry, IMountPoint $mountPoint): INode { + $path = $cacheEntry->getPath(); + $fullPath = $mountPoint->getMountPoint() . $path; + // todo: LazyNode? + $info = new FileInfo($fullPath, $mountPoint->getStorage(), $path, $cacheEntry, $mountPoint); + $parentPath = dirname($fullPath); + $parent = new LazyFolder($this, function () use ($parentPath) { + $parent = $this->get($parentPath); + if ($parent instanceof \OCP\Files\Folder) { + return $parent; + } else { + throw new \Exception("parent $parentPath is not a folder"); + } + }, [ + 'path' => $parentPath, + ]); + $isDir = $info->getType() === FileInfo::TYPE_FOLDER; + $view = new View(''); + if ($isDir) { + return new Folder($this, $view, $path, $info, $parent); + } else { + return new File($this, $view, $path, $info, $parent); + } + } } diff --git a/lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php b/lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php index 2f6db935236..2c473cb6da9 100644 --- a/lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php @@ -26,9 +26,12 @@ declare(strict_types=1); namespace OC\Files\ObjectStore; class AppdataPreviewObjectStoreStorage extends ObjectStoreStorage { - /** @var string */ - private $internalId; + private string $internalId; + /** + * @param array $params + * @throws \Exception + */ public function __construct($params) { if (!isset($params['internal-id'])) { throw new \Exception('missing id in parameters'); @@ -37,7 +40,7 @@ class AppdataPreviewObjectStoreStorage extends ObjectStoreStorage { parent::__construct($params); } - public function getId() { + public function getId(): string { return 'object::appdata::preview:' . $this->internalId; } } diff --git a/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php b/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php index 824adcc1d0e..443c5147742 100644 --- a/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php @@ -7,6 +7,7 @@ * @author Jörn Friedrich Dreyer <jfd@butonic.de> * @author Morris Jobke <hey@morrisjobke.de> * @author Roeland Jago Douma <roeland@famdouma.nl> + * @author Thomas Citharel <nextcloud@tcit.fr> * * @license AGPL-3.0 * @@ -25,22 +26,28 @@ */ namespace OC\Files\ObjectStore; -use OC\User\User; +use Exception; +use OCP\Files\IHomeStorage; +use OCP\IUser; + +class HomeObjectStoreStorage extends ObjectStoreStorage implements IHomeStorage { + protected IUser $user; -class HomeObjectStoreStorage extends ObjectStoreStorage implements \OCP\Files\IHomeStorage { /** * The home user storage requires a user object to create a unique storage id + * * @param array $params + * @throws Exception */ public function __construct($params) { - if (! isset($params['user']) || ! $params['user'] instanceof User) { - throw new \Exception('missing user object in parameters'); + if (! isset($params['user']) || ! $params['user'] instanceof IUser) { + throw new Exception('missing user object in parameters'); } $this->user = $params['user']; parent::__construct($params); } - public function getId() { + public function getId(): string { return 'object::user:' . $this->user->getUID(); } @@ -48,20 +55,13 @@ class HomeObjectStoreStorage extends ObjectStoreStorage implements \OCP\Files\IH * get the owner of a path * * @param string $path The path to get the owner - * @return false|string uid + * @return string uid */ - public function getOwner($path) { - if (is_object($this->user)) { - return $this->user->getUID(); - } - return false; + public function getOwner($path): string { + return $this->user->getUID(); } - /** - * @param string $path, optional - * @return \OC\User\User - */ - public function getUser($path = null) { + public function getUser(): IUser { return $this->user; } } diff --git a/lib/private/Files/ObjectStore/ObjectStoreScanner.php b/lib/private/Files/ObjectStore/ObjectStoreScanner.php index f001f90fdaa..8a9b844c47f 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreScanner.php +++ b/lib/private/Files/ObjectStore/ObjectStoreScanner.php @@ -39,7 +39,7 @@ class ObjectStoreScanner extends Scanner { return []; } - protected function scanChildren(string $path, $recursive, int $reuse, int $folderId, bool $lock, int $oldSize) { + protected function scanChildren(string $path, $recursive, int $reuse, int $folderId, bool $lock, int|float $oldSize, &$etagChanged = false) { return 0; } diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index d918bd98729..7eb284fc774 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -47,30 +47,24 @@ use OCP\Files\ObjectStore\IObjectStore; use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload; use OCP\Files\Storage\IChunkedFileWrite; use OCP\Files\Storage\IStorage; +use Psr\Log\LoggerInterface; class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFileWrite { use CopyDirectory; - /** - * @var \OCP\Files\ObjectStore\IObjectStore $objectStore - */ - protected $objectStore; - /** - * @var string $id - */ - protected $id; - /** - * @var \OC\User\User $user - */ - protected $user; + protected IObjectStore $objectStore; + protected string $id; + private string $objectPrefix = 'urn:oid:'; - private $objectPrefix = 'urn:oid:'; + private LoggerInterface $logger; - private $logger; - - /** @var bool */ - protected $validateWrites = true; + private bool $handleCopiesAsOwned; + protected bool $validateWrites = true; + /** + * @param array $params + * @throws \Exception + */ public function __construct($params) { if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) { $this->objectStore = $params['objectstore']; @@ -88,8 +82,9 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil if (isset($params['validateWrites'])) { $this->validateWrites = (bool)$params['validateWrites']; } + $this->handleCopiesAsOwned = (bool)($params['handleCopiesAsOwned'] ?? false); - $this->logger = \OC::$server->getLogger(); + $this->logger = \OCP\Server::get(LoggerInterface::class); } public function mkdir($path, bool $force = false) { @@ -225,10 +220,13 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil $this->objectStore->deleteObject($this->getURN($entry->getId())); } catch (\Exception $ex) { if ($ex->getCode() !== 404) { - $this->logger->logException($ex, [ - 'app' => 'objectstore', - 'message' => 'Could not delete object ' . $this->getURN($entry->getId()) . ' for ' . $entry->getPath(), - ]); + $this->logger->error( + 'Could not delete object ' . $this->getURN($entry->getId()) . ' for ' . $entry->getPath(), + [ + 'app' => 'objectstore', + 'exception' => $ex, + ] + ); return false; } //removing from cache is ok as it does not exist in the objectstore anyway @@ -291,7 +289,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil return IteratorDirectory::wrap($files); } catch (\Exception $e) { - $this->logger->logException($e); + $this->logger->error($e->getMessage(), ['exception' => $e]); return false; } } @@ -341,16 +339,22 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil } return $handle; } catch (NotFoundException $e) { - $this->logger->logException($e, [ - 'app' => 'objectstore', - 'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path, - ]); + $this->logger->error( + 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path, + [ + 'app' => 'objectstore', + 'exception' => $e, + ] + ); throw $e; - } catch (\Exception $ex) { - $this->logger->logException($ex, [ - 'app' => 'objectstore', - 'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path, - ]); + } catch (\Exception $e) { + $this->logger->error( + 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path, + [ + 'app' => 'objectstore', + 'exception' => $e, + ] + ); return false; } } else { @@ -447,10 +451,13 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil ]; $this->getCache()->put($path, $stat); } catch (\Exception $ex) { - $this->logger->logException($ex, [ - 'app' => 'objectstore', - 'message' => 'Could not create object for ' . $path, - ]); + $this->logger->error( + 'Could not create object for ' . $path, + [ + 'app' => 'objectstore', + 'exception' => $ex, + ] + ); throw $ex; } } @@ -545,20 +552,28 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil * Else people lose access to existing files */ $this->getCache()->remove($uploadPath); - $this->logger->logException($ex, [ - 'app' => 'objectstore', - 'message' => 'Could not create object ' . $urn . ' for ' . $path, - ]); + $this->logger->error( + 'Could not create object ' . $urn . ' for ' . $path, + [ + 'app' => 'objectstore', + 'exception' => $ex, + ] + ); } else { - $this->logger->logException($ex, [ - 'app' => 'objectstore', - 'message' => 'Could not update object ' . $urn . ' for ' . $path, - ]); + $this->logger->error( + 'Could not update object ' . $urn . ' for ' . $path, + [ + 'app' => 'objectstore', + 'exception' => $ex, + ] + ); } throw $ex; // make this bubble up } if ($exists) { + // Always update the unencrypted size, for encryption the Encryption wrapper will update this afterwards anyways + $stat['unencrypted_size'] = $stat['size']; $this->getCache()->update($fileId, $stat); } else { if (!$this->validateWrites || $this->objectStore->objectExists($urn)) { @@ -649,6 +664,10 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil try { $this->objectStore->copyObject($sourceUrn, $targetUrn); + if ($this->handleCopiesAsOwned) { + // Copied the file thus we gain all permissions as we are the owner now ! warning while this aligns with local storage it should not be used and instead fix local storage ! + $cache->update($targetId, ['permissions' => \OCP\Constants::PERMISSION_ALL]); + } } catch (\Exception $e) { $cache->remove($to); @@ -712,10 +731,13 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil } } catch (S3MultipartUploadException|S3Exception $e) { $this->objectStore->abortMultipartUpload($urn, $writeToken); - $this->logger->logException($e, [ - 'app' => 'objectstore', - 'message' => 'Could not compete multipart upload ' . $urn . ' with uploadId ' . $writeToken, - ]); + $this->logger->error( + 'Could not compete multipart upload ' . $urn . ' with uploadId ' . $writeToken, + [ + 'app' => 'objectstore', + 'exception' => $e, + ] + ); throw new GenericFileException('Could not write chunked file'); } return $size; diff --git a/lib/private/Files/ObjectStore/S3ConnectionTrait.php b/lib/private/Files/ObjectStore/S3ConnectionTrait.php index deb03571c76..a1edfa1eb99 100644 --- a/lib/private/Files/ObjectStore/S3ConnectionTrait.php +++ b/lib/private/Files/ObjectStore/S3ConnectionTrait.php @@ -71,6 +71,11 @@ trait S3ConnectionTrait { /** @var int */ private $putSizeLimit; + /** @var int */ + private $copySizeLimit; + + private bool $useMultipartCopy = true; + protected $test; protected function parseParams($params) { @@ -87,12 +92,14 @@ trait S3ConnectionTrait { $this->storageClass = !empty($params['storageClass']) ? $params['storageClass'] : 'STANDARD'; $this->uploadPartSize = $params['uploadPartSize'] ?? 524288000; $this->putSizeLimit = $params['putSizeLimit'] ?? 104857600; + $this->copySizeLimit = $params['copySizeLimit'] ?? 5242880000; + $this->useMultipartCopy = (bool)($params['useMultipartCopy'] ?? true); $params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region']; $params['hostname'] = empty($params['hostname']) ? 's3.' . $params['region'] . '.amazonaws.com' : $params['hostname']; if (!isset($params['port']) || $params['port'] === '') { $params['port'] = (isset($params['use_ssl']) && $params['use_ssl'] === false) ? 80 : 443; } - $params['verify_bucket_exists'] = empty($params['verify_bucket_exists']) ? true : $params['verify_bucket_exists']; + $params['verify_bucket_exists'] = $params['verify_bucket_exists'] ?? true; $this->params = $params; } @@ -128,7 +135,7 @@ trait S3ConnectionTrait { ); $options = [ - 'version' => isset($this->params['version']) ? $this->params['version'] : 'latest', + 'version' => $this->params['version'] ?? 'latest', 'credentials' => $provider, 'endpoint' => $base_url, 'region' => $this->params['region'], diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php index e0d0f2ce9c7..623c4d08c74 100644 --- a/lib/private/Files/ObjectStore/S3ObjectTrait.php +++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php @@ -27,6 +27,7 @@ namespace OC\Files\ObjectStore; use Aws\S3\Exception\S3MultipartUploadException; +use Aws\S3\MultipartCopy; use Aws\S3\MultipartUploader; use Aws\S3\S3Client; use GuzzleHttp\Psr7; @@ -189,9 +190,31 @@ trait S3ObjectTrait { return $this->getConnection()->doesObjectExist($this->bucket, $urn, $this->getSSECParameters()); } - public function copyObject($from, $to) { - $this->getConnection()->copy($this->getBucket(), $from, $this->getBucket(), $to, 'private', [ - 'params' => $this->getSSECParameters() + $this->getSSECParameters(true) - ]); + public function copyObject($from, $to, array $options = []) { + $sourceMetadata = $this->getConnection()->headObject([ + 'Bucket' => $this->getBucket(), + 'Key' => $from, + ] + $this->getSSECParameters()); + + $size = (int)($sourceMetadata->get('Size') ?? $sourceMetadata->get('ContentLength')); + + if ($this->useMultipartCopy && $size > $this->copySizeLimit) { + $copy = new MultipartCopy($this->getConnection(), [ + "source_bucket" => $this->getBucket(), + "source_key" => $from + ], array_merge([ + "bucket" => $this->getBucket(), + "key" => $to, + "acl" => "private", + "params" => $this->getSSECParameters() + $this->getSSECParameters(true), + "source_metadata" => $sourceMetadata + ], $options)); + $copy->copy(); + } else { + $this->getConnection()->copy($this->getBucket(), $from, $this->getBucket(), $to, 'private', array_merge([ + 'params' => $this->getSSECParameters() + $this->getSSECParameters(true), + 'mup_threshold' => PHP_INT_MAX, + ], $options)); + } } } diff --git a/lib/private/Files/Search/QueryOptimizer/FlattenNestedBool.php b/lib/private/Files/Search/QueryOptimizer/FlattenNestedBool.php new file mode 100644 index 00000000000..c573e3af3c0 --- /dev/null +++ b/lib/private/Files/Search/QueryOptimizer/FlattenNestedBool.php @@ -0,0 +1,29 @@ +<?php + +namespace OC\Files\Search\QueryOptimizer; + +use OC\Files\Search\SearchBinaryOperator; +use OCP\Files\Search\ISearchBinaryOperator; +use OCP\Files\Search\ISearchOperator; + +class FlattenNestedBool extends QueryOptimizerStep { + public function processOperator(ISearchOperator &$operator) { + if ( + $operator instanceof SearchBinaryOperator && ( + $operator->getType() === ISearchBinaryOperator::OPERATOR_OR || + $operator->getType() === ISearchBinaryOperator::OPERATOR_AND + ) + ) { + $newArguments = []; + foreach ($operator->getArguments() as $oldArgument) { + if ($oldArgument instanceof SearchBinaryOperator && $oldArgument->getType() === $operator->getType()) { + $newArguments = array_merge($newArguments, $oldArgument->getArguments()); + } else { + $newArguments[] = $oldArgument; + } + } + $operator->setArguments($newArguments); + } + parent::processOperator($operator); + } +} diff --git a/lib/private/Files/Search/QueryOptimizer/FlattenSingleArgumentBinaryOperation.php b/lib/private/Files/Search/QueryOptimizer/FlattenSingleArgumentBinaryOperation.php new file mode 100644 index 00000000000..2c32f2e0174 --- /dev/null +++ b/lib/private/Files/Search/QueryOptimizer/FlattenSingleArgumentBinaryOperation.php @@ -0,0 +1,27 @@ +<?php + +namespace OC\Files\Search\QueryOptimizer; + +use OCP\Files\Search\ISearchBinaryOperator; +use OCP\Files\Search\ISearchOperator; + +/** + * replace single argument AND and OR operations with their single argument + */ +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 = $operator->getArguments()[0]; + return true; + } + return false; + } +} diff --git a/lib/private/Files/Search/QueryOptimizer/MergeDistributiveOperations.php b/lib/private/Files/Search/QueryOptimizer/MergeDistributiveOperations.php new file mode 100644 index 00000000000..7986df82adc --- /dev/null +++ b/lib/private/Files/Search/QueryOptimizer/MergeDistributiveOperations.php @@ -0,0 +1,95 @@ +<?php + +namespace OC\Files\Search\QueryOptimizer; + +use OC\Files\Search\SearchBinaryOperator; +use OC\Files\Search\SearchComparison; +use OCP\Files\Search\ISearchBinaryOperator; +use OCP\Files\Search\ISearchOperator; + +/** + * Attempt to transform + * + * (A AND B) OR (A AND C) OR (A AND D AND E) into A AND (B OR C OR (D AND E)) + * + * This is always valid because logical 'AND' and 'OR' are distributive[1]. + * + * [1]: https://en.wikipedia.org/wiki/Distributive_property + */ +class MergeDistributiveOperations extends ReplacingOptimizerStep { + public function processOperator(ISearchOperator &$operator): bool { + if ($operator instanceof SearchBinaryOperator) { + // either 'AND' or 'OR' + $topLevelType = $operator->getType(); + + // split the arguments into groups that share a first argument + $groups = $this->groupBinaryOperatorsByChild($operator->getArguments(), 0); + $outerOperations = array_map(function (array $operators) use ($topLevelType) { + // no common operations, no need to change anything + if (count($operators) === 1) { + return $operators[0]; + } + + // for groups with size >1 we know they are binary operators with at least 1 child + /** @var ISearchBinaryOperator $firstArgument */ + $firstArgument = $operators[0]; + + // we already checked that all arguments have the same type, so this type applies for all, either 'AND' or 'OR' + $innerType = $firstArgument->getType(); + + // the common operation we move out ('A' from the example) + $extractedLeftHand = $firstArgument->getArguments()[0]; + + // for each argument we remove the extracted operation to get the leftovers ('B', 'C' and '(D AND E)' in the example) + // note that we leave them inside the "inner" binary operation for when the "inner" operation contained more than two parts + // in the (common) case where the "inner" operation only has 1 item left it will be cleaned up in a follow up step + $rightHandArguments = array_map(function (ISearchOperator $inner) { + /** @var ISearchBinaryOperator $inner */ + $arguments = $inner->getArguments(); + array_shift($arguments); + if (count($arguments) === 1) { + return $arguments[0]; + } + return new SearchBinaryOperator($inner->getType(), $arguments); + }, $operators); + + // combine the extracted operation ('A') with the remaining bit ('(B OR C OR (D AND E))') + // note that because of how distribution work, we use the "outer" type "inside" and the "inside" type "outside". + $extractedRightHand = new SearchBinaryOperator($topLevelType, $rightHandArguments); + return new SearchBinaryOperator( + $innerType, + [$extractedLeftHand, $extractedRightHand] + ); + }, $groups); + + // combine all groups again + $operator = new SearchBinaryOperator($topLevelType, $outerOperations); + parent::processOperator($operator); + return true; + } + return parent::processOperator($operator); + } + + /** + * Group a list of binary search operators that have a common argument + * + * Non-binary operators, or empty binary operators will each get their own 1-sized group + * + * @param ISearchOperator[] $operators + * @return ISearchOperator[][] + */ + private function groupBinaryOperatorsByChild(array $operators, int $index = 0): array { + $result = []; + foreach ($operators as $operator) { + if ($operator instanceof ISearchBinaryOperator && count($operator->getArguments()) > 0) { + /** @var SearchBinaryOperator|SearchComparison $child */ + $child = $operator->getArguments()[$index]; + $childKey = (string)$child; + $result[$childKey][] = $operator; + } else { + $result[] = [$operator]; + } + } + return array_values($result); + } +} diff --git a/lib/private/Files/Search/QueryOptimizer/OrEqualsToIn.php b/lib/private/Files/Search/QueryOptimizer/OrEqualsToIn.php new file mode 100644 index 00000000000..d39eb2e29a9 --- /dev/null +++ b/lib/private/Files/Search/QueryOptimizer/OrEqualsToIn.php @@ -0,0 +1,70 @@ +<?php + +namespace OC\Files\Search\QueryOptimizer; + +use OC\Files\Search\SearchBinaryOperator; +use OC\Files\Search\SearchComparison; +use OCP\Files\Search\ISearchBinaryOperator; +use OCP\Files\Search\ISearchComparison; +use OCP\Files\Search\ISearchOperator; + +/** + * transform (field == A OR field == B ...) into field IN (A, B, ...) + */ +class OrEqualsToIn extends ReplacingOptimizerStep { + public function processOperator(ISearchOperator &$operator): bool { + if ( + $operator instanceof ISearchBinaryOperator && + $operator->getType() === ISearchBinaryOperator::OPERATOR_OR + ) { + $groups = $this->groupEqualsComparisonsByField($operator->getArguments()); + $newParts = array_map(function (array $group) { + if (count($group) > 1) { + // because of the logic from `groupEqualsComparisonsByField` we now that group is all comparisons on the same field + /** @var ISearchComparison[] $group */ + $field = $group[0]->getField(); + $values = array_map(function (ISearchComparison $comparison) { + /** @var string|integer|bool|\DateTime $value */ + $value = $comparison->getValue(); + return $value; + }, $group); + $in = new SearchComparison(ISearchComparison::COMPARE_IN, $field, $values); + $pathEqHash = array_reduce($group, function ($pathEqHash, ISearchComparison $comparison) { + return $comparison->getQueryHint(ISearchComparison::HINT_PATH_EQ_HASH, true) && $pathEqHash; + }, true); + $in->setQueryHint(ISearchComparison::HINT_PATH_EQ_HASH, $pathEqHash); + return $in; + } else { + return $group[0]; + } + }, $groups); + if (count($newParts) === 1) { + $operator = $newParts[0]; + } else { + $operator = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, $newParts); + } + parent::processOperator($operator); + return true; + } + parent::processOperator($operator); + return false; + } + + /** + * Non-equals operators are put in a separate group for each + * + * @param ISearchOperator[] $operators + * @return ISearchOperator[][] + */ + private function groupEqualsComparisonsByField(array $operators): array { + $result = []; + foreach ($operators as $operator) { + if ($operator instanceof ISearchComparison && $operator->getType() === ISearchComparison::COMPARE_EQUAL) { + $result[$operator->getField()][] = $operator; + } else { + $result[] = [$operator]; + } + } + return array_values($result); + } +} diff --git a/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php b/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php index 0caa9b12a02..664402f1238 100644 --- a/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php +++ b/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php @@ -4,6 +4,9 @@ declare(strict_types=1); /** * @copyright Copyright (c) 2021 Robin Appelman <robin@icewind.nl> * + * @author Maxence Lange <maxence@artificial-owl.com> + * @author Robin Appelman <robin@icewind.nl> + * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify @@ -48,7 +51,7 @@ class PathPrefixOptimizer extends QueryOptimizerStep { } public function processOperator(ISearchOperator &$operator) { - if (!$this->useHashEq && $operator instanceof ISearchComparison && $operator->getField() === 'path' && $operator->getType() === ISearchComparison::COMPARE_EQUAL) { + if (!$this->useHashEq && $operator instanceof ISearchComparison && !$operator->getExtra() && $operator->getField() === 'path' && $operator->getType() === ISearchComparison::COMPARE_EQUAL) { $operator->setQueryHint(ISearchComparison::HINT_PATH_EQ_HASH, false); } @@ -69,7 +72,7 @@ class PathPrefixOptimizer extends QueryOptimizerStep { private function operatorPairIsPathPrefix(ISearchOperator $like, ISearchOperator $equal): bool { return ( $like instanceof ISearchComparison && $equal instanceof ISearchComparison && - $like->getField() === 'path' && $equal->getField() === 'path' && + !$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/QueryOptimizer.php b/lib/private/Files/Search/QueryOptimizer/QueryOptimizer.php index 160b27b7f11..46d27e38081 100644 --- a/lib/private/Files/Search/QueryOptimizer/QueryOptimizer.php +++ b/lib/private/Files/Search/QueryOptimizer/QueryOptimizer.php @@ -29,15 +29,20 @@ class QueryOptimizer { /** @var QueryOptimizerStep[] */ private $steps = []; - public function __construct( - PathPrefixOptimizer $pathPrefixOptimizer - ) { + public function __construct() { + // note that the order here is relevant $this->steps = [ - $pathPrefixOptimizer + new PathPrefixOptimizer(), + new MergeDistributiveOperations(), + new FlattenSingleArgumentBinaryOperation(), + new FlattenNestedBool(), + new OrEqualsToIn(), + new FlattenNestedBool(), + new SplitLargeIn(), ]; } - public function processOperator(ISearchOperator $operator) { + public function processOperator(ISearchOperator &$operator) { foreach ($this->steps as $step) { $step->inspectOperator($operator); } diff --git a/lib/private/Files/Search/QueryOptimizer/ReplacingOptimizerStep.php b/lib/private/Files/Search/QueryOptimizer/ReplacingOptimizerStep.php new file mode 100644 index 00000000000..473f8a87151 --- /dev/null +++ b/lib/private/Files/Search/QueryOptimizer/ReplacingOptimizerStep.php @@ -0,0 +1,33 @@ +<?php + +namespace OC\Files\Search\QueryOptimizer; + +use OC\Files\Search\SearchBinaryOperator; +use OCP\Files\Search\ISearchOperator; + +/** + * Optimizer step that can replace the $operator altogether instead of just modifying it + * These steps need some extra logic to properly replace the arguments of binary operators + */ +class ReplacingOptimizerStep extends QueryOptimizerStep { + /** + * Allow optimizer steps to modify query operators + * + * Returns true if the reference $operator points to a new value + */ + public function processOperator(ISearchOperator &$operator): bool { + if ($operator instanceof SearchBinaryOperator) { + $modified = false; + $arguments = $operator->getArguments(); + foreach ($arguments as &$argument) { + if ($this->processOperator($argument)) { + $modified = true; + } + } + if ($modified) { + $operator->setArguments($arguments); + } + } + return false; + } +} diff --git a/lib/private/Files/Search/QueryOptimizer/SplitLargeIn.php b/lib/private/Files/Search/QueryOptimizer/SplitLargeIn.php new file mode 100644 index 00000000000..6f85037b3e9 --- /dev/null +++ b/lib/private/Files/Search/QueryOptimizer/SplitLargeIn.php @@ -0,0 +1,32 @@ +<?php + +namespace OC\Files\Search\QueryOptimizer; + +use OC\Files\Search\SearchBinaryOperator; +use OC\Files\Search\SearchComparison; +use OCP\Files\Search\ISearchBinaryOperator; +use OCP\Files\Search\ISearchComparison; +use OCP\Files\Search\ISearchOperator; + +/** + * transform IN (1000+ element) into (IN (1000 elements) OR IN(...)) + */ +class SplitLargeIn extends ReplacingOptimizerStep { + public function processOperator(ISearchOperator &$operator): bool { + if ( + $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) { + return new SearchComparison(ISearchComparison::COMPARE_IN, $operator->getField(), $values); + }, $chunks); + + $operator = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, $chunkComparisons); + return true; + } + parent::processOperator($operator); + return false; + } +} diff --git a/lib/private/Files/Search/SearchBinaryOperator.php b/lib/private/Files/Search/SearchBinaryOperator.php index d7bba8f1b4e..2b01ad58e5f 100644 --- a/lib/private/Files/Search/SearchBinaryOperator.php +++ b/lib/private/Files/Search/SearchBinaryOperator.php @@ -28,7 +28,7 @@ use OCP\Files\Search\ISearchOperator; class SearchBinaryOperator implements ISearchBinaryOperator { /** @var string */ private $type; - /** @var ISearchOperator[] */ + /** @var (SearchBinaryOperator|SearchComparison)[] */ private $arguments; private $hints = []; @@ -36,7 +36,7 @@ class SearchBinaryOperator implements ISearchBinaryOperator { * SearchBinaryOperator constructor. * * @param string $type - * @param ISearchOperator[] $arguments + * @param (SearchBinaryOperator|SearchComparison)[] $arguments */ public function __construct($type, array $arguments) { $this->type = $type; @@ -57,6 +57,14 @@ class SearchBinaryOperator implements ISearchBinaryOperator { return $this->arguments; } + /** + * @param ISearchOperator[] $arguments + * @return void + */ + public function setArguments(array $arguments): void { + $this->arguments = $arguments; + } + public function getQueryHint(string $name, $default) { return $this->hints[$name] ?? $default; } @@ -64,4 +72,11 @@ class SearchBinaryOperator implements ISearchBinaryOperator { public function setQueryHint(string $name, $value): void { $this->hints[$name] = $value; } + + public function __toString(): string { + if ($this->type === ISearchBinaryOperator::OPERATOR_NOT) { + return '(not ' . $this->arguments[0] . ')'; + } + return '(' . implode(' ' . $this->type . ' ', $this->arguments) . ')'; + } } diff --git a/lib/private/Files/Search/SearchComparison.php b/lib/private/Files/Search/SearchComparison.php index 122a1f730b4..b3c4832d776 100644 --- a/lib/private/Files/Search/SearchComparison.php +++ b/lib/private/Files/Search/SearchComparison.php @@ -1,7 +1,10 @@ <?php + +declare(strict_types=1); /** * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> * + * @author Maxence Lange <maxence@artificial-owl.com> * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version @@ -24,47 +27,45 @@ namespace OC\Files\Search; use OCP\Files\Search\ISearchComparison; +/** + * @psalm-import-type ParamValue from ISearchComparison + */ class SearchComparison implements ISearchComparison { - /** @var string */ - private $type; - /** @var string */ - private $field; - /** @var string|integer|\DateTime */ - private $value; - private $hints = []; + private array $hints = []; - /** - * SearchComparison constructor. - * - * @param string $type - * @param string $field - * @param \DateTime|int|string $value - */ - public function __construct($type, $field, $value) { - $this->type = $type; - $this->field = $field; - $this->value = $value; + public function __construct( + private string $type, + private string $field, + /** @var ParamValue $value */ + private \DateTime|int|string|bool|array $value, + private string $extra = '' + ) { } /** * @return string */ - public function getType() { + public function getType(): string { return $this->type; } /** * @return string */ - public function getField() { + public function getField(): string { return $this->field; } + public function getValue(): string|int|bool|\DateTime|array { + return $this->value; + } + /** - * @return \DateTime|int|string + * @return string + * @since 28.0.0 */ - public function getValue() { - return $this->value; + public function getExtra(): string { + return $this->extra; } public function getQueryHint(string $name, $default) { @@ -78,4 +79,8 @@ class SearchComparison implements ISearchComparison { public static function escapeLikeParameter(string $param): string { return addcslashes($param, '\\_%'); } + + public function __toString(): string { + return $this->field . ' ' . $this->type . ' ' . json_encode($this->value); + } } diff --git a/lib/private/Files/Search/SearchOrder.php b/lib/private/Files/Search/SearchOrder.php index 1395a87ac72..de514262bf5 100644 --- a/lib/private/Files/Search/SearchOrder.php +++ b/lib/private/Files/Search/SearchOrder.php @@ -2,6 +2,7 @@ /** * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> * + * @author Maxence Lange <maxence@artificial-owl.com> * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version @@ -26,34 +27,33 @@ use OCP\Files\FileInfo; use OCP\Files\Search\ISearchOrder; class SearchOrder implements ISearchOrder { - /** @var string */ - private $direction; - /** @var string */ - private $field; + public function __construct( + private string $direction, + private string $field, + private string $extra = '' + ) { + } /** - * SearchOrder constructor. - * - * @param string $direction - * @param string $field + * @return string */ - public function __construct($direction, $field) { - $this->direction = $direction; - $this->field = $field; + public function getDirection(): string { + return $this->direction; } /** * @return string */ - public function getDirection() { - return $this->direction; + public function getField(): string { + return $this->field; } /** * @return string + * @since 28.0.0 */ - public function getField() { - return $this->field; + public function getExtra(): string { + return $this->extra; } public function sortFileInfo(FileInfo $a, FileInfo $b): int { diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index b44ead003a8..93b7dc37b6b 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -24,8 +24,8 @@ declare(strict_types=1); namespace OC\Files; use OC\Files\Config\MountProviderCollection; +use OC\Files\Mount\HomeMountPoint; use OC\Files\Mount\MountPoint; -use OC\Files\ObjectStore\HomeObjectStoreStorage; use OC\Files\Storage\Common; use OC\Files\Storage\Home; use OC\Files\Storage\Storage; @@ -34,9 +34,15 @@ use OC\Files\Storage\Wrapper\Encoding; use OC\Files\Storage\Wrapper\PermissionsMask; use OC\Files\Storage\Wrapper\Quota; use OC\Lockdown\Filesystem\NullStorage; +use OC\Share\Share; +use OC\Share20\ShareDisableChecker; use OC_App; use OC_Hook; use OC_Util; +use OCA\Files_External\Config\ConfigAdapter; +use OCA\Files_Sharing\External\Mount; +use OCA\Files_Sharing\ISharedMountPoint; +use OCA\Files_Sharing\SharedMount; use OCP\Constants; use OCP\Diagnostics\IEventLogger; use OCP\EventDispatcher\IEventDispatcher; @@ -64,52 +70,35 @@ use Psr\Log\LoggerInterface; class SetupManager { private bool $rootSetup = false; - private IEventLogger $eventLogger; - private MountProviderCollection $mountProviderCollection; - private IMountManager $mountManager; - private IUserManager $userManager; // List of users for which at least one mount is setup private array $setupUsers = []; // List of users for which all mounts are setup private array $setupUsersComplete = []; /** @var array<string, string[]> */ private array $setupUserMountProviders = []; - private IEventDispatcher $eventDispatcher; - private IUserMountCache $userMountCache; - private ILockdownManager $lockdownManager; - private IUserSession $userSession; private ICache $cache; - private LoggerInterface $logger; - private IConfig $config; private bool $listeningForProviders; private array $fullSetupRequired = []; private bool $setupBuiltinWrappersDone = false; + private bool $forceFullSetup = false; public function __construct( - IEventLogger $eventLogger, - MountProviderCollection $mountProviderCollection, - IMountManager $mountManager, - IUserManager $userManager, - IEventDispatcher $eventDispatcher, - IUserMountCache $userMountCache, - ILockdownManager $lockdownManager, - IUserSession $userSession, + private IEventLogger $eventLogger, + private MountProviderCollection $mountProviderCollection, + private IMountManager $mountManager, + private IUserManager $userManager, + private IEventDispatcher $eventDispatcher, + private IUserMountCache $userMountCache, + private ILockdownManager $lockdownManager, + private IUserSession $userSession, ICacheFactory $cacheFactory, - LoggerInterface $logger, - IConfig $config + private LoggerInterface $logger, + private IConfig $config, + private ShareDisableChecker $shareDisableChecker, ) { - $this->eventLogger = $eventLogger; - $this->mountProviderCollection = $mountProviderCollection; - $this->mountManager = $mountManager; - $this->userManager = $userManager; - $this->eventDispatcher = $eventDispatcher; - $this->userMountCache = $userMountCache; - $this->lockdownManager = $lockdownManager; - $this->logger = $logger; - $this->userSession = $userSession; $this->cache = $cacheFactory->createDistributed('setupmanager::'); $this->listeningForProviders = false; - $this->config = $config; + $this->forceFullSetup = $this->config->getSystemValueBool('debug.force-full-fs-setup'); $this->setupListeners(); } @@ -133,52 +122,55 @@ class SetupManager { $prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false); Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) { - if ($storage->instanceOfStorage(Common::class)) { + if ($mount->getOptions() && $storage->instanceOfStorage(Common::class)) { $storage->setMountOptions($mount->getOptions()); } return $storage; }); - Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, IStorage $storage, IMountPoint $mount) { - if (!$mount->getOption('enable_sharing', true)) { - return new PermissionsMask([ - 'storage' => $storage, - 'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE, - ]); + $reSharingEnabled = Share::isResharingAllowed(); + $user = $this->userSession->getUser(); + $sharingEnabledForUser = $user ? !$this->shareDisableChecker->sharingDisabledForUser($user->getUID()) : true; + Filesystem::addStorageWrapper( + 'sharing_mask', + function ($mountPoint, IStorage $storage, IMountPoint $mount) use ($reSharingEnabled, $sharingEnabledForUser) { + $sharingEnabledForMount = $mount->getOption('enable_sharing', true); + $isShared = $mount instanceof ISharedMountPoint; + if (!$sharingEnabledForMount || !$sharingEnabledForUser || (!$reSharingEnabled && $isShared)) { + return new PermissionsMask([ + 'storage' => $storage, + 'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE, + ]); + } + return $storage; } - return $storage; - }); + ); // install storage availability wrapper, before most other wrappers - Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage) { - if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) { + Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage, IMountPoint $mount) { + $externalMount = $mount instanceof ConfigAdapter || $mount instanceof Mount; + if ($externalMount && !$storage->isLocal()) { return new Availability(['storage' => $storage]); } return $storage; }); Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) { - if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { + if ($mount->getOption('encoding_compatibility', false) && !$mount instanceof SharedMount) { return new Encoding(['storage' => $storage]); } return $storage; }); $quotaIncludeExternal = $this->config->getSystemValue('quota_include_external_storage', false); - Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) use ($quotaIncludeExternal) { + Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage, IMountPoint $mount) use ($quotaIncludeExternal) { // set up quota for home storages, even for other users // which can happen when using sharing - - /** - * @var Storage $storage - */ - if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) { - if (is_object($storage->getUser())) { - $user = $storage->getUser(); - return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) { - return OC_Util::getUserQuota($user); - }, 'root' => 'files', 'include_external_storage' => $quotaIncludeExternal]); - } + if ($mount instanceof HomeMountPoint) { + $user = $mount->getUser(); + return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) { + return OC_Util::getUserQuota($user); + }, 'root' => 'files', 'include_external_storage' => $quotaIncludeExternal]); } return $storage; @@ -345,12 +337,13 @@ class SetupManager { if ($this->rootSetup) { return; } + + $this->setupBuiltinWrappers(); + $this->rootSetup = true; $this->eventLogger->start('fs:setup:root', 'Setup root filesystem'); - $this->setupBuiltinWrappers(); - $rootMounts = $this->mountProviderCollection->getRootMounts(); foreach ($rootMounts as $rootMountProvider) { $this->mountManager->addMount($rootMountProvider); @@ -479,6 +472,10 @@ class SetupManager { } private function fullSetupRequired(IUser $user): bool { + if ($this->forceFullSetup) { + return true; + } + // we perform a "cached" setup only after having done the full setup recently // this is also used to trigger a full setup after handling events that are likely // to change the available mounts diff --git a/lib/private/Files/SetupManagerFactory.php b/lib/private/Files/SetupManagerFactory.php index 1d9efbd411f..8589cbdea42 100644 --- a/lib/private/Files/SetupManagerFactory.php +++ b/lib/private/Files/SetupManagerFactory.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace OC\Files; +use OC\Share20\ShareDisableChecker; use OCP\Diagnostics\IEventLogger; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IMountProviderCollection; @@ -36,40 +37,21 @@ use OCP\Lockdown\ILockdownManager; use Psr\Log\LoggerInterface; class SetupManagerFactory { - private IEventLogger $eventLogger; - private IMountProviderCollection $mountProviderCollection; - private IUserManager $userManager; - private IEventDispatcher $eventDispatcher; - private IUserMountCache $userMountCache; - private ILockdownManager $lockdownManager; - private IUserSession $userSession; private ?SetupManager $setupManager; - private ICacheFactory $cacheFactory; - private LoggerInterface $logger; - private IConfig $config; public function __construct( - IEventLogger $eventLogger, - IMountProviderCollection $mountProviderCollection, - IUserManager $userManager, - IEventDispatcher $eventDispatcher, - IUserMountCache $userMountCache, - ILockdownManager $lockdownManager, - IUserSession $userSession, - ICacheFactory $cacheFactory, - LoggerInterface $logger, - IConfig $config + private IEventLogger $eventLogger, + private IMountProviderCollection $mountProviderCollection, + private IUserManager $userManager, + private IEventDispatcher $eventDispatcher, + private IUserMountCache $userMountCache, + private ILockdownManager $lockdownManager, + private IUserSession $userSession, + private ICacheFactory $cacheFactory, + private LoggerInterface $logger, + private IConfig $config, + private ShareDisableChecker $shareDisableChecker, ) { - $this->eventLogger = $eventLogger; - $this->mountProviderCollection = $mountProviderCollection; - $this->userManager = $userManager; - $this->eventDispatcher = $eventDispatcher; - $this->userMountCache = $userMountCache; - $this->lockdownManager = $lockdownManager; - $this->userSession = $userSession; - $this->cacheFactory = $cacheFactory; - $this->logger = $logger; - $this->config = $config; $this->setupManager = null; } @@ -86,7 +68,8 @@ class SetupManagerFactory { $this->userSession, $this->cacheFactory, $this->logger, - $this->config + $this->config, + $this->shareDisableChecker, ); } return $this->setupManager; diff --git a/lib/private/Files/SimpleFS/SimpleFolder.php b/lib/private/Files/SimpleFS/SimpleFolder.php index 4d24aa138c1..2c1f23f8e44 100644 --- a/lib/private/Files/SimpleFS/SimpleFolder.php +++ b/lib/private/Files/SimpleFS/SimpleFolder.php @@ -28,8 +28,8 @@ use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\Node; use OCP\Files\NotFoundException; -use OCP\Files\SimpleFS\ISimpleFolder; use OCP\Files\SimpleFS\ISimpleFile; +use OCP\Files\SimpleFS\ISimpleFolder; class SimpleFolder implements ISimpleFolder { /** @var Folder */ diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php index 5ab411434d0..0d4e8d29295 100644 --- a/lib/private/Files/Storage/Common.php +++ b/lib/private/Files/Storage/Common.php @@ -43,6 +43,7 @@ namespace OC\Files\Storage; use OC\Files\Cache\Cache; +use OC\Files\Cache\CacheDependencies; use OC\Files\Cache\Propagator; use OC\Files\Cache\Scanner; use OC\Files\Cache\Updater; @@ -61,8 +62,10 @@ use OCP\Files\ReservedWordException; use OCP\Files\Storage\ILockingStorage; use OCP\Files\Storage\IStorage; use OCP\Files\Storage\IWriteStreamStorage; +use OCP\Files\StorageNotAvailableException; use OCP\Lock\ILockingProvider; use OCP\Lock\LockedException; +use OCP\Server; use Psr\Log\LoggerInterface; /** @@ -338,12 +341,20 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { return $this->filemtime($path) > $time; } + protected function getCacheDependencies(): CacheDependencies { + static $dependencies = null; + if (!$dependencies) { + $dependencies = Server::get(CacheDependencies::class); + } + return $dependencies; + } + public function getCache($path = '', $storage = null) { if (!$storage) { $storage = $this; } if (!isset($storage->cache)) { - $storage->cache = new Cache($storage); + $storage->cache = new Cache($storage, $this->getCacheDependencies()); } return $storage->cache; } @@ -398,13 +409,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { } public function getStorageCache($storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($this->storageCache)) { - $this->storageCache = new \OC\Files\Cache\Storage($storage); - } - return $this->storageCache; + return $this->getCache($storage)->getStorageCache(); } /** @@ -562,7 +567,9 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { * @throws InvalidPathException */ protected function verifyPosixPath($fileName) { - $this->scanForInvalidCharacters($fileName, "\\/"); + $invalidChars = \OCP\Util::getForbiddenFileNameChars(); + $this->scanForInvalidCharacters($fileName, $invalidChars); + $fileName = trim($fileName); $reservedNames = ['*']; if (in_array($fileName, $reservedNames)) { @@ -572,11 +579,11 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { /** * @param string $fileName - * @param string $invalidChars + * @param string[] $invalidChars * @throws InvalidPathException */ - private function scanForInvalidCharacters($fileName, $invalidChars) { - foreach (str_split($invalidChars) as $char) { + private function scanForInvalidCharacters(string $fileName, array $invalidChars) { + foreach ($invalidChars as $char) { if (str_contains($fileName, $char)) { throw new InvalidCharacterInPathException(); } @@ -601,7 +608,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { * @return mixed */ public function getMountOption($name, $default = null) { - return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default; + return $this->mountOptions[$name] ?? $default; } /** @@ -663,7 +670,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { private function isSameStorage(IStorage $storage): bool { while ($storage->instanceOfStorage(Wrapper::class)) { /** - * @var Wrapper $sourceStorage + * @var Wrapper $storage */ $storage = $storage->getWrapperStorage(); } @@ -894,6 +901,11 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { public function getDirectoryContent($directory): \Traversable { $dh = $this->opendir($directory); + + if ($dh === false) { + throw new StorageNotAvailableException('Directory listing failed'); + } + if (is_resource($dh)) { $basePath = rtrim($directory, '/'); while (($file = readdir($dh)) !== false) { diff --git a/lib/private/Files/Storage/DAV.php b/lib/private/Files/Storage/DAV.php index 70f22a17034..e5bbbb560da 100644 --- a/lib/private/Files/Storage/DAV.php +++ b/lib/private/Files/Storage/DAV.php @@ -55,11 +55,11 @@ use OCP\ICertificateManager; use OCP\IConfig; use OCP\Util; use Psr\Http\Message\ResponseInterface; +use Psr\Log\LoggerInterface; use Sabre\DAV\Client; use Sabre\DAV\Xml\Property\ResourceType; use Sabre\HTTP\ClientException; use Sabre\HTTP\ClientHttpException; -use Psr\Log\LoggerInterface; use Sabre\HTTP\RequestInterface; /** @@ -120,9 +120,9 @@ class DAV extends Common { if (isset($params['host']) && isset($params['user']) && isset($params['password'])) { $host = $params['host']; //remove leading http[s], will be generated in createBaseUri() - if (substr($host, 0, 8) == "https://") { + if (str_starts_with($host, "https://")) { $host = substr($host, 8); - } elseif (substr($host, 0, 7) == "http://") { + } elseif (str_starts_with($host, "http://")) { $host = substr($host, 7); } $this->host = $host; @@ -921,7 +921,7 @@ class DAV extends Common { } foreach ($responses as $file => $response) { - $file = urldecode($file); + $file = rawurldecode($file); $file = substr($file, strlen($this->root)); $file = $this->cleanPath($file); $this->statCache->set($file, $response); diff --git a/lib/private/Files/Storage/Home.php b/lib/private/Files/Storage/Home.php index 5427bc425c2..051652b7562 100644 --- a/lib/private/Files/Storage/Home.php +++ b/lib/private/Files/Storage/Home.php @@ -26,6 +26,7 @@ namespace OC\Files\Storage; use OC\Files\Cache\HomePropagator; +use OCP\IUser; /** * Specialized version of Local storage for home directory usage @@ -67,7 +68,7 @@ class Home extends Local implements \OCP\Files\IHomeStorage { $storage = $this; } if (!isset($this->cache)) { - $this->cache = new \OC\Files\Cache\HomeCache($storage); + $this->cache = new \OC\Files\Cache\HomeCache($storage, $this->getCacheDependencies()); } return $this->cache; } @@ -94,7 +95,7 @@ class Home extends Local implements \OCP\Files\IHomeStorage { * * @return \OC\User\User owner of this home storage */ - public function getUser() { + public function getUser(): IUser { return $this->user; } diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php index 02708ed4f7d..c49cf91dc91 100644 --- a/lib/private/Files/Storage/Local.php +++ b/lib/private/Files/Storage/Local.php @@ -51,6 +51,7 @@ use OCP\Files\ForbiddenException; use OCP\Files\GenericFileException; use OCP\Files\IMimeTypeDetector; use OCP\Files\Storage\IStorage; +use OCP\Files\StorageNotAvailableException; use OCP\IConfig; use OCP\Util; use Psr\Log\LoggerInterface; @@ -73,6 +74,8 @@ class Local extends \OC\Files\Storage\Common { protected bool $unlinkOnTruncate; + protected bool $caseInsensitive = false; + public function __construct($arguments) { if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) { throw new \InvalidArgumentException('No data directory set for local storage'); @@ -85,16 +88,23 @@ class Local extends \OC\Files\Storage\Common { $realPath = realpath($this->datadir) ?: $this->datadir; $this->realDataDir = rtrim($realPath, '/') . '/'; } - if (substr($this->datadir, -1) !== '/') { + if (!str_ends_with($this->datadir, '/')) { $this->datadir .= '/'; } $this->dataDirLength = strlen($this->realDataDir); $this->config = \OC::$server->get(IConfig::class); $this->mimeTypeDetector = \OC::$server->get(IMimeTypeDetector::class); $this->defUMask = $this->config->getSystemValue('localstorage.umask', 0022); + $this->caseInsensitive = $this->config->getSystemValueBool('localstorage.case_insensitive', false); // support Write-Once-Read-Many file systems $this->unlinkOnTruncate = $this->config->getSystemValueBool('localstorage.unlink_on_truncate', false); + + if (isset($arguments['isExternal']) && $arguments['isExternal'] && !$this->stat('')) { + // data dir not accessible or available, can happen when using an external storage of type Local + // on an unmounted system mount point + throw new StorageNotAvailableException('Local storage path does not exist "' . $this->getSourcePath('') . '"'); + } } public function __destruct() { @@ -155,13 +165,19 @@ class Local extends \OC\Files\Storage\Common { } public function is_dir($path) { - if (substr($path, -1) == '/') { + if ($this->caseInsensitive && !$this->file_exists($path)) { + return false; + } + if (str_ends_with($path, '/')) { $path = substr($path, 0, -1); } return is_dir($this->getSourcePath($path)); } public function is_file($path) { + if ($this->caseInsensitive && !$this->file_exists($path)) { + return false; + } return is_file($this->getSourcePath($path)); } @@ -264,7 +280,17 @@ class Local extends \OC\Files\Storage\Common { } public function file_exists($path) { - return file_exists($this->getSourcePath($path)); + if ($this->caseInsensitive) { + $fullPath = $this->getSourcePath($path); + $parentPath = dirname($fullPath); + if (!is_dir($parentPath)) { + return false; + } + $content = scandir($parentPath, SCANDIR_SORT_NONE); + return is_array($content) && array_search(basename($fullPath), $content) !== false; + } else { + return file_exists($this->getSourcePath($path)); + } } public function filemtime($path) { @@ -365,6 +391,11 @@ class Local extends \OC\Files\Storage\Common { } if (@rename($this->getSourcePath($source), $this->getSourcePath($target))) { + if ($this->caseInsensitive) { + if (mb_strtolower($target) === mb_strtolower($source) && !$this->file_exists($target)) { + return false; + } + } return true; } @@ -381,6 +412,11 @@ class Local extends \OC\Files\Storage\Common { } $result = copy($this->getSourcePath($source), $this->getSourcePath($target)); umask($oldMask); + if ($this->caseInsensitive) { + if (mb_strtolower($target) === mb_strtolower($source) && !$this->file_exists($target)) { + return false; + } + } return $result; } } diff --git a/lib/private/Files/Storage/Wrapper/Encoding.php b/lib/private/Files/Storage/Wrapper/Encoding.php index 6633cbf41e3..1bdb0e39f14 100644 --- a/lib/private/Files/Storage/Wrapper/Encoding.php +++ b/lib/private/Files/Storage/Wrapper/Encoding.php @@ -28,8 +28,8 @@ */ namespace OC\Files\Storage\Wrapper; -use OCP\Cache\CappedMemoryCache; use OC\Files\Filesystem; +use OCP\Cache\CappedMemoryCache; use OCP\Files\Storage\IStorage; use OCP\ICache; diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index a27f499a210..7ce4338256f 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -100,6 +100,8 @@ class Encryption extends Wrapper { /** @var CappedMemoryCache<bool> */ private CappedMemoryCache $encryptedPaths; + private $enabled = true; + /** * @param array $parameters */ @@ -392,6 +394,10 @@ class Encryption extends Wrapper { return $this->storage->fopen($path, $mode); } + if (!$this->enabled) { + return $this->storage->fopen($path, $mode); + } + $encryptionEnabled = $this->encryptionManager->isEnabled(); $shouldEncrypt = false; $encryptionModule = null; @@ -938,34 +944,6 @@ class Encryption extends Wrapper { } /** - * parse raw header to array - * - * @param string $rawHeader - * @return array - */ - protected function parseRawHeader($rawHeader) { - $result = []; - if (str_starts_with($rawHeader, Util::HEADER_START)) { - $header = $rawHeader; - $endAt = strpos($header, Util::HEADER_END); - if ($endAt !== false) { - $header = substr($header, 0, $endAt + strlen(Util::HEADER_END)); - - // +1 to not start with an ':' which would result in empty element at the beginning - $exploded = explode(':', substr($header, strlen(Util::HEADER_START) + 1)); - - $element = array_shift($exploded); - while ($element !== Util::HEADER_END) { - $result[$element] = array_shift($exploded); - $element = array_shift($exploded); - } - } - } - - return $result; - } - - /** * read header from file * * @param string $path @@ -988,7 +966,7 @@ class Encryption extends Wrapper { if ($isEncrypted) { $firstBlock = $this->readFirstBlock($path); - $result = $this->parseRawHeader($firstBlock); + $result = $this->util->parseRawHeader($firstBlock); // if the header doesn't contain a encryption module we check if it is a // legacy file. If true, we add the default encryption module @@ -1093,7 +1071,7 @@ class Encryption extends Wrapper { // object store, stores the size after write and doesn't update this during scan // manually store the unencrypted size - if ($result && $this->getWrapperStorage()->instanceOfStorage(ObjectStoreStorage::class)) { + if ($result && $this->getWrapperStorage()->instanceOfStorage(ObjectStoreStorage::class) && $this->shouldEncrypt($path)) { $this->getCache()->put($path, ['unencrypted_size' => $count]); } @@ -1103,4 +1081,14 @@ class Encryption extends Wrapper { public function clearIsEncryptedCache(): void { $this->encryptedPaths->clear(); } + + /** + * Allow temporarily disabling the wrapper + * + * @param bool $enabled + * @return void + */ + public function setEnabled(bool $enabled): void { + $this->enabled = $enabled; + } } diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php index 1921ac27848..592acd418ec 100644 --- a/lib/private/Files/Storage/Wrapper/Jail.php +++ b/lib/private/Files/Storage/Wrapper/Jail.php @@ -396,10 +396,7 @@ class Jail extends Wrapper { * @return \OC\Files\Cache\Cache */ public function getCache($path = '', $storage = null) { - if (!$storage) { - $storage = $this->getWrapperStorage(); - } - $sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path), $storage); + $sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path)); return new CacheJail($sourceCache, $this->rootPath); } diff --git a/lib/private/Files/Storage/Wrapper/KnownMtime.php b/lib/private/Files/Storage/Wrapper/KnownMtime.php new file mode 100644 index 00000000000..dde209c44ab --- /dev/null +++ b/lib/private/Files/Storage/Wrapper/KnownMtime.php @@ -0,0 +1,142 @@ +<?php + +namespace OC\Files\Storage\Wrapper; + +use OCP\Cache\CappedMemoryCache; +use OCP\Files\Storage\IStorage; +use Psr\Clock\ClockInterface; + +/** + * Wrapper that overwrites the mtime return by stat/getMetaData if the returned value + * is lower than when we last modified the file. + * + * This is useful because some storage servers can return an outdated mtime right after writes + */ +class KnownMtime extends Wrapper { + private CappedMemoryCache $knowMtimes; + private ClockInterface $clock; + + public function __construct($arguments) { + parent::__construct($arguments); + $this->knowMtimes = new CappedMemoryCache(); + $this->clock = $arguments['clock']; + } + + public function file_put_contents($path, $data) { + $result = parent::file_put_contents($path, $data); + if ($result) { + $now = $this->clock->now()->getTimestamp(); + $this->knowMtimes->set($path, $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function stat($path) { + $stat = parent::stat($path); + if ($stat) { + $this->applyKnownMtime($path, $stat); + } + return $stat; + } + + public function getMetaData($path) { + $stat = parent::getMetaData($path); + if ($stat) { + $this->applyKnownMtime($path, $stat); + } + return $stat; + } + + private function applyKnownMtime(string $path, array &$stat) { + if (isset($stat['mtime'])) { + $knownMtime = $this->knowMtimes->get($path) ?? 0; + $stat['mtime'] = max($stat['mtime'], $knownMtime); + } + } + + public function filemtime($path) { + $knownMtime = $this->knowMtimes->get($path) ?? 0; + return max(parent::filemtime($path), $knownMtime); + } + + public function mkdir($path) { + $result = parent::mkdir($path); + if ($result) { + $this->knowMtimes->set($path, $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function rmdir($path) { + $result = parent::rmdir($path); + if ($result) { + $this->knowMtimes->set($path, $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function unlink($path) { + $result = parent::unlink($path); + if ($result) { + $this->knowMtimes->set($path, $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function rename($source, $target) { + $result = parent::rename($source, $target); + if ($result) { + $this->knowMtimes->set($target, $this->clock->now()->getTimestamp()); + $this->knowMtimes->set($source, $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function copy($source, $target) { + $result = parent::copy($source, $target); + if ($result) { + $this->knowMtimes->set($target, $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function fopen($path, $mode) { + $result = parent::fopen($path, $mode); + if ($result && $mode === 'w') { + $this->knowMtimes->set($path, $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function touch($path, $mtime = null) { + $result = parent::touch($path, $mtime); + if ($result) { + $this->knowMtimes->set($path, $mtime ?? $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + $result = parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); + if ($result) { + $this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + $result = parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); + if ($result) { + $this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp()); + } + return $result; + } + + public function writeStream(string $path, $stream, int $size = null): int { + $result = parent::writeStream($path, $stream, $size); + if ($result) { + $this->knowMtimes->set($path, $this->clock->now()->getTimestamp()); + } + return $result; + } +} diff --git a/lib/private/Files/Storage/Wrapper/PermissionsMask.php b/lib/private/Files/Storage/Wrapper/PermissionsMask.php index 0d140e0a39d..a79eaad0569 100644 --- a/lib/private/Files/Storage/Wrapper/PermissionsMask.php +++ b/lib/private/Files/Storage/Wrapper/PermissionsMask.php @@ -140,7 +140,7 @@ class PermissionsMask extends Wrapper { $data = parent::getMetaData($path); if ($data && isset($data['permissions'])) { - $data['scan_permissions'] = isset($data['scan_permissions']) ? $data['scan_permissions'] : $data['permissions']; + $data['scan_permissions'] = $data['scan_permissions'] ?? $data['permissions']; $data['permissions'] &= $this->mask; } return $data; @@ -155,7 +155,7 @@ class PermissionsMask extends Wrapper { public function getDirectoryContent($directory): \Traversable { foreach ($this->getWrapperStorage()->getDirectoryContent($directory) as $data) { - $data['scan_permissions'] = isset($data['scan_permissions']) ? $data['scan_permissions'] : $data['permissions']; + $data['scan_permissions'] = $data['scan_permissions'] ?? $data['permissions']; $data['permissions'] &= $this->mask; yield $data; diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php index 9f5564b4490..665914df2a7 100644 --- a/lib/private/Files/Storage/Wrapper/Wrapper.php +++ b/lib/private/Files/Storage/Wrapper/Wrapper.php @@ -654,4 +654,15 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea public function getDirectoryContent($directory): \Traversable { return $this->getWrapperStorage()->getDirectoryContent($directory); } + + public function isWrapperOf(IStorage $storage) { + $wrapped = $this->getWrapperStorage(); + if ($wrapped === $storage) { + return true; + } + if ($wrapped instanceof Wrapper) { + return $wrapped->isWrapperOf($storage); + } + return false; + } } diff --git a/lib/private/Files/Stream/Encryption.php b/lib/private/Files/Stream/Encryption.php index bcf0a10740b..c57991f35a9 100644 --- a/lib/private/Files/Stream/Encryption.php +++ b/lib/private/Files/Stream/Encryption.php @@ -153,18 +153,18 @@ class Encryption extends Wrapper { * @throws \BadMethodCallException */ public static function wrap($source, $internalPath, $fullPath, array $header, - $uid, - \OCP\Encryption\IEncryptionModule $encryptionModule, - \OC\Files\Storage\Storage $storage, - \OC\Files\Storage\Wrapper\Encryption $encStorage, - \OC\Encryption\Util $util, - \OC\Encryption\File $file, - $mode, - $size, - $unencryptedSize, - $headerSize, - $signed, - $wrapper = Encryption::class) { + $uid, + \OCP\Encryption\IEncryptionModule $encryptionModule, + \OC\Files\Storage\Storage $storage, + \OC\Files\Storage\Wrapper\Encryption $encStorage, + \OC\Encryption\Util $util, + \OC\Encryption\File $file, + $mode, + $size, + $unencryptedSize, + $headerSize, + $signed, + $wrapper = Encryption::class) { $context = stream_context_create([ 'ocencryption' => [ 'source' => $source, diff --git a/lib/private/Files/Template/TemplateManager.php b/lib/private/Files/Template/TemplateManager.php index bf72e9e23e8..9d9f6416208 100644 --- a/lib/private/Files/Template/TemplateManager.php +++ b/lib/private/Files/Template/TemplateManager.php @@ -31,8 +31,8 @@ use OC\AppFramework\Bootstrap\Coordinator; use OC\Files\Cache\Scanner; use OC\Files\Filesystem; use OCP\EventDispatcher\IEventDispatcher; -use OCP\Files\Folder; use OCP\Files\File; +use OCP\Files\Folder; use OCP\Files\GenericFileException; use OCP\Files\IRootFolder; use OCP\Files\Node; @@ -240,7 +240,8 @@ class TemplateManager implements ITemplateManager { 'mime' => $file->getMimetype(), 'size' => $file->getSize(), 'type' => $file->getType(), - 'hasPreview' => $this->previewManager->isAvailable($file) + 'hasPreview' => $this->previewManager->isAvailable($file), + 'permissions' => $file->getPermissions(), ]; } @@ -274,6 +275,11 @@ class TemplateManager implements ITemplateManager { $isDefaultTemplates = $skeletonTemplatePath === $defaultTemplateDirectory; $userLang = $this->l10nFactory->getUserLanguage($this->userManager->get($this->userId)); + if ($skeletonTemplatePath === '') { + $this->setTemplatePath(''); + return ''; + } + try { $l10n = $this->l10nFactory->get('lib', $userLang); $userFolder = $this->rootFolder->getUserFolder($this->userId); diff --git a/lib/private/Files/Type/Detection.php b/lib/private/Files/Type/Detection.php index 9a61aa93b95..71b8cb986d7 100644 --- a/lib/private/Files/Type/Detection.php +++ b/lib/private/Files/Type/Detection.php @@ -75,9 +75,9 @@ class Detection implements IMimeTypeDetector { private $defaultConfigDir; public function __construct(IURLGenerator $urlGenerator, - LoggerInterface $logger, - string $customConfigDir, - string $defaultConfigDir) { + LoggerInterface $logger, + string $customConfigDir, + string $defaultConfigDir) { $this->urlGenerator = $urlGenerator; $this->logger = $logger; $this->customConfigDir = $customConfigDir; @@ -96,8 +96,8 @@ class Detection implements IMimeTypeDetector { * @param string|null $secureMimeType */ public function registerType(string $extension, - string $mimetype, - ?string $secureMimeType = null): void { + string $mimetype, + ?string $secureMimeType = null): void { $this->mimetypes[$extension] = [$mimetype, $secureMimeType]; $this->secureMimeTypes[$mimetype] = $secureMimeType ?: $mimetype; } diff --git a/lib/private/Files/Type/Loader.php b/lib/private/Files/Type/Loader.php index 20c298f21b3..f0dbf0c665a 100644 --- a/lib/private/Files/Type/Loader.php +++ b/lib/private/Files/Type/Loader.php @@ -38,14 +38,13 @@ use OCP\IDBConnection; class Loader implements IMimeTypeLoader { use TTransactional; - /** @var IDBConnection */ - private $dbConnection; + private IDBConnection $dbConnection; - /** @var array [id => mimetype] */ - protected $mimetypes; + /** @psalm-var array<int, string> */ + protected array $mimetypes; - /** @var array [mimetype => id] */ - protected $mimetypeIds; + /** @psalm-var array<string, int> */ + protected array $mimetypeIds; /** * @param IDBConnection $dbConnection @@ -58,11 +57,8 @@ class Loader implements IMimeTypeLoader { /** * Get a mimetype from its ID - * - * @param int $id - * @return string|null */ - public function getMimetypeById($id) { + public function getMimetypeById(int $id): ?string { if (!$this->mimetypes) { $this->loadMimetypes(); } @@ -74,11 +70,8 @@ class Loader implements IMimeTypeLoader { /** * Get a mimetype ID, adding the mimetype to the DB if it does not exist - * - * @param string $mimetype - * @return int */ - public function getId($mimetype) { + public function getId(string $mimetype): int { if (!$this->mimetypeIds) { $this->loadMimetypes(); } @@ -90,11 +83,8 @@ class Loader implements IMimeTypeLoader { /** * Test if a mimetype exists in the database - * - * @param string $mimetype - * @return bool */ - public function exists($mimetype) { + public function exists(string $mimetype): bool { if (!$this->mimetypeIds) { $this->loadMimetypes(); } @@ -104,7 +94,7 @@ class Loader implements IMimeTypeLoader { /** * Clear all loaded mimetypes, allow for re-loading */ - public function reset() { + public function reset(): void { $this->mimetypes = []; $this->mimetypeIds = []; } @@ -115,9 +105,9 @@ class Loader implements IMimeTypeLoader { * @param string $mimetype * @return int inserted ID */ - protected function store($mimetype) { - $mimetypeId = $this->atomic(function () use ($mimetype) { - try { + protected function store(string $mimetype): int { + try { + $mimetypeId = $this->atomic(function () use ($mimetype) { $insert = $this->dbConnection->getQueryBuilder(); $insert->insert('mimetypes') ->values([ @@ -125,26 +115,24 @@ class Loader implements IMimeTypeLoader { ]) ->executeStatement(); return $insert->getLastInsertId(); - } catch (DbalException $e) { - if ($e->getReason() !== DBException::REASON_UNIQUE_CONSTRAINT_VIOLATION) { - throw $e; - } - $qb = $this->dbConnection->getQueryBuilder(); - $qb->select('id') - ->from('mimetypes') - ->where($qb->expr()->eq('mimetype', $qb->createNamedParameter($mimetype))); - $result = $qb->executeQuery(); - $id = $result->fetchOne(); - $result->closeCursor(); - if ($id !== false) { - return (int) $id; - } + }, $this->dbConnection); + } catch (DbalException $e) { + if ($e->getReason() !== DBException::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + throw $e; + } + + $qb = $this->dbConnection->getQueryBuilder(); + $qb->select('id') + ->from('mimetypes') + ->where($qb->expr()->eq('mimetype', $qb->createNamedParameter($mimetype))); + $result = $qb->executeQuery(); + $id = $result->fetchOne(); + $result->closeCursor(); + if ($id === false) { throw new \Exception("Database threw an unique constraint on inserting a new mimetype, but couldn't return the ID for this very mimetype"); } - }, $this->dbConnection); - if (!$mimetypeId) { - throw new \Exception("Failed to get mimetype id for $mimetype after trying to store it"); + $mimetypeId = (int) $id; } $this->mimetypes[$mimetypeId] = $mimetype; @@ -155,29 +143,27 @@ class Loader implements IMimeTypeLoader { /** * Load all mimetypes from DB */ - private function loadMimetypes() { + private function loadMimetypes(): void { $qb = $this->dbConnection->getQueryBuilder(); $qb->select('id', 'mimetype') ->from('mimetypes'); - $result = $qb->execute(); + $result = $qb->executeQuery(); $results = $result->fetchAll(); $result->closeCursor(); foreach ($results as $row) { - $this->mimetypes[$row['id']] = $row['mimetype']; - $this->mimetypeIds[$row['mimetype']] = $row['id']; + $this->mimetypes[(int) $row['id']] = $row['mimetype']; + $this->mimetypeIds[$row['mimetype']] = (int) $row['id']; } } /** * Update filecache mimetype based on file extension * - * @param string $ext file extension - * @param int $mimeTypeId * @return int number of changed rows */ - public function updateFilecache($ext, $mimeTypeId) { + public function updateFilecache(string $ext, int $mimeTypeId): int { $folderMimeTypeId = $this->getId('httpd/unix-directory'); $update = $this->dbConnection->getQueryBuilder(); $update->update('filecache') diff --git a/lib/private/Files/Utils/Scanner.php b/lib/private/Files/Utils/Scanner.php index b7f6972ee10..6348427cb3b 100644 --- a/lib/private/Files/Utils/Scanner.php +++ b/lib/private/Files/Utils/Scanner.php @@ -41,11 +41,11 @@ use OCA\Files_Sharing\SharedStorage; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Events\BeforeFileScannedEvent; use OCP\Files\Events\BeforeFolderScannedEvent; -use OCP\Files\Events\NodeAddedToCache; use OCP\Files\Events\FileCacheUpdated; -use OCP\Files\Events\NodeRemovedFromCache; use OCP\Files\Events\FileScannedEvent; use OCP\Files\Events\FolderScannedEvent; +use OCP\Files\Events\NodeAddedToCache; +use OCP\Files\Events\NodeRemovedFromCache; use OCP\Files\NotFoundException; use OCP\Files\Storage\IStorage; use OCP\Files\StorageNotAvailableException; @@ -156,33 +156,37 @@ class Scanner extends PublicEmitter { public function backgroundScan($dir) { $mounts = $this->getMounts($dir); foreach ($mounts as $mount) { - $storage = $mount->getStorage(); - if (is_null($storage)) { - continue; - } + try { + $storage = $mount->getStorage(); + if (is_null($storage)) { + continue; + } - // don't bother scanning failed storages (shortcut for same result) - if ($storage->instanceOfStorage(FailedStorage::class)) { - continue; - } + // don't bother scanning failed storages (shortcut for same result) + if ($storage->instanceOfStorage(FailedStorage::class)) { + continue; + } - $scanner = $storage->getScanner(); - $this->attachListener($mount); + $scanner = $storage->getScanner(); + $this->attachListener($mount); - $scanner->listen('\OC\Files\Cache\Scanner', 'removeFromCache', function ($path) use ($storage) { - $this->triggerPropagator($storage, $path); - }); - $scanner->listen('\OC\Files\Cache\Scanner', 'updateCache', function ($path) use ($storage) { - $this->triggerPropagator($storage, $path); - }); - $scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', function ($path) use ($storage) { - $this->triggerPropagator($storage, $path); - }); + $scanner->listen('\OC\Files\Cache\Scanner', 'removeFromCache', function ($path) use ($storage) { + $this->triggerPropagator($storage, $path); + }); + $scanner->listen('\OC\Files\Cache\Scanner', 'updateCache', function ($path) use ($storage) { + $this->triggerPropagator($storage, $path); + }); + $scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', function ($path) use ($storage) { + $this->triggerPropagator($storage, $path); + }); - $propagator = $storage->getPropagator(); - $propagator->beginBatch(); - $scanner->backgroundScan(); - $propagator->commitBatch(); + $propagator = $storage->getPropagator(); + $propagator->beginBatch(); + $scanner->backgroundScan(); + $propagator->commitBatch(); + } catch (\Exception $e) { + $this->logger->error("Error while trying to scan mount as {$mount->getMountPoint()}:" . $e->getMessage(), ['exception' => $e, 'app' => 'files']); + } } } diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index 71815939310..c80b42134c4 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -49,13 +49,14 @@ namespace OC\Files; use Icewind\Streams\CallbackWrapper; use OC\Files\Mount\MoveableMount; use OC\Files\Storage\Storage; -use OC\User\LazyUser; use OC\Share\Share; -use OC\User\User; +use OC\User\LazyUser; use OC\User\Manager as UserManager; +use OC\User\User; use OCA\Files_Sharing\SharedMount; use OCP\Constants; use OCP\Files\Cache\ICacheEntry; +use OCP\Files\ConnectionLostException; use OCP\Files\EmptyFileNameException; use OCP\Files\FileNameTooLongException; use OCP\Files\InvalidCharacterInPathException; @@ -64,10 +65,12 @@ use OCP\Files\InvalidPathException; use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; use OCP\Files\ReservedWordException; -use OCP\Files\Storage\IStorage; use OCP\IUser; use OCP\Lock\ILockingProvider; use OCP\Lock\LockedException; +use OCP\Server; +use OCP\Share\IManager; +use OCP\Share\IShare; use Psr\Log\LoggerInterface; /** @@ -286,12 +289,12 @@ class View { $this->updaterEnabled = true; } - protected function writeUpdate(Storage $storage, string $internalPath, ?int $time = null): void { + protected function writeUpdate(Storage $storage, string $internalPath, ?int $time = null, ?int $sizeDifference = null): void { if ($this->updaterEnabled) { if (is_null($time)) { $time = time(); } - $storage->getUpdater()->update($internalPath, $time); + $storage->getUpdater()->update($internalPath, $time, $sizeDifference); } } @@ -397,10 +400,11 @@ class View { } $handle = $this->fopen($path, 'rb'); if ($handle) { - $chunkSize = 524288; // 512 kB chunks + $chunkSize = 524288; // 512 kiB chunks while (!feof($handle)) { echo fread($handle, $chunkSize); flush(); + $this->checkConnectionStatus(); } fclose($handle); return $this->filesize($path); @@ -423,7 +427,7 @@ class View { } $handle = $this->fopen($path, 'rb'); if ($handle) { - $chunkSize = 524288; // 512 kB chunks + $chunkSize = 524288; // 512 kiB chunks $startReading = true; if ($from !== 0 && $from !== '0' && fseek($handle, $from) !== 0) { @@ -453,6 +457,7 @@ class View { } echo fread($handle, $len); flush(); + $this->checkConnectionStatus(); } return ftell($handle) - $from; } @@ -462,6 +467,13 @@ class View { return false; } + private function checkConnectionStatus(): void { + $connectionStatus = \connection_status(); + if ($connectionStatus !== CONNECTION_NORMAL) { + throw new ConnectionLostException("Connection lost. Status: $connectionStatus"); + } + } + /** * @param string $path * @return mixed @@ -721,6 +733,8 @@ class View { public function rename($source, $target) { $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($source)); $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($target)); + $targetParts = explode('/', $absolutePath2); + $targetUser = $targetParts[1] ?? null; $result = false; if ( Filesystem::isValidPath($target) @@ -775,7 +789,7 @@ class View { if ($internalPath1 === '') { if ($mount1 instanceof MoveableMount) { $sourceParentMount = $this->getMount(dirname($source)); - if ($sourceParentMount === $mount2 && $this->targetIsNotShared($storage2, $internalPath2)) { + if ($sourceParentMount === $mount2 && $this->targetIsNotShared($targetUser, $absolutePath2)) { /** * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1 */ @@ -1163,7 +1177,9 @@ class View { $this->removeUpdate($storage, $internalPath); } if ($result !== false && in_array('write', $hooks, true) && $operation !== 'fopen' && $operation !== 'touch') { - $this->writeUpdate($storage, $internalPath); + $isCreateOperation = $operation === 'mkdir' || ($operation === 'file_put_contents' && in_array('create', $hooks, true)); + $sizeDifference = $operation === 'mkdir' ? 0 : $result; + $this->writeUpdate($storage, $internalPath, null, $isCreateOperation ? $sizeDifference : null); } if ($result !== false && in_array('touch', $hooks)) { $this->writeUpdate($storage, $internalPath, $extraParam); @@ -1515,7 +1531,7 @@ class View { $rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/ // if sharing was disabled for the user we remove the share permissions - if (\OCP\Util::isSharingDisabledForUser()) { + if ($sharingDisabled) { $rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } @@ -1769,28 +1785,29 @@ class View { * It is not allowed to move a mount point into a different mount point or * into an already shared folder */ - private function targetIsNotShared(IStorage $targetStorage, string $targetInternalPath): bool { - // note: cannot use the view because the target is already locked - $fileId = $targetStorage->getCache()->getId($targetInternalPath); - if ($fileId === -1) { - // target might not exist, need to check parent instead - $fileId = $targetStorage->getCache()->getId(dirname($targetInternalPath)); - } - - // check if any of the parents were shared by the current owner (include collections) - $shares = Share::getItemShared( - 'folder', - (string)$fileId, - \OC\Share\Constants::FORMAT_NONE, - null, - true - ); - - if (count($shares) > 0) { - $this->logger->debug( - 'It is not allowed to move one mount point into a shared folder', - ['app' => 'files']); - return false; + private function targetIsNotShared(string $user, string $targetPath): bool { + $providers = [ + IShare::TYPE_USER, + IShare::TYPE_GROUP, + IShare::TYPE_EMAIL, + IShare::TYPE_CIRCLE, + IShare::TYPE_ROOM, + IShare::TYPE_DECK, + IShare::TYPE_SCIENCEMESH + ]; + $shareManager = Server::get(IManager::class); + /** @var IShare[] $shares */ + $shares = array_merge(...array_map(function (int $type) use ($shareManager, $user) { + return $shareManager->getSharesBy($user, $type); + }, $providers)); + + foreach ($shares as $share) { + if (str_starts_with($targetPath, $share->getNode()->getPath())) { + $this->logger->debug( + 'It is not allowed to move one mount point into a shared folder', + ['app' => 'files']); + return false; + } } return true; @@ -1834,19 +1851,19 @@ class View { [$storage, $internalPath] = $this->resolvePath($path); $storage->verifyPath($internalPath, $fileName); } catch (ReservedWordException $ex) { - $l = \OC::$server->getL10N('lib'); + $l = \OCP\Util::getL10N('lib'); throw new InvalidPathException($l->t('File name is a reserved word')); } catch (InvalidCharacterInPathException $ex) { - $l = \OC::$server->getL10N('lib'); + $l = \OCP\Util::getL10N('lib'); throw new InvalidPathException($l->t('File name contains at least one invalid character')); } catch (FileNameTooLongException $ex) { - $l = \OC::$server->getL10N('lib'); + $l = \OCP\Util::getL10N('lib'); throw new InvalidPathException($l->t('File name is too long')); } catch (InvalidDirectoryException $ex) { - $l = \OC::$server->getL10N('lib'); + $l = \OCP\Util::getL10N('lib'); throw new InvalidPathException($l->t('Dot files are not allowed')); } catch (EmptyFileNameException $ex) { - $l = \OC::$server->getL10N('lib'); + $l = \OCP\Util::getL10N('lib'); throw new InvalidPathException($l->t('Empty filename is not allowed')); } } diff --git a/lib/private/FilesMetadata/FilesMetadataManager.php b/lib/private/FilesMetadata/FilesMetadataManager.php new file mode 100644 index 00000000000..9bfa8ae49d6 --- /dev/null +++ b/lib/private/FilesMetadata/FilesMetadataManager.php @@ -0,0 +1,348 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\FilesMetadata; + +use JsonException; +use OC\FilesMetadata\Job\UpdateSingleMetadata; +use OC\FilesMetadata\Listener\MetadataDelete; +use OC\FilesMetadata\Listener\MetadataUpdate; +use OC\FilesMetadata\Model\FilesMetadata; +use OC\FilesMetadata\Service\IndexRequestService; +use OC\FilesMetadata\Service\MetadataRequestService; +use OCP\BackgroundJob\IJobList; +use OCP\DB\Exception; +use OCP\DB\Exception as DBException; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Cache\CacheEntryRemovedEvent; +use OCP\Files\Events\Node\NodeWrittenEvent; +use OCP\Files\InvalidPathException; +use OCP\Files\Node; +use OCP\Files\NotFoundException; +use OCP\FilesMetadata\Event\MetadataBackgroundEvent; +use OCP\FilesMetadata\Event\MetadataLiveEvent; +use OCP\FilesMetadata\Event\MetadataNamedEvent; +use OCP\FilesMetadata\Exceptions\FilesMetadataException; +use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; +use OCP\FilesMetadata\IFilesMetadataManager; +use OCP\FilesMetadata\IMetadataQuery; +use OCP\FilesMetadata\Model\IFilesMetadata; +use OCP\FilesMetadata\Model\IMetadataValueWrapper; +use OCP\IConfig; +use OCP\IDBConnection; +use Psr\Log\LoggerInterface; + +/** + * @inheritDoc + * @since 28.0.0 + */ +class FilesMetadataManager implements IFilesMetadataManager { + public const CONFIG_KEY = 'files_metadata'; + public const MIGRATION_DONE = 'files_metadata_installed'; + private const JSON_MAXSIZE = 100000; + + private ?IFilesMetadata $all = null; + + public function __construct( + private IEventDispatcher $eventDispatcher, + private IJobList $jobList, + private IConfig $config, + private LoggerInterface $logger, + private MetadataRequestService $metadataRequestService, + private IndexRequestService $indexRequestService, + ) { + } + + /** + * @inheritDoc + * + * @param Node $node related node + * @param int $process type of process + * + * @return IFilesMetadata + * @throws FilesMetadataException if metadata are invalid + * @throws InvalidPathException if path to file is not valid + * @throws NotFoundException if file cannot be found + * @see self::PROCESS_BACKGROUND + * @see self::PROCESS_LIVE + * @since 28.0.0 + */ + public function refreshMetadata( + Node $node, + int $process = self::PROCESS_LIVE, + string $namedEvent = '' + ): IFilesMetadata { + try { + $metadata = $this->metadataRequestService->getMetadataFromFileId($node->getId()); + } catch (FilesMetadataNotFoundException) { + $metadata = new FilesMetadata($node->getId()); + } + + // if $process is LIVE, we enforce LIVE + // if $process is NAMED, we go NAMED + // else BACKGROUND + if ((self::PROCESS_LIVE & $process) !== 0) { + $event = new MetadataLiveEvent($node, $metadata); + } elseif ((self::PROCESS_NAMED & $process) !== 0) { + $event = new MetadataNamedEvent($node, $metadata, $namedEvent); + } else { + $event = new MetadataBackgroundEvent($node, $metadata); + } + + $this->eventDispatcher->dispatchTyped($event); + $this->saveMetadata($event->getMetadata()); + + // if requested, we add a new job for next cron to refresh metadata out of main thread + // if $process was set to LIVE+BACKGROUND, we run background process directly + if ($event instanceof MetadataLiveEvent && $event->isRunAsBackgroundJobRequested()) { + if ((self::PROCESS_BACKGROUND & $process) !== 0) { + return $this->refreshMetadata($node, self::PROCESS_BACKGROUND); + } + + $this->jobList->add(UpdateSingleMetadata::class, [$node->getOwner()->getUID(), $node->getId()]); + } + + return $metadata; + } + + /** + * @param int $fileId file id + * @param boolean $generate Generate if metadata does not exists + * + * @inheritDoc + * @return IFilesMetadata + * @throws FilesMetadataNotFoundException if not found + * @since 28.0.0 + */ + public function getMetadata(int $fileId, bool $generate = false): IFilesMetadata { + try { + return $this->metadataRequestService->getMetadataFromFileId($fileId); + } catch (FilesMetadataNotFoundException $ex) { + if ($generate) { + return new FilesMetadata($fileId); + } + + throw $ex; + } + } + + /** + * returns metadata of multiple file ids + * + * @param int[] $fileIds file ids + * + * @return array File ID is the array key, files without metadata are not returned in the array + * @psalm-return array<int, IFilesMetadata> + * @since 28.0.0 + */ + public function getMetadataForFiles(array $fileIds): array { + return $this->metadataRequestService->getMetadataFromFileIds($fileIds); + } + + /** + * @param IFilesMetadata $filesMetadata metadata + * + * @inheritDoc + * @throws FilesMetadataException if metadata seems malformed + * @since 28.0.0 + */ + public function saveMetadata(IFilesMetadata $filesMetadata): void { + if ($filesMetadata->getFileId() === 0 || !$filesMetadata->updated()) { + return; + } + + $json = json_encode($filesMetadata->jsonSerialize()); + if (strlen($json) > self::JSON_MAXSIZE) { + $this->logger->debug('huge metadata content detected: ' . $json); + throw new FilesMetadataException('json cannot exceed ' . self::JSON_MAXSIZE . ' characters long; fileId: ' . $filesMetadata->getFileId() . '; size: ' . strlen($json)); + } + + try { + if ($filesMetadata->getSyncToken() === '') { + $this->metadataRequestService->store($filesMetadata); + } else { + $this->metadataRequestService->updateMetadata($filesMetadata); + } + } catch (DBException $e) { + // most of the logged exception are the result of race condition + // between 2 simultaneous process trying to create/update metadata + $this->logger->warning('issue while saveMetadata', ['exception' => $e, 'metadata' => $filesMetadata]); + + return; + } + + // update indexes + foreach ($filesMetadata->getIndexes() as $index) { + try { + $this->indexRequestService->updateIndex($filesMetadata, $index); + } catch (DBException $e) { + $this->logger->warning('issue while updateIndex', ['exception' => $e]); + } + } + + // update metadata types list + $current = $this->getKnownMetadata(); + $current->import($filesMetadata->jsonSerialize(true)); + $this->config->setAppValue('core', self::CONFIG_KEY, json_encode($current)); + } + + /** + * @param int $fileId file id + * + * @inheritDoc + * @since 28.0.0 + */ + public function deleteMetadata(int $fileId): void { + try { + $this->metadataRequestService->dropMetadata($fileId); + } catch (Exception $e) { + $this->logger->warning('issue while deleteMetadata', ['exception' => $e, 'fileId' => $fileId]); + } + + try { + $this->indexRequestService->dropIndex($fileId); + } catch (Exception $e) { + $this->logger->warning('issue while deleteMetadata', ['exception' => $e, 'fileId' => $fileId]); + } + } + + /** + * @param IQueryBuilder $qb + * @param string $fileTableAlias alias of the table that contains data about files + * @param string $fileIdField alias of the field that contains file ids + * + * @inheritDoc + * @return IMetadataQuery|null + * @see IMetadataQuery + * @since 28.0.0 + */ + public function getMetadataQuery( + IQueryBuilder $qb, + string $fileTableAlias, + string $fileIdField + ): ?IMetadataQuery { + if (!$this->metadataInitiated()) { + return null; + } + + return new MetadataQuery($qb, $this->getKnownMetadata(), $fileTableAlias, $fileIdField); + } + + /** + * @inheritDoc + * @return IFilesMetadata + * @since 28.0.0 + */ + public function getKnownMetadata(): IFilesMetadata { + if (null !== $this->all) { + return $this->all; + } + $this->all = new FilesMetadata(); + + try { + $data = json_decode($this->config->getAppValue('core', self::CONFIG_KEY, '[]'), true, 127, JSON_THROW_ON_ERROR); + $this->all->import($data); + } catch (JsonException) { + $this->logger->warning('issue while reading stored list of metadata. Advised to run ./occ files:scan --all --generate-metadata'); + } + + return $this->all; + } + + /** + * @param string $key metadata key + * @param string $type metadata type + * @param bool $indexed TRUE if metadata can be search + * @param int $editPermission remote edit permission via Webdav PROPPATCH + * + * @inheritDoc + * @since 28.0.0 + * @see IMetadataValueWrapper::TYPE_INT + * @see IMetadataValueWrapper::TYPE_FLOAT + * @see IMetadataValueWrapper::TYPE_BOOL + * @see IMetadataValueWrapper::TYPE_ARRAY + * @see IMetadataValueWrapper::TYPE_STRING_LIST + * @see IMetadataValueWrapper::TYPE_INT_LIST + * @see IMetadataValueWrapper::TYPE_STRING + * @see IMetadataValueWrapper::EDIT_FORBIDDEN + * @see IMetadataValueWrapper::EDIT_REQ_OWNERSHIP + * @see IMetadataValueWrapper::EDIT_REQ_WRITE_PERMISSION + * @see IMetadataValueWrapper::EDIT_REQ_READ_PERMISSION + */ + public function initMetadata( + string $key, + string $type, + bool $indexed = false, + int $editPermission = IMetadataValueWrapper::EDIT_FORBIDDEN + ): void { + $current = $this->getKnownMetadata(); + try { + if ($current->getType($key) === $type + && $indexed === $current->isIndex($key) + && $editPermission === $current->getEditPermission($key)) { + return; // if key exists, with same type and indexed, we do nothing. + } + } catch (FilesMetadataNotFoundException) { + // if value does not exist, we keep on the writing of course + } + + $current->import([$key => ['type' => $type, 'indexed' => $indexed, 'editPermission' => $editPermission]]); + $this->config->setAppValue('core', self::CONFIG_KEY, json_encode($current)); + $this->all = $current; + } + + /** + * load listeners + * + * @param IEventDispatcher $eventDispatcher + */ + public static function loadListeners(IEventDispatcher $eventDispatcher): void { + $eventDispatcher->addServiceListener(NodeWrittenEvent::class, MetadataUpdate::class); + $eventDispatcher->addServiceListener(CacheEntryRemovedEvent::class, MetadataDelete::class); + } + + /** + * Will confirm that tables were created and store an app value to cache the result. + * Can be removed in 29 as this is to avoid strange situation when Nextcloud files were + * replaced but the upgrade was not triggered yet. + * + * @return bool + */ + private function metadataInitiated(): bool { + if ($this->config->getAppValue('core', self::MIGRATION_DONE, '0') === '1') { + return true; + } + + $dbConnection = \OCP\Server::get(IDBConnection::class); + if ($dbConnection->tableExists(MetadataRequestService::TABLE_METADATA)) { + $this->config->setAppValue('core', self::MIGRATION_DONE, '1'); + + return true; + } + + return false; + } +} diff --git a/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php b/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php new file mode 100644 index 00000000000..3a3b35ce205 --- /dev/null +++ b/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php @@ -0,0 +1,66 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\FilesMetadata\Job; + +use OC\FilesMetadata\FilesMetadataManager; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\QueuedJob; +use OCP\Files\IRootFolder; +use OCP\FilesMetadata\Event\MetadataLiveEvent; +use OCP\FilesMetadata\IFilesMetadataManager; +use Psr\Log\LoggerInterface; + +/** + * Simple background job, created when requested by an app during the + * dispatch of MetadataLiveEvent. + * This background job will re-run the event to refresh metadata on a non-live thread. + * + * @see MetadataLiveEvent::requestBackgroundJob() + * @since 28.0.0 + */ +class UpdateSingleMetadata extends QueuedJob { + public function __construct( + ITimeFactory $time, + private IRootFolder $rootFolder, + private FilesMetadataManager $filesMetadataManager, + private LoggerInterface $logger + ) { + parent::__construct($time); + } + + protected function run($argument) { + [$userId, $fileId] = $argument; + + try { + $node = $this->rootFolder->getUserFolder($userId)->getFirstNodeById($fileId); + if ($node) { + $this->filesMetadataManager->refreshMetadata($node, IFilesMetadataManager::PROCESS_BACKGROUND); + } + } catch (\Exception $e) { + $this->logger->warning('issue while running UpdateSingleMetadata', ['exception' => $e, 'userId' => $userId, 'fileId' => $fileId]); + } + } +} diff --git a/lib/private/FilesMetadata/Listener/MetadataDelete.php b/lib/private/FilesMetadata/Listener/MetadataDelete.php new file mode 100644 index 00000000000..d950c2cea5f --- /dev/null +++ b/lib/private/FilesMetadata/Listener/MetadataDelete.php @@ -0,0 +1,61 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\FilesMetadata\Listener; + +use Exception; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Files\Cache\CacheEntryRemovedEvent; +use OCP\FilesMetadata\IFilesMetadataManager; +use Psr\Log\LoggerInterface; + +/** + * Handle file deletion event and remove stored metadata related to the deleted file + * + * @template-implements IEventListener<CacheEntryRemovedEvent> + */ +class MetadataDelete implements IEventListener { + public function __construct( + private IFilesMetadataManager $filesMetadataManager, + private LoggerInterface $logger + ) { + } + + public function handle(Event $event): void { + if (!($event instanceof CacheEntryRemovedEvent)) { + return; + } + + try { + $nodeId = $event->getFileId(); + if ($nodeId > 0) { + $this->filesMetadataManager->deleteMetadata($nodeId); + } + } catch (Exception $e) { + $this->logger->warning('issue while running MetadataDelete', ['exception' => $e]); + } + } +} diff --git a/lib/private/FilesMetadata/Listener/MetadataUpdate.php b/lib/private/FilesMetadata/Listener/MetadataUpdate.php new file mode 100644 index 00000000000..9848f079882 --- /dev/null +++ b/lib/private/FilesMetadata/Listener/MetadataUpdate.php @@ -0,0 +1,64 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\FilesMetadata\Listener; + +use Exception; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Files\Events\Node\NodeCreatedEvent; +use OCP\Files\Events\Node\NodeWrittenEvent; +use OCP\FilesMetadata\IFilesMetadataManager; +use Psr\Log\LoggerInterface; + +/** + * Handle file creation/modification events and initiate a new event related to the created/edited file. + * The generated new event is broadcast in order to obtain file related metadata from other apps. + * metadata will be stored in database. + * + * @template-implements IEventListener<NodeCreatedEvent|NodeWrittenEvent> + */ +class MetadataUpdate implements IEventListener { + public function __construct( + private IFilesMetadataManager $filesMetadataManager, + private LoggerInterface $logger + ) { + } + + /** + * @param Event $event + */ + public function handle(Event $event): void { + if (!($event instanceof NodeWrittenEvent)) { + return; + } + + try { + $this->filesMetadataManager->refreshMetadata($event->getNode()); + } catch (Exception $e) { + $this->logger->warning('issue while running MetadataUpdate', ['exception' => $e]); + } + } +} diff --git a/lib/private/FilesMetadata/MetadataQuery.php b/lib/private/FilesMetadata/MetadataQuery.php new file mode 100644 index 00000000000..aa079c678d7 --- /dev/null +++ b/lib/private/FilesMetadata/MetadataQuery.php @@ -0,0 +1,167 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\FilesMetadata; + +use OC\FilesMetadata\Model\FilesMetadata; +use OC\FilesMetadata\Service\IndexRequestService; +use OC\FilesMetadata\Service\MetadataRequestService; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; +use OCP\FilesMetadata\Exceptions\FilesMetadataTypeException; +use OCP\FilesMetadata\IMetadataQuery; +use OCP\FilesMetadata\Model\IFilesMetadata; +use OCP\FilesMetadata\Model\IMetadataValueWrapper; + +/** + * @inheritDoc + * @since 28.0.0 + */ +class MetadataQuery implements IMetadataQuery { + private array $knownJoinedIndex = []; + public function __construct( + private IQueryBuilder $queryBuilder, + private IFilesMetadata $knownMetadata, + private string $fileTableAlias = 'fc', + private string $fileIdField = 'fileid', + private string $alias = 'meta', + private string $aliasIndexPrefix = 'meta_index' + ) { + } + + /** + * @inheritDoc + * @see self::extractMetadata() + * @since 28.0.0 + */ + public function retrieveMetadata(): void { + $this->queryBuilder->selectAlias($this->alias . '.json', 'meta_json'); + $this->queryBuilder->selectAlias($this->alias . '.sync_token', 'meta_sync_token'); + $this->queryBuilder->leftJoin( + $this->fileTableAlias, MetadataRequestService::TABLE_METADATA, $this->alias, + $this->queryBuilder->expr()->eq($this->fileTableAlias . '.' . $this->fileIdField, $this->alias . '.file_id') + ); + } + + /** + * @param array $row result row + * + * @inheritDoc + * @return IFilesMetadata metadata + * @see self::retrieveMetadata() + * @since 28.0.0 + */ + public function extractMetadata(array $row): IFilesMetadata { + $fileId = (array_key_exists($this->fileIdField, $row)) ? $row[$this->fileIdField] : 0; + $metadata = new FilesMetadata((int)$fileId); + try { + $metadata->importFromDatabase($row, $this->alias . '_'); + } catch (FilesMetadataNotFoundException) { + // can be ignored as files' metadata are optional and might not exist in database + } + + return $metadata; + } + + /** + * @param string $metadataKey metadata key + * @param bool $enforce limit the request only to existing metadata + * + * @inheritDoc + * @since 28.0.0 + */ + public function joinIndex(string $metadataKey, bool $enforce = false): string { + if (array_key_exists($metadataKey, $this->knownJoinedIndex)) { + return $this->knownJoinedIndex[$metadataKey]; + } + + $aliasIndex = $this->aliasIndexPrefix . '_' . count($this->knownJoinedIndex); + $this->knownJoinedIndex[$metadataKey] = $aliasIndex; + + $expr = $this->queryBuilder->expr(); + $andX = $expr->andX($expr->eq($aliasIndex . '.file_id', $this->fileTableAlias . '.' . $this->fileIdField)); + $andX->add($expr->eq($this->getMetadataKeyField($metadataKey), $this->queryBuilder->createNamedParameter($metadataKey))); + + if ($enforce) { + $this->queryBuilder->innerJoin( + $this->fileTableAlias, + IndexRequestService::TABLE_METADATA_INDEX, + $aliasIndex, + $andX + ); + } else { + $this->queryBuilder->leftJoin( + $this->fileTableAlias, + IndexRequestService::TABLE_METADATA_INDEX, + $aliasIndex, + $andX + ); + } + + return $aliasIndex; + } + + /** + * @throws FilesMetadataNotFoundException + */ + private function joinedTableAlias(string $metadataKey): string { + if (!array_key_exists($metadataKey, $this->knownJoinedIndex)) { + throw new FilesMetadataNotFoundException('table related to ' . $metadataKey . ' not initiated, you need to use leftJoin() first.'); + } + + return $this->knownJoinedIndex[$metadataKey]; + } + + /** + * @inheritDoc + * + * @param string $metadataKey metadata key + * + * @return string table field + * @throws FilesMetadataNotFoundException + * @since 28.0.0 + */ + public function getMetadataKeyField(string $metadataKey): string { + return $this->joinedTableAlias($metadataKey) . '.meta_key'; + } + + /** + * @inheritDoc + * + * @param string $metadataKey metadata key + * + * @return string table field + * @throws FilesMetadataNotFoundException if metadataKey is not known + * @throws FilesMetadataTypeException is metadataKey is not set as indexed + * @since 28.0.0 + */ + public function getMetadataValueField(string $metadataKey): string { + return match ($this->knownMetadata->getType($metadataKey)) { + IMetadataValueWrapper::TYPE_STRING => $this->joinedTableAlias($metadataKey) . '.meta_value_string', + IMetadataValueWrapper::TYPE_INT, IMetadataValueWrapper::TYPE_BOOL => $this->joinedTableAlias($metadataKey) . '.meta_value_int', + default => throw new FilesMetadataTypeException('metadata is not set as indexed'), + }; + } +} diff --git a/lib/private/FilesMetadata/Model/FilesMetadata.php b/lib/private/FilesMetadata/Model/FilesMetadata.php new file mode 100644 index 00000000000..3de72357431 --- /dev/null +++ b/lib/private/FilesMetadata/Model/FilesMetadata.php @@ -0,0 +1,638 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\FilesMetadata\Model; + +use JsonException; +use OCP\FilesMetadata\Exceptions\FilesMetadataKeyFormatException; +use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; +use OCP\FilesMetadata\Exceptions\FilesMetadataTypeException; +use OCP\FilesMetadata\Model\IFilesMetadata; +use OCP\FilesMetadata\Model\IMetadataValueWrapper; + +/** + * Model that represent metadata linked to a specific file. + * + * @inheritDoc + * @since 28.0.0 + */ +class FilesMetadata implements IFilesMetadata { + /** @var array<string, MetadataValueWrapper> */ + private array $metadata = []; + private bool $updated = false; + private int $lastUpdate = 0; + private string $syncToken = ''; + + public function __construct( + private int $fileId = 0 + ) { + } + + /** + * @inheritDoc + * @return int related file id + * @since 28.0.0 + */ + public function getFileId(): int { + return $this->fileId; + } + + /** + * @inheritDoc + * @return int timestamp + * @since 28.0.0 + */ + public function lastUpdateTimestamp(): int { + return $this->lastUpdate; + } + + /** + * @inheritDoc + * @return string token + * @since 28.0.0 + */ + public function getSyncToken(): string { + return $this->syncToken; + } + + /** + * @inheritDoc + * @return string[] list of keys + * @since 28.0.0 + */ + public function getKeys(): array { + return array_keys($this->metadata); + } + + /** + * @param string $needle metadata key to search + * + * @inheritDoc + * @return bool TRUE if key exist + * @since 28.0.0 + */ + public function hasKey(string $needle): bool { + return (in_array($needle, $this->getKeys())); + } + + /** + * @inheritDoc + * @return string[] list of indexes + * @since 28.0.0 + */ + public function getIndexes(): array { + $indexes = []; + foreach ($this->getKeys() as $key) { + if ($this->metadata[$key]->isIndexed()) { + $indexes[] = $key; + } + } + + return $indexes; + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return bool TRUE if key exists and is set as indexed + * @since 28.0.0 + */ + public function isIndex(string $key): bool { + return $this->metadata[$key]?->isIndexed() ?? false; + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return int edit permission + * @throws FilesMetadataNotFoundException + * @since 28.0.0 + */ + public function getEditPermission(string $key): int { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getEditPermission(); + } + + /** + * @param string $key metadata key + * @param int $permission edit permission + * + * @inheritDoc + * @throws FilesMetadataNotFoundException + * @since 28.0.0 + */ + public function setEditPermission(string $key, int $permission): void { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + $this->metadata[$key]->setEditPermission($permission); + } + + + public function getEtag(string $key): string { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getEtag(); + } + + public function setEtag(string $key, string $etag): void { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + $this->metadata[$key]->setEtag($etag); + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return string metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getString(string $key): string { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getValueString(); + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return int metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getInt(string $key): int { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getValueInt(); + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return float metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getFloat(string $key): float { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getValueFloat(); + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return bool metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getBool(string $key): bool { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getValueBool(); + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return array metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getArray(string $key): array { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getValueArray(); + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return string[] metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getStringList(string $key): array { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getValueStringList(); + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return int[] metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getIntList(string $key): array { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getValueIntList(); + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return string value type + * @throws FilesMetadataNotFoundException + * @see IMetadataValueWrapper::TYPE_STRING + * @see IMetadataValueWrapper::TYPE_INT + * @see IMetadataValueWrapper::TYPE_FLOAT + * @see IMetadataValueWrapper::TYPE_BOOL + * @see IMetadataValueWrapper::TYPE_ARRAY + * @see IMetadataValueWrapper::TYPE_STRING_LIST + * @see IMetadataValueWrapper::TYPE_INT_LIST + * @since 28.0.0 + */ + public function getType(string $key): string { + if (!array_key_exists($key, $this->metadata)) { + throw new FilesMetadataNotFoundException(); + } + + return $this->metadata[$key]->getType(); + } + + /** + * @param string $key metadata key + * @param string $value metadata value + * @param bool $index set TRUE if value must be indexed + * + * @inheritDoc + * @return self + * @throws FilesMetadataKeyFormatException + * @since 28.0.0 + */ + public function setString(string $key, string $value, bool $index = false): IFilesMetadata { + $this->confirmKeyFormat($key); + try { + if ($this->getString($key) === $value && $index === $this->isIndex($key)) { + return $this; // we ignore if value and index have not changed + } + } catch (FilesMetadataNotFoundException|FilesMetadataTypeException $e) { + // if value does not exist, or type has changed, we keep on the writing + } + + $meta = new MetadataValueWrapper(IMetadataValueWrapper::TYPE_STRING); + $this->updated = true; + $this->metadata[$key] = $meta->setValueString($value)->setIndexed($index); + + return $this; + } + + /** + * @param string $key metadata key + * @param int $value metadata value + * @param bool $index set TRUE if value must be indexed + * + * @inheritDoc + * @return self + * @throws FilesMetadataKeyFormatException + * @since 28.0.0 + */ + public function setInt(string $key, int $value, bool $index = false): IFilesMetadata { + $this->confirmKeyFormat($key); + try { + if ($this->getInt($key) === $value && $index === $this->isIndex($key)) { + return $this; // we ignore if value have not changed + } + } catch (FilesMetadataNotFoundException|FilesMetadataTypeException $e) { + // if value does not exist, or type has changed, we keep on the writing + } + + $meta = new MetadataValueWrapper(IMetadataValueWrapper::TYPE_INT); + $this->metadata[$key] = $meta->setValueInt($value)->setIndexed($index); + $this->updated = true; + + return $this; + } + + /** + * @param string $key metadata key + * @param float $value metadata value + * + * @inheritDoc + * @return self + * @throws FilesMetadataKeyFormatException + * @since 28.0.0 + */ + public function setFloat(string $key, float $value, bool $index = false): IFilesMetadata { + $this->confirmKeyFormat($key); + try { + if ($this->getFloat($key) === $value && $index === $this->isIndex($key)) { + return $this; // we ignore if value have not changed + } + } catch (FilesMetadataNotFoundException|FilesMetadataTypeException $e) { + // if value does not exist, or type has changed, we keep on the writing + } + + $meta = new MetadataValueWrapper(IMetadataValueWrapper::TYPE_FLOAT); + $this->metadata[$key] = $meta->setValueFloat($value)->setIndexed($index); + $this->updated = true; + + return $this; + } + + + /** + * @param string $key metadata key + * @param bool $value metadata value + * @param bool $index set TRUE if value must be indexed + * + * @inheritDoc + * @return self + * @throws FilesMetadataKeyFormatException + * @since 28.0.0 + */ + public function setBool(string $key, bool $value, bool $index = false): IFilesMetadata { + $this->confirmKeyFormat($key); + try { + if ($this->getBool($key) === $value && $index === $this->isIndex($key)) { + return $this; // we ignore if value have not changed + } + } catch (FilesMetadataNotFoundException|FilesMetadataTypeException $e) { + // if value does not exist, or type has changed, we keep on the writing + } + + $meta = new MetadataValueWrapper(IMetadataValueWrapper::TYPE_BOOL); + $this->metadata[$key] = $meta->setValueBool($value)->setIndexed($index); + $this->updated = true; + + return $this; + } + + + /** + * @param string $key metadata key + * @param array $value metadata value + * + * @inheritDoc + * @return self + * @throws FilesMetadataKeyFormatException + * @since 28.0.0 + */ + public function setArray(string $key, array $value): IFilesMetadata { + $this->confirmKeyFormat($key); + try { + if ($this->getArray($key) === $value) { + return $this; // we ignore if value have not changed + } + } catch (FilesMetadataNotFoundException|FilesMetadataTypeException $e) { + // if value does not exist, or type has changed, we keep on the writing + } + + $meta = new MetadataValueWrapper(IMetadataValueWrapper::TYPE_ARRAY); + $this->metadata[$key] = $meta->setValueArray($value); + $this->updated = true; + + return $this; + } + + /** + * @param string $key metadata key + * @param string[] $value metadata value + * @param bool $index set TRUE if each values from the list must be indexed + * + * @inheritDoc + * @return self + * @throws FilesMetadataKeyFormatException + * @since 28.0.0 + */ + public function setStringList(string $key, array $value, bool $index = false): IFilesMetadata { + $this->confirmKeyFormat($key); + try { + if ($this->getStringList($key) === $value) { + return $this; // we ignore if value have not changed + } + } catch (FilesMetadataNotFoundException|FilesMetadataTypeException $e) { + // if value does not exist, or type has changed, we keep on the writing + } + + $meta = new MetadataValueWrapper(IMetadataValueWrapper::TYPE_STRING_LIST); + $this->metadata[$key] = $meta->setValueStringList($value)->setIndexed($index); + $this->updated = true; + + return $this; + } + + /** + * @param string $key metadata key + * @param int[] $value metadata value + * @param bool $index set TRUE if each values from the list must be indexed + * + * @inheritDoc + * @return self + * @throws FilesMetadataKeyFormatException + * @since 28.0.0 + */ + public function setIntList(string $key, array $value, bool $index = false): IFilesMetadata { + $this->confirmKeyFormat($key); + try { + if ($this->getIntList($key) === $value) { + return $this; // we ignore if value have not changed + } + } catch (FilesMetadataNotFoundException|FilesMetadataTypeException $e) { + // if value does not exist, or type has changed, we keep on the writing + } + + $valueWrapper = new MetadataValueWrapper(IMetadataValueWrapper::TYPE_INT_LIST); + $this->metadata[$key] = $valueWrapper->setValueIntList($value)->setIndexed($index); + $this->updated = true; + + return $this; + } + + /** + * @param string $key metadata key + * + * @inheritDoc + * @return self + * @since 28.0.0 + */ + public function unset(string $key): IFilesMetadata { + if (!array_key_exists($key, $this->metadata)) { + return $this; + } + + unset($this->metadata[$key]); + $this->updated = true; + + return $this; + } + + /** + * @param string $keyPrefix metadata key prefix + * + * @inheritDoc + * @return self + * @since 28.0.0 + */ + public function removeStartsWith(string $keyPrefix): IFilesMetadata { + if ($keyPrefix === '') { + return $this; + } + + foreach ($this->getKeys() as $key) { + if (str_starts_with($key, $keyPrefix)) { + $this->unset($key); + } + } + + return $this; + } + + /** + * @param string $key + * + * @return void + * @throws FilesMetadataKeyFormatException + */ + private function confirmKeyFormat(string $key): void { + $acceptedChars = ['-', '_']; + if (ctype_alnum(str_replace($acceptedChars, '', $key))) { + return; + } + + throw new FilesMetadataKeyFormatException('key can only contains alphanumerical characters, and dash (-, _)'); + } + + /** + * @inheritDoc + * @return bool TRUE if metadata have been modified + * @since 28.0.0 + */ + public function updated(): bool { + return $this->updated; + } + + public function jsonSerialize(bool $emptyValues = false): array { + $data = []; + foreach ($this->metadata as $metaKey => $metaValueWrapper) { + $data[$metaKey] = $metaValueWrapper->jsonSerialize($emptyValues); + } + + return $data; + } + + /** + * @return array<string, string|int|bool|float|string[]|int[]> + */ + public function asArray(): array { + $data = []; + foreach ($this->metadata as $metaKey => $metaValueWrapper) { + try { + $data[$metaKey] = $metaValueWrapper->getValueAny(); + } catch (FilesMetadataNotFoundException $e) { + // ignore exception + } + } + + return $data; + } + + /** + * @param array $data + * + * @inheritDoc + * @return IFilesMetadata + * @since 28.0.0 + */ + public function import(array $data): IFilesMetadata { + foreach ($data as $k => $v) { + $valueWrapper = new MetadataValueWrapper(); + $this->metadata[$k] = $valueWrapper->import($v); + } + $this->updated = false; + + return $this; + } + + /** + * import data from database to configure this model + * + * @param array $data + * @param string $prefix + * + * @return IFilesMetadata + * @throws FilesMetadataNotFoundException + * @since 28.0.0 + */ + public function importFromDatabase(array $data, string $prefix = ''): IFilesMetadata { + try { + $this->syncToken = $data[$prefix . 'sync_token'] ?? ''; + + return $this->import( + json_decode( + $data[$prefix . 'json'] ?? '[]', + true, + 512, + JSON_THROW_ON_ERROR + ) + ); + } catch (JsonException) { + throw new FilesMetadataNotFoundException(); + } + } +} diff --git a/lib/private/FilesMetadata/Model/MetadataValueWrapper.php b/lib/private/FilesMetadata/Model/MetadataValueWrapper.php new file mode 100644 index 00000000000..70dec89650a --- /dev/null +++ b/lib/private/FilesMetadata/Model/MetadataValueWrapper.php @@ -0,0 +1,445 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\FilesMetadata\Model; + +use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; +use OCP\FilesMetadata\Exceptions\FilesMetadataTypeException; +use OCP\FilesMetadata\Model\IMetadataValueWrapper; + +/** + * @inheritDoc + * @see IFilesMetadata + * @since 28.0.0 + */ +class MetadataValueWrapper implements IMetadataValueWrapper { + private string $type; + /** @var string|int|float|bool|array|string[]|int[] */ + private mixed $value = null; + private string $etag = ''; + private bool $indexed = false; + private int $editPermission = self::EDIT_FORBIDDEN; + + /** + * @param string $type value type + * + * @inheritDoc + * @see self::TYPE_INT + * @see self::TYPE_FLOAT + * @see self::TYPE_BOOL + * @see self::TYPE_ARRAY + * @see self::TYPE_STRING_LIST + * @see self::TYPE_INT_LIST + * @see self::TYPE_STRING + * @since 28.0.0 + */ + public function __construct(string $type = '') { + $this->type = $type; + } + + /** + * @inheritDoc + * @return string value type + * @see self::TYPE_INT + * @see self::TYPE_FLOAT + * @see self::TYPE_BOOL + * @see self::TYPE_ARRAY + * @see self::TYPE_STRING_LIST + * @see self::TYPE_INT_LIST + * @see self::TYPE_STRING + * @since 28.0.0 + */ + public function getType(): string { + return $this->type; + } + + /** + * @param string $type value type + * + * @inheritDoc + * @return bool + * @see self::TYPE_INT + * @see self::TYPE_FLOAT + * @see self::TYPE_BOOL + * @see self::TYPE_ARRAY + * @see self::TYPE_STRING_LIST + * @see self::TYPE_INT_LIST + * @see self::TYPE_STRING + * @since 28.0.0 + */ + public function isType(string $type): bool { + return (strtolower($type) === strtolower($this->type)); + } + + /** + * @param string $type value type + * + * @inheritDoc + * @return self + * @throws FilesMetadataTypeException if type cannot be confirmed + * @see self::TYPE_INT + * @see self::TYPE_BOOL + * @see self::TYPE_ARRAY + * @see self::TYPE_STRING_LIST + * @see self::TYPE_INT_LIST + * @see self::TYPE_STRING + * @see self::TYPE_FLOAT + * @since 28.0.0 + */ + public function assertType(string $type): self { + if (!$this->isType($type)) { + throw new FilesMetadataTypeException('type is \'' . $this->getType() . '\', expecting \'' . $type . '\''); + } + + return $this; + } + + /** + * @param string $value string to be set as value + * + * @inheritDoc + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store a string + * @since 28.0.0 + */ + public function setValueString(string $value): self { + $this->assertType(self::TYPE_STRING); + $this->value = $value; + + return $this; + } + + /** + * @param int $value int to be set as value + * + * @inheritDoc + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store an int + * @since 28.0.0 + */ + public function setValueInt(int $value): self { + $this->assertType(self::TYPE_INT); + $this->value = $value; + + return $this; + } + + /** + * @param float $value float to be set as value + * + * @inheritDoc + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store a float + * @since 28.0.0 + */ + public function setValueFloat(float $value): self { + $this->assertType(self::TYPE_FLOAT); + $this->value = $value; + + return $this; + } + + /** + * @param bool $value bool to be set as value + * + * @inheritDoc + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store a bool + * @since 28.0.0 + */ + public function setValueBool(bool $value): self { + $this->assertType(self::TYPE_BOOL); + $this->value = $value; + + + return $this; + } + + /** + * @param array $value array to be set as value + * + * @inheritDoc + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store an array + * @since 28.0.0 + */ + public function setValueArray(array $value): self { + $this->assertType(self::TYPE_ARRAY); + $this->value = $value; + + return $this; + } + + /** + * @param string[] $value string list to be set as value + * + * @inheritDoc + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store a string list + * @since 28.0.0 + */ + public function setValueStringList(array $value): self { + $this->assertType(self::TYPE_STRING_LIST); + // TODO confirm value is an array or string ? + $this->value = $value; + + return $this; + } + + /** + * @param int[] $value int list to be set as value + * + * @inheritDoc + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store an int list + * @since 28.0.0 + */ + public function setValueIntList(array $value): self { + $this->assertType(self::TYPE_INT_LIST); + // TODO confirm value is an array of int ? + $this->value = $value; + + return $this; + } + + + /** + * @inheritDoc + * @return string set value + * @throws FilesMetadataTypeException if wrapper was not set to store a string + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueString(): string { + $this->assertType(self::TYPE_STRING); + if (null === $this->value) { + throw new FilesMetadataNotFoundException('value is not set'); + } + + return (string)$this->value; + } + + /** + * @inheritDoc + * @return int set value + * @throws FilesMetadataTypeException if wrapper was not set to store an int + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueInt(): int { + $this->assertType(self::TYPE_INT); + if (null === $this->value) { + throw new FilesMetadataNotFoundException('value is not set'); + } + + return (int)$this->value; + } + + /** + * @inheritDoc + * @return float set value + * @throws FilesMetadataTypeException if wrapper was not set to store a float + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueFloat(): float { + $this->assertType(self::TYPE_FLOAT); + if (null === $this->value) { + throw new FilesMetadataNotFoundException('value is not set'); + } + + return (float)$this->value; + } + + /** + * @inheritDoc + * @return bool set value + * @throws FilesMetadataTypeException if wrapper was not set to store a bool + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueBool(): bool { + $this->assertType(self::TYPE_BOOL); + if (null === $this->value) { + throw new FilesMetadataNotFoundException('value is not set'); + } + + return (bool)$this->value; + } + + /** + * @inheritDoc + * @return array set value + * @throws FilesMetadataTypeException if wrapper was not set to store an array + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueArray(): array { + $this->assertType(self::TYPE_ARRAY); + if (null === $this->value) { + throw new FilesMetadataNotFoundException('value is not set'); + } + + return (array)$this->value; + } + + /** + * @inheritDoc + * @return string[] set value + * @throws FilesMetadataTypeException if wrapper was not set to store a string list + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueStringList(): array { + $this->assertType(self::TYPE_STRING_LIST); + if (null === $this->value) { + throw new FilesMetadataNotFoundException('value is not set'); + } + + return (array)$this->value; + } + + /** + * @inheritDoc + * @return int[] set value + * @throws FilesMetadataTypeException if wrapper was not set to store an int list + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueIntList(): array { + $this->assertType(self::TYPE_INT_LIST); + if (null === $this->value) { + throw new FilesMetadataNotFoundException('value is not set'); + } + + return (array)$this->value; + } + + /** + * @inheritDoc + * @return string|int|float|bool|array|string[]|int[] set value + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueAny(): mixed { + if (null === $this->value) { + throw new FilesMetadataNotFoundException('value is not set'); + } + + return $this->value; + } + + /** + * @inheritDoc + * @return string stored etag + * @since 29.0.0 + */ + public function getEtag(): string { + return $this->etag; + } + + /** + * @param string $etag etag value + * + * @inheritDoc + * @return self + * @since 29.0.0 + */ + public function setEtag(string $etag): self { + $this->etag = $etag; + return $this; + } + + /** + * @param bool $indexed TRUE to set the stored value as an indexed value + * + * @inheritDoc + * @return self + * @since 28.0.0 + */ + public function setIndexed(bool $indexed): self { + $this->indexed = $indexed; + + return $this; + } + + /** + * @inheritDoc + * @return bool TRUE if value is an indexed value + * @since 28.0.0 + */ + public function isIndexed(): bool { + return $this->indexed; + } + + /** + * @param int $permission edit permission + * + * @inheritDoc + * @return self + * @since 28.0.0 + */ + public function setEditPermission(int $permission): self { + $this->editPermission = $permission; + + return $this; + } + + /** + * @inheritDoc + * @return int edit permission + * @since 28.0.0 + */ + public function getEditPermission(): int { + return $this->editPermission; + } + + /** + * @param array $data serialized version of the object + * + * @inheritDoc + * @return self + * @see jsonSerialize + * @since 28.0.0 + */ + public function import(array $data): self { + $this->value = $data['value'] ?? null; + $this->type = $data['type'] ?? ''; + $this->setEtag($data['etag'] ?? ''); + $this->setIndexed($data['indexed'] ?? false); + $this->setEditPermission($data['editPermission'] ?? self::EDIT_FORBIDDEN); + return $this; + } + + public function jsonSerialize(bool $emptyValues = false): array { + return [ + 'value' => ($emptyValues) ? null : $this->value, + 'type' => $this->getType(), + 'etag' => $this->getEtag(), + 'indexed' => $this->isIndexed(), + 'editPermission' => $this->getEditPermission() + ]; + } +} diff --git a/lib/private/FilesMetadata/Service/IndexRequestService.php b/lib/private/FilesMetadata/Service/IndexRequestService.php new file mode 100644 index 00000000000..2a23e2c9a67 --- /dev/null +++ b/lib/private/FilesMetadata/Service/IndexRequestService.php @@ -0,0 +1,195 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\FilesMetadata\Service; + +use OCP\DB\Exception as DbException; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; +use OCP\FilesMetadata\Exceptions\FilesMetadataTypeException; +use OCP\FilesMetadata\Model\IFilesMetadata; +use OCP\FilesMetadata\Model\IMetadataValueWrapper; +use OCP\IDBConnection; +use Psr\Log\LoggerInterface; + +/** + * manage sql request to the metadata_index table + */ +class IndexRequestService { + public const TABLE_METADATA_INDEX = 'files_metadata_index'; + + public function __construct( + private IDBConnection $dbConnection, + private LoggerInterface $logger + ) { + } + + /** + * update the index for a specific metadata key + * + * @param IFilesMetadata $filesMetadata metadata + * @param string $key metadata key to update + * + * @throws DbException + */ + public function updateIndex(IFilesMetadata $filesMetadata, string $key): void { + $fileId = $filesMetadata->getFileId(); + try { + $metadataType = $filesMetadata->getType($key); + } catch (FilesMetadataNotFoundException $e) { + return; + } + + /** + * might look harsh, but a lot simpler than comparing current indexed data, as we can expect + * conflict with a change of types. + * We assume that each time one random metadata were modified we can drop all index for this + * key and recreate them. + * To make it slightly cleaner, we'll use transaction + */ + $this->dbConnection->beginTransaction(); + try { + $this->dropIndex($fileId, $key); + match ($metadataType) { + IMetadataValueWrapper::TYPE_STRING => $this->insertIndexString($fileId, $key, $filesMetadata->getString($key)), + IMetadataValueWrapper::TYPE_INT => $this->insertIndexInt($fileId, $key, $filesMetadata->getInt($key)), + IMetadataValueWrapper::TYPE_BOOL => $this->insertIndexBool($fileId, $key, $filesMetadata->getBool($key)), + IMetadataValueWrapper::TYPE_STRING_LIST => $this->insertIndexStringList($fileId, $key, $filesMetadata->getStringList($key)), + IMetadataValueWrapper::TYPE_INT_LIST => $this->insertIndexIntList($fileId, $key, $filesMetadata->getIntList($key)) + }; + } catch (FilesMetadataNotFoundException|FilesMetadataTypeException|DbException $e) { + $this->dbConnection->rollBack(); + $this->logger->warning('issue while updateIndex', ['exception' => $e, 'fileId' => $fileId, 'key' => $key]); + } + + $this->dbConnection->commit(); + } + + /** + * insert a new entry in the metadata_index table for a string value + * + * @param int $fileId file id + * @param string $key metadata key + * @param string $value metadata value + * + * @throws DbException + */ + private function insertIndexString(int $fileId, string $key, string $value): void { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->insert(self::TABLE_METADATA_INDEX) + ->setValue('meta_key', $qb->createNamedParameter($key)) + ->setValue('meta_value_string', $qb->createNamedParameter($value)) + ->setValue('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)); + $qb->executeStatement(); + } + + /** + * insert a new entry in the metadata_index table for an int value + * + * @param int $fileId file id + * @param string $key metadata key + * @param int $value metadata value + * + * @throws DbException + */ + public function insertIndexInt(int $fileId, string $key, int $value): void { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->insert(self::TABLE_METADATA_INDEX) + ->setValue('meta_key', $qb->createNamedParameter($key)) + ->setValue('meta_value_int', $qb->createNamedParameter($value, IQueryBuilder::PARAM_INT)) + ->setValue('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)); + $qb->executeStatement(); + } + + /** + * insert a new entry in the metadata_index table for a bool value + * + * @param int $fileId file id + * @param string $key metadata key + * @param bool $value metadata value + * + * @throws DbException + */ + public function insertIndexBool(int $fileId, string $key, bool $value): void { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->insert(self::TABLE_METADATA_INDEX) + ->setValue('meta_key', $qb->createNamedParameter($key)) + ->setValue('meta_value_int', $qb->createNamedParameter(($value) ? '1' : '0', IQueryBuilder::PARAM_INT)) + ->setValue('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)); + $qb->executeStatement(); + } + + /** + * insert entries in the metadata_index table for list of string + * + * @param int $fileId file id + * @param string $key metadata key + * @param string[] $values metadata values + * + * @throws DbException + */ + public function insertIndexStringList(int $fileId, string $key, array $values): void { + foreach ($values as $value) { + $this->insertIndexString($fileId, $key, $value); + } + } + + /** + * insert entries in the metadata_index table for list of int + * + * @param int $fileId file id + * @param string $key metadata key + * @param int[] $values metadata values + * + * @throws DbException + */ + public function insertIndexIntList(int $fileId, string $key, array $values): void { + foreach ($values as $value) { + $this->insertIndexInt($fileId, $key, $value); + } + } + + /** + * drop indexes related to a file id + * if a key is specified, only drop entries related to it + * + * @param int $fileId file id + * @param string $key metadata key + * + * @throws DbException + */ + public function dropIndex(int $fileId, string $key = ''): void { + $qb = $this->dbConnection->getQueryBuilder(); + $expr = $qb->expr(); + $qb->delete(self::TABLE_METADATA_INDEX) + ->where($expr->eq('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); + + if ($key !== '') { + $qb->andWhere($expr->eq('meta_key', $qb->createNamedParameter($key))); + } + + $qb->executeStatement(); + } +} diff --git a/lib/private/FilesMetadata/Service/MetadataRequestService.php b/lib/private/FilesMetadata/Service/MetadataRequestService.php new file mode 100644 index 00000000000..b6d1b277a00 --- /dev/null +++ b/lib/private/FilesMetadata/Service/MetadataRequestService.php @@ -0,0 +1,186 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\FilesMetadata\Service; + +use OC\FilesMetadata\Model\FilesMetadata; +use OCP\DB\Exception; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; +use OCP\FilesMetadata\Model\IFilesMetadata; +use OCP\IDBConnection; +use Psr\Log\LoggerInterface; + +/** + * manage sql request to the metadata table + */ +class MetadataRequestService { + public const TABLE_METADATA = 'files_metadata'; + + public function __construct( + private IDBConnection $dbConnection, + private LoggerInterface $logger + ) { + } + + /** + * store metadata into database + * + * @param IFilesMetadata $filesMetadata + * + * @throws Exception + */ + public function store(IFilesMetadata $filesMetadata): void { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->insert(self::TABLE_METADATA) + ->setValue('file_id', $qb->createNamedParameter($filesMetadata->getFileId(), IQueryBuilder::PARAM_INT)) + ->setValue('json', $qb->createNamedParameter(json_encode($filesMetadata->jsonSerialize()))) + ->setValue('sync_token', $qb->createNamedParameter($this->generateSyncToken())) + ->setValue('last_update', (string) $qb->createFunction('NOW()')); + $qb->executeStatement(); + } + + /** + * returns metadata for a file id + * + * @param int $fileId file id + * + * @return IFilesMetadata + * @throws FilesMetadataNotFoundException if no metadata are found in database + */ + public function getMetadataFromFileId(int $fileId): IFilesMetadata { + try { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->select('json', 'sync_token')->from(self::TABLE_METADATA); + $qb->where($qb->expr()->eq('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); + $result = $qb->executeQuery(); + $data = $result->fetch(); + $result->closeCursor(); + } catch (Exception $e) { + $this->logger->warning('exception while getMetadataFromDatabase()', ['exception' => $e, 'fileId' => $fileId]); + throw new FilesMetadataNotFoundException(); + } + + if ($data === false) { + throw new FilesMetadataNotFoundException(); + } + + $metadata = new FilesMetadata($fileId); + $metadata->importFromDatabase($data); + + return $metadata; + } + + /** + * returns metadata for multiple file ids + * + * @param array $fileIds file ids + * + * @return array File ID is the array key, files without metadata are not returned in the array + * @psalm-return array<int, IFilesMetadata> + */ + public function getMetadataFromFileIds(array $fileIds): array { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->select('file_id', 'json', 'sync_token')->from(self::TABLE_METADATA); + $qb->where($qb->expr()->in('file_id', $qb->createNamedParameter($fileIds, IQueryBuilder::PARAM_INT_ARRAY))); + + $list = []; + $result = $qb->executeQuery(); + while ($data = $result->fetch()) { + $fileId = (int) $data['file_id']; + $metadata = new FilesMetadata($fileId); + try { + $metadata->importFromDatabase($data); + } catch (FilesMetadataNotFoundException) { + continue; + } + $list[$fileId] = $metadata; + } + $result->closeCursor(); + + return $list; + } + + /** + * drop metadata related to a file id + * + * @param int $fileId file id + * + * @return void + * @throws Exception + */ + public function dropMetadata(int $fileId): void { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->delete(self::TABLE_METADATA) + ->where($qb->expr()->eq('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); + $qb->executeStatement(); + } + + /** + * update metadata in the database + * + * @param IFilesMetadata $filesMetadata metadata + * + * @return int number of affected rows + * @throws Exception + */ + public function updateMetadata(IFilesMetadata $filesMetadata): int { + $qb = $this->dbConnection->getQueryBuilder(); + $expr = $qb->expr(); + + $qb->update(self::TABLE_METADATA) + ->set('json', $qb->createNamedParameter(json_encode($filesMetadata->jsonSerialize()))) + ->set('sync_token', $qb->createNamedParameter($this->generateSyncToken())) + ->set('last_update', $qb->createFunction('NOW()')) + ->where( + $expr->andX( + $expr->eq('file_id', $qb->createNamedParameter($filesMetadata->getFileId(), IQueryBuilder::PARAM_INT)), + $expr->eq('sync_token', $qb->createNamedParameter($filesMetadata->getSyncToken())) + ) + ); + + return $qb->executeStatement(); + } + + /** + * generate a random token + * @return string + */ + private function generateSyncToken(): string { + $chars = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890'; + + $str = ''; + $max = strlen($chars); + for ($i = 0; $i < 7; $i++) { + try { + $str .= $chars[random_int(0, $max - 2)]; + } catch (\Exception $e) { + $this->logger->warning('exception during generateSyncToken', ['exception' => $e]); + } + } + + return $str; + } +} diff --git a/lib/private/FullTextSearch/FullTextSearchManager.php b/lib/private/FullTextSearch/FullTextSearchManager.php index 8d850513949..d4d2e740613 100644 --- a/lib/private/FullTextSearch/FullTextSearchManager.php +++ b/lib/private/FullTextSearch/FullTextSearchManager.php @@ -39,47 +39,35 @@ use OCP\FullTextSearch\Service\ISearchService; * @package OC\FullTextSearch */ class FullTextSearchManager implements IFullTextSearchManager { - /** @var IProviderService */ - private $providerService; + private ?IProviderService $providerService = null; - /** @var IIndexService */ - private $indexService; - - /** @var ISearchService */ - private $searchService; + private ?IIndexService $indexService = null; + private ?ISearchService $searchService = null; /** * @since 15.0.0 - * - * @param IProviderService $providerService */ - public function registerProviderService(IProviderService $providerService) { + public function registerProviderService(IProviderService $providerService): void { $this->providerService = $providerService; } /** * @since 15.0.0 - * - * @param IIndexService $indexService */ - public function registerIndexService(IIndexService $indexService) { + public function registerIndexService(IIndexService $indexService): void { $this->indexService = $indexService; } /** * @since 15.0.0 - * - * @param ISearchService $searchService */ - public function registerSearchService(ISearchService $searchService) { + public function registerSearchService(ISearchService $searchService): void { $this->searchService = $searchService; } /** * @since 16.0.0 - * - * @return bool */ public function isAvailable(): bool { if ($this->indexService === null || @@ -93,7 +81,6 @@ class FullTextSearchManager implements IFullTextSearchManager { /** - * @return IProviderService * @throws FullTextSearchAppNotAvailableException */ private function getProviderService(): IProviderService { @@ -106,7 +93,6 @@ class FullTextSearchManager implements IFullTextSearchManager { /** - * @return IIndexService * @throws FullTextSearchAppNotAvailableException */ private function getIndexService(): IIndexService { @@ -119,7 +105,6 @@ class FullTextSearchManager implements IFullTextSearchManager { /** - * @return ISearchService * @throws FullTextSearchAppNotAvailableException */ private function getSearchService(): ISearchService { @@ -134,15 +119,12 @@ class FullTextSearchManager implements IFullTextSearchManager { /** * @throws FullTextSearchAppNotAvailableException */ - public function addJavascriptAPI() { + public function addJavascriptAPI(): void { $this->getProviderService()->addJavascriptAPI(); } /** - * @param string $providerId - * - * @return bool * @throws FullTextSearchAppNotAvailableException */ public function isProviderIndexed(string $providerId): bool { @@ -151,9 +133,6 @@ class FullTextSearchManager implements IFullTextSearchManager { /** - * @param string $providerId - * @param string $documentId - * @return IIndex * @throws FullTextSearchAppNotAvailableException */ public function getIndex(string $providerId, string $documentId): IIndex { @@ -161,46 +140,45 @@ class FullTextSearchManager implements IFullTextSearchManager { } /** - * @param string $providerId - * @param string $documentId - * @param string $userId - * @param int $status - * * @see IIndex for available value for $status. * - * @return IIndex * @throws FullTextSearchAppNotAvailableException */ - public function createIndex(string $providerId, string $documentId, string $userId, int $status = 0): IIndex { + public function createIndex( + string $providerId, + string $documentId, + string $userId, + int $status = 0, + ): IIndex { return $this->getIndexService()->createIndex($providerId, $documentId, $userId, $status); } /** - * @param string $providerId - * @param string $documentId - * @param int $status - * @param bool $reset - * * @see IIndex for available value for $status. * * @throws FullTextSearchAppNotAvailableException */ - public function updateIndexStatus(string $providerId, string $documentId, int $status, bool $reset = false) { + public function updateIndexStatus( + string $providerId, + string $documentId, + int $status, + bool $reset = false, + ): void { $this->getIndexService()->updateIndexStatus($providerId, $documentId, $status, $reset); } /** - * @param string $providerId - * @param array $documentIds - * @param int $status - * @param bool $reset - * * @see IIndex for available value for $status. * * @throws FullTextSearchAppNotAvailableException */ - public function updateIndexesStatus(string $providerId, array $documentIds, int $status, bool $reset = false) { + public function updateIndexesStatus( + string $providerId, + array $documentIds, + int $status, + bool $reset = false, + ): void { $this->getIndexService()->updateIndexesStatus($providerId, $documentIds, $status, $reset); } @@ -210,15 +188,12 @@ class FullTextSearchManager implements IFullTextSearchManager { * * @throws FullTextSearchAppNotAvailableException */ - public function updateIndexes(array $indexes) { + public function updateIndexes(array $indexes): void { $this->getIndexService()->updateIndexes($indexes); } /** - * @param array $request - * @param string $userId - * * @return ISearchResult[] * @throws FullTextSearchAppNotAvailableException */ diff --git a/lib/private/FullTextSearch/Model/DocumentAccess.php b/lib/private/FullTextSearch/Model/DocumentAccess.php index cb2b95284f1..eecd038ca03 100644 --- a/lib/private/FullTextSearch/Model/DocumentAccess.php +++ b/lib/private/FullTextSearch/Model/DocumentAccess.php @@ -49,23 +49,17 @@ use OCP\FullTextSearch\Model\IDocumentAccess; * @package OC\FullTextSearch\Model */ final class DocumentAccess implements IDocumentAccess, JsonSerializable { - /** @var string */ - private $ownerId; + private string $ownerId; - /** @var string */ - private $viewerId = ''; + private string $viewerId = ''; - /** @var array */ - private $users = []; + private array $users = []; - /** @var array */ - private $groups = []; + private array $groups = []; - /** @var array */ - private $circles = []; + private array $circles = []; - /** @var array */ - private $links = []; + private array $links = []; /** @@ -74,8 +68,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * @since 16.0.0 * * IDocumentAccess constructor. - * - * @param string $ownerId */ public function __construct(string $ownerId = '') { $this->setOwnerId($ownerId); @@ -86,10 +78,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Set the Owner of the document. * * @since 16.0.0 - * - * @param string $ownerId - * - * @return IDocumentAccess */ public function setOwnerId(string $ownerId): IDocumentAccess { $this->ownerId = $ownerId; @@ -101,8 +89,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Get the Owner of the document. * * @since 16.0.0 - * - * @return string */ public function getOwnerId(): string { return $this->ownerId; @@ -113,10 +99,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Set the viewer of the document. * * @since 16.0.0 - * - * @param string $viewerId - * - * @return IDocumentAccess */ public function setViewerId(string $viewerId): IDocumentAccess { $this->viewerId = $viewerId; @@ -128,8 +110,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Get the viewer of the document. * * @since 16.0.0 - * - * @return string */ public function getViewerId(): string { return $this->viewerId; @@ -140,10 +120,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Set the list of users that have read access to the document. * * @since 16.0.0 - * - * @param array $users - * - * @return IDocumentAccess */ public function setUsers(array $users): IDocumentAccess { $this->users = $users; @@ -155,10 +131,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Add an entry to the list of users that have read access to the document. * * @since 16.0.0 - * - * @param string $user - * - * @return IDocumentAccess */ public function addUser(string $user): IDocumentAccess { $this->users[] = $user; @@ -171,10 +143,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * document. * * @since 16.0.0 - * - * @param array $users - * - * @return IDocumentAccess */ public function addUsers($users): IDocumentAccess { $this->users = array_merge($this->users, $users); @@ -186,8 +154,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Get the complete list of users that have read access to the document. * * @since 16.0.0 - * - * @return array */ public function getUsers(): array { return $this->users; @@ -198,10 +164,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Set the list of groups that have read access to the document. * * @since 16.0.0 - * - * @param array $groups - * - * @return IDocumentAccess */ public function setGroups(array $groups): IDocumentAccess { $this->groups = $groups; @@ -213,10 +175,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Add an entry to the list of groups that have read access to the document. * * @since 16.0.0 - * - * @param string $group - * - * @return IDocumentAccess */ public function addGroup(string $group): IDocumentAccess { $this->groups[] = $group; @@ -229,12 +187,8 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * document. * * @since 16.0.0 - * - * @param array $groups - * - * @return IDocumentAccess */ - public function addGroups(array $groups) { + public function addGroups(array $groups): IDocumentAccess { $this->groups = array_merge($this->groups, $groups); return $this; @@ -244,8 +198,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Get the complete list of groups that have read access to the document. * * @since 16.0.0 - * - * @return array */ public function getGroups(): array { return $this->groups; @@ -256,10 +208,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Set the list of circles that have read access to the document. * * @since 16.0.0 - * - * @param array $circles - * - * @return IDocumentAccess */ public function setCircles(array $circles): IDocumentAccess { $this->circles = $circles; @@ -271,10 +219,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Add an entry to the list of circles that have read access to the document. * * @since 16.0.0 - * - * @param string $circle - * - * @return IDocumentAccess */ public function addCircle(string $circle): IDocumentAccess { $this->circles[] = $circle; @@ -287,10 +231,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * document. * * @since 16.0.0 - * - * @param array $circles - * - * @return IDocumentAccess */ public function addCircles(array $circles): IDocumentAccess { $this->circles = array_merge($this->circles, $circles); @@ -302,8 +242,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Get the complete list of circles that have read access to the document. * * @since 16.0.0 - * - * @return array */ public function getCircles(): array { return $this->circles; @@ -314,10 +252,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Set the list of links that have read access to the document. * * @since 16.0.0 - * - * @param array $links - * - * @return IDocumentAccess */ public function setLinks(array $links): IDocumentAccess { $this->links = $links; @@ -329,8 +263,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { * Get the list of links that have read access to the document. * * @since 16.0.0 - * - * @return array */ public function getLinks(): array { return $this->links; @@ -339,8 +271,6 @@ final class DocumentAccess implements IDocumentAccess, JsonSerializable { /** * @since 16.0.0 - * - * @return array */ public function jsonSerialize(): array { return [ diff --git a/lib/private/FullTextSearch/Model/IndexDocument.php b/lib/private/FullTextSearch/Model/IndexDocument.php index 74788463693..1b2e0eb5896 100644 --- a/lib/private/FullTextSearch/Model/IndexDocument.php +++ b/lib/private/FullTextSearch/Model/IndexDocument.php @@ -26,6 +26,7 @@ declare(strict_types=1); namespace OC\FullTextSearch\Model; use JsonSerializable; +use OCP\FullTextSearch\Exceptions\FullTextSearchIndexNotAvailableException; use OCP\FullTextSearch\Model\IDocumentAccess; use OCP\FullTextSearch\Model\IIndex; use OCP\FullTextSearch\Model\IIndexDocument; @@ -47,62 +48,41 @@ use OCP\FullTextSearch\Model\IIndexDocument; * @package OC\FullTextSearch\Model */ class IndexDocument implements IIndexDocument, JsonSerializable { - /** @var string */ - protected $id = ''; + protected string $id = ''; - /** @var string */ - protected $providerId = ''; + protected DocumentAccess $access; - /** @var DocumentAccess */ - protected $access; + protected ?IIndex $index = null; - /** @var IIndex */ - protected $index; + protected int $modifiedTime = 0; - /** @var int */ - protected $modifiedTime = 0; + protected string $source = ''; - /** @var string */ - protected $source = ''; + protected array $tags = []; - /** @var array */ - protected $tags = []; + protected array $metaTags = []; - /** @var array */ - protected $metaTags = []; + protected array $subTags = []; - /** @var array */ - protected $subTags = []; + protected string $title = ''; - /** @var string */ - protected $title = ''; + protected string $content = ''; - /** @var string */ - protected $content = ''; + protected string $hash = ''; - /** @var string */ - protected $hash = ''; + protected array $parts = []; - /** @var array */ - protected $parts = []; + protected string $link = ''; - /** @var string */ - protected $link = ''; + protected array $more = []; - /** @var array */ - protected $more = []; + protected array $excerpts = []; - /** @var array */ - protected $excerpts = []; + protected string $score = ''; - /** @var string */ - protected $score = ''; + protected array $info = []; - /** @var array */ - protected $info = []; - - /** @var int */ - protected $contentEncoded = 0; + protected int $contentEncoded = 0; /** @@ -112,12 +92,11 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * and the Id of the original document. * * @since 15.0.0 - * - * @param string $providerId - * @param string $documentId */ - public function __construct(string $providerId, string $documentId) { - $this->providerId = $providerId; + public function __construct( + protected string $providerId, + string $documentId, + ) { $this->id = $documentId; } @@ -126,8 +105,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Returns the Id of the original document. * * @since 15.0.0 - * - * @return string */ final public function getId(): string { return $this->id; @@ -138,8 +115,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Returns the Id of the provider. * * @since 15.0.0 - * - * @return string */ final public function getProviderId(): string { return $this->providerId; @@ -152,10 +127,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * @see IIndex * * @since 15.0.0 - * - * @param IIndex $index - * - * @return IIndexDocument */ final public function setIndex(IIndex $index): IIndexDocument { $this->index = $index; @@ -166,11 +137,14 @@ class IndexDocument implements IIndexDocument, JsonSerializable { /** * Get the Index. * + * @throws FullTextSearchIndexNotAvailableException * @since 15.0.0 - * - * @return IIndex */ final public function getIndex(): IIndex { + if ($this->index === null) { + throw new FullTextSearchIndexNotAvailableException('No IIndex generated'); + } + return $this->index; } @@ -178,22 +152,15 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * return if Index is defined. * * @since 16.0.0 - * - * @return bool */ final public function hasIndex(): bool { - return ($this->index !== null); + return $this->index !== null; } - /** * Set the modified time of the original document. * * @since 15.0.0 - * - * @param int $modifiedTime - * - * @return IIndexDocument */ final public function setModifiedTime(int $modifiedTime): IIndexDocument { $this->modifiedTime = $modifiedTime; @@ -205,8 +172,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the modified time of the original document. * * @since 15.0.0 - * - * @return int */ final public function getModifiedTime(): int { return $this->modifiedTime; @@ -216,10 +181,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Check if the original document of the IIndexDocument is older than $time. * * @since 15.0.0 - * - * @param int $time - * - * @return bool */ final public function isOlderThan(int $time): bool { return ($this->modifiedTime < $time); @@ -232,10 +193,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * @see IDocumentAccess * * @since 15.0.0 - * - * @param IDocumentAccess $access - * - * @return $this */ final public function setAccess(IDocumentAccess $access): IIndexDocument { $this->access = $access; @@ -247,8 +204,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the IDocumentAccess related to the original document. * * @since 15.0.0 - * - * @return IDocumentAccess */ final public function getAccess(): IDocumentAccess { return $this->access; @@ -259,10 +214,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Add a tag to the list. * * @since 15.0.0 - * - * @param string $tag - * - * @return IIndexDocument */ final public function addTag(string $tag): IIndexDocument { $this->tags[] = $tag; @@ -274,10 +225,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Set the list of tags assigned to the original document. * * @since 15.0.0 - * - * @param array $tags - * - * @return IIndexDocument */ final public function setTags(array $tags): IIndexDocument { $this->tags = $tags; @@ -289,8 +236,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the list of tags assigned to the original document. * * @since 15.0.0 - * - * @return array */ final public function getTags(): array { return $this->tags; @@ -301,10 +246,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Add a meta tag to the list. * * @since 15.0.0 - * - * @param string $tag - * - * @return IIndexDocument */ final public function addMetaTag(string $tag): IIndexDocument { $this->metaTags[] = $tag; @@ -316,10 +257,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Set the list of meta tags assigned to the original document. * * @since 15.0.0 - * - * @param array $tags - * - * @return IIndexDocument */ final public function setMetaTags(array $tags): IIndexDocument { $this->metaTags = $tags; @@ -331,8 +268,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the list of meta tags assigned to the original document. * * @since 15.0.0 - * - * @return array */ final public function getMetaTags(): array { return $this->metaTags; @@ -343,11 +278,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Add a sub tag to the list. * * @since 15.0.0 - * - * @param string $sub - * @param string $tag - * - * @return IIndexDocument */ final public function addSubTag(string $sub, string $tag): IIndexDocument { if (!array_key_exists($sub, $this->subTags)) { @@ -364,10 +294,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Set the list of sub tags assigned to the original document. * * @since 15.0.0 - * - * @param array $tags - * - * @return IIndexDocument */ final public function setSubTags(array $tags): IIndexDocument { $this->subTags = $tags; @@ -381,10 +307,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * dimensional array. * * @since 15.0.0 - * - * @param bool $formatted - * - * @return array */ final public function getSubTags(bool $formatted = false): array { if ($formatted === false) { @@ -408,10 +330,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Set the source of the original document. * * @since 15.0.0 - * - * @param string $source - * - * @return IIndexDocument */ final public function setSource(string $source): IIndexDocument { $this->source = $source; @@ -423,8 +341,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the source of the original document. * * @since 15.0.0 - * - * @return string */ final public function getSource(): string { return $this->source; @@ -435,10 +351,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Set the title of the original document. * * @since 15.0.0 - * - * @param string $title - * - * @return IIndexDocument */ final public function setTitle(string $title): IIndexDocument { $this->title = $title; @@ -450,8 +362,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the title of the original document. * * @since 15.0.0 - * - * @return string */ final public function getTitle(): string { return $this->title; @@ -464,11 +374,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * encoded in base64. * * @since 15.0.0 - * - * @param string $content - * @param int $encoded - * - * @return IIndexDocument */ final public function setContent(string $content, int $encoded = 0): IIndexDocument { $this->content = $content; @@ -481,8 +386,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the content of the original document. * * @since 15.0.0 - * - * @return string */ final public function getContent(): string { return $this->content; @@ -492,8 +395,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Returns the type of the encoding on the content. * * @since 15.0.0 - * - * @return int */ final public function isContentEncoded(): int { return $this->contentEncoded; @@ -503,8 +404,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Return the size of the content. * * @since 15.0.0 - * - * @return int */ final public function getContentSize(): int { return strlen($this->getContent()); @@ -512,11 +411,9 @@ class IndexDocument implements IIndexDocument, JsonSerializable { /** - * Generate an hash, based on the content of the original document. + * Generate a hash, based on the content of the original document. * * @since 15.0.0 - * - * @return IIndexDocument */ final public function initHash(): IIndexDocument { if ($this->getContent() === '' || is_null($this->getContent())) { @@ -532,10 +429,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Set the hash of the original document. * * @since 15.0.0 - * - * @param string $hash - * - * @return IIndexDocument */ final public function setHash(string $hash): IIndexDocument { $this->hash = $hash; @@ -547,8 +440,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the hash of the original document. * * @since 15.0.0 - * - * @return string */ final public function getHash(): string { return $this->hash; @@ -562,11 +453,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * $part string. * * @since 15.0.0 - * - * @param string $part - * @param string $content - * - * @return IIndexDocument */ final public function addPart(string $part, string $content): IIndexDocument { $this->parts[$part] = $content; @@ -578,10 +464,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Set all parts and their content. * * @since 15.0.0 - * - * @param array $parts - * - * @return IIndexDocument */ final public function setParts(array $parts): IIndexDocument { $this->parts = $parts; @@ -593,8 +475,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get all parts of the IIndexDocument. * * @since 15.0.0 - * - * @return array */ final public function getParts(): array { return $this->parts; @@ -605,10 +485,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Add a link, usable by the frontend. * * @since 15.0.0 - * - * @param string $link - * - * @return IIndexDocument */ final public function setLink(string $link): IIndexDocument { $this->link = $link; @@ -620,8 +496,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the link. * * @since 15.0.0 - * - * @return string */ final public function getLink(): string { return $this->link; @@ -632,10 +506,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Set more information that couldn't be set using other method. * * @since 15.0.0 - * - * @param array $more - * - * @return IIndexDocument */ final public function setMore(array $more): IIndexDocument { $this->more = $more; @@ -647,8 +517,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get more information. * * @since 15.0.0 - * - * @return array */ final public function getMore(): array { return $this->more; @@ -660,11 +528,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * on the search request. * * @since 16.0.0 - * - * @param string $source - * @param string $excerpt - * - * @return IIndexDocument */ final public function addExcerpt(string $source, string $excerpt): IIndexDocument { $this->excerpts[] = @@ -681,10 +544,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Set all excerpts of the content of the original document. * * @since 16.0.0 - * - * @param array $excerpts - * - * @return IIndexDocument */ final public function setExcerpts(array $excerpts): IIndexDocument { $new = []; @@ -704,8 +563,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get all excerpts of the content of the original document. * * @since 15.0.0 - * - * @return array */ final public function getExcerpts(): array { return $this->excerpts; @@ -715,9 +572,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Clean excerpt. * * @since 16.0.0 - * - * @param string $excerpt - * @return string */ private function cleanExcerpt(string $excerpt): string { $excerpt = str_replace("\\n", ' ', $excerpt); @@ -736,10 +590,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * request. * * @since 15.0.0 - * - * @param string $score - * - * @return IIndexDocument */ final public function setScore(string $score): IIndexDocument { $this->score = $score; @@ -751,8 +601,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get the score. * * @since 15.0.0 - * - * @return string */ final public function getScore(): string { return $this->score; @@ -767,11 +615,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * indexing. * * @since 15.0.0 - * - * @param string $info - * @param string $value - * - * @return IIndexDocument */ final public function setInfo(string $info, string $value): IIndexDocument { $this->info[$info] = $value; @@ -783,11 +626,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get an information about a document. (string) * * @since 15.0.0 - * - * @param string $info - * @param string $default - * - * @return string */ final public function getInfo(string $info, string $default = ''): string { if (!key_exists($info, $this->info)) { @@ -805,11 +643,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * indexing. * * @since 15.0.0 - * - * @param string $info - * @param array $value - * - * @return IIndexDocument */ final public function setInfoArray(string $info, array $value): IIndexDocument { $this->info[$info] = $value; @@ -821,11 +654,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get an information about a document. (array) * * @since 15.0.0 - * - * @param string $info - * @param array $default - * - * @return array */ final public function getInfoArray(string $info, array $default = []): array { if (!key_exists($info, $this->info)) { @@ -843,11 +671,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * indexing. * * @since 15.0.0 - * - * @param string $info - * @param int $value - * - * @return IIndexDocument */ final public function setInfoInt(string $info, int $value): IIndexDocument { $this->info[$info] = $value; @@ -859,11 +682,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get an information about a document. (int) * * @since 15.0.0 - * - * @param string $info - * @param int $default - * - * @return int */ final public function getInfoInt(string $info, int $default = 0): int { if (!key_exists($info, $this->info)) { @@ -881,11 +699,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * indexing. * * @since 15.0.0 - * - * @param string $info - * @param bool $value - * - * @return IIndexDocument */ final public function setInfoBool(string $info, bool $value): IIndexDocument { $this->info[$info] = $value; @@ -897,11 +710,6 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get an information about a document. (bool) * * @since 15.0.0 - * - * @param string $info - * @param bool $default - * - * @return bool */ final public function getInfoBool(string $info, bool $default = false): bool { if (!key_exists($info, $this->info)) { @@ -915,13 +723,11 @@ class IndexDocument implements IIndexDocument, JsonSerializable { * Get all info. * * @since 15.0.0 - * - * @return array */ final public function getInfoAll(): array { $info = []; foreach ($this->info as $k => $v) { - if (substr($k, 0, 1) === '_') { + if (str_starts_with($k, '_')) { continue; } diff --git a/lib/private/FullTextSearch/Model/SearchOption.php b/lib/private/FullTextSearch/Model/SearchOption.php index 91f45db5fb4..c8fa2b22a24 100644 --- a/lib/private/FullTextSearch/Model/SearchOption.php +++ b/lib/private/FullTextSearch/Model/SearchOption.php @@ -36,22 +36,6 @@ use OCP\FullTextSearch\Model\ISearchOption; * @package OC\FullTextSearch\Model */ final class SearchOption implements ISearchOption, JsonSerializable { - /** @var string */ - private $name = ''; - - /** @var string */ - private $title = ''; - - /** @var string */ - private $type = ''; - - /** @var string */ - private $size = ''; - - /** @var string */ - private $placeholder = ''; - - /** * * * @@ -104,37 +88,28 @@ final class SearchOption implements ISearchOption, JsonSerializable { /** * ISearchOption constructor. * - * Some value can be setduring the creation of the object. + * Some value can be set during the creation of the object. * * @since 15.0.0 - * - * @param string $name - * @param string $title - * @param string $type - * @param string $size - * @param string $placeholder */ - public function __construct(string $name = '', string $title = '', string $type = '', string $size = '', string $placeholder = '') { - $this->name = $name; - $this->title = $title; - $this->type = $type; - $this->size = $size; - $this->placeholder = $placeholder; + public function __construct( + private string $name = '', + private string $title = '', + private string $type = '', + private string $size = '', + private string $placeholder = '', + ) { } /** * Set the name/key of the option. - * The string should only contains alphanumerical chars and underscore. - * The key can be retrieve when using ISearchRequest::getOption + * The string should only contain alphanumerical chars and underscore. + * The key can be retrieved when using ISearchRequest::getOption * * @see ISearchRequest::getOption * * @since 15.0.0 - * - * @param string $name - * - * @return ISearchOption */ public function setName(string $name): ISearchOption { $this->name = $name; @@ -146,8 +121,6 @@ final class SearchOption implements ISearchOption, JsonSerializable { * Get the name/key of the option. * * @since 15.0.0 - * - * @return string */ public function getName(): string { return $this->name; @@ -158,10 +131,6 @@ final class SearchOption implements ISearchOption, JsonSerializable { * Set the title/display name of the option. * * @since 15.0.0 - * - * @param string $title - * - * @return ISearchOption */ public function setTitle(string $title): ISearchOption { $this->title = $title; @@ -173,8 +142,6 @@ final class SearchOption implements ISearchOption, JsonSerializable { * Get the title of the option. * * @since 15.0.0 - * - * @return string */ public function getTitle(): string { return $this->title; @@ -186,10 +153,6 @@ final class SearchOption implements ISearchOption, JsonSerializable { * $type can be ISearchOption::CHECKBOX or ISearchOption::INPUT * * @since 15.0.0 - * - * @param string $type - * - * @return ISearchOption */ public function setType(string $type): ISearchOption { $this->type = $type; @@ -201,8 +164,6 @@ final class SearchOption implements ISearchOption, JsonSerializable { * Get the type of the option. * * @since 15.0.0 - * - * @return string */ public function getType(): string { return $this->type; @@ -214,10 +175,6 @@ final class SearchOption implements ISearchOption, JsonSerializable { * Value can be ISearchOption::INPUT_SMALL or not defined. * * @since 15.0.0 - * - * @param string $size - * - * @return ISearchOption */ public function setSize(string $size): ISearchOption { $this->size = $size; @@ -229,23 +186,16 @@ final class SearchOption implements ISearchOption, JsonSerializable { * Get the size of the INPUT. * * @since 15.0.0 - * - * @return string */ public function getSize(): string { return $this->size; } - /** * In case of Type is , set the placeholder to be displayed in the input * field. * * @since 15.0.0 - * - * @param string $placeholder - * - * @return ISearchOption */ public function setPlaceholder(string $placeholder): ISearchOption { $this->placeholder = $placeholder; @@ -257,18 +207,13 @@ final class SearchOption implements ISearchOption, JsonSerializable { * Get the placeholder. * * @since 15.0.0 - * - * @return string */ public function getPlaceholder(): string { return $this->placeholder; } - /** * @since 15.0.0 - * - * @return array */ public function jsonSerialize(): array { return [ diff --git a/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php b/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php index c58d55b9b55..25887cd90ac 100644 --- a/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php +++ b/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php @@ -37,34 +37,24 @@ use OCP\FullTextSearch\Model\ISearchRequestSimpleQuery; * @package OC\FullTextSearch\Model */ final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonSerializable { - /** @var int */ - private $type = 0; - - /** @var string */ - private $field = ''; - - /** @var array */ - private $values = []; + private array $values = []; /** * SearchRequestQuery constructor. * - * @param $type - * @param $field - * * @since 17.0.0 */ - public function __construct(string $field, int $type) { - $this->field = $field; - $this->type = $type; + public function __construct( + private string $field, + private int $type, + ) { } /** * Get the compare type of the query * - * @return int * @since 17.0.0 */ public function getType(): int { @@ -75,7 +65,6 @@ final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonS /** * Get the field to apply query * - * @return string * @since 17.0.0 */ public function getField(): string { @@ -85,9 +74,6 @@ final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonS /** * Set the field to apply query * - * @param string $field - * - * @return ISearchRequestSimpleQuery * @since 17.0.0 */ public function setField(string $field): ISearchRequestSimpleQuery { @@ -100,7 +86,6 @@ final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonS /** * Get the value to compare (string) * - * @return array * @since 17.0.0 */ public function getValues(): array { @@ -111,9 +96,6 @@ final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonS /** * Add value to compare (string) * - * @param string $value - * - * @return ISearchRequestSimpleQuery * @since 17.0.0 */ public function addValue(string $value): ISearchRequestSimpleQuery { @@ -125,9 +107,6 @@ final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonS /** * Add value to compare (int) * - * @param int $value - * - * @return ISearchRequestSimpleQuery * @since 17.0.0 */ public function addValueInt(int $value): ISearchRequestSimpleQuery { @@ -139,9 +118,6 @@ final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonS /** * Add value to compare (array) * - * @param array $value - * - * @return ISearchRequestSimpleQuery * @since 17.0.0 */ public function addValueArray(array $value): ISearchRequestSimpleQuery { @@ -153,9 +129,6 @@ final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonS /** * Add value to compare (bool) * - * @param bool $value - * - * @return ISearchRequestSimpleQuery * @since 17.0.0 */ public function addValueBool(bool $value): ISearchRequestSimpleQuery { diff --git a/lib/private/FullTextSearch/Model/SearchTemplate.php b/lib/private/FullTextSearch/Model/SearchTemplate.php index 4bb56f24b58..f1ecc0709e5 100644 --- a/lib/private/FullTextSearch/Model/SearchTemplate.php +++ b/lib/private/FullTextSearch/Model/SearchTemplate.php @@ -56,21 +56,13 @@ use OCP\FullTextSearch\Model\ISearchTemplate; * @package OC\FullTextSearch\Model */ final class SearchTemplate implements ISearchTemplate, JsonSerializable { - /** @var string */ - private $icon = ''; - - /** @var string */ - private $css = ''; - - /** @var string */ - private $template = ''; + private string $template = ''; /** @var SearchOption[] */ - private $panelOptions = []; + private array $panelOptions = []; /** @var SearchOption[] */ - private $navigationOptions = []; - + private array $navigationOptions = []; /** * ISearchTemplate constructor. @@ -79,13 +71,11 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { * creation of the object. * * @since 15.0.0 - * - * @param string $icon - * @param string $css */ - public function __construct(string $icon = '', string $css = '') { - $this->icon = $icon; - $this->css = $css; + public function __construct( + private string $icon = '', + private string $css = '', + ) { } @@ -94,10 +84,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { * FullTextSearch navigation page, in front of the related Content Provider. * * @since 15.0.0 - * - * @param string $class - * - * @return ISearchTemplate */ public function setIcon(string $class): ISearchTemplate { $this->icon = $class; @@ -107,10 +93,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { /** * Get the class of the icon. - * - * @since 15.0.0 - * - * @return string */ public function getIcon(): string { return $this->icon; @@ -121,10 +103,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { * Set the path of a CSS file that will be loaded when needed. * * @since 15.0.0 - * - * @param string $css - * - * @return ISearchTemplate */ public function setCss(string $css): ISearchTemplate { $this->css = $css; @@ -136,8 +114,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { * Get the path of the CSS file. * * @since 15.0.0 - * - * @return string */ public function getCss(): string { return $this->css; @@ -151,10 +127,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { * a way not generated by FullTextSearch * * @since 15.0.0 - * - * @param string $template - * - * @return ISearchTemplate */ public function setTemplate(string $template): ISearchTemplate { $this->template = $template; @@ -166,8 +138,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { * Get the path of the template file. * * @since 15.0.0 - * - * @return string */ public function getTemplate(): string { return $this->template; @@ -181,10 +151,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { * @see ISearchOption * * @since 15.0.0 - * - * @param ISearchOption $option - * - * @return ISearchTemplate */ public function addPanelOption(ISearchOption $option): ISearchTemplate { $this->panelOptions[] = $option; @@ -210,10 +176,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { * @see ISearchOption * * @since 15.0.0 - * - * @param ISearchOption $option - * - * @return ISearchTemplate */ public function addNavigationOption(ISearchOption $option): ISearchTemplate { $this->navigationOptions[] = $option; @@ -225,8 +187,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { * Get all options to be displayed in the FullTextSearch navigation page. * * @since 15.0.0 - * - * @return array */ public function getNavigationOptions(): array { return $this->navigationOptions; @@ -235,8 +195,6 @@ final class SearchTemplate implements ISearchTemplate, JsonSerializable { /** * @since 15.0.0 - * - * @return array */ public function jsonSerialize(): array { return [ diff --git a/lib/private/Group/Database.php b/lib/private/Group/Database.php index ef5641d8137..13837eef552 100644 --- a/lib/private/Group/Database.php +++ b/lib/private/Group/Database.php @@ -30,22 +30,23 @@ namespace OC\Group; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; +use OC\User\LazyUser; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Group\Backend\ABackend; use OCP\Group\Backend\IAddToGroupBackend; +use OCP\Group\Backend\IBatchMethodsBackend; use OCP\Group\Backend\ICountDisabledInGroup; use OCP\Group\Backend\ICountUsersBackend; use OCP\Group\Backend\ICreateGroupBackend; use OCP\Group\Backend\IDeleteGroupBackend; use OCP\Group\Backend\IGetDisplayNameBackend; use OCP\Group\Backend\IGroupDetailsBackend; +use OCP\Group\Backend\INamedBackend; use OCP\Group\Backend\IRemoveFromGroupBackend; use OCP\Group\Backend\ISearchableGroupBackend; use OCP\Group\Backend\ISetDisplayNameBackend; -use OCP\Group\Backend\INamedBackend; use OCP\IDBConnection; use OCP\IUserManager; -use OC\User\LazyUser; /** * Class for group management in a SQL Database (e.g. MySQL, SQLite) @@ -61,12 +62,11 @@ class Database extends ABackend implements IRemoveFromGroupBackend, ISetDisplayNameBackend, ISearchableGroupBackend, + IBatchMethodsBackend, INamedBackend { - /** @var string[] */ + /** @var array<string, array{gid: string, displayname: string}> */ private $groupCache = []; - - /** @var IDBConnection */ - private $dbConn; + private ?IDBConnection $dbConn; /** * \OC\Group\Database constructor. @@ -270,7 +270,7 @@ class Database extends ABackend implements $this->fixDI(); $query = $this->dbConn->getQueryBuilder(); - $query->select('gid') + $query->select('gid', 'displayname') ->from('groups') ->orderBy('gid', 'ASC'); @@ -293,6 +293,10 @@ class Database extends ABackend implements $groups = []; while ($row = $result->fetch()) { + $this->groupCache[$row['gid']] = [ + 'displayname' => $row['displayname'], + 'gid' => $row['gid'], + ]; $groups[] = $row['gid']; } $result->closeCursor(); @@ -332,6 +336,43 @@ class Database extends ABackend implements } /** + * {@inheritdoc} + */ + public function groupsExists(array $gids): array { + $notFoundGids = []; + $existingGroups = []; + + // In case the data is already locally accessible, not need to do SQL query + // or do a SQL query but with a smaller in clause + foreach ($gids as $gid) { + if (isset($this->groupCache[$gid])) { + $existingGroups[] = $gid; + } else { + $notFoundGids[] = $gid; + } + } + + $qb = $this->dbConn->getQueryBuilder(); + $qb->select('gid', 'displayname') + ->from('groups') + ->where($qb->expr()->in('gid', $qb->createParameter('ids'))); + foreach (array_chunk($notFoundGids, 1000) as $chunk) { + $qb->setParameter('ids', $chunk, IQueryBuilder::PARAM_STR_ARRAY); + $result = $qb->executeQuery(); + while ($row = $result->fetch()) { + $this->groupCache[(string)$row['gid']] = [ + 'displayname' => (string)$row['displayname'], + 'gid' => (string)$row['gid'], + ]; + $existingGroups[] = (string)$row['gid']; + } + $result->closeCursor(); + } + + return $existingGroups; + } + + /** * Get a list of all users in a group * @param string $gid * @param string $search @@ -488,6 +529,43 @@ class Database extends ABackend implements return []; } + /** + * {@inheritdoc} + */ + public function getGroupsDetails(array $gids): array { + $notFoundGids = []; + $details = []; + + // In case the data is already locally accessible, not need to do SQL query + // or do a SQL query but with a smaller in clause + foreach ($gids as $gid) { + if (isset($this->groupCache[$gid])) { + $details[$gid] = ['displayName' => $this->groupCache[$gid]['displayname']]; + } else { + $notFoundGids[] = $gid; + } + } + + foreach (array_chunk($notFoundGids, 1000) as $chunk) { + $query = $this->dbConn->getQueryBuilder(); + $query->select('gid', 'displayname') + ->from('groups') + ->where($query->expr()->in('gid', $query->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY))); + + $result = $query->executeQuery(); + while ($row = $result->fetch()) { + $details[(string)$row['gid']] = ['displayName' => (string)$row['displayname']]; + $this->groupCache[(string)$row['gid']] = [ + 'displayname' => (string)$row['displayname'], + 'gid' => (string)$row['gid'], + ]; + } + $result->closeCursor(); + } + + return $details; + } + public function setDisplayName(string $gid, string $displayName): bool { if (!$this->groupExists($gid)) { return false; diff --git a/lib/private/Group/DisplayNameCache.php b/lib/private/Group/DisplayNameCache.php index 4eb8211be6e..28f9d817b0d 100644 --- a/lib/private/Group/DisplayNameCache.php +++ b/lib/private/Group/DisplayNameCache.php @@ -38,6 +38,7 @@ use OCP\IGroupManager; * Class that cache the relation Group ID -> Display name * * This saves fetching the group from the backend for "just" the display name + * @template-implements IEventListener<GroupChangedEvent|GroupDeletedEvent> */ class DisplayNameCache implements IEventListener { private CappedMemoryCache $cache; diff --git a/lib/private/Group/Group.php b/lib/private/Group/Group.php index 441ee64604d..d8d1a73762d 100644 --- a/lib/private/Group/Group.php +++ b/lib/private/Group/Group.php @@ -35,13 +35,6 @@ namespace OC\Group; use OC\Hooks\PublicEmitter; use OC\User\LazyUser; use OCP\EventDispatcher\IEventDispatcher; -use OCP\Group\Events\BeforeGroupDeletedEvent; -use OCP\Group\Events\BeforeUserAddedEvent; -use OCP\Group\Events\BeforeUserRemovedEvent; -use OCP\Group\Events\GroupDeletedEvent; -use OCP\Group\Events\UserAddedEvent; -use OCP\Group\Events\UserRemovedEvent; -use OCP\GroupInterface; use OCP\Group\Backend\ICountDisabledInGroup; use OCP\Group\Backend\IGetDisplayNameBackend; use OCP\Group\Backend\IHideFromCollaborationBackend; @@ -49,7 +42,14 @@ use OCP\Group\Backend\INamedBackend; use OCP\Group\Backend\ISearchableGroupBackend; use OCP\Group\Backend\ISetDisplayNameBackend; use OCP\Group\Events\BeforeGroupChangedEvent; +use OCP\Group\Events\BeforeGroupDeletedEvent; +use OCP\Group\Events\BeforeUserAddedEvent; +use OCP\Group\Events\BeforeUserRemovedEvent; use OCP\Group\Events\GroupChangedEvent; +use OCP\Group\Events\GroupDeletedEvent; +use OCP\Group\Events\UserAddedEvent; +use OCP\Group\Events\UserRemovedEvent; +use OCP\GroupInterface; use OCP\IGroup; use OCP\IUser; use OCP\IUserManager; @@ -85,11 +85,11 @@ class Group implements IGroup { $this->displayName = $displayName; } - public function getGID() { + public function getGID(): string { return $this->gid; } - public function getDisplayName() { + public function getDisplayName(): string { if (is_null($this->displayName)) { foreach ($this->backends as $backend) { if ($backend instanceof IGetDisplayNameBackend) { @@ -126,7 +126,7 @@ class Group implements IGroup { * * @return \OC\User\User[] */ - public function getUsers() { + public function getUsers(): array { if ($this->usersLoaded) { return $this->users; } @@ -153,7 +153,7 @@ class Group implements IGroup { * @param IUser $user * @return bool */ - public function inGroup(IUser $user) { + public function inGroup(IUser $user): bool { if (isset($this->users[$user->getUID()])) { return true; } @@ -171,7 +171,7 @@ class Group implements IGroup { * * @param IUser $user */ - public function addUser(IUser $user) { + public function addUser(IUser $user): void { if ($this->inGroup($user)) { return; } @@ -200,10 +200,8 @@ class Group implements IGroup { /** * remove a user from the group - * - * @param \OC\User\User $user */ - public function removeUser($user) { + public function removeUser(IUser $user): void { $result = false; $this->dispatcher->dispatchTyped(new BeforeUserRemovedEvent($this, $user)); if ($this->emitter) { @@ -262,7 +260,7 @@ class Group implements IGroup { * @param string $search * @return int|bool */ - public function count($search = '') { + public function count($search = ''): int|bool { $users = false; foreach ($this->backends as $backend) { if ($backend->implementsActions(\OC\Group\Backend::COUNT_USERS)) { @@ -282,7 +280,7 @@ class Group implements IGroup { * * @return int|bool */ - public function countDisabled() { + public function countDisabled(): int|bool { $users = false; foreach ($this->backends as $backend) { if ($backend instanceof ICountDisabledInGroup) { @@ -306,7 +304,7 @@ class Group implements IGroup { * @return IUser[] * @deprecated 27.0.0 Use searchUsers instead (same implementation) */ - public function searchDisplayName($search, $limit = null, $offset = null) { + public function searchDisplayName(string $search, int $limit = null, int $offset = null): array { return $this->searchUsers($search, $limit, $offset); } @@ -315,7 +313,7 @@ class Group implements IGroup { * * @return string[] */ - public function getBackendNames() { + public function getBackendNames(): array { $backends = []; foreach ($this->backends as $backend) { if ($backend instanceof INamedBackend) { @@ -329,11 +327,11 @@ class Group implements IGroup { } /** - * delete the group + * Delete the group * * @return bool */ - public function delete() { + public function delete(): bool { // Prevent users from deleting group admin if ($this->getGID() === 'admin') { return false; @@ -378,7 +376,7 @@ class Group implements IGroup { * @return bool * @since 14.0.0 */ - public function canRemoveUser() { + public function canRemoveUser(): bool { foreach ($this->backends as $backend) { if ($backend->implementsActions(GroupInterface::REMOVE_FROM_GOUP)) { return true; @@ -391,7 +389,7 @@ class Group implements IGroup { * @return bool * @since 14.0.0 */ - public function canAddUser() { + public function canAddUser(): bool { foreach ($this->backends as $backend) { if ($backend->implementsActions(GroupInterface::ADD_TO_GROUP)) { return true; diff --git a/lib/private/Group/Manager.php b/lib/private/Group/Manager.php index c43b5165a79..dafbe4295a4 100644 --- a/lib/private/Group/Manager.php +++ b/lib/private/Group/Manager.php @@ -21,6 +21,7 @@ * @author Vincent Petry <vincent@nextcloud.com> * @author Vinicius Cubas Brand <vinicius@eita.org.br> * @author voxsim "Simon Vocella" + * @author Carl Schwan <carl@carlschwan.eu> * * @license AGPL-3.0 * @@ -41,6 +42,8 @@ namespace OC\Group; use OC\Hooks\PublicEmitter; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Group\Backend\IBatchMethodsBackend; +use OCP\Group\Backend\IGroupDetailsBackend; use OCP\Group\Events\BeforeGroupCreatedEvent; use OCP\Group\Events\GroupCreatedEvent; use OCP\GroupInterface; @@ -49,6 +52,7 @@ use OCP\IGroup; use OCP\IGroupManager; use OCP\IUser; use Psr\Log\LoggerInterface; +use function is_string; /** * Class Manager @@ -74,10 +78,10 @@ class Manager extends PublicEmitter implements IGroupManager { private IEventDispatcher $dispatcher; private LoggerInterface $logger; - /** @var \OC\Group\Group[] */ + /** @var array<string, IGroup> */ private $cachedGroups = []; - /** @var (string[])[] */ + /** @var array<string, list<string>> */ private $cachedUserGroups = []; /** @var \OC\SubAdmin */ @@ -86,9 +90,9 @@ class Manager extends PublicEmitter implements IGroupManager { private DisplayNameCache $displayNameCache; public function __construct(\OC\User\Manager $userManager, - IEventDispatcher $dispatcher, - LoggerInterface $logger, - ICacheFactory $cacheFactory) { + IEventDispatcher $dispatcher, + LoggerInterface $logger, + ICacheFactory $cacheFactory) { $this->userManager = $userManager; $this->dispatcher = $dispatcher; $this->logger = $logger; @@ -185,7 +189,7 @@ class Manager extends PublicEmitter implements IGroupManager { if ($backend->implementsActions(Backend::GROUP_DETAILS)) { $groupData = $backend->getGroupDetails($gid); if (is_array($groupData) && !empty($groupData)) { - // take the display name from the first backend that has a non-null one + // take the display name from the last backend that has a non-null one if (is_null($displayName) && isset($groupData['displayName'])) { $displayName = $groupData['displayName']; } @@ -198,11 +202,69 @@ class Manager extends PublicEmitter implements IGroupManager { if (count($backends) === 0) { return null; } + /** @var GroupInterface[] $backends */ $this->cachedGroups[$gid] = new Group($gid, $backends, $this->dispatcher, $this->userManager, $this, $displayName); return $this->cachedGroups[$gid]; } /** + * @brief Batch method to create group objects + * + * @param list<string> $gids List of groupIds for which we want to create a IGroup object + * @param array<string, string> $displayNames Array containing already know display name for a groupId + * @return array<string, IGroup> + */ + protected function getGroupsObjects(array $gids, array $displayNames = []): array { + $backends = []; + $groups = []; + foreach ($gids as $gid) { + $backends[$gid] = []; + if (!isset($displayNames[$gid])) { + $displayNames[$gid] = null; + } + } + foreach ($this->backends as $backend) { + if ($backend instanceof IGroupDetailsBackend || $backend->implementsActions(GroupInterface::GROUP_DETAILS)) { + /** @var IGroupDetailsBackend $backend */ + if ($backend instanceof IBatchMethodsBackend) { + $groupDatas = $backend->getGroupsDetails($gids); + } else { + $groupDatas = []; + foreach ($gids as $gid) { + $groupDatas[$gid] = $backend->getGroupDetails($gid); + } + } + foreach ($groupDatas as $gid => $groupData) { + if (!empty($groupData)) { + // take the display name from the last backend that has a non-null one + if (isset($groupData['displayName'])) { + $displayNames[$gid] = $groupData['displayName']; + } + $backends[$gid][] = $backend; + } + } + } else { + if ($backend instanceof IBatchMethodsBackend) { + $existingGroups = $backend->groupsExists($gids); + } else { + $existingGroups = array_filter($gids, fn (string $gid): bool => $backend->groupExists($gid)); + } + foreach ($existingGroups as $group) { + $backends[$group][] = $backend; + } + } + } + foreach ($gids as $gid) { + if (count($backends[$gid]) === 0) { + continue; + } + $this->cachedGroups[$gid] = new Group($gid, $backends[$gid], $this->dispatcher, $this->userManager, $this, $displayNames[$gid]); + $groups[$gid] = $this->cachedGroups[$gid]; + } + return $groups; + } + + /** * @param string $gid * @return bool */ @@ -246,13 +308,9 @@ class Manager extends PublicEmitter implements IGroupManager { $groups = []; foreach ($this->backends as $backend) { $groupIds = $backend->getGroups($search, $limit ?? -1, $offset ?? 0); - foreach ($groupIds as $groupId) { - $aGroup = $this->get($groupId); - if ($aGroup instanceof IGroup) { - $groups[$groupId] = $aGroup; - } else { - $this->logger->debug('Group "' . $groupId . '" was returned by search but not found through direct access', ['app' => 'core']); - } + $newGroups = $this->getGroupsObjects($groupIds); + foreach ($newGroups as $groupId => $group) { + $groups[$groupId] = $group; } if (!is_null($limit) and $limit <= 0) { return array_values($groups); @@ -299,7 +357,7 @@ class Manager extends PublicEmitter implements IGroupManager { */ public function isAdmin($userId) { foreach ($this->backends as $backend) { - if ($backend->implementsActions(Backend::IS_ADMIN) && $backend->isAdmin($userId)) { + if (is_string($userId) && $backend->implementsActions(Backend::IS_ADMIN) && $backend->isAdmin($userId)) { return true; } } @@ -314,7 +372,7 @@ class Manager extends PublicEmitter implements IGroupManager { * @return bool if in group */ public function isInGroup($userId, $group) { - return array_search($group, $this->getUserIdGroupIds($userId)) !== false; + return in_array($group, $this->getUserIdGroupIds($userId)); } /** diff --git a/lib/private/Group/MetaData.php b/lib/private/Group/MetaData.php index a58d7e78bfc..973db134728 100644 --- a/lib/private/Group/MetaData.php +++ b/lib/private/Group/MetaData.php @@ -57,11 +57,11 @@ class MetaData { * @param bool $isAdmin whether the current users is an admin */ public function __construct( - string $user, - bool $isAdmin, - IGroupManager $groupManager, - IUserSession $userSession - ) { + string $user, + bool $isAdmin, + IGroupManager $groupManager, + IUserSession $userSession + ) { $this->user = $user; $this->isAdmin = $isAdmin; $this->groupManager = $groupManager; diff --git a/lib/private/Hooks/EmitterTrait.php b/lib/private/Hooks/EmitterTrait.php index da4e3da2bd6..fe9cba893de 100644 --- a/lib/private/Hooks/EmitterTrait.php +++ b/lib/private/Hooks/EmitterTrait.php @@ -43,7 +43,7 @@ trait EmitterTrait { if (!isset($this->listeners[$eventName])) { $this->listeners[$eventName] = []; } - if (array_search($callback, $this->listeners[$eventName], true) === false) { + if (!in_array($callback, $this->listeners[$eventName], true)) { $this->listeners[$eventName][] = $callback; } } diff --git a/lib/private/Http/Client/Client.php b/lib/private/Http/Client/Client.php index 3bf43e6c07e..65784e6cb58 100644 --- a/lib/private/Http/Client/Client.php +++ b/lib/private/Http/Client/Client.php @@ -192,7 +192,7 @@ class Client implements IClient { throw new LocalServerException('Could not detect any host'); } if (!$this->remoteHostValidator->isValid($host)) { - throw new LocalServerException('Host violates local access rules'); + throw new LocalServerException('Host "'.$host.'" violates local access rules'); } } @@ -408,6 +408,59 @@ class Client implements IClient { return new Response($response); } + /** + * Get the response of a Throwable thrown by the request methods when possible + * + * @param \Throwable $e + * @return IResponse + * @throws \Throwable When $e did not have a response + * @since 29.0.0 + */ + public function getResponseFromThrowable(\Throwable $e): IResponse { + if (method_exists($e, 'hasResponse') && method_exists($e, 'getResponse') && $e->hasResponse()) { + return new Response($e->getResponse()); + } + + throw $e; + } + + /** + * Sends a HTTP request + * + * @param string $method The HTTP method to use + * @param string $uri + * @param array $options Array such as + * 'query' => [ + * 'field' => 'abc', + * 'other_field' => '123', + * 'file_name' => fopen('/path/to/file', 'r'), + * ], + * 'headers' => [ + * 'foo' => 'bar', + * ], + * 'cookies' => [ + * 'foo' => 'bar', + * ], + * 'allow_redirects' => [ + * 'max' => 10, // allow at most 10 redirects. + * 'strict' => true, // use "strict" RFC compliant redirects. + * 'referer' => true, // add a Referer header + * 'protocols' => ['https'] // only allow https URLs + * ], + * 'sink' => '/path/to/file', // save to a file or a stream + * 'verify' => true, // bool or string to CA file + * 'debug' => true, + * 'timeout' => 5, + * @return IResponse + * @throws \Exception If the request could not get completed + */ + public function request(string $method, string $uri, array $options = []): IResponse { + $this->preventLocalAddress($uri, $options); + $response = $this->client->request($method, $uri, $this->buildRequestOptions($options)); + $isStream = isset($options['stream']) && $options['stream']; + return new Response($response, $isStream); + } + protected function wrapGuzzlePromise(PromiseInterface $promise): IPromise { return new GuzzlePromiseAdapter( $promise, diff --git a/lib/private/Http/Client/ClientService.php b/lib/private/Http/Client/ClientService.php index 532aa7f566a..66f84e14c57 100644 --- a/lib/private/Http/Client/ClientService.php +++ b/lib/private/Http/Client/ClientService.php @@ -27,8 +27,8 @@ declare(strict_types=1); namespace OC\Http\Client; use GuzzleHttp\Client as GuzzleClient; -use GuzzleHttp\HandlerStack; use GuzzleHttp\Handler\CurlHandler; +use GuzzleHttp\HandlerStack; use GuzzleHttp\Middleware; use OCP\Diagnostics\IEventLogger; use OCP\Http\Client\IClient; @@ -75,7 +75,9 @@ class ClientService implements IClientService { public function newClient(): IClient { $handler = new CurlHandler(); $stack = HandlerStack::create($handler); - $stack->push($this->dnsPinMiddleware->addDnsPinning()); + if ($this->config->getSystemValueBool('dns_pinning', true)) { + $stack->push($this->dnsPinMiddleware->addDnsPinning()); + } $stack->push(Middleware::tap(function (RequestInterface $request) { $this->eventLogger->start('http:request', $request->getMethod() . " request to " . $request->getRequestTarget()); }, function () { diff --git a/lib/private/Http/Client/DnsPinMiddleware.php b/lib/private/Http/Client/DnsPinMiddleware.php index c6a58972fdd..518281e4af0 100644 --- a/lib/private/Http/Client/DnsPinMiddleware.php +++ b/lib/private/Http/Client/DnsPinMiddleware.php @@ -55,7 +55,7 @@ class DnsPinMiddleware { $second = array_pop($labels); $hostname = $second . '.' . $top; - $responses = dns_get_record($hostname, DNS_SOA); + $responses = $this->dnsGetRecord($hostname, DNS_SOA); if ($responses === false || count($responses) === 0) { return null; @@ -81,7 +81,7 @@ class DnsPinMiddleware { continue; } - $dnsResponses = dns_get_record($target, $dnsType); + $dnsResponses = $this->dnsGetRecord($target, $dnsType); $canHaveCnameRecord = true; if ($dnsResponses !== false && count($dnsResponses) > 0) { foreach ($dnsResponses as $dnsResponse) { @@ -104,6 +104,13 @@ class DnsPinMiddleware { return $targetIps; } + /** + * Wrapper for dns_get_record + */ + protected function dnsGetRecord(string $hostname, int $type): array|false { + return \dns_get_record($hostname, $type); + } + public function addDnsPinning() { return function (callable $handler) { return function ( @@ -128,6 +135,10 @@ class DnsPinMiddleware { $targetIps = $this->dnsResolve(idn_to_utf8($hostName), 0); + if (empty($targetIps)) { + throw new LocalServerException('No DNS record found for ' . $hostName); + } + $curlResolves = []; foreach ($ports as $port) { @@ -136,7 +147,7 @@ class DnsPinMiddleware { foreach ($targetIps as $ip) { if ($this->ipAddressClassifier->isLocalAddress($ip)) { // TODO: continue with all non-local IPs? - throw new LocalServerException('Host violates local access rules'); + throw new LocalServerException('Host "'.$ip.'" ('.$hostName.':'.$port.') violates local access rules'); } $curlResolves["$hostName:$port"][] = $ip; } diff --git a/lib/private/Http/CookieHelper.php b/lib/private/Http/CookieHelper.php index 720a1e9185d..eedb6e05c39 100644 --- a/lib/private/Http/CookieHelper.php +++ b/lib/private/Http/CookieHelper.php @@ -33,13 +33,13 @@ class CookieHelper { public const SAMESITE_STRICT = 2; public static function setCookie(string $name, - string $value = '', - int $maxAge = 0, - string $path = '', - string $domain = '', - bool $secure = false, - bool $httponly = false, - int $samesite = self::SAMESITE_NONE) { + string $value = '', + int $maxAge = 0, + string $path = '', + string $domain = '', + bool $secure = false, + bool $httponly = false, + int $samesite = self::SAMESITE_NONE) { $header = sprintf( 'Set-Cookie: %s=%s', $name, diff --git a/lib/private/Http/WellKnown/RequestManager.php b/lib/private/Http/WellKnown/RequestManager.php index b83ff2ada50..783b04c0f5d 100644 --- a/lib/private/Http/WellKnown/RequestManager.php +++ b/lib/private/Http/WellKnown/RequestManager.php @@ -49,8 +49,8 @@ class RequestManager { private $logger; public function __construct(Coordinator $coordinator, - IServerContainer $container, - LoggerInterface $logger) { + IServerContainer $container, + LoggerInterface $logger) { $this->coordinator = $coordinator; $this->container = $container; $this->logger = $logger; diff --git a/lib/private/Installer.php b/lib/private/Installer.php index dc81135b644..6ab497b9dea 100644 --- a/lib/private/Installer.php +++ b/lib/private/Installer.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch> @@ -53,6 +56,7 @@ use OCP\HintException; use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\ITempManager; +use OCP\Migration\IOutput; use phpseclib\File\X509; use Psr\Log\LoggerInterface; @@ -60,37 +64,17 @@ use Psr\Log\LoggerInterface; * This class provides the functionality needed to install, update and remove apps */ class Installer { - /** @var AppFetcher */ - private $appFetcher; - /** @var IClientService */ - private $clientService; - /** @var ITempManager */ - private $tempManager; - /** @var LoggerInterface */ - private $logger; - /** @var IConfig */ - private $config; - /** @var array - for caching the result of app fetcher */ - private $apps = null; - /** @var bool|null - for caching the result of the ready status */ - private $isInstanceReadyForUpdates = null; - /** @var bool */ - private $isCLI; + private ?bool $isInstanceReadyForUpdates = null; + private ?array $apps = null; public function __construct( - AppFetcher $appFetcher, - IClientService $clientService, - ITempManager $tempManager, - LoggerInterface $logger, - IConfig $config, - bool $isCLI + private AppFetcher $appFetcher, + private IClientService $clientService, + private ITempManager $tempManager, + private LoggerInterface $logger, + private IConfig $config, + private bool $isCLI, ) { - $this->appFetcher = $appFetcher; - $this->clientService = $clientService; - $this->tempManager = $tempManager; - $this->logger = $logger; - $this->config = $config; - $this->isCLI = $isCLI; } /** @@ -113,7 +97,7 @@ class Installer { throw new \Exception('The appinfo/database.xml file is not longer supported. Used in ' . $appId); } - $l = \OC::$server->getL10N('core'); + $l = \OCP\Util::getL10N('core'); $info = \OCP\Server::get(IAppManager::class)->getAppInfo($basedir . '/appinfo/info.xml', true, $l->getLanguageCode()); if (!is_array($info)) { @@ -150,7 +134,7 @@ class Installer { } //install the database - $ms = new MigrationService($info['id'], \OC::$server->get(Connection::class)); + $ms = new MigrationService($info['id'], \OCP\Server::get(Connection::class)); $ms->migrate('latest', !$previousVersion); if ($previousVersion) { @@ -164,16 +148,17 @@ class Installer { OC_App::executeRepairSteps($appId, $info['repair-steps']['install']); + $config = \OCP\Server::get(IConfig::class); //set the installed version - \OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', \OCP\Server::get(IAppManager::class)->getAppVersion($info['id'], false)); - \OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no'); + $config->setAppValue($info['id'], 'installed_version', \OCP\Server::get(IAppManager::class)->getAppVersion($info['id'], false)); + $config->setAppValue($info['id'], 'enabled', 'no'); //set remote/public handlers foreach ($info['remote'] as $name => $path) { - \OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path); + $config->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path); } foreach ($info['public'] as $name => $path) { - \OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path); + $config->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path); } OC_App::setAppTypes($info['id']); @@ -184,11 +169,9 @@ class Installer { /** * Updates the specified app from the appstore * - * @param string $appId - * @param bool [$allowUnstable] Allow unstable releases - * @return bool + * @param bool $allowUnstable Allow unstable releases */ - public function updateAppstoreApp($appId, $allowUnstable = false) { + public function updateAppstoreApp(string $appId, bool $allowUnstable = false): bool { if ($this->isUpdateAvailable($appId, $allowUnstable)) { try { $this->downloadApp($appId, $allowUnstable); @@ -224,7 +207,7 @@ class Installer { * * @throws \Exception If the installation was not successful */ - public function downloadApp($appId, $allowUnstable = false) { + public function downloadApp(string $appId, bool $allowUnstable = false): void { $appId = strtolower($appId); $apps = $this->appFetcher->get($allowUnstable); @@ -400,10 +383,10 @@ class Installer { * @param bool $allowUnstable * @return string|false false or the version number of the update */ - public function isUpdateAvailable($appId, $allowUnstable = false) { + public function isUpdateAvailable($appId, $allowUnstable = false): string|false { if ($this->isInstanceReadyForUpdates === null) { $installPath = OC_App::getInstallPath(); - if ($installPath === false || $installPath === null) { + if ($installPath === null) { $this->isInstanceReadyForUpdates = false; } else { $this->isInstanceReadyForUpdates = true; @@ -443,12 +426,10 @@ class Installer { /** * Check if app has been installed from git - * @param string $name name of the application to remove - * @return boolean * * The function will check if the path contains a .git folder */ - private function isInstalledFromGit($appId) { + private function isInstalledFromGit(string $appId): bool { $app = \OC_App::findAppInDirectories($appId); if ($app === false) { return false; @@ -459,12 +440,10 @@ class Installer { /** * Check if app is already downloaded - * @param string $name name of the application to remove - * @return boolean * * The function will check if the app is already downloaded in the apps repository */ - public function isDownloaded($name) { + public function isDownloaded(string $name): bool { foreach (\OC::$APPSROOTS as $dir) { $dirToTest = $dir['path']; $dirToTest .= '/'; @@ -481,9 +460,6 @@ class Installer { /** * Removes an app - * @param string $appId ID of the application to remove - * @return boolean - * * * This function works as follows * -# call uninstall repair steps @@ -492,9 +468,9 @@ class Installer { * The function will not delete preferences, tables and the configuration, * this has to be done by the function oc_app_uninstall(). */ - public function removeApp($appId) { + public function removeApp(string $appId): bool { if ($this->isDownloaded($appId)) { - if (\OC::$server->getAppManager()->isShipped($appId)) { + if (\OCP\Server::get(IAppManager::class)->isShipped($appId)) { return false; } $appDir = OC_App::getInstallPath() . '/' . $appId; @@ -510,10 +486,9 @@ class Installer { /** * Installs the app within the bundle and marks the bundle as installed * - * @param Bundle $bundle * @throws \Exception If app could not get installed */ - public function installAppBundle(Bundle $bundle) { + public function installAppBundle(Bundle $bundle): void { $appIds = $bundle->getAppIdentifiers(); foreach ($appIds as $appId) { if (!$this->isDownloaded($appId)) { @@ -536,9 +511,12 @@ class Installer { * working ownCloud at the end instead of an aborted update. * @return array Array of error messages (appid => Exception) */ - public static function installShippedApps($softErrors = false) { - $appManager = \OC::$server->getAppManager(); - $config = \OC::$server->getConfig(); + public static function installShippedApps(bool $softErrors = false, ?IOutput $output = null): array { + if ($output instanceof IOutput) { + $output->debug('Installing shipped apps'); + } + $appManager = \OCP\Server::get(IAppManager::class); + $config = \OCP\Server::get(IConfig::class); $errors = []; foreach (\OC::$APPSROOTS as $app_dir) { if ($dir = opendir($app_dir['path'])) { @@ -551,7 +529,7 @@ class Installer { && $config->getAppValue($filename, 'enabled') !== 'no') { if ($softErrors) { try { - Installer::installShippedApp($filename); + Installer::installShippedApp($filename, $output); } catch (HintException $e) { if ($e->getPrevious() instanceof TableExistsException) { $errors[$filename] = $e; @@ -560,7 +538,7 @@ class Installer { throw $e; } } else { - Installer::installShippedApp($filename); + Installer::installShippedApp($filename, $output); } $config->setAppValue($filename, 'enabled', 'yes'); } @@ -577,17 +555,21 @@ class Installer { /** * install an app already placed in the app folder - * @param string $app id of the app to install - * @return integer */ - public static function installShippedApp($app) { + public static function installShippedApp(string $app, ?IOutput $output = null): string|false { + if ($output instanceof IOutput) { + $output->debug('Installing ' . $app); + } //install the database $appPath = OC_App::getAppPath($app); \OC_App::registerAutoloading($app, $appPath); - $config = \OC::$server->getConfig(); + $config = \OCP\Server::get(IConfig::class); - $ms = new MigrationService($app, \OC::$server->get(Connection::class)); + $ms = new MigrationService($app, \OCP\Server::get(Connection::class)); + if ($output instanceof IOutput) { + $ms->setOutput($output); + } $previousVersion = $config->getAppValue($app, 'installed_version', false); $ms->migrate('latest', !$previousVersion); @@ -598,6 +580,9 @@ class Installer { if (is_null($info)) { return false; } + if ($output instanceof IOutput) { + $output->debug('Registering tasks of ' . $app); + } \OC_App::setupBackgroundJobs($info['background-jobs']); OC_App::executeRepairSteps($app, $info['repair-steps']['install']); @@ -620,10 +605,7 @@ class Installer { return $info['id']; } - /** - * @param string $script - */ - private static function includeAppScript($script) { + private static function includeAppScript(string $script): void { if (file_exists($script)) { include $script; } diff --git a/lib/private/IntegrityCheck/Checker.php b/lib/private/IntegrityCheck/Checker.php index a2ff62e4070..e8fd087ebc2 100644 --- a/lib/private/IntegrityCheck/Checker.php +++ b/lib/private/IntegrityCheck/Checker.php @@ -40,6 +40,7 @@ use OC\IntegrityCheck\Iterator\ExcludeFileByNameFilterIterator; use OC\IntegrityCheck\Iterator\ExcludeFoldersByPathFilterIterator; use OCP\App\IAppManager; use OCP\Files\IMimeTypeDetector; +use OCP\IAppConfig; use OCP\ICache; use OCP\ICacheFactory; use OCP\IConfig; @@ -58,44 +59,20 @@ use phpseclib\File\X509; */ class Checker { public const CACHE_KEY = 'oc.integritycheck.checker'; - /** @var EnvironmentHelper */ - private $environmentHelper; - /** @var AppLocator */ - private $appLocator; - /** @var FileAccessHelper */ - private $fileAccessHelper; - /** @var IConfig|null */ - private $config; - /** @var ICache */ - private $cache; - /** @var IAppManager|null */ - private $appManager; - /** @var IMimeTypeDetector */ - private $mimeTypeDetector; - /** - * @param EnvironmentHelper $environmentHelper - * @param FileAccessHelper $fileAccessHelper - * @param AppLocator $appLocator - * @param IConfig|null $config - * @param ICacheFactory $cacheFactory - * @param IAppManager|null $appManager - * @param IMimeTypeDetector $mimeTypeDetector - */ - public function __construct(EnvironmentHelper $environmentHelper, - FileAccessHelper $fileAccessHelper, - AppLocator $appLocator, - ?IConfig $config, - ICacheFactory $cacheFactory, - ?IAppManager $appManager, - IMimeTypeDetector $mimeTypeDetector) { - $this->environmentHelper = $environmentHelper; - $this->fileAccessHelper = $fileAccessHelper; - $this->appLocator = $appLocator; - $this->config = $config; + private ICache $cache; + + public function __construct( + private EnvironmentHelper $environmentHelper, + private FileAccessHelper $fileAccessHelper, + private AppLocator $appLocator, + private ?IConfig $config, + private ?IAppConfig $appConfig, + ICacheFactory $cacheFactory, + private ?IAppManager $appManager, + private IMimeTypeDetector $mimeTypeDetector, + ) { $this->cache = $cacheFactory->createDistributed(self::CACHE_KEY); - $this->appManager = $appManager; - $this->mimeTypeDetector = $mimeTypeDetector; } /** @@ -114,15 +91,7 @@ class Checker { * applicable for very specific scenarios and we should not advertise it * too prominent. So please do not add it to config.sample.php. */ - $isIntegrityCheckDisabled = false; - if ($this->config !== null) { - $isIntegrityCheckDisabled = $this->config->getSystemValueBool('integrity.check.disabled', false); - } - if ($isIntegrityCheckDisabled) { - return false; - } - - return true; + return !($this->config?->getSystemValueBool('integrity.check.disabled', false) ?? false); } /** @@ -161,7 +130,7 @@ class Checker { * @return array Array of hashes. */ private function generateHashes(\RecursiveIteratorIterator $iterator, - string $path): array { + string $path): array { $hashes = []; $baseDirectoryLength = \strlen($path); @@ -223,8 +192,8 @@ class Checker { * @return array */ private function createSignatureData(array $hashes, - X509 $certificate, - RSA $privateKey): array { + X509 $certificate, + RSA $privateKey): array { ksort($hashes); $privateKey->setSignatureMode(RSA::SIGNATURE_PSS); @@ -249,8 +218,8 @@ class Checker { * @throws \Exception */ public function writeAppSignature($path, - X509 $certificate, - RSA $privateKey) { + X509 $certificate, + RSA $privateKey) { $appInfoDir = $path . '/appinfo'; try { $this->fileAccessHelper->assertDirectoryExists($appInfoDir); @@ -279,8 +248,8 @@ class Checker { * @throws \Exception */ public function writeCoreSignature(X509 $certificate, - RSA $rsa, - $path) { + RSA $rsa, + $path) { $coreDir = $path . '/core'; try { $this->fileAccessHelper->assertDirectoryExists($coreDir); @@ -443,10 +412,7 @@ class Checker { return json_decode($cachedResults, true); } - if ($this->config !== null) { - return json_decode($this->config->getAppValue('core', self::CACHE_KEY, '{}'), true); - } - return []; + return $this->appConfig?->getValueArray('core', self::CACHE_KEY, lazy: true) ?? []; } /** @@ -461,9 +427,7 @@ class Checker { if (!empty($result)) { $resultArray[$scope] = $result; } - if ($this->config !== null) { - $this->config->setAppValue('core', self::CACHE_KEY, json_encode($resultArray)); - } + $this->appConfig?->setValueArray('core', self::CACHE_KEY, $resultArray, lazy: true); $this->cache->set(self::CACHE_KEY, json_encode($resultArray)); } @@ -472,7 +436,7 @@ class Checker { * Clean previous results for a proper rescanning. Otherwise */ private function cleanResults() { - $this->config->deleteAppValue('core', self::CACHE_KEY); + $this->appConfig->deleteKey('core', self::CACHE_KEY); $this->cache->remove(self::CACHE_KEY); } diff --git a/lib/private/L10N/Factory.php b/lib/private/L10N/Factory.php index 778124c4c38..6de620e7ec7 100644 --- a/lib/private/L10N/Factory.php +++ b/lib/private/L10N/Factory.php @@ -358,7 +358,7 @@ class Factory implements IFactory { $files = scandir($dir); if ($files !== false) { foreach ($files as $file) { - if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') { + if (str_ends_with($file, '.json') && !str_starts_with($file, 'l10n')) { $available[] = substr($file, 0, -5); } } @@ -374,7 +374,7 @@ class Factory implements IFactory { $files = scandir($themeDir); if ($files !== false) { foreach ($files as $file) { - if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') { + if (str_ends_with($file, '.json') && !str_starts_with($file, 'l10n')) { $available[] = substr($file, 0, -5); } } @@ -490,10 +490,14 @@ class Factory implements IFactory { [$preferred_language] = explode(';', $preference); $preferred_language = str_replace('-', '_', $preferred_language); + $preferred_language_parts = explode('_', $preferred_language); foreach ($available as $available_language) { if ($preferred_language === strtolower($available_language)) { return $this->respectDefaultLanguage($app, $available_language); } + if ($preferred_language_parts[0].'_'.end($preferred_language_parts) === strtolower($available_language)) { + return $available_language; + } } // Fallback from de_De to de diff --git a/lib/private/L10N/L10N.php b/lib/private/L10N/L10N.php index ea4aa0527bb..c44e4f9cf49 100644 --- a/lib/private/L10N/L10N.php +++ b/lib/private/L10N/L10N.php @@ -30,6 +30,7 @@ namespace OC\L10N; use OCP\IL10N; use OCP\L10N\IFactory; +use Psr\Log\LoggerInterface; use Punic\Calendar; use Symfony\Component\Translation\IdentityTranslator; @@ -234,7 +235,7 @@ class L10N implements IL10N { $json = json_decode(file_get_contents($translationFile), true); if (!\is_array($json)) { $jsonError = json_last_error(); - \OC::$server->getLogger()->warning("Failed to load $translationFile - json error code: $jsonError", ['app' => 'l10n']); + \OCP\Server::get(LoggerInterface::class)->warning("Failed to load $translationFile - json error code: $jsonError", ['app' => 'l10n']); return false; } diff --git a/lib/private/Lock/AbstractLockingProvider.php b/lib/private/Lock/AbstractLockingProvider.php index 6e8289db12e..604d098fa65 100644 --- a/lib/private/Lock/AbstractLockingProvider.php +++ b/lib/private/Lock/AbstractLockingProvider.php @@ -33,14 +33,18 @@ use OCP\Lock\ILockingProvider; * to release any leftover locks at the end of the request */ abstract class AbstractLockingProvider implements ILockingProvider { - /** how long until we clear stray locks in seconds */ - protected int $ttl; - - protected $acquiredLocks = [ + protected array $acquiredLocks = [ 'shared' => [], 'exclusive' => [] ]; + /** + * + * @param int $ttl how long until we clear stray locks in seconds + */ + public function __construct(protected int $ttl) { + } + /** @inheritDoc */ protected function hasAcquiredLock(string $path, int $type): bool { if ($type === self::LOCK_SHARED) { diff --git a/lib/private/Lock/DBLockingProvider.php b/lib/private/Lock/DBLockingProvider.php index fb8af8ac55b..087b1287754 100644 --- a/lib/private/Lock/DBLockingProvider.php +++ b/lib/private/Lock/DBLockingProvider.php @@ -39,21 +39,15 @@ use OCP\Lock\LockedException; * Locking provider that stores the locks in the database */ class DBLockingProvider extends AbstractLockingProvider { - private IDBConnection $connection; - private ITimeFactory $timeFactory; private array $sharedLocks = []; - private bool $cacheSharedLocks; public function __construct( - IDBConnection $connection, - ITimeFactory $timeFactory, + private IDBConnection $connection, + private ITimeFactory $timeFactory, int $ttl = 3600, - bool $cacheSharedLocks = true + private bool $cacheSharedLocks = true ) { - $this->connection = $connection; - $this->timeFactory = $timeFactory; - $this->ttl = $ttl; - $this->cacheSharedLocks = $cacheSharedLocks; + parent::__construct($ttl); } /** diff --git a/lib/private/Lock/MemcacheLockingProvider.php b/lib/private/Lock/MemcacheLockingProvider.php index d4eebd7c302..b9c3e995460 100644 --- a/lib/private/Lock/MemcacheLockingProvider.php +++ b/lib/private/Lock/MemcacheLockingProvider.php @@ -27,21 +27,42 @@ declare(strict_types=1); */ namespace OC\Lock; +use OCP\AppFramework\Utility\ITimeFactory; use OCP\IMemcache; use OCP\IMemcacheTTL; use OCP\Lock\LockedException; class MemcacheLockingProvider extends AbstractLockingProvider { - private IMemcache $memcache; + /** @var array<string, array{time: int, ttl: int}> */ + private array $oldTTLs = []; - public function __construct(IMemcache $memcache, int $ttl = 3600) { - $this->memcache = $memcache; - $this->ttl = $ttl; + public function __construct( + private IMemcache $memcache, + private ITimeFactory $timeFactory, + int $ttl = 3600, + ) { + parent::__construct($ttl); } - private function setTTL(string $path): void { + private function setTTL(string $path, int $ttl = null, ?int $compare = null): void { + if (is_null($ttl)) { + $ttl = $this->ttl; + } + if ($this->memcache instanceof IMemcacheTTL) { + if ($compare !== null) { + $this->memcache->compareSetTTL($path, $compare, $ttl); + } else { + $this->memcache->setTTL($path, $ttl); + } + } + } + + private function getTTL(string $path): int { if ($this->memcache instanceof IMemcacheTTL) { - $this->memcache->setTTL($path, $this->ttl); + $ttl = $this->memcache->getTTL($path); + return $ttl === false ? -1 : $ttl; + } else { + return -1; } } @@ -58,14 +79,22 @@ class MemcacheLockingProvider extends AbstractLockingProvider { public function acquireLock(string $path, int $type, ?string $readablePath = null): void { if ($type === self::LOCK_SHARED) { + // save the old TTL to for `restoreTTL` + $this->oldTTLs[$path] = [ + "ttl" => $this->getTTL($path), + "time" => $this->timeFactory->getTime() + ]; if (!$this->memcache->inc($path)) { throw new LockedException($path, null, $this->getExistingLockForException($path), $readablePath); } } else { + // when getting exclusive locks, we know there are no old TTLs to restore $this->memcache->add($path, 0); + // ttl is updated automatically when the `set` succeeds if (!$this->memcache->cas($path, 0, 'exclusive')) { throw new LockedException($path, null, $this->getExistingLockForException($path), $readablePath); } + unset($this->oldTTLs[$path]); } $this->setTTL($path); $this->markAcquire($path, $type); @@ -88,6 +117,12 @@ class MemcacheLockingProvider extends AbstractLockingProvider { $newValue = $this->memcache->dec($path); } + if ($newValue > 0) { + $this->restoreTTL($path); + } else { + unset($this->oldTTLs[$path]); + } + // if we somehow release more locks then exists, reset the lock if ($newValue < 0) { $this->memcache->cad($path, $newValue); @@ -106,13 +141,52 @@ class MemcacheLockingProvider extends AbstractLockingProvider { } elseif ($targetType === self::LOCK_EXCLUSIVE) { // we can only change a shared lock to an exclusive if there's only a single owner of the shared lock if (!$this->memcache->cas($path, 1, 'exclusive')) { + $this->restoreTTL($path); throw new LockedException($path, null, $this->getExistingLockForException($path)); } + unset($this->oldTTLs[$path]); } $this->setTTL($path); $this->markChange($path, $targetType); } + /** + * With shared locks, each time the lock is acquired, the ttl for the path is reset. + * + * Due to this "ttl extension" when a shared lock isn't freed correctly for any reason + * the lock won't expire until no shared locks are required for the path for 1h. + * This can lead to a client repeatedly trying to upload a file, and failing forever + * because the lock never gets the opportunity to expire. + * + * To help the lock expire in this case, we lower the TTL back to what it was before we + * took the shared lock *only* if nobody else got a shared lock after we did. + * + * This doesn't handle all cases where multiple requests are acquiring shared locks + * but it should handle some of the more common ones and not hurt things further + */ + private function restoreTTL(string $path): void { + if (isset($this->oldTTLs[$path])) { + $saved = $this->oldTTLs[$path]; + $elapsed = $this->timeFactory->getTime() - $saved['time']; + + // old value to compare to when setting ttl in case someone else changes the lock in the middle of this function + $value = $this->memcache->get($path); + + $currentTtl = $this->getTTL($path); + + // what the old ttl would be given the time elapsed since we acquired the lock + // note that if this gets negative the key will be expired directly when we set the ttl + $remainingOldTtl = $saved['ttl'] - $elapsed; + // what the currently ttl would be if nobody else acquired a lock since we did (+1 to cover rounding errors) + $expectedTtl = $this->ttl - $elapsed + 1; + + // check if another request has acquired a lock (and didn't release it yet) + if ($currentTtl <= $expectedTtl) { + $this->setTTL($path, $remainingOldTtl, $value); + } + } + } + private function getExistingLockForException(string $path): string { $existing = $this->memcache->get($path); if (!$existing) { diff --git a/lib/private/Log.php b/lib/private/Log.php index d6750491d92..2ad214ddec5 100644 --- a/lib/private/Log.php +++ b/lib/private/Log.php @@ -38,6 +38,8 @@ namespace OC; use Exception; use Nextcloud\LogNormalizer\Normalizer; +use OC\AppFramework\Bootstrap\Coordinator; +use OC\Log\ExceptionSerializer; use OCP\EventDispatcher\IEventDispatcher; use OCP\ILogger; use OCP\IUserSession; @@ -46,8 +48,6 @@ use OCP\Log\IDataLogger; use OCP\Log\IFileBased; use OCP\Log\IWriter; use OCP\Support\CrashReport\IRegistry; -use OC\AppFramework\Bootstrap\Coordinator; -use OC\Log\ExceptionSerializer; use Throwable; use function array_merge; use function strtr; @@ -62,24 +62,22 @@ use function strtr; * MonoLog is an example implementing this interface. */ class Log implements ILogger, IDataLogger { - private IWriter $logger; private ?SystemConfig $config; private ?bool $logConditionSatisfied = null; private ?Normalizer $normalizer; - private ?IRegistry $crashReporters; private ?IEventDispatcher $eventDispatcher; /** * @param IWriter $logger The logger that should be used - * @param SystemConfig $config the system config object + * @param SystemConfig|null $config the system config object * @param Normalizer|null $normalizer - * @param IRegistry|null $registry + * @param IRegistry|null $crashReporters */ public function __construct( - IWriter $logger, + private IWriter $logger, SystemConfig $config = null, Normalizer $normalizer = null, - IRegistry $registry = null + private ?IRegistry $crashReporters = null ) { // FIXME: Add this for backwards compatibility, should be fixed at some point probably if ($config === null) { @@ -87,13 +85,11 @@ class Log implements ILogger, IDataLogger { } $this->config = $config; - $this->logger = $logger; if ($normalizer === null) { $this->normalizer = new Normalizer(); } else { $this->normalizer = $normalizer; } - $this->crashReporters = $registry; $this->eventDispatcher = null; } @@ -211,15 +207,18 @@ class Log implements ILogger, IDataLogger { */ public function log(int $level, string $message, array $context = []) { $minLevel = $this->getLogLevel($context); + if ($level < $minLevel + && (($this->crashReporters?->hasReporters() ?? false) === false) + && (($this->eventDispatcher?->hasListeners(BeforeMessageLoggedEvent::class) ?? false) === false)) { + return; // no crash reporter, no listeners, we can stop for lower log level + } array_walk($context, [$this->normalizer, 'format']); $app = $context['app'] ?? 'no app in context'; $entry = $this->interpolateMessage($context, $message); - if ($this->eventDispatcher) { - $this->eventDispatcher->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $entry)); - } + $this->eventDispatcher?->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $entry)); $hasBacktrace = isset($entry['exception']); $logBacktrace = $this->config->getValue('log.backtrace', false); @@ -241,9 +240,7 @@ class Log implements ILogger, IDataLogger { $this->crashReporters->delegateMessage($entry['message'], $messageContext); } } else { - if ($this->crashReporters !== null) { - $this->crashReporters->delegateBreadcrumb($entry['message'], 'log', $context); - } + $this->crashReporters?->delegateBreadcrumb($entry['message'], 'log', $context); } } catch (Throwable $e) { // make sure we dont hard crash if logging fails @@ -329,8 +326,10 @@ class Log implements ILogger, IDataLogger { $level = $context['level'] ?? ILogger::ERROR; $minLevel = $this->getLogLevel($context); - if ($level < $minLevel && ($this->crashReporters === null || !$this->crashReporters->hasReporters())) { - return; + if ($level < $minLevel + && (($this->crashReporters?->hasReporters() ?? false) === false) + && (($this->eventDispatcher?->hasListeners(BeforeMessageLoggedEvent::class) ?? false) === false)) { + return; // no crash reporter, no listeners, we can stop for lower log level } // if an error is raised before the autoloader is properly setup, we can't serialize exceptions @@ -344,14 +343,11 @@ class Log implements ILogger, IDataLogger { unset($data['app']); unset($data['level']); $data = array_merge($serializer->serializeException($exception), $data); - $data = $this->interpolateMessage($data, $context['message'] ?? '--', 'CustomMessage'); - + $data = $this->interpolateMessage($data, isset($context['message']) && $context['message'] !== '' ? $context['message'] : ('Exception thrown: ' . get_class($exception)), 'CustomMessage'); array_walk($context, [$this->normalizer, 'format']); - if ($this->eventDispatcher) { - $this->eventDispatcher->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $data)); - } + $this->eventDispatcher?->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $data)); try { if ($level >= $minLevel) { diff --git a/lib/private/Log/ErrorHandler.php b/lib/private/Log/ErrorHandler.php index c4b9631e75a..e5e04182cd0 100644 --- a/lib/private/Log/ErrorHandler.php +++ b/lib/private/Log/ErrorHandler.php @@ -36,10 +36,9 @@ use Psr\Log\LoggerInterface; use Throwable; class ErrorHandler { - private LoggerInterface $logger; - - public function __construct(LoggerInterface $logger) { - $this->logger = $logger; + public function __construct( + private LoggerInterface $logger, + ) { } /** @@ -94,20 +93,11 @@ class ErrorHandler { } private static function errnoToLogLevel(int $errno): int { - switch ($errno) { - case E_USER_WARNING: - return ILogger::WARN; - - case E_DEPRECATED: - case E_USER_DEPRECATED: - return ILogger::DEBUG; - - case E_USER_NOTICE: - return ILogger::INFO; - - case E_USER_ERROR: - default: - return ILogger::ERROR; - } + return match ($errno) { + E_USER_WARNING => ILogger::WARN, + E_DEPRECATED, E_USER_DEPRECATED => ILogger::DEBUG, + E_USER_NOTICE => ILogger::INFO, + default => ILogger::ERROR, + }; } } diff --git a/lib/private/Log/Errorlog.php b/lib/private/Log/Errorlog.php index 72d11aa098c..aaea8234f27 100644 --- a/lib/private/Log/Errorlog.php +++ b/lib/private/Log/Errorlog.php @@ -32,22 +32,19 @@ use OC\SystemConfig; use OCP\Log\IWriter; class Errorlog extends LogDetails implements IWriter { - /** @var string */ - protected $tag; - - public function __construct(SystemConfig $config, string $tag = 'nextcloud') { + public function __construct( + SystemConfig $config, + protected string $tag = 'nextcloud', + ) { parent::__construct($config); - $this->tag = $tag; } /** * Write a message in the log * - * @param string $app * @param string|array $message - * @param int $level */ - public function write(string $app, $message, int $level) { + public function write(string $app, $message, int $level): void { error_log('[' . $this->tag . ']['.$app.']['.$level.'] '.$this->logDetailsAsJSON($app, $message, $level)); } } diff --git a/lib/private/Log/ExceptionSerializer.php b/lib/private/Log/ExceptionSerializer.php index b585461e8d9..8b895bcb6be 100644 --- a/lib/private/Log/ExceptionSerializer.php +++ b/lib/private/Log/ExceptionSerializer.php @@ -112,11 +112,9 @@ class ExceptionSerializer { ]; - /** @var SystemConfig */ - private $systemConfig; - - public function __construct(SystemConfig $systemConfig) { - $this->systemConfig = $systemConfig; + public function __construct( + private SystemConfig $systemConfig, + ) { } protected array $methodsWithSensitiveParametersByClass = [ @@ -219,7 +217,7 @@ class ExceptionSerializer { }, $trace); } - private function removeValuesFromArgs($args, $values) { + private function removeValuesFromArgs($args, $values): array { $workArgs = []; foreach ($args as $arg) { if (in_array($arg, $values, true)) { @@ -279,7 +277,7 @@ class ExceptionSerializer { return $arg; } - public function serializeException(\Throwable $exception) { + public function serializeException(\Throwable $exception): array { $data = [ 'Exception' => get_class($exception), 'Message' => $exception->getMessage(), diff --git a/lib/private/Log/File.php b/lib/private/Log/File.php index a33667c9b68..328b0346985 100644 --- a/lib/private/Log/File.php +++ b/lib/private/Log/File.php @@ -48,14 +48,15 @@ use OCP\Log\IWriter; */ class File extends LogDetails implements IWriter, IFileBased { - /** @var string */ - protected $logFile; - /** @var int */ - protected $logFileMode; - /** @var SystemConfig */ - private $config; + protected string $logFile; - public function __construct(string $path, string $fallbackPath, SystemConfig $config) { + protected int $logFileMode; + + public function __construct( + string $path, + string $fallbackPath, + private SystemConfig $config, + ) { parent::__construct($config); $this->logFile = $path; if (!file_exists($this->logFile)) { @@ -69,17 +70,14 @@ class File extends LogDetails implements IWriter, IFileBased { $this->logFile = $fallbackPath; } } - $this->config = $config; $this->logFileMode = $config->getValue('logfilemode', 0640); } /** * write a message in the log - * @param string $app * @param string|array $message - * @param int $level */ - public function write(string $app, $message, int $level) { + public function write(string $app, $message, int $level): void { $entry = $this->logDetailsAsJSON($app, $message, $level); $handle = @fopen($this->logFile, 'a'); if ($this->logFileMode > 0 && is_file($this->logFile) && (fileperms($this->logFile) & 0777) != $this->logFileMode) { @@ -102,11 +100,8 @@ class File extends LogDetails implements IWriter, IFileBased { /** * get entries from the log in reverse chronological order - * @param int $limit - * @param int $offset - * @return array */ - public function getEntries(int $limit = 50, int $offset = 0):array { + public function getEntries(int $limit = 50, int $offset = 0): array { $minLevel = $this->config->getValue("loglevel", ILogger::WARN); $entries = []; $handle = @fopen($this->logFile, 'rb'); @@ -148,9 +143,6 @@ class File extends LogDetails implements IWriter, IFileBased { return $entries; } - /** - * @return string - */ public function getLogFilePath():string { return $this->logFile; } diff --git a/lib/private/Log/LogDetails.php b/lib/private/Log/LogDetails.php index c82904d7cea..f8b43881f66 100644 --- a/lib/private/Log/LogDetails.php +++ b/lib/private/Log/LogDetails.php @@ -28,11 +28,9 @@ namespace OC\Log; use OC\SystemConfig; abstract class LogDetails { - /** @var SystemConfig */ - private $config; - - public function __construct(SystemConfig $config) { - $this->config = $config; + public function __construct( + private SystemConfig $config, + ) { } public function logDetails(string $app, $message, int $level): array { @@ -108,7 +106,7 @@ abstract class LogDetails { if (is_string($value)) { $testEncode = json_encode($value, JSON_UNESCAPED_SLASHES); if ($testEncode === false) { - $entry[$key] = utf8_encode($value); + $entry[$key] = mb_convert_encoding($value, 'UTF-8', mb_detect_encoding($value)); } } } diff --git a/lib/private/Log/LogFactory.php b/lib/private/Log/LogFactory.php index a5008f5ef77..c395c31eb98 100644 --- a/lib/private/Log/LogFactory.php +++ b/lib/private/Log/LogFactory.php @@ -33,57 +33,37 @@ use OCP\Log\IWriter; use Psr\Log\LoggerInterface; class LogFactory implements ILogFactory { - /** @var IServerContainer */ - private $c; - /** @var SystemConfig */ - private $systemConfig; - - public function __construct(IServerContainer $c, SystemConfig $systemConfig) { - $this->c = $c; - $this->systemConfig = $systemConfig; + public function __construct( + private IServerContainer $c, + private SystemConfig $systemConfig, + ) { } /** * @throws \OCP\AppFramework\QueryException */ public function get(string $type):IWriter { - switch (strtolower($type)) { - case 'errorlog': - return new Errorlog($this->systemConfig); - case 'syslog': - return $this->c->resolve(Syslog::class); - case 'systemd': - return $this->c->resolve(Systemdlog::class); - case 'file': - return $this->buildLogFile(); - - // Backwards compatibility for old and fallback for unknown log types - case 'owncloud': - case 'nextcloud': - default: - return $this->buildLogFile(); - } + return match (strtolower($type)) { + 'errorlog' => new Errorlog($this->systemConfig), + 'syslog' => $this->c->resolve(Syslog::class), + 'systemd' => $this->c->resolve(Systemdlog::class), + 'file' => $this->buildLogFile(), + default => $this->buildLogFile(), + }; } - public function getCustomLogger(string $path):ILogger { + public function getCustomLogger(string $path): ILogger { $log = $this->buildLogFile($path); return new Log($log, $this->systemConfig); } protected function createNewLogger(string $type, string $tag, string $path): IWriter { - switch (strtolower($type)) { - case 'errorlog': - return new Errorlog($this->systemConfig, $tag); - case 'syslog': - return new Syslog($this->systemConfig, $tag); - case 'systemd': - return new Systemdlog($this->systemConfig, $tag); - case 'file': - case 'owncloud': - case 'nextcloud': - default: - return $this->buildLogFile($path); - } + return match (strtolower($type)) { + 'errorlog' => new Errorlog($this->systemConfig, $tag), + 'syslog' => new Syslog($this->systemConfig, $tag), + 'systemd' => new Systemdlog($this->systemConfig, $tag), + default => $this->buildLogFile($path), + }; } public function getCustomPsrLogger(string $path, string $type = 'file', string $tag = 'Nextcloud'): LoggerInterface { @@ -93,7 +73,7 @@ class LogFactory implements ILogFactory { ); } - protected function buildLogFile(string $logFile = ''):File { + protected function buildLogFile(string $logFile = ''): File { $defaultLogFile = $this->systemConfig->getValue('datadirectory', \OC::$SERVERROOT.'/data').'/nextcloud.log'; if ($logFile === '') { $logFile = $this->systemConfig->getValue('logfile', $defaultLogFile); diff --git a/lib/private/Log/PsrLoggerAdapter.php b/lib/private/Log/PsrLoggerAdapter.php index 07a898e2528..12254bfc67f 100644 --- a/lib/private/Log/PsrLoggerAdapter.php +++ b/lib/private/Log/PsrLoggerAdapter.php @@ -36,14 +36,12 @@ use function array_key_exists; use function array_merge; final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { - /** @var Log */ - private $logger; - - public function __construct(Log $logger) { - $this->logger = $logger; + public function __construct( + private Log $logger, + ) { } - public function setEventDispatcher(IEventDispatcher $eventDispatcher) { + public function setEventDispatcher(IEventDispatcher $eventDispatcher): void { $this->logger->setEventDispatcher($eventDispatcher); } @@ -55,9 +53,6 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { * System is unusable. * * @param string $message - * @param array $context - * - * @return void */ public function emergency($message, array $context = []): void { if ($this->containsThrowable($context)) { @@ -80,11 +75,8 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { * trigger the SMS alerts and wake you up. * * @param string $message - * @param array $context - * - * @return void */ - public function alert($message, array $context = []) { + public function alert($message, array $context = []): void { if ($this->containsThrowable($context)) { $this->logger->logException($context['exception'], array_merge( [ @@ -104,11 +96,8 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { * Example: Application component unavailable, unexpected exception. * * @param string $message - * @param array $context - * - * @return void */ - public function critical($message, array $context = []) { + public function critical($message, array $context = []): void { if ($this->containsThrowable($context)) { $this->logger->logException($context['exception'], array_merge( [ @@ -127,11 +116,8 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { * be logged and monitored. * * @param string $message - * @param array $context - * - * @return void */ - public function error($message, array $context = []) { + public function error($message, array $context = []): void { if ($this->containsThrowable($context)) { $this->logger->logException($context['exception'], array_merge( [ @@ -152,11 +138,8 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { * that are not necessarily wrong. * * @param string $message - * @param array $context - * - * @return void */ - public function warning($message, array $context = []) { + public function warning($message, array $context = []): void { if ($this->containsThrowable($context)) { $this->logger->logException($context['exception'], array_merge( [ @@ -174,11 +157,8 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { * Normal but significant events. * * @param string $message - * @param array $context - * - * @return void */ - public function notice($message, array $context = []) { + public function notice($message, array $context = []): void { if ($this->containsThrowable($context)) { $this->logger->logException($context['exception'], array_merge( [ @@ -198,11 +178,8 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { * Example: User logs in, SQL logs. * * @param string $message - * @param array $context - * - * @return void */ - public function info($message, array $context = []) { + public function info($message, array $context = []): void { if ($this->containsThrowable($context)) { $this->logger->logException($context['exception'], array_merge( [ @@ -220,11 +197,8 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { * Detailed debug information. * * @param string $message - * @param array $context - * - * @return void */ - public function debug($message, array $context = []) { + public function debug($message, array $context = []): void { if ($this->containsThrowable($context)) { $this->logger->logException($context['exception'], array_merge( [ @@ -243,13 +217,10 @@ final class PsrLoggerAdapter implements LoggerInterface, IDataLogger { * * @param mixed $level * @param string $message - * @param array $context - * - * @return void * * @throws InvalidArgumentException */ - public function log($level, $message, array $context = []) { + public function log($level, $message, array $context = []): void { if (!is_int($level) || $level < ILogger::DEBUG || $level > ILogger::FATAL) { throw new InvalidArgumentException('Nextcloud allows only integer log levels'); } diff --git a/lib/private/Log/Rotate.php b/lib/private/Log/Rotate.php index dfb588837f3..71965a12035 100644 --- a/lib/private/Log/Rotate.php +++ b/lib/private/Log/Rotate.php @@ -24,7 +24,9 @@ */ namespace OC\Log; +use OCP\IConfig; use OCP\Log\RotationTrait; +use Psr\Log\LoggerInterface; /** * This rotates the current logfile to a new name, this way the total log usage @@ -35,15 +37,15 @@ use OCP\Log\RotationTrait; class Rotate extends \OCP\BackgroundJob\Job { use RotationTrait; - public function run($dummy) { - $systemConfig = \OC::$server->getSystemConfig(); - $this->filePath = $systemConfig->getValue('logfile', $systemConfig->getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/nextcloud.log'); + public function run($argument): void { + $config = \OCP\Server::get(IConfig::class); + $this->filePath = $config->getSystemValueString('logfile', $config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/nextcloud.log'); - $this->maxSize = \OC::$server->getConfig()->getSystemValueInt('log_rotate_size', 100 * 1024 * 1024); + $this->maxSize = $config->getSystemValueInt('log_rotate_size', 100 * 1024 * 1024); if ($this->shouldRotateBySize()) { $rotatedFile = $this->rotate(); $msg = 'Log file "'.$this->filePath.'" was over '.$this->maxSize.' bytes, moved to "'.$rotatedFile.'"'; - \OC::$server->getLogger()->warning($msg, ['app' => Rotate::class]); + \OCP\Server::get(LoggerInterface::class)->info($msg, ['app' => Rotate::class]); } } } diff --git a/lib/private/Log/Syslog.php b/lib/private/Log/Syslog.php index f4ba857742f..5f220ee1eb7 100644 --- a/lib/private/Log/Syslog.php +++ b/lib/private/Log/Syslog.php @@ -30,7 +30,7 @@ use OCP\ILogger; use OCP\Log\IWriter; class Syslog extends LogDetails implements IWriter { - protected $levels = [ + protected array $levels = [ ILogger::DEBUG => LOG_DEBUG, ILogger::INFO => LOG_INFO, ILogger::WARN => LOG_WARNING, @@ -38,7 +38,10 @@ class Syslog extends LogDetails implements IWriter { ILogger::FATAL => LOG_CRIT, ]; - public function __construct(SystemConfig $config, ?string $tag = null) { + public function __construct( + SystemConfig $config, + ?string $tag = null, + ) { parent::__construct($config); if ($tag === null) { $tag = $config->getValue('syslog_tag', 'Nextcloud'); @@ -52,11 +55,9 @@ class Syslog extends LogDetails implements IWriter { /** * write a message in the log - * @param string $app * @param string|array $message - * @param int $level */ - public function write(string $app, $message, int $level) { + public function write(string $app, $message, int $level): void { $syslog_level = $this->levels[$level]; syslog($syslog_level, $this->logDetailsAsJSON($app, $message, $level)); } diff --git a/lib/private/Log/Systemdlog.php b/lib/private/Log/Systemdlog.php index 8619cb5e4dd..e4b4ce35c12 100644 --- a/lib/private/Log/Systemdlog.php +++ b/lib/private/Log/Systemdlog.php @@ -46,7 +46,7 @@ use OCP\Log\IWriter; // Syslog compatibility fields class Systemdlog extends LogDetails implements IWriter { - protected $levels = [ + protected array $levels = [ ILogger::DEBUG => 7, ILogger::INFO => 6, ILogger::WARN => 4, @@ -54,9 +54,12 @@ class Systemdlog extends LogDetails implements IWriter { ILogger::FATAL => 2, ]; - protected $syslogId; + protected string $syslogId; - public function __construct(SystemConfig $config, ?string $tag = null) { + public function __construct( + SystemConfig $config, + ?string $tag = null, + ) { parent::__construct($config); if (!function_exists('sd_journal_send')) { throw new HintException( @@ -71,11 +74,9 @@ class Systemdlog extends LogDetails implements IWriter { /** * Write a message to the log. - * @param string $app * @param string|array $message - * @param int $level */ - public function write(string $app, $message, int $level) { + public function write(string $app, $message, int $level): void { $journal_level = $this->levels[$level]; sd_journal_send('PRIORITY='.$journal_level, 'SYSLOG_IDENTIFIER='.$this->syslogId, diff --git a/lib/private/Mail/Mailer.php b/lib/private/Mail/Mailer.php index 9b7b3cf117b..61dc6f9214b 100644 --- a/lib/private/Mail/Mailer.php +++ b/lib/private/Mail/Mailer.php @@ -331,7 +331,7 @@ class Mailer implements IMailer { } $binaryParam = match ($this->config->getSystemValueString('mail_sendmailmode', 'smtp')) { - 'pipe' => ' -t', + 'pipe' => ' -t -i', default => ' -bs', }; diff --git a/lib/private/Memcache/Cache.php b/lib/private/Memcache/Cache.php index 1d54a705098..f0e794d6582 100644 --- a/lib/private/Memcache/Cache.php +++ b/lib/private/Memcache/Cache.php @@ -24,6 +24,9 @@ */ namespace OC\Memcache; +/** + * @template-implements \ArrayAccess<string,mixed> + */ abstract class Cache implements \ArrayAccess, \OCP\ICache { /** * @var string $prefix diff --git a/lib/private/Memcache/Factory.php b/lib/private/Memcache/Factory.php index 788a7c2e8c9..ab8fcea4e6a 100644 --- a/lib/private/Memcache/Factory.php +++ b/lib/private/Memcache/Factory.php @@ -31,10 +31,11 @@ */ namespace OC\Memcache; -use OCP\Profiler\IProfiler; +use OCP\Cache\CappedMemoryCache; use OCP\ICache; use OCP\ICacheFactory; use OCP\IMemcache; +use OCP\Profiler\IProfiler; use Psr\Log\LoggerInterface; class Factory implements ICacheFactory { @@ -184,13 +185,8 @@ class Factory implements ICacheFactory { return $this->distributedCacheClass !== self::NULL_CACHE; } - /** - * @see \OC\Memcache\Factory::createLocal() - * @param string $prefix - * @return ICache - */ - public function createLowLatency(string $prefix = ''): ICache { - return $this->createLocal($prefix); + public function createInMemory(int $capacity = 512): ICache { + return new CappedMemoryCache($capacity); } /** diff --git a/lib/private/Memcache/LoggerWrapperCache.php b/lib/private/Memcache/LoggerWrapperCache.php index 55c0e76db79..55d5104dedb 100644 --- a/lib/private/Memcache/LoggerWrapperCache.php +++ b/lib/private/Memcache/LoggerWrapperCache.php @@ -167,10 +167,18 @@ class LoggerWrapperCache extends Cache implements IMemcacheTTL { } /** @inheritDoc */ - public function setTTL($key, $ttl) { + public function setTTL(string $key, int $ttl) { $this->wrappedCache->setTTL($key, $ttl); } + public function getTTL(string $key): int|false { + return $this->wrappedCache->getTTL($key); + } + + public function compareSetTTL(string $key, mixed $value, int $ttl): bool { + return $this->wrappedCache->compareSetTTL($key, $value, $ttl); + } + public static function isAvailable(): bool { return true; } diff --git a/lib/private/Memcache/ProfilerWrapperCache.php b/lib/private/Memcache/ProfilerWrapperCache.php index 6e76989dddd..0d991a87ab8 100644 --- a/lib/private/Memcache/ProfilerWrapperCache.php +++ b/lib/private/Memcache/ProfilerWrapperCache.php @@ -32,6 +32,7 @@ use OCP\IMemcacheTTL; /** * Cache wrapper that logs profiling information + * @template-implements \ArrayAccess<string,mixed> */ class ProfilerWrapperCache extends AbstractDataCollector implements IMemcacheTTL, \ArrayAccess { /** @var Redis $wrappedCache*/ @@ -183,10 +184,18 @@ class ProfilerWrapperCache extends AbstractDataCollector implements IMemcacheTTL } /** @inheritDoc */ - public function setTTL($key, $ttl) { + public function setTTL(string $key, int $ttl) { $this->wrappedCache->setTTL($key, $ttl); } + public function getTTL(string $key): int|false { + return $this->wrappedCache->getTTL($key); + } + + public function compareSetTTL(string $key, mixed $value, int $ttl): bool { + return $this->wrappedCache->compareSetTTL($key, $value, $ttl); + } + public function offsetExists($offset): bool { return $this->hasKey($offset); } diff --git a/lib/private/Memcache/Redis.php b/lib/private/Memcache/Redis.php index bde25a3385a..5e9554eb94e 100644 --- a/lib/private/Memcache/Redis.php +++ b/lib/private/Memcache/Redis.php @@ -46,8 +46,15 @@ class Redis extends Cache implements IMemcacheTTL { 'if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end', 'cf0e94b2e9ffc7e04395cf88f7583fc309985910', ], + 'caSetTtl' => [ + 'if redis.call("get", KEYS[1]) == ARGV[1] then redis.call("expire", KEYS[1], ARGV[2]) return 1 else return 0 end', + 'fa4acbc946d23ef41d7d3910880b60e6e4972d72', + ], ]; + private const DEFAULT_TTL = 24 * 60 * 60; // 1 day + private const MAX_TTL = 30 * 24 * 60 * 60; // 1 month + /** * @var \Redis|\RedisCluster $cache */ @@ -79,11 +86,12 @@ class Redis extends Cache implements IMemcacheTTL { public function set($key, $value, $ttl = 0) { $value = self::encodeValue($value); - if ($ttl > 0) { - return $this->getCache()->setex($this->getPrefix() . $key, $ttl, $value); - } else { - return $this->getCache()->set($this->getPrefix() . $key, $value); + if ($ttl === 0) { + // having infinite TTL can lead to leaked keys as the prefix changes with version upgrades + $ttl = self::DEFAULT_TTL; } + $ttl = min($ttl, self::MAX_TTL); + return $this->getCache()->setex($this->getPrefix() . $key, $ttl, $value); } public function hasKey($key) { @@ -117,11 +125,14 @@ class Redis extends Cache implements IMemcacheTTL { */ public function add($key, $value, $ttl = 0) { $value = self::encodeValue($value); + if ($ttl === 0) { + // having infinite TTL can lead to leaked keys as the prefix changes with version upgrades + $ttl = self::DEFAULT_TTL; + } + $ttl = min($ttl, self::MAX_TTL); $args = ['nx']; - if ($ttl !== 0 && is_int($ttl)) { - $args['ex'] = $ttl; - } + $args['ex'] = $ttl; return $this->getCache()->set($this->getPrefix() . $key, $value, $args); } @@ -178,9 +189,25 @@ class Redis extends Cache implements IMemcacheTTL { } public function setTTL($key, $ttl) { + if ($ttl === 0) { + // having infinite TTL can lead to leaked keys as the prefix changes with version upgrades + $ttl = self::DEFAULT_TTL; + } + $ttl = min($ttl, self::MAX_TTL); $this->getCache()->expire($this->getPrefix() . $key, $ttl); } + public function getTTL(string $key): int|false { + $ttl = $this->getCache()->ttl($this->getPrefix() . $key); + return $ttl > 0 ? (int)$ttl : false; + } + + public function compareSetTTL(string $key, mixed $value, int $ttl): bool { + $value = self::encodeValue($value); + + return $this->evalLua('caSetTtl', [$key], [$value, $ttl]) > 0; + } + public static function isAvailable(): bool { return \OC::$server->getGetRedisFactory()->isAvailable(); } diff --git a/lib/private/Metadata/FileEventListener.php b/lib/private/Metadata/FileEventListener.php deleted file mode 100644 index 162e85ff3aa..00000000000 --- a/lib/private/Metadata/FileEventListener.php +++ /dev/null @@ -1,110 +0,0 @@ -<?php - -declare(strict_types=1); -/** - * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu> - * @license AGPL-3.0-or-later - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Metadata; - -use OC\Files\Filesystem; -use OCP\EventDispatcher\Event; -use OCP\EventDispatcher\IEventListener; -use OCP\Files\Events\Node\NodeDeletedEvent; -use OCP\Files\Events\Node\NodeWrittenEvent; -use OCP\Files\Events\NodeRemovedFromCache; -use OCP\Files\File; -use OCP\Files\Node; -use OCP\Files\NotFoundException; -use OCP\Files\FileInfo; -use Psr\Log\LoggerInterface; - -/** - * @template-implements IEventListener<NodeRemovedFromCache> - * @template-implements IEventListener<NodeDeletedEvent> - * @template-implements IEventListener<NodeWrittenEvent> - */ -class FileEventListener implements IEventListener { - private IMetadataManager $manager; - private LoggerInterface $logger; - - public function __construct(IMetadataManager $manager, LoggerInterface $logger) { - $this->manager = $manager; - $this->logger = $logger; - } - - private function shouldExtractMetadata(Node $node): bool { - try { - if ($node->getMimetype() === 'httpd/unix-directory') { - return false; - } - } catch (NotFoundException $e) { - return false; - } - if ($node->getSize(false) <= 0) { - return false; - } - - $path = $node->getPath(); - return $this->isCorrectPath($path); - } - - private function isCorrectPath(string $path): bool { - // TODO make this more dynamic, we have the same issue in other places - return !str_starts_with($path, 'appdata_') && !str_starts_with($path, 'files_versions/') && !str_starts_with($path, 'files_trashbin/'); - } - - public function handle(Event $event): void { - if ($event instanceof NodeRemovedFromCache) { - if (!$this->isCorrectPath($event->getPath())) { - // Don't listen to paths for which we don't extract metadata - return; - } - $view = Filesystem::getView(); - if (!$view) { - // Should not happen since a scan in the user folder should setup - // the file system. - $e = new \Exception(); // don't trigger, just get backtrace - $this->logger->error('Detecting deletion of a file with possible metadata but file system setup is not setup', [ - 'exception' => $e, - 'app' => 'metadata' - ]); - return; - } - $info = $view->getFileInfo($event->getPath()); - if ($info && $info->getType() === FileInfo::TYPE_FILE) { - $this->manager->clearMetadata($info->getId()); - } - } - - if ($event instanceof NodeDeletedEvent) { - $node = $event->getNode(); - if ($this->shouldExtractMetadata($node)) { - /** @var File $node */ - $this->manager->clearMetadata($event->getNode()->getId()); - } - } - - if ($event instanceof NodeWrittenEvent) { - $node = $event->getNode(); - if ($this->shouldExtractMetadata($node)) { - /** @var File $node */ - $this->manager->generateMetadata($event->getNode(), false); - } - } - } -} diff --git a/lib/private/Metadata/FileMetadata.php b/lib/private/Metadata/FileMetadata.php deleted file mode 100644 index a9808a86998..00000000000 --- a/lib/private/Metadata/FileMetadata.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php - -declare(strict_types=1); -/** - * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Metadata; - -use OCP\AppFramework\Db\Entity; -use OCP\DB\Types; - -/** - * @method string getGroupName() - * @method void setGroupName(string $groupName) - * @method string getValue() - * @method void setValue(string $value) - * @see \OC\Core\Migrations\Version240000Date20220404230027 - */ -class FileMetadata extends Entity { - protected ?string $groupName = null; - protected ?string $value = null; - - public function __construct() { - $this->addType('groupName', 'string'); - $this->addType('value', Types::STRING); - } - - public function getDecodedValue(): array { - return json_decode($this->getValue(), true) ?? []; - } - - public function setArrayAsValue(array $value): void { - $this->setValue(json_encode($value, JSON_THROW_ON_ERROR)); - } -} diff --git a/lib/private/Metadata/FileMetadataMapper.php b/lib/private/Metadata/FileMetadataMapper.php deleted file mode 100644 index 003ab13126e..00000000000 --- a/lib/private/Metadata/FileMetadataMapper.php +++ /dev/null @@ -1,177 +0,0 @@ -<?php - -declare(strict_types=1); -/** - * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu> - * @copyright Copyright 2022 Louis Chmn <louis@chmn.me> - * @license AGPL-3.0-or-later - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Metadata; - -use OCP\AppFramework\Db\DoesNotExistException; -use OCP\AppFramework\Db\MultipleObjectsReturnedException; -use OCP\AppFramework\Db\QBMapper; -use OCP\AppFramework\Db\Entity; -use OCP\DB\Exception; -use OCP\DB\QueryBuilder\IQueryBuilder; -use OCP\IDBConnection; - -/** - * @template-extends QBMapper<FileMetadata> - */ -class FileMetadataMapper extends QBMapper { - public function __construct(IDBConnection $db) { - parent::__construct($db, 'file_metadata', FileMetadata::class); - } - - /** - * @return FileMetadata[] - * @throws Exception - */ - public function findForFile(int $fileId): array { - $qb = $this->db->getQueryBuilder(); - $qb->select('*') - ->from($this->getTableName()) - ->where($qb->expr()->eq('id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); - - return $this->findEntities($qb); - } - - /** - * @throws DoesNotExistException - * @throws MultipleObjectsReturnedException - * @throws Exception - */ - public function findForGroupForFile(int $fileId, string $groupName): FileMetadata { - $qb = $this->db->getQueryBuilder(); - $qb->select('*') - ->from($this->getTableName()) - ->where($qb->expr()->eq('id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))) - ->andWhere($qb->expr()->eq('group_name', $qb->createNamedParameter($groupName, IQueryBuilder::PARAM_STR))); - - return $this->findEntity($qb); - } - - /** - * @return array<int, FileMetadata> - * @throws Exception - */ - public function findForGroupForFiles(array $fileIds, string $groupName): array { - $qb = $this->db->getQueryBuilder(); - $qb->select('*') - ->from($this->getTableName()) - ->where($qb->expr()->in('id', $qb->createParameter('fileIds'))) - ->andWhere($qb->expr()->eq('group_name', $qb->createNamedParameter($groupName, IQueryBuilder::PARAM_STR))); - - $metadata = []; - foreach (array_chunk($fileIds, 1000) as $fileIdsChunk) { - $qb->setParameter('fileIds', $fileIdsChunk, IQueryBuilder::PARAM_INT_ARRAY); - /** @var FileMetadata[] $rawEntities */ - $rawEntities = $this->findEntities($qb); - foreach ($rawEntities as $entity) { - $metadata[$entity->getId()] = $entity; - } - } - - foreach ($fileIds as $id) { - if (isset($metadata[$id])) { - continue; - } - $empty = new FileMetadata(); - $empty->setValue(''); - $empty->setGroupName($groupName); - $empty->setId($id); - $metadata[$id] = $empty; - } - return $metadata; - } - - public function clear(int $fileId): void { - $qb = $this->db->getQueryBuilder(); - $qb->delete($this->getTableName()) - ->where($qb->expr()->eq('id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); - - $qb->executeStatement(); - } - - /** - * Updates an entry in the db from an entity - * - * @param FileMetadata $entity the entity that should be created - * @return FileMetadata the saved entity with the set id - * @throws Exception - * @throws \InvalidArgumentException if entity has no id - */ - public function update(Entity $entity): FileMetadata { - if (!($entity instanceof FileMetadata)) { - throw new \Exception("Entity should be a FileMetadata entity"); - } - - // entity needs an id - $id = $entity->getId(); - if ($id === null) { - throw new \InvalidArgumentException('Entity which should be updated has no id'); - } - - // entity needs an group_name - $groupName = $entity->getGroupName(); - if ($groupName === null) { - throw new \InvalidArgumentException('Entity which should be updated has no group_name'); - } - - $idType = $this->getParameterTypeForProperty($entity, 'id'); - $groupNameType = $this->getParameterTypeForProperty($entity, 'groupName'); - $value = $entity->getValue(); - $valueType = $this->getParameterTypeForProperty($entity, 'value'); - - $qb = $this->db->getQueryBuilder(); - - $qb->update($this->tableName) - ->set('value', $qb->createNamedParameter($value, $valueType)) - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, $idType))) - ->andWhere($qb->expr()->eq('group_name', $qb->createNamedParameter($groupName, $groupNameType))) - ->executeStatement(); - - return $entity; - } - - /** - * Override the insertOrUpdate as we could be in a transaction in which case we can not afford on error. - * - * @param FileMetadata $entity the entity that should be created/updated - * @return FileMetadata the saved entity with the (new) id - * @throws Exception - * @throws \InvalidArgumentException if entity has no id - */ - public function insertOrUpdate(Entity $entity): FileMetadata { - try { - $existingEntity = $this->findForGroupForFile($entity->getId(), $entity->getGroupName()); - } catch (\Throwable) { - $existingEntity = null; - } - - if ($existingEntity !== null) { - if ($entity->getValue() !== $existingEntity->getValue()) { - return $this->update($entity); - } else { - return $existingEntity; - } - } else { - return parent::insertOrUpdate($entity); - } - } -} diff --git a/lib/private/Metadata/IMetadataManager.php b/lib/private/Metadata/IMetadataManager.php deleted file mode 100644 index fa0bcc22801..00000000000 --- a/lib/private/Metadata/IMetadataManager.php +++ /dev/null @@ -1,35 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace OC\Metadata; - -use OCP\Files\File; - -/** - * Interface to manage additional metadata for files - */ -interface IMetadataManager { - /** - * @param class-string<IMetadataProvider> $className - */ - public function registerProvider(string $className): void; - - /** - * Generate the metadata for one file - */ - public function generateMetadata(File $file, bool $checkExisting = false): void; - - /** - * Clear the metadata for one file - */ - public function clearMetadata(int $fileId): void; - - /** @return array<int, FileMetadata> */ - public function fetchMetadataFor(string $group, array $fileIds): array; - - /** - * Get the capabilities as an array of mimetype regex to the type provided - */ - public function getCapabilities(): array; -} diff --git a/lib/private/Metadata/IMetadataProvider.php b/lib/private/Metadata/IMetadataProvider.php deleted file mode 100644 index 7cbe102a538..00000000000 --- a/lib/private/Metadata/IMetadataProvider.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php - -namespace OC\Metadata; - -use OCP\Files\File; - -/** - * Interface for the metadata providers. If you want an application to provide - * some metadata, you can use this to store them. - */ -interface IMetadataProvider { - /** - * The list of groups that this metadata provider is able to provide. - * - * @return string[] - */ - public static function groupsProvided(): array; - - /** - * Check if the metadata provider is available. A metadata provider might be - * unavailable due to a php extension not being installed. - */ - public static function isAvailable(): bool; - - /** - * Get the mimetypes supported as a regex. - */ - public static function getMimetypesSupported(): string; - - /** - * Execute the extraction on the specified file. The metadata should be - * grouped by metadata - * - * Each group should be json serializable and the string representation - * shouldn't be longer than 4000 characters. - * - * @param File $file The file to extract the metadata from - * @param array<string, FileMetadata> An array containing all the metadata fetched. - */ - public function execute(File $file): array; -} diff --git a/lib/private/Metadata/MetadataManager.php b/lib/private/Metadata/MetadataManager.php deleted file mode 100644 index 6d96ff1ab68..00000000000 --- a/lib/private/Metadata/MetadataManager.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php -/** - * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu> - * @license AGPL-3.0-or-later - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Metadata; - -use OC\Metadata\Provider\ExifProvider; -use OCP\Files\File; - -class MetadataManager implements IMetadataManager { - /** @var array<string, IMetadataProvider> */ - private array $providers; - private array $providerClasses; - private FileMetadataMapper $fileMetadataMapper; - - public function __construct( - FileMetadataMapper $fileMetadataMapper - ) { - $this->providers = []; - $this->providerClasses = []; - $this->fileMetadataMapper = $fileMetadataMapper; - - // TODO move to another place, where? - $this->registerProvider(ExifProvider::class); - } - - /** - * @param class-string<IMetadataProvider> $className - */ - public function registerProvider(string $className):void { - if (in_array($className, $this->providerClasses)) { - return; - } - - if (call_user_func([$className, 'isAvailable'])) { - $this->providers[call_user_func([$className, 'getMimetypesSupported'])] = \OC::$server->get($className); - } - } - - public function generateMetadata(File $file, bool $checkExisting = false): void { - $existingMetadataGroups = []; - - if ($checkExisting) { - $existingMetadata = $this->fileMetadataMapper->findForFile($file->getId()); - foreach ($existingMetadata as $metadata) { - $existingMetadataGroups[] = $metadata->getGroupName(); - } - } - - foreach ($this->providers as $supportedMimetype => $provider) { - if (preg_match($supportedMimetype, $file->getMimeType())) { - if (count(array_diff($provider::groupsProvided(), $existingMetadataGroups)) > 0) { - $metaDataGroup = $provider->execute($file); - foreach ($metaDataGroup as $group => $metadata) { - $this->fileMetadataMapper->insertOrUpdate($metadata); - } - } - } - } - } - - public function clearMetadata(int $fileId): void { - $this->fileMetadataMapper->clear($fileId); - } - - /** - * @return array<int, FileMetadata> - */ - public function fetchMetadataFor(string $group, array $fileIds): array { - return $this->fileMetadataMapper->findForGroupForFiles($fileIds, $group); - } - - public function getCapabilities(): array { - $capabilities = []; - foreach ($this->providers as $supportedMimetype => $provider) { - foreach ($provider::groupsProvided() as $group) { - if (isset($capabilities[$group])) { - $capabilities[$group][] = $supportedMimetype; - } - $capabilities[$group] = [$supportedMimetype]; - } - } - return $capabilities; - } -} diff --git a/lib/private/Metadata/Provider/ExifProvider.php b/lib/private/Metadata/Provider/ExifProvider.php deleted file mode 100644 index b1598abbbc8..00000000000 --- a/lib/private/Metadata/Provider/ExifProvider.php +++ /dev/null @@ -1,142 +0,0 @@ -<?php - -declare(strict_types=1); -/** - * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu> - * @copyright Copyright 2022 Louis Chmn <louis@chmn.me> - * @license AGPL-3.0-or-later - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OC\Metadata\Provider; - -use OC\Metadata\FileMetadata; -use OC\Metadata\IMetadataProvider; -use OCP\Files\File; -use Psr\Log\LoggerInterface; - -class ExifProvider implements IMetadataProvider { - private LoggerInterface $logger; - - public function __construct( - LoggerInterface $logger - ) { - $this->logger = $logger; - } - - public static function groupsProvided(): array { - return ['size', 'gps']; - } - - public static function isAvailable(): bool { - return extension_loaded('exif'); - } - - /** @return array{'gps'?: FileMetadata, 'size'?: FileMetadata} */ - public function execute(File $file): array { - $exifData = []; - $fileDescriptor = $file->fopen('rb'); - - if ($fileDescriptor === false) { - return []; - } - - $data = null; - try { - // Needed to make reading exif data reliable. - // This is to trigger this condition: https://github.com/php/php-src/blob/d64aa6f646a7b5e58359dc79479860164239580a/main/streams/streams.c#L710 - // But I don't understand why 1 as a special meaning. - // Revert right after reading the exif data. - $oldBufferSize = stream_set_chunk_size($fileDescriptor, 1); - $data = @exif_read_data($fileDescriptor, 'ANY_TAG', true); - stream_set_chunk_size($fileDescriptor, $oldBufferSize); - } catch (\Exception $ex) { - $this->logger->info("Couldn't extract metadata for ".$file->getId(), ['exception' => $ex]); - } - - $size = new FileMetadata(); - $size->setGroupName('size'); - $size->setId($file->getId()); - $size->setArrayAsValue([]); - - if (!$data) { - $sizeResult = getimagesizefromstring($file->getContent()); - if ($sizeResult !== false) { - $size->setArrayAsValue([ - 'width' => $sizeResult[0], - 'height' => $sizeResult[1], - ]); - - $exifData['size'] = $size; - } - } elseif (array_key_exists('COMPUTED', $data)) { - if (array_key_exists('Width', $data['COMPUTED']) && array_key_exists('Height', $data['COMPUTED'])) { - $size->setArrayAsValue([ - 'width' => $data['COMPUTED']['Width'], - 'height' => $data['COMPUTED']['Height'], - ]); - - $exifData['size'] = $size; - } - } - - if ($data && array_key_exists('GPS', $data) - && array_key_exists('GPSLatitude', $data['GPS']) && array_key_exists('GPSLatitudeRef', $data['GPS']) - && array_key_exists('GPSLongitude', $data['GPS']) && array_key_exists('GPSLongitudeRef', $data['GPS']) - ) { - $gps = new FileMetadata(); - $gps->setGroupName('gps'); - $gps->setId($file->getId()); - $gps->setArrayAsValue([ - 'latitude' => $this->gpsDegreesToDecimal($data['GPS']['GPSLatitude'], $data['GPS']['GPSLatitudeRef']), - 'longitude' => $this->gpsDegreesToDecimal($data['GPS']['GPSLongitude'], $data['GPS']['GPSLongitudeRef']), - ]); - - $exifData['gps'] = $gps; - } - - return $exifData; - } - - public static function getMimetypesSupported(): string { - return '/image\/(png|jpeg|heif|webp|tiff)/'; - } - - /** - * @param array|string $coordinates - */ - private static function gpsDegreesToDecimal($coordinates, ?string $hemisphere): float { - if (is_string($coordinates)) { - $coordinates = array_map("trim", explode(",", $coordinates)); - } - - if (count($coordinates) !== 3) { - throw new \Exception('Invalid coordinate format: ' . json_encode($coordinates)); - } - - [$degrees, $minutes, $seconds] = array_map(function (string $rawDegree) { - $parts = explode('/', $rawDegree); - - if ($parts[1] === '0') { - return 0; - } - - return floatval($parts[0]) / floatval($parts[1] ?? 1); - }, $coordinates); - - $sign = ($hemisphere === 'W' || $hemisphere === 'S') ? -1 : 1; - return $sign * ($degrees + $minutes / 60 + $seconds / 3600); - } -} diff --git a/lib/private/Migration/BackgroundRepair.php b/lib/private/Migration/BackgroundRepair.php index 579ba494e58..afc3dcc9ac7 100644 --- a/lib/private/Migration/BackgroundRepair.php +++ b/lib/private/Migration/BackgroundRepair.php @@ -26,13 +26,12 @@ */ namespace OC\Migration; -use OCP\AppFramework\Utility\ITimeFactory; -use OCP\BackgroundJob\IJobList; -use OCP\BackgroundJob\TimedJob; -use OCP\EventDispatcher\IEventDispatcher; use OC\NeedsUpdateException; use OC\Repair; use OC_App; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\IJobList; +use OCP\BackgroundJob\TimedJob; use Psr\Log\LoggerInterface; /** @@ -41,15 +40,13 @@ use Psr\Log\LoggerInterface; * @package OC\Migration */ class BackgroundRepair extends TimedJob { - private IJobList $jobList; - private LoggerInterface $logger; - private IEventDispatcher $dispatcher; - - public function __construct(IEventDispatcher $dispatcher, ITimeFactory $time, LoggerInterface $logger, IJobList $jobList) { + public function __construct( + private Repair $repair, + ITimeFactory $time, + private LoggerInterface $logger, + private IJobList $jobList, + ) { parent::__construct($time); - $this->dispatcher = $dispatcher; - $this->logger = $logger; - $this->jobList = $jobList; $this->setInterval(15 * 60); } @@ -58,7 +55,7 @@ class BackgroundRepair extends TimedJob { * @throws \Exception * @throws \OC\NeedsUpdateException */ - protected function run($argument) { + protected function run($argument): void { if (!isset($argument['app']) || !isset($argument['step'])) { // remove the job - we can never execute it $this->jobList->remove($this, $this->argument); @@ -75,9 +72,9 @@ class BackgroundRepair extends TimedJob { } $step = $argument['step']; - $repair = new Repair([], $this->dispatcher, \OC::$server->get(LoggerInterface::class)); + $this->repair->setRepairSteps([]); try { - $repair->addStep($step); + $this->repair->addStep($step); } catch (\Exception $ex) { $this->logger->error($ex->getMessage(), [ 'app' => 'migration', @@ -90,7 +87,7 @@ class BackgroundRepair extends TimedJob { } // execute the repair step - $repair->run(); + $this->repair->run(); // remove the job once executed successfully $this->jobList->remove($this, $this->argument); @@ -101,7 +98,7 @@ class BackgroundRepair extends TimedJob { * @param $app * @throws NeedsUpdateException */ - protected function loadApp($app) { + protected function loadApp($app): void { OC_App::loadApp($app); } } diff --git a/lib/private/Migration/ConsoleOutput.php b/lib/private/Migration/ConsoleOutput.php index 9e3396f2a75..841e3d302fc 100644 --- a/lib/private/Migration/ConsoleOutput.php +++ b/lib/private/Migration/ConsoleOutput.php @@ -34,34 +34,35 @@ use Symfony\Component\Console\Output\OutputInterface; * @package OC\Migration */ class ConsoleOutput implements IOutput { - /** @var OutputInterface */ - private $output; + private ?ProgressBar $progressBar = null; - /** @var ProgressBar */ - private $progressBar; + public function __construct( + private OutputInterface $output, + ) { + } - public function __construct(OutputInterface $output) { - $this->output = $output; + public function debug(string $message): void { + $this->output->writeln($message, OutputInterface::VERBOSITY_VERBOSE); } /** * @param string $message */ - public function info($message) { + public function info($message): void { $this->output->writeln("<info>$message</info>"); } /** * @param string $message */ - public function warning($message) { + public function warning($message): void { $this->output->writeln("<comment>$message</comment>"); } /** * @param int $max */ - public function startProgress($max = 0) { + public function startProgress($max = 0): void { if (!is_null($this->progressBar)) { $this->progressBar->finish(); } @@ -73,7 +74,7 @@ class ConsoleOutput implements IOutput { * @param int $step * @param string $description */ - public function advance($step = 1, $description = '') { + public function advance($step = 1, $description = ''): void { if (is_null($this->progressBar)) { $this->progressBar = new ProgressBar($this->output); $this->progressBar->start(); @@ -84,7 +85,7 @@ class ConsoleOutput implements IOutput { } } - public function finishProgress() { + public function finishProgress(): void { if (is_null($this->progressBar)) { return; } diff --git a/lib/private/Migration/SimpleOutput.php b/lib/private/Migration/SimpleOutput.php index f97bcb767f8..f1b06d008bb 100644 --- a/lib/private/Migration/SimpleOutput.php +++ b/lib/private/Migration/SimpleOutput.php @@ -33,19 +33,21 @@ use Psr\Log\LoggerInterface; * @package OC\Migration */ class SimpleOutput implements IOutput { - private LoggerInterface $logger; - private $appName; + public function __construct( + private LoggerInterface $logger, + private $appName, + ) { + } - public function __construct(LoggerInterface $logger, $appName) { - $this->logger = $logger; - $this->appName = $appName; + public function debug(string $message): void { + $this->logger->debug($message, ['app' => $this->appName]); } /** * @param string $message * @since 9.1.0 */ - public function info($message) { + public function info($message): void { $this->logger->info($message, ['app' => $this->appName]); } @@ -53,7 +55,7 @@ class SimpleOutput implements IOutput { * @param string $message * @since 9.1.0 */ - public function warning($message) { + public function warning($message): void { $this->logger->warning($message, ['app' => $this->appName]); } @@ -61,7 +63,7 @@ class SimpleOutput implements IOutput { * @param int $max * @since 9.1.0 */ - public function startProgress($max = 0) { + public function startProgress($max = 0): void { } /** @@ -69,12 +71,12 @@ class SimpleOutput implements IOutput { * @param string $description * @since 9.1.0 */ - public function advance($step = 1, $description = '') { + public function advance($step = 1, $description = ''): void { } /** * @since 9.1.0 */ - public function finishProgress() { + public function finishProgress(): void { } } diff --git a/lib/private/NavigationManager.php b/lib/private/NavigationManager.php index 56f55e80331..0ce2b3124b2 100644 --- a/lib/private/NavigationManager.php +++ b/lib/private/NavigationManager.php @@ -65,19 +65,25 @@ class NavigationManager implements INavigationManager { private $groupManager; /** @var IConfig */ private $config; + /** The default app for the current user (cached for the `add` function) */ + private ?string $defaultApp; + /** User defined app order (cached for the `add` function) */ + private array $customAppOrder; public function __construct(IAppManager $appManager, - IURLGenerator $urlGenerator, - IFactory $l10nFac, - IUserSession $userSession, - IGroupManager $groupManager, - IConfig $config) { + IURLGenerator $urlGenerator, + IFactory $l10nFac, + IUserSession $userSession, + IGroupManager $groupManager, + IConfig $config) { $this->appManager = $appManager; $this->urlGenerator = $urlGenerator; $this->l10nFac = $l10nFac; $this->userSession = $userSession; $this->groupManager = $groupManager; $this->config = $config; + + $this->defaultApp = null; } /** @@ -88,8 +94,12 @@ class NavigationManager implements INavigationManager { $this->closureEntries[] = $entry; return; } + $this->init(); + + $id = $entry['id']; $entry['active'] = false; + $entry['unread'] = $this->unreadCounters[$id] ?? 0; if (!isset($entry['icon'])) { $entry['icon'] = ''; } @@ -100,8 +110,17 @@ class NavigationManager implements INavigationManager { $entry['type'] = 'link'; } - $id = $entry['id']; - $entry['unread'] = isset($this->unreadCounters[$id]) ? $this->unreadCounters[$id] : 0; + if ($entry['type'] === 'link') { + // app might not be set when using closures, in this case try to fallback to ID + if (!isset($entry['app']) && $this->appManager->isEnabledForUser($id)) { + $entry['app'] = $id; + } + + // This is the default app that will always be shown first + $entry['default'] = ($entry['app'] ?? false) === $this->defaultApp; + // Set order from user defined app order + $entry['order'] = $this->customAppOrder[$id]['order'] ?? $entry['order'] ?? 100; + } $this->entries[$id] = $entry; } @@ -123,26 +142,44 @@ class NavigationManager implements INavigationManager { }); } - return $this->proceedNavigation($result); + return $this->proceedNavigation($result, $type); } /** - * Sort navigation entries by order, name and set active flag + * Sort navigation entries default app is always sorted first, then by order, name and set active flag * * @param array $list * @return array */ - private function proceedNavigation(array $list): array { + private function proceedNavigation(array $list, string $type): array { uasort($list, function ($a, $b) { - if (isset($a['order']) && isset($b['order'])) { + if (($a['default'] ?? false) xor ($b['default'] ?? false)) { + // Always sort the default app first + return ($a['default'] ?? false) ? -1 : 1; + } elseif (isset($a['order']) && isset($b['order'])) { + // Sort by order return ($a['order'] < $b['order']) ? -1 : 1; } elseif (isset($a['order']) || isset($b['order'])) { + // Sort the one that has an order property first return isset($a['order']) ? -1 : 1; } else { + // Sort by name otherwise return ($a['name'] < $b['name']) ? -1 : 1; } }); + if ($type === 'all' || $type === 'link') { + // There might be the case that no default app was set, in this case the first app is the default app. + // Otherwise the default app is already the ordered first, so setting the default prop will make no difference. + foreach ($list as $index => &$navEntry) { + if ($navEntry['type'] === 'link') { + $navEntry['default'] = true; + break; + } + } + unset($navEntry); + } + $activeApp = $this->getActiveEntry(); if ($activeApp !== null) { foreach ($list as $index => &$navEntry) { @@ -171,8 +208,8 @@ class NavigationManager implements INavigationManager { /** * @inheritDoc */ - public function setActiveEntry($id) { - $this->activeEntry = $id; + public function setActiveEntry($appId) { + $this->activeEntry = $appId; } /** @@ -200,7 +237,21 @@ class NavigationManager implements INavigationManager { ]); } + $this->defaultApp = $this->appManager->getDefaultAppForUser($this->userSession->getUser(), false); + if ($this->userSession->isLoggedIn()) { + // Profile + $this->add([ + 'type' => 'settings', + 'id' => 'profile', + 'order' => 1, + 'href' => $this->urlGenerator->linkToRoute( + 'core.ProfilePage.index', + ['targetUserId' => $this->userSession->getUser()->getUID()], + ), + 'name' => $l->t('View profile'), + ]); + // Accessibility settings if ($this->appManager->isEnabledForUser('theming', $this->userSession->getUser())) { $this->add([ @@ -212,6 +263,7 @@ class NavigationManager implements INavigationManager { 'icon' => $this->urlGenerator->imagePath('theming', 'accessibility-dark.svg'), ]); } + if ($this->isAdmin()) { // App management $this->add([ @@ -280,14 +332,13 @@ class NavigationManager implements INavigationManager { } } - if ($this->appManager === 'null') { - return; - } - if ($this->userSession->isLoggedIn()) { - $apps = $this->appManager->getEnabledAppsForUser($this->userSession->getUser()); + $user = $this->userSession->getUser(); + $apps = $this->appManager->getEnabledAppsForUser($user); + $this->customAppOrder = json_decode($this->config->getUserValue($user->getUID(), 'core', 'apporder', '[]'), true, flags:JSON_THROW_ON_ERROR); } else { $apps = $this->appManager->getInstalledApps(); + $this->customAppOrder = []; } foreach ($apps as $app) { @@ -309,36 +360,48 @@ class NavigationManager implements INavigationManager { if (!isset($nav['route']) && $nav['type'] !== 'settings') { continue; } - $role = isset($nav['@attributes']['role']) ? $nav['@attributes']['role'] : 'all'; + $role = $nav['@attributes']['role'] ?? 'all'; if ($role === 'admin' && !$this->isAdmin()) { continue; } $l = $this->l10nFac->get($app); $id = $nav['id'] ?? $app . ($key === 0 ? '' : $key); - $order = isset($nav['order']) ? $nav['order'] : 100; + $order = $nav['order'] ?? 100; $type = $nav['type']; $route = !empty($nav['route']) ? $this->urlGenerator->linkToRoute($nav['route']) : ''; - $icon = isset($nav['icon']) ? $nav['icon'] : 'app.svg'; - foreach ([$icon, "$app.svg"] as $i) { + $icon = $nav['icon'] ?? null; + if ($icon !== null) { try { - $icon = $this->urlGenerator->imagePath($app, $i); - break; + $icon = $this->urlGenerator->imagePath($app, $icon); } catch (\RuntimeException $ex) { - // no icon? - ignore it then + // ignore } } if ($icon === null) { + $icon = $this->appManager->getAppIcon($app); + } + if ($icon === null) { $icon = $this->urlGenerator->imagePath('core', 'default-app-icon'); } - $this->add([ + $this->add(array_merge([ + // Navigation id 'id' => $id, + // Order where this entry should be shown 'order' => $order, + // Target of the navigation entry 'href' => $route, + // The icon used for the naviation entry 'icon' => $icon, + // Type of the navigation entry ('link' vs 'settings') 'type' => $type, + // Localized name of the navigation entry 'name' => $l->t($nav['name']), - ]); + ], $type === 'link' ? [ + // App that registered this navigation entry (not necessarly the same as the id) + 'app' => $app, + ] : [] + )); } } } diff --git a/lib/private/Net/HostnameClassifier.php b/lib/private/Net/HostnameClassifier.php index 626aa47083e..42dae790152 100644 --- a/lib/private/Net/HostnameClassifier.php +++ b/lib/private/Net/HostnameClassifier.php @@ -52,10 +52,6 @@ class HostnameClassifier { * Check host identifier for local hostname * * IP addresses are not considered local. Use the IpAddressClassifier for those. - * - * @param string $hostname - * - * @return bool */ public function isLocalHostname(string $hostname): bool { // Disallow local network top-level domains from RFC 6762 diff --git a/lib/private/Net/IpAddressClassifier.php b/lib/private/Net/IpAddressClassifier.php index d4698864ec8..b012ca8e956 100644 --- a/lib/private/Net/IpAddressClassifier.php +++ b/lib/private/Net/IpAddressClassifier.php @@ -46,10 +46,6 @@ class IpAddressClassifier { * Check host identifier for local IPv4 and IPv6 address ranges * * Hostnames are not considered local. Use the HostnameClassifier for those. - * - * @param string $ip - * - * @return bool */ public function isLocalAddress(string $ip): bool { $parsedIp = Factory::parseAddressString( diff --git a/lib/private/Notification/Action.php b/lib/private/Notification/Action.php index ff9cf9e38f5..9590d28af4a 100644 --- a/lib/private/Notification/Action.php +++ b/lib/private/Notification/Action.php @@ -27,23 +27,17 @@ namespace OC\Notification; use OCP\Notification\IAction; class Action implements IAction { - /** @var string */ - protected $label; + protected string $label; - /** @var string */ - protected $labelParsed; + protected string $labelParsed; - /** @var string */ - protected $link; + protected string $link; - /** @var string */ - protected $requestType; + protected string $requestType; - /** @var string */ - protected $icon; + protected string $icon; - /** @var bool */ - protected $primary; + protected bool $primary; public function __construct() { $this->label = ''; diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php index 3d77f643d93..348ddb03df9 100644 --- a/lib/private/Notification/Manager.php +++ b/lib/private/Notification/Manager.php @@ -43,48 +43,35 @@ use Psr\Container\ContainerExceptionInterface; use Psr\Log\LoggerInterface; class Manager implements IManager { - /** @var IValidator */ - protected $validator; - /** @var IUserManager */ - private $userManager; /** @var ICache */ - protected $cache; - /** @var IRegistry */ - protected $subscription; - /** @var LoggerInterface */ - protected $logger; - /** @var Coordinator */ - private $coordinator; + protected ICache $cache; /** @var IApp[] */ - protected $apps; + protected array $apps; /** @var string[] */ - protected $appClasses; + protected array $appClasses; /** @var INotifier[] */ - protected $notifiers; + protected array $notifiers; /** @var string[] */ - protected $notifierClasses; + protected array $notifierClasses; /** @var bool */ - protected $preparingPushNotification; + protected bool $preparingPushNotification; /** @var bool */ - protected $deferPushing; + protected bool $deferPushing; /** @var bool */ - private $parsedRegistrationContext; - - public function __construct(IValidator $validator, - IUserManager $userManager, - ICacheFactory $cacheFactory, - IRegistry $subscription, - LoggerInterface $logger, - Coordinator $coordinator) { - $this->validator = $validator; - $this->userManager = $userManager; + private bool $parsedRegistrationContext; + + public function __construct( + protected IValidator $validator, + private IUserManager $userManager, + ICacheFactory $cacheFactory, + protected IRegistry $subscription, + protected LoggerInterface $logger, + private Coordinator $coordinator, + ) { $this->cache = $cacheFactory->createDistributed('notifications'); - $this->subscription = $subscription; - $this->logger = $logger; - $this->coordinator = $coordinator; $this->apps = []; $this->notifiers = []; @@ -111,7 +98,7 @@ class Manager implements IManager { * @deprecated 17.0.0 use registerNotifierService instead. * @since 8.2.0 - Parameter $info was added in 9.0.0 */ - public function registerNotifier(\Closure $service, \Closure $info) { + public function registerNotifier(\Closure $service, \Closure $info): void { $infoData = $info(); $exception = new \InvalidArgumentException( 'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.' @@ -379,6 +366,7 @@ class Manager implements IManager { } if (!$notification->isValidParsed()) { + $this->logger->info('Notification was not parsed by any notifier [app: ' . $notification->getApp() . ', subject: ' . $notification->getSubject() . ']'); throw new \InvalidArgumentException('The given notification has not been handled'); } diff --git a/lib/private/Notification/Notification.php b/lib/private/Notification/Notification.php index 2291c4ae34f..ed2a84b0de2 100644 --- a/lib/private/Notification/Notification.php +++ b/lib/private/Notification/Notification.php @@ -32,94 +32,33 @@ use OCP\RichObjectStrings\InvalidObjectExeption; use OCP\RichObjectStrings\IValidator; class Notification implements INotification { - /** @var IValidator */ - protected $richValidator; - - /** @var string */ - protected $app; - - /** @var string */ - protected $user; - - /** @var \DateTime */ - protected $dateTime; - - /** @var string */ - protected $objectType; - - /** @var string */ - protected $objectId; - - /** @var string */ - protected $subject; - - /** @var array */ - protected $subjectParameters; - - /** @var string */ - protected $subjectParsed; - - /** @var string */ - protected $subjectRich; - - /** @var array */ - protected $subjectRichParameters; - - /** @var string */ - protected $message; - - /** @var array */ - protected $messageParameters; - - /** @var string */ - protected $messageParsed; - - /** @var string */ - protected $messageRich; - - /** @var array */ - protected $messageRichParameters; - - /** @var string */ - protected $link; - - /** @var string */ - protected $icon; - - /** @var array */ - protected $actions; - - /** @var array */ - protected $actionsParsed; - - /** @var bool */ - protected $hasPrimaryAction; - - /** @var bool */ - protected $hasPrimaryParsedAction; - - public function __construct(IValidator $richValidator) { - $this->richValidator = $richValidator; - $this->app = ''; - $this->user = ''; + protected string $app = ''; + protected string $user = ''; + protected \DateTime $dateTime; + protected string $objectType = ''; + protected string $objectId = ''; + protected string $subject = ''; + protected array $subjectParameters = []; + protected string $subjectParsed = ''; + protected string $subjectRich = ''; + protected array $subjectRichParameters = []; + protected string $message = ''; + protected array $messageParameters = []; + protected string $messageParsed = ''; + protected string $messageRich = ''; + protected array $messageRichParameters = []; + protected string $link = ''; + protected string $icon = ''; + protected array $actions = []; + protected array $actionsParsed = []; + protected bool $hasPrimaryAction = false; + protected bool $hasPrimaryParsedAction = false; + + public function __construct( + protected IValidator $richValidator, + ) { $this->dateTime = new \DateTime(); $this->dateTime->setTimestamp(0); - $this->objectType = ''; - $this->objectId = ''; - $this->subject = ''; - $this->subjectParameters = []; - $this->subjectParsed = ''; - $this->subjectRich = ''; - $this->subjectRichParameters = []; - $this->message = ''; - $this->messageParameters = []; - $this->messageParsed = ''; - $this->messageRich = ''; - $this->messageRichParameters = []; - $this->link = ''; - $this->icon = ''; - $this->actions = []; - $this->actionsParsed = []; } /** diff --git a/lib/private/OCM/Model/OCMProvider.php b/lib/private/OCM/Model/OCMProvider.php new file mode 100644 index 00000000000..084d4f8479d --- /dev/null +++ b/lib/private/OCM/Model/OCMProvider.php @@ -0,0 +1,234 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023, Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\OCM\Model; + +use OCP\EventDispatcher\IEventDispatcher; +use OCP\OCM\Events\ResourceTypeRegisterEvent; +use OCP\OCM\Exceptions\OCMArgumentException; +use OCP\OCM\Exceptions\OCMProviderException; +use OCP\OCM\IOCMProvider; +use OCP\OCM\IOCMResource; + +/** + * @since 28.0.0 + */ +class OCMProvider implements IOCMProvider { + private bool $enabled = false; + private string $apiVersion = ''; + private string $endPoint = ''; + /** @var IOCMResource[] */ + private array $resourceTypes = []; + + private bool $emittedEvent = false; + + public function __construct( + protected IEventDispatcher $dispatcher, + ) { + } + + /** + * @param bool $enabled + * + * @return $this + */ + public function setEnabled(bool $enabled): static { + $this->enabled = $enabled; + + return $this; + } + + /** + * @return bool + */ + public function isEnabled(): bool { + return $this->enabled; + } + + /** + * @param string $apiVersion + * + * @return $this + */ + public function setApiVersion(string $apiVersion): static { + $this->apiVersion = $apiVersion; + + return $this; + } + + /** + * @return string + */ + public function getApiVersion(): string { + return $this->apiVersion; + } + + /** + * @param string $endPoint + * + * @return $this + */ + public function setEndPoint(string $endPoint): static { + $this->endPoint = $endPoint; + + return $this; + } + + /** + * @return string + */ + public function getEndPoint(): string { + return $this->endPoint; + } + + /** + * create a new resource to later add it with {@see IOCMProvider::addResourceType()} + * @return IOCMResource + */ + public function createNewResourceType(): IOCMResource { + return new OCMResource(); + } + + /** + * @param IOCMResource $resource + * + * @return $this + */ + public function addResourceType(IOCMResource $resource): static { + $this->resourceTypes[] = $resource; + + return $this; + } + + /** + * @param IOCMResource[] $resourceTypes + * + * @return $this + */ + public function setResourceTypes(array $resourceTypes): static { + $this->resourceTypes = $resourceTypes; + + return $this; + } + + /** + * @return IOCMResource[] + */ + public function getResourceTypes(): array { + if (!$this->emittedEvent) { + $this->emittedEvent = true; + $event = new ResourceTypeRegisterEvent($this); + $this->dispatcher->dispatchTyped($event); + } + + return $this->resourceTypes; + } + + /** + * @param string $resourceName + * @param string $protocol + * + * @return string + * @throws OCMArgumentException + */ + public function extractProtocolEntry(string $resourceName, string $protocol): string { + foreach ($this->getResourceTypes() as $resource) { + if ($resource->getName() === $resourceName) { + $entry = $resource->getProtocols()[$protocol] ?? null; + if (is_null($entry)) { + throw new OCMArgumentException('protocol not found'); + } + + return (string)$entry; + } + } + + throw new OCMArgumentException('resource not found'); + } + + /** + * import data from an array + * + * @param array $data + * + * @return $this + * @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) + ->setApiVersion((string)($data['apiVersion'] ?? '')) + ->setEndPoint($data['endPoint'] ?? ''); + + $resources = []; + foreach (($data['resourceTypes'] ?? []) as $resourceData) { + $resource = new OCMResource(); + $resources[] = $resource->import($resourceData); + } + $this->setResourceTypes($resources); + + if (!$this->looksValid()) { + throw new OCMProviderException('remote provider does not look valid'); + } + + return $this; + } + + + /** + * @return bool + */ + private function looksValid(): bool { + return ($this->getApiVersion() !== '' && $this->getEndPoint() !== ''); + } + + + /** + * @return array{ + * enabled: bool, + * apiVersion: string, + * endPoint: string, + * resourceTypes: array{ + * name: string, + * shareTypes: string[], + * protocols: array<string, string> + * }[] + * } + */ + public function jsonSerialize(): array { + $resourceTypes = []; + foreach ($this->getResourceTypes() as $res) { + $resourceTypes[] = $res->jsonSerialize(); + } + + return [ + 'enabled' => $this->isEnabled(), + 'apiVersion' => $this->getApiVersion(), + 'endPoint' => $this->getEndPoint(), + 'resourceTypes' => $resourceTypes + ]; + } +} diff --git a/lib/private/OCM/Model/OCMResource.php b/lib/private/OCM/Model/OCMResource.php new file mode 100644 index 00000000000..c4a91f2eabf --- /dev/null +++ b/lib/private/OCM/Model/OCMResource.php @@ -0,0 +1,123 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023, Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\OCM\Model; + +use OCP\OCM\IOCMResource; + +/** + * @since 28.0.0 + */ +class OCMResource implements IOCMResource { + private string $name = ''; + /** @var string[] */ + private array $shareTypes = []; + /** @var array<string, string> */ + private array $protocols = []; + + /** + * @param string $name + * + * @return $this + */ + public function setName(string $name): static { + $this->name = $name; + + return $this; + } + + /** + * @return string + */ + public function getName(): string { + return $this->name; + } + + /** + * @param string[] $shareTypes + * + * @return $this + */ + public function setShareTypes(array $shareTypes): static { + $this->shareTypes = $shareTypes; + + return $this; + } + + /** + * @return string[] + */ + public function getShareTypes(): array { + return $this->shareTypes; + } + + /** + * @param array<string, string> $protocols + * + * @return $this + */ + public function setProtocols(array $protocols): static { + $this->protocols = $protocols; + + return $this; + } + + /** + * @return array<string, string> + */ + public function getProtocols(): array { + return $this->protocols; + } + + /** + * import data from an array + * + * @param array $data + * + * @return $this + * @see self::jsonSerialize() + */ + public function import(array $data): static { + return $this->setName((string)($data['name'] ?? '')) + ->setShareTypes($data['shareTypes'] ?? []) + ->setProtocols($data['protocols'] ?? []); + } + + /** + * @return array{ + * name: string, + * shareTypes: string[], + * protocols: array<string, string> + * } + */ + public function jsonSerialize(): array { + return [ + 'name' => $this->getName(), + 'shareTypes' => $this->getShareTypes(), + 'protocols' => $this->getProtocols() + ]; + } +} diff --git a/lib/private/OCM/OCMDiscoveryService.php b/lib/private/OCM/OCMDiscoveryService.php new file mode 100644 index 00000000000..ac9bf2a3965 --- /dev/null +++ b/lib/private/OCM/OCMDiscoveryService.php @@ -0,0 +1,137 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023, Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\OCM; + +use JsonException; +use OCP\AppFramework\Http; +use OCP\Http\Client\IClientService; +use OCP\ICache; +use OCP\ICacheFactory; +use OCP\IConfig; +use OCP\OCM\Exceptions\OCMProviderException; +use OCP\OCM\IOCMDiscoveryService; +use OCP\OCM\IOCMProvider; +use Psr\Log\LoggerInterface; + +/** + * @since 28.0.0 + */ +class OCMDiscoveryService implements IOCMDiscoveryService { + private ICache $cache; + private array $supportedAPIVersion = + [ + '1.0-proposal1', + '1.0', + '1.1' + ]; + + public function __construct( + ICacheFactory $cacheFactory, + private IClientService $clientService, + private IConfig $config, + private IOCMProvider $provider, + private LoggerInterface $logger, + ) { + $this->cache = $cacheFactory->createDistributed('ocm-discovery'); + } + + + /** + * @param string $remote + * @param bool $skipCache + * + * @return IOCMProvider + * @throws OCMProviderException + */ + public function discover(string $remote, bool $skipCache = false): IOCMProvider { + $remote = rtrim($remote, '/'); + + if (!$skipCache) { + try { + $this->provider->import(json_decode($this->cache->get($remote) ?? '', true, 8, JSON_THROW_ON_ERROR) ?? []); + if ($this->supportedAPIVersion($this->provider->getApiVersion())) { + return $this->provider; // if cache looks valid, we use it + } + } catch (JsonException|OCMProviderException $e) { + // we ignore cache on issues + } + } + + $client = $this->clientService->newClient(); + try { + $response = $client->get( + $remote . '/ocm-provider/', + [ + 'timeout' => 10, + 'verify' => !$this->config->getSystemValueBool('sharing.federation.allowSelfSignedCertificates'), + 'connect_timeout' => 10, + ] + ); + + if ($response->getStatusCode() === Http::STATUS_OK) { + $body = $response->getBody(); + // update provider with data returned by the request + $this->provider->import(json_decode($body, true, 8, JSON_THROW_ON_ERROR) ?? []); + $this->cache->set($remote, $body, 60 * 60 * 24); + } + } catch (JsonException|OCMProviderException $e) { + throw new OCMProviderException('data returned by remote seems invalid - ' . ($body ?? '')); + } catch (\Exception $e) { + $this->logger->warning('error while discovering ocm provider', [ + 'exception' => $e, + 'remote' => $remote + ]); + throw new OCMProviderException('error while requesting remote ocm provider'); + } + + if (!$this->supportedAPIVersion($this->provider->getApiVersion())) { + throw new OCMProviderException('API version not supported'); + } + + return $this->provider; + } + + /** + * Check the version from remote is supported. + * The minor version of the API will be ignored: + * 1.0.1 is identified as 1.0 + * + * @param string $version + * + * @return bool + */ + private function supportedAPIVersion(string $version): bool { + $dot1 = strpos($version, '.'); + $dot2 = strpos($version, '.', $dot1 + 1); + + if ($dot2 > 0) { + $version = substr($version, 0, $dot2); + } + + return (in_array($version, $this->supportedAPIVersion)); + } +} diff --git a/lib/private/OCS/CoreCapabilities.php b/lib/private/OCS/CoreCapabilities.php index 9cead57c6a3..0e9be3460ca 100644 --- a/lib/private/OCS/CoreCapabilities.php +++ b/lib/private/OCS/CoreCapabilities.php @@ -32,20 +32,18 @@ use OCP\IURLGenerator; * @package OC\OCS */ class CoreCapabilities implements ICapability { - /** @var IConfig */ - private $config; - /** * @param IConfig $config */ - public function __construct(IConfig $config) { - $this->config = $config; + public function __construct( + private IConfig $config, + ) { } /** * Return this classes capabilities */ - public function getCapabilities() { + public function getCapabilities(): array { return [ 'core' => [ 'pollinterval' => $this->config->getSystemValue('pollinterval', 60), diff --git a/lib/private/OCS/DiscoveryService.php b/lib/private/OCS/DiscoveryService.php index 8f98ff7d5ae..9bc83d42b1a 100644 --- a/lib/private/OCS/DiscoveryService.php +++ b/lib/private/OCS/DiscoveryService.php @@ -37,17 +37,17 @@ use OCP\OCS\IDiscoveryService; class DiscoveryService implements IDiscoveryService { /** @var ICache */ - private $cache; + private ICache $cache; /** @var IClient */ - private $client; + private IClient $client; /** * @param ICacheFactory $cacheFactory * @param IClientService $clientService */ public function __construct(ICacheFactory $cacheFactory, - IClientService $clientService + IClientService $clientService ) { $this->cache = $cacheFactory->createDistributed('ocs-discovery'); $this->client = $clientService->newClient(); diff --git a/lib/private/OCS/Exception.php b/lib/private/OCS/Exception.php index ca3c3f70430..a4e80d12dcc 100644 --- a/lib/private/OCS/Exception.php +++ b/lib/private/OCS/Exception.php @@ -23,15 +23,13 @@ namespace OC\OCS; class Exception extends \Exception { - /** @var Result */ - private $result; - - public function __construct(Result $result) { + public function __construct( + private Result $result, + ) { parent::__construct(); - $this->result = $result; } - public function getResult() { + public function getResult(): Result { return $this->result; } } diff --git a/lib/private/OCS/Provider.php b/lib/private/OCS/Provider.php index 5e7a86a1341..b9bcb389c57 100644 --- a/lib/private/OCS/Provider.php +++ b/lib/private/OCS/Provider.php @@ -24,26 +24,27 @@ */ namespace OC\OCS; -class Provider extends \OCP\AppFramework\Controller { - /** @var \OCP\App\IAppManager */ - private $appManager; +use OCP\App\IAppManager; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\JSONResponse; +use OCP\IRequest; +class Provider extends Controller { /** * @param string $appName - * @param \OCP\IRequest $request - * @param \OCP\App\IAppManager $appManager + * @param IRequest $request + * @param IAppManager $appManager */ public function __construct($appName, - \OCP\IRequest $request, - \OCP\App\IAppManager $appManager) { + \OCP\IRequest $request, + private \OCP\App\IAppManager $appManager) { parent::__construct($appName, $request); - $this->appManager = $appManager; } /** - * @return \OCP\AppFramework\Http\JSONResponse + * @return JSONResponse */ - public function buildProviderList() { + public function buildProviderList(): JSONResponse { $services = [ 'PRIVATE_DATA' => [ 'version' => 1, @@ -108,7 +109,7 @@ class Provider extends \OCP\AppFramework\Controller { ]; } - return new \OCP\AppFramework\Http\JSONResponse([ + return new JSONResponse([ 'version' => 2, 'services' => $services, ]); diff --git a/lib/private/OCS/Result.php b/lib/private/OCS/Result.php index d77e360e6d2..567fe8378a9 100644 --- a/lib/private/OCS/Result.php +++ b/lib/private/OCS/Result.php @@ -31,14 +31,13 @@ namespace OC\OCS; class Result { - /** @var array */ - protected $data; + protected array $data; /** @var null|string */ - protected $message; + protected ?string $message; /** @var int */ - protected $statusCode; + protected int $statusCode; /** @var integer */ protected $items; @@ -47,16 +46,17 @@ class Result { protected $perPage; /** @var array */ - private $headers = []; + private array $headers = []; /** * create the OCS_Result object - * @param mixed $data the data to return + * + * @param mixed|null $data the data to return * @param int $code - * @param null|string $message + * @param string|null $message * @param array $headers */ - public function __construct($data = null, $code = 100, $message = null, $headers = []) { + public function __construct(mixed $data = null, int $code = 100, string $message = null, array $headers = []) { if ($data === null) { $this->data = []; } elseif (!is_array($data)) { @@ -71,17 +71,19 @@ class Result { /** * optionally set the total number of items available + * * @param int $items */ - public function setTotalItems($items) { + public function setTotalItems(int $items): void { $this->items = $items; } /** - * optionally set the the number of items per page + * optionally set the number of items per page + * * @param int $items */ - public function setItemsPerPage($items) { + public function setItemsPerPage(int $items): void { $this->perPage = $items; } @@ -89,7 +91,7 @@ class Result { * get the status code * @return int */ - public function getStatusCode() { + public function getStatusCode(): int { return $this->statusCode; } @@ -97,7 +99,7 @@ class Result { * get the meta data for the result * @return array */ - public function getMeta() { + public function getMeta(): array { $meta = []; $meta['status'] = $this->succeeded() ? 'ok' : 'failure'; $meta['statuscode'] = $this->statusCode; @@ -115,7 +117,7 @@ class Result { * get the result data * @return array */ - public function getData() { + public function getData(): array { return $this->data; } @@ -123,17 +125,18 @@ class Result { * return bool Whether the method succeeded * @return bool */ - public function succeeded() { + public function succeeded(): bool { return ($this->statusCode == 100); } /** * Adds a new header to the response + * * @param string $name The name of the HTTP header * @param string $value The value, null will delete it * @return $this */ - public function addHeader($name, $value) { + public function addHeader(string $name, ?string $value): static { $name = trim($name); // always remove leading and trailing whitespace // to be able to reliably check for security // headers @@ -151,7 +154,7 @@ class Result { * Returns the set headers * @return array the headers */ - public function getHeaders() { + public function getHeaders(): array { return $this->headers; } } diff --git a/lib/private/PhoneNumberUtil.php b/lib/private/PhoneNumberUtil.php new file mode 100644 index 00000000000..a1eb2f13233 --- /dev/null +++ b/lib/private/PhoneNumberUtil.php @@ -0,0 +1,61 @@ +<?php + +declare(strict_types=1); +/** + * + * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC; + +use libphonenumber\NumberParseException; +use libphonenumber\PhoneNumberFormat; +use OCP\IPhoneNumberUtil; + +/** + * @since 28.0.0 + */ +class PhoneNumberUtil implements IPhoneNumberUtil { + /** + * {@inheritDoc} + */ + public function getCountryCodeForRegion(string $regionCode): ?int { + $phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance(); + $countryCode = $phoneUtil->getCountryCodeForRegion($regionCode); + return $countryCode === 0 ? null : $countryCode; + } + + /** + * {@inheritDoc} + */ + public function convertToStandardFormat(string $input, ?string $defaultRegion = null): ?string { + $phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance(); + try { + $phoneNumber = $phoneUtil->parse($input, $defaultRegion); + if ($phoneUtil->isValidNumber($phoneNumber)) { + return $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164); + } + } catch (NumberParseException) { + } + + return null; + } +} diff --git a/lib/private/Preview/BackgroundCleanupJob.php b/lib/private/Preview/BackgroundCleanupJob.php index 4eba96d1a82..4376cc06eca 100644 --- a/lib/private/Preview/BackgroundCleanupJob.php +++ b/lib/private/Preview/BackgroundCleanupJob.php @@ -48,10 +48,10 @@ class BackgroundCleanupJob extends TimedJob { private $mimeTypeLoader; public function __construct(ITimeFactory $timeFactory, - IDBConnection $connection, - Root $previewFolder, - IMimeTypeLoader $mimeTypeLoader, - bool $isCLI) { + IDBConnection $connection, + Root $previewFolder, + IMimeTypeLoader $mimeTypeLoader, + bool $isCLI) { parent::__construct($timeFactory); // Run at most once an hour $this->setInterval(3600); diff --git a/lib/private/Preview/EMF.php b/lib/private/Preview/EMF.php new file mode 100644 index 00000000000..2b5f40e66af --- /dev/null +++ b/lib/private/Preview/EMF.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Daniel Kesselberg <mail@danielkesselberg.de> + * + * @author Daniel Kesselberg <mail@danielkesselberg.de> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Preview; + +class EMF extends Office { + public function getMimeType(): string { + return '/image\/emf/'; + } +} diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php index 4e4571f0857..695d4a3357f 100644 --- a/lib/private/Preview/Generator.php +++ b/lib/private/Preview/Generator.php @@ -139,23 +139,6 @@ class Generator { $previewVersion = $file->getPreviewVersion() . '-'; } - // If imaginary is enabled, and we request a small thumbnail, - // let's not generate the max preview for performance reasons - if (count($specifications) === 1 - && ($specifications[0]['width'] <= 256 || $specifications[0]['height'] <= 256) - && preg_match(Imaginary::supportedMimeTypes(), $mimeType) - && $this->config->getSystemValueString('preview_imaginary_url', 'invalid') !== 'invalid') { - $crop = $specifications[0]['crop'] ?? false; - $preview = $this->getSmallImagePreview($previewFolder, $previewFiles, $file, $mimeType, $previewVersion, $crop); - - if ($preview->getSize() === 0) { - $preview->delete(); - throw new NotFoundException('Cached preview size 0, invalid!'); - } - - return $preview; - } - // Get the max preview and infer the max preview sizes from that $maxPreview = $this->getMaxPreview($previewFolder, $previewFiles, $file, $mimeType, $previewVersion); $maxPreviewImage = null; // only load the image when we need it @@ -232,32 +215,13 @@ class Generator { } /** - * Generate a small image straight away without generating a max preview first - * Preview generated is 256x256 - * - * @param ISimpleFile[] $previewFiles - * - * @throws NotFoundException - */ - private function getSmallImagePreview(ISimpleFolder $previewFolder, array $previewFiles, File $file, string $mimeType, string $prefix, bool $crop): ISimpleFile { - $width = 256; - $height = 256; - - try { - return $this->getCachedPreview($previewFiles, $width, $height, $crop, $mimeType, $prefix); - } catch (NotFoundException $e) { - return $this->generateProviderPreview($previewFolder, $file, $width, $height, $crop, false, $mimeType, $prefix); - } - } - - /** * Acquire a semaphore of the specified id and concurrency, blocking if necessary. * Return an identifier of the semaphore on success, which can be used to release it via * {@see Generator::unguardWithSemaphore()}. * * @param int $semId * @param int $concurrency - * @return false|resource the semaphore on success or false on failure + * @return false|\SysvSemaphore the semaphore on success or false on failure */ public static function guardWithSemaphore(int $semId, int $concurrency) { if (!extension_loaded('sysvsem')) { @@ -276,11 +240,11 @@ class Generator { /** * Releases the semaphore acquired from {@see Generator::guardWithSemaphore()}. * - * @param resource|bool $semId the semaphore identifier returned by guardWithSemaphore + * @param false|\SysvSemaphore $semId the semaphore identifier returned by guardWithSemaphore * @return bool */ - public static function unguardWithSemaphore($semId): bool { - if (!is_resource($semId) || !extension_loaded('sysvsem')) { + public static function unguardWithSemaphore(false|\SysvSemaphore $semId): bool { + if ($semId === false || !($semId instanceof \SysvSemaphore)) { return false; } return sem_release($semId); @@ -293,9 +257,15 @@ class Generator { */ public static function getHardwareConcurrency(): int { static $width; + if (!isset($width)) { - if (is_file("/proc/cpuinfo")) { - $width = substr_count(file_get_contents("/proc/cpuinfo"), "processor"); + if (function_exists('ini_get')) { + $openBasedir = ini_get('open_basedir'); + if (empty($openBasedir) || strpos($openBasedir, '/proc/cpuinfo') !== false) { + $width = is_readable('/proc/cpuinfo') ? substr_count(file_get_contents('/proc/cpuinfo'), 'processor') : 0; + } else { + $width = 0; + } } else { $width = 0; } @@ -651,6 +621,8 @@ class Generator { return 'png'; case 'image/jpeg': return 'jpg'; + case 'image/webp': + return 'webp'; case 'image/gif': return 'gif'; default: diff --git a/lib/private/Preview/Imaginary.php b/lib/private/Preview/Imaginary.php index da4864b1a22..faf84696e17 100644 --- a/lib/private/Preview/Imaginary.php +++ b/lib/private/Preview/Imaginary.php @@ -23,13 +23,13 @@ namespace OC\Preview; +use OC\StreamImage; use OCP\Files\File; use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\IImage; -use OCP\Image; -use OC\StreamImage; +use OCP\Image; use Psr\Log\LoggerInterface; class Imaginary extends ProviderV2 { @@ -78,6 +78,9 @@ class Imaginary extends ProviderV2 { // Object store $stream = $file->fopen('r'); + if (!$stream || !is_resource($stream) || feof($stream)) { + return null; + } $httpClient = $this->service->newClient(); @@ -106,6 +109,15 @@ class Imaginary extends ProviderV2 { $mimeType = 'jpeg'; } + $preview_format = $this->config->getSystemValueString('preview_format', 'jpeg'); + + switch ($preview_format) { // Change the format to the correct one + case 'webp': + $mimeType = 'webp'; + break; + default: + } + $operations = []; if ($convert) { @@ -121,7 +133,16 @@ class Imaginary extends ProviderV2 { ]; } - $quality = $this->config->getAppValue('preview', 'jpeg_quality', '80'); + switch ($mimeType) { + case 'jpeg': + $quality = $this->config->getAppValue('preview', 'jpeg_quality', '80'); + break; + case 'webp': + $quality = $this->config->getAppValue('preview', 'webp_quality', '80'); + break; + default: + $quality = $this->config->getAppValue('preview', 'jpeg_quality', '80'); + } $operations[] = [ 'operation' => ($crop ? 'smartcrop' : 'fit'), @@ -147,7 +168,7 @@ class Imaginary extends ProviderV2 { 'timeout' => 120, 'connect_timeout' => 3, ]); - } catch (\Exception $e) { + } catch (\Throwable $e) { $this->logger->info('Imaginary preview generation failed: ' . $e->getMessage(), [ 'exception' => $e, ]); diff --git a/lib/private/Preview/MimeIconProvider.php b/lib/private/Preview/MimeIconProvider.php index 1e44e8ca80a..80073c307c9 100644 --- a/lib/private/Preview/MimeIconProvider.php +++ b/lib/private/Preview/MimeIconProvider.php @@ -82,7 +82,7 @@ class MimeIconProvider implements IMimeIconProvider { } } - // Previously, we used to pass thi through Theming + // 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, // we can just use the default core icons. diff --git a/lib/private/Preview/Movie.php b/lib/private/Preview/Movie.php index 13d868cd583..1943bd97591 100644 --- a/lib/private/Preview/Movie.php +++ b/lib/private/Preview/Movie.php @@ -163,7 +163,7 @@ class Movie extends ProviderV2 { if ($second === 0) { $logger = \OC::$server->get(LoggerInterface::class); - $logger->error('Movie preview generation failed Output: {output}', ['app' => 'core', 'output' => $output]); + $logger->info('Movie preview generation failed Output: {output}', ['app' => 'core', 'output' => $output]); } unlink($tmpPath); diff --git a/lib/private/Preview/Office.php b/lib/private/Preview/Office.php index 3ba7c5a21a0..68499a6fea6 100644 --- a/lib/private/Preview/Office.php +++ b/lib/private/Preview/Office.php @@ -31,7 +31,8 @@ namespace OC\Preview; use OCP\Files\File; use OCP\Files\FileInfo; use OCP\IImage; -use Psr\Log\LoggerInterface; +use OCP\ITempManager; +use OCP\Server; abstract class Office extends ProviderV2 { /** @@ -49,51 +50,60 @@ abstract class Office extends ProviderV2 { return null; } - $absPath = $this->getLocalFile($file); - - $tmpDir = \OC::$server->getTempManager()->getTempBaseDir(); + $tempManager = Server::get(ITempManager::class); - $defaultParameters = ' -env:UserInstallation=file://' . escapeshellarg($tmpDir . '/owncloud-' . \OC_Util::getInstanceId() . '/') . ' --headless --nologo --nofirststartwizard --invisible --norestore --convert-to png --outdir '; - $clParameters = \OC::$server->getConfig()->getSystemValue('preview_office_cl_parameters', $defaultParameters); + // The file to generate the preview for. + $absPath = $this->getLocalFile($file); - $cmd = $this->options['officeBinary'] . $clParameters . escapeshellarg($tmpDir) . ' ' . escapeshellarg($absPath); + // The destination for the LibreOffice user profile. + // LibreOffice can rune once per user profile and therefore instance id and file id are included. + $profile = $tempManager->getTemporaryFolder( + 'nextcloud-office-profile-' . \OC_Util::getInstanceId() . '-' . $file->getId() + ); - exec($cmd, $output, $returnCode); + // The destination for the LibreOffice convert result. + $outdir = $tempManager->getTemporaryFolder( + 'nextcloud-office-preview-' . \OC_Util::getInstanceId() . '-' . $file->getId() + ); - if ($returnCode !== 0) { + if ($profile === false || $outdir === false) { $this->cleanTmpFiles(); return null; } - //create imagick object from png - $pngPreview = null; - try { - [$dirname, , , $filename] = array_values(pathinfo($absPath)); - $pngPreview = $tmpDir . '/' . $filename . '.png'; + $parameters = [ + $this->options['officeBinary'], + '-env:UserInstallation=file://' . escapeshellarg($profile), + '--headless', + '--nologo', + '--nofirststartwizard', + '--invisible', + '--norestore', + '--convert-to png', + '--outdir ' . escapeshellarg($outdir), + escapeshellarg($absPath), + ]; - $png = new \Imagick($pngPreview . '[0]'); - $png->setImageFormat('jpg'); - } catch (\Exception $e) { + $cmd = implode(' ', $parameters); + exec($cmd, $output, $returnCode); + + if ($returnCode !== 0) { $this->cleanTmpFiles(); - unlink($pngPreview); - \OC::$server->get(LoggerInterface::class)->error($e->getMessage(), [ - 'exception' => $e, - 'app' => 'core', - ]); return null; } + $preview = $outdir . pathinfo($absPath, PATHINFO_FILENAME) . '.png'; + $image = new \OCP\Image(); - $image->loadFromData((string) $png); + $image->loadFromFile($preview); $this->cleanTmpFiles(); - unlink($pngPreview); if ($image->valid()) { $image->scaleDownToFit($maxX, $maxY); - return $image; } + return null; } } diff --git a/lib/private/Preview/Watcher.php b/lib/private/Preview/Watcher.php index 7f4593f9fe3..ad6fed56020 100644 --- a/lib/private/Preview/Watcher.php +++ b/lib/private/Preview/Watcher.php @@ -61,6 +61,9 @@ class Watcher { } try { + if (is_null($node->getId())) { + return; + } $folder = $this->appData->getFolder((string)$node->getId()); $folder->delete(); } catch (NotFoundException $e) { diff --git a/lib/private/Preview/WatcherConnector.php b/lib/private/Preview/WatcherConnector.php index ffbdf825211..b11a6ab86da 100644 --- a/lib/private/Preview/WatcherConnector.php +++ b/lib/private/Preview/WatcherConnector.php @@ -43,7 +43,7 @@ class WatcherConnector { * @param SystemConfig $config */ public function __construct(IRootFolder $root, - SystemConfig $config) { + SystemConfig $config) { $this->root = $root; $this->config = $config; } diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php index 3af6848686e..aedcbbce335 100644 --- a/lib/private/PreviewManager.php +++ b/lib/private/PreviewManager.php @@ -366,7 +366,7 @@ class PreviewManager implements IPreview { $this->registerCoreProvider(Preview\OpenDocument::class, '/application\/vnd.oasis.opendocument.*/'); $this->registerCoreProvider(Preview\Imaginary::class, Preview\Imaginary::supportedMimeTypes()); - // SVG, Office and Bitmap require imagick + // SVG and Bitmap require imagick if ($this->imagickSupport->hasExtension()) { $imagickProviders = [ 'SVG' => ['mimetype' => '/image\/svg\+xml/', 'class' => Preview\SVG::class], @@ -391,27 +391,10 @@ class PreviewManager implements IPreview { $this->registerCoreProvider($class, $provider['mimetype']); } } - - if ($this->imagickSupport->supportsFormat('PDF')) { - // Office requires openoffice or libreoffice - $officeBinary = $this->config->getSystemValue('preview_libreoffice_path', null); - if (!is_string($officeBinary)) { - $officeBinary = $this->binaryFinder->findBinaryPath('libreoffice'); - } - if (!is_string($officeBinary)) { - $officeBinary = $this->binaryFinder->findBinaryPath('openoffice'); - } - - if (is_string($officeBinary)) { - $this->registerCoreProvider(Preview\MSOfficeDoc::class, '/application\/msword/', ["officeBinary" => $officeBinary]); - $this->registerCoreProvider(Preview\MSOffice2003::class, '/application\/vnd.ms-.*/', ["officeBinary" => $officeBinary]); - $this->registerCoreProvider(Preview\MSOffice2007::class, '/application\/vnd.openxmlformats-officedocument.*/', ["officeBinary" => $officeBinary]); - $this->registerCoreProvider(Preview\OpenDocument::class, '/application\/vnd.oasis.opendocument.*/', ["officeBinary" => $officeBinary]); - $this->registerCoreProvider(Preview\StarOffice::class, '/application\/vnd.sun.xml.*/', ["officeBinary" => $officeBinary]); - } - } } + $this->registerCoreProvidersOffice(); + // Video requires avconv or ffmpeg if (in_array(Preview\Movie::class, $this->getEnabledDefaultProvider())) { $movieBinary = $this->config->getSystemValue('preview_ffmpeg_path', null); @@ -429,6 +412,43 @@ class PreviewManager implements IPreview { } } + private function registerCoreProvidersOffice(): void { + $officeProviders = [ + ['mimetype' => '/application\/msword/', 'class' => Preview\MSOfficeDoc::class], + ['mimetype' => '/application\/vnd.ms-.*/', 'class' => Preview\MSOffice2003::class], + ['mimetype' => '/application\/vnd.openxmlformats-officedocument.*/', 'class' => Preview\MSOffice2007::class], + ['mimetype' => '/application\/vnd.oasis.opendocument.*/', 'class' => Preview\OpenDocument::class], + ['mimetype' => '/application\/vnd.sun.xml.*/', 'class' => Preview\StarOffice::class], + ['mimetype' => '/image\/emf/', 'class' => Preview\EMF::class], + ]; + + $findBinary = true; + $officeBinary = false; + + foreach ($officeProviders as $provider) { + $class = $provider['class']; + if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) { + continue; + } + + if ($findBinary) { + // Office requires openoffice or libreoffice + $officeBinary = $this->config->getSystemValue('preview_libreoffice_path', false); + if ($officeBinary === false) { + $officeBinary = $this->binaryFinder->findBinaryPath('libreoffice'); + } + if ($officeBinary === false) { + $officeBinary = $this->binaryFinder->findBinaryPath('openoffice'); + } + $findBinary = false; + } + + if ($officeBinary) { + $this->registerCoreProvider($class, $provider['mimetype'], ['officeBinary' => $officeBinary]); + } + } + } + private function registerBootstrapProviders(): void { $context = $this->bootstrapCoordinator->getRegistrationContext(); diff --git a/lib/private/Profile/Actions/EmailAction.php b/lib/private/Profile/Actions/EmailAction.php index 8ab4939b515..a676f6e228e 100644 --- a/lib/private/Profile/Actions/EmailAction.php +++ b/lib/private/Profile/Actions/EmailAction.php @@ -33,26 +33,13 @@ use OCP\L10N\IFactory; use OCP\Profile\ILinkAction; class EmailAction implements ILinkAction { - /** @var string */ - private $value; - - /** @var IAccountManager */ - private $accountManager; - - /** @var IFactory */ - private $l10nFactory; - - /** @var IUrlGenerator */ - private $urlGenerator; + private string $value = ''; public function __construct( - IAccountManager $accountManager, - IFactory $l10nFactory, - IURLGenerator $urlGenerator + private IAccountManager $accountManager, + private IFactory $l10nFactory, + private IURLGenerator $urlGenerator, ) { - $this->accountManager = $accountManager; - $this->l10nFactory = $l10nFactory; - $this->urlGenerator = $urlGenerator; } public function preload(IUser $targetUser): void { diff --git a/lib/private/Profile/Actions/FediverseAction.php b/lib/private/Profile/Actions/FediverseAction.php index ed3fcd80b52..4c73f785dd0 100644 --- a/lib/private/Profile/Actions/FediverseAction.php +++ b/lib/private/Profile/Actions/FediverseAction.php @@ -26,27 +26,21 @@ declare(strict_types=1); namespace OC\Profile\Actions; -use function Safe\substr; use OCP\Accounts\IAccountManager; use OCP\IURLGenerator; use OCP\IUser; use OCP\L10N\IFactory; use OCP\Profile\ILinkAction; +use function substr; class FediverseAction implements ILinkAction { - private ?string $value = null; - private IAccountManager $accountManager; - private IFactory $l10nFactory; - private IURLGenerator $urlGenerator; + private string $value = ''; public function __construct( - IAccountManager $accountManager, - IFactory $l10nFactory, - IURLGenerator $urlGenerator + private IAccountManager $accountManager, + private IFactory $l10nFactory, + private IURLGenerator $urlGenerator, ) { - $this->accountManager = $accountManager; - $this->l10nFactory = $l10nFactory; - $this->urlGenerator = $urlGenerator; } public function preload(IUser $targetUser): void { diff --git a/lib/private/Profile/Actions/PhoneAction.php b/lib/private/Profile/Actions/PhoneAction.php index 6081a04ad7e..6a4b2dd49d4 100644 --- a/lib/private/Profile/Actions/PhoneAction.php +++ b/lib/private/Profile/Actions/PhoneAction.php @@ -33,26 +33,13 @@ use OCP\L10N\IFactory; use OCP\Profile\ILinkAction; class PhoneAction implements ILinkAction { - /** @var string */ - private $value; - - /** @var IAccountManager */ - private $accountManager; - - /** @var IFactory */ - private $l10nFactory; - - /** @var IUrlGenerator */ - private $urlGenerator; + private string $value = ''; public function __construct( - IAccountManager $accountManager, - IFactory $l10nFactory, - IURLGenerator $urlGenerator + private IAccountManager $accountManager, + private IFactory $l10nFactory, + private IURLGenerator $urlGenerator, ) { - $this->accountManager = $accountManager; - $this->l10nFactory = $l10nFactory; - $this->urlGenerator = $urlGenerator; } public function preload(IUser $targetUser): void { diff --git a/lib/private/Profile/Actions/TwitterAction.php b/lib/private/Profile/Actions/TwitterAction.php index 041da42e539..f7f57d4c6d1 100644 --- a/lib/private/Profile/Actions/TwitterAction.php +++ b/lib/private/Profile/Actions/TwitterAction.php @@ -26,34 +26,21 @@ declare(strict_types=1); namespace OC\Profile\Actions; -use function Safe\substr; use OCP\Accounts\IAccountManager; use OCP\IURLGenerator; use OCP\IUser; use OCP\L10N\IFactory; use OCP\Profile\ILinkAction; +use function substr; class TwitterAction implements ILinkAction { - /** @var string */ - private $value; - - /** @var IAccountManager */ - private $accountManager; - - /** @var IFactory */ - private $l10nFactory; - - /** @var IUrlGenerator */ - private $urlGenerator; + private string $value = ''; public function __construct( - IAccountManager $accountManager, - IFactory $l10nFactory, - IURLGenerator $urlGenerator + private IAccountManager $accountManager, + private IFactory $l10nFactory, + private IURLGenerator $urlGenerator, ) { - $this->accountManager = $accountManager; - $this->l10nFactory = $l10nFactory; - $this->urlGenerator = $urlGenerator; } public function preload(IUser $targetUser): void { diff --git a/lib/private/Profile/Actions/WebsiteAction.php b/lib/private/Profile/Actions/WebsiteAction.php index 6b052be57bd..22e2692c4c5 100644 --- a/lib/private/Profile/Actions/WebsiteAction.php +++ b/lib/private/Profile/Actions/WebsiteAction.php @@ -33,26 +33,13 @@ use OCP\L10N\IFactory; use OCP\Profile\ILinkAction; class WebsiteAction implements ILinkAction { - /** @var string */ - private $value; - - /** @var IAccountManager */ - private $accountManager; - - /** @var IFactory */ - private $l10nFactory; - - /** @var IUrlGenerator */ - private $urlGenerator; + private string $value = ''; public function __construct( - IAccountManager $accountManager, - IFactory $l10nFactory, - IURLGenerator $urlGenerator + private IAccountManager $accountManager, + private IFactory $l10nFactory, + private IURLGenerator $urlGenerator, ) { - $this->accountManager = $accountManager; - $this->l10nFactory = $l10nFactory; - $this->urlGenerator = $urlGenerator; } public function preload(IUser $targetUser): void { diff --git a/lib/private/Profile/ProfileManager.php b/lib/private/Profile/ProfileManager.php index f20ae74768e..c8fb780bbe8 100644 --- a/lib/private/Profile/ProfileManager.php +++ b/lib/private/Profile/ProfileManager.php @@ -26,62 +26,36 @@ declare(strict_types=1); namespace OC\Profile; -use function Safe\array_flip; -use function Safe\usort; use OC\AppFramework\Bootstrap\Coordinator; use OC\Core\Db\ProfileConfig; use OC\Core\Db\ProfileConfigMapper; use OC\KnownUser\KnownUserService; use OC\Profile\Actions\EmailAction; +use OC\Profile\Actions\FediverseAction; use OC\Profile\Actions\PhoneAction; use OC\Profile\Actions\TwitterAction; -use OC\Profile\Actions\FediverseAction; use OC\Profile\Actions\WebsiteAction; use OCP\Accounts\IAccountManager; use OCP\Accounts\PropertyDoesNotExistException; use OCP\App\IAppManager; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\Cache\CappedMemoryCache; use OCP\IConfig; use OCP\IUser; use OCP\L10N\IFactory; use OCP\Profile\ILinkAction; -use OCP\Cache\CappedMemoryCache; +use OCP\Profile\IProfileManager; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use function array_flip; +use function usort; -class ProfileManager { - /** @var IAccountManager */ - private $accountManager; - - /** @var IAppManager */ - private $appManager; - - /** @var IConfig */ - private $config; - - /** @var ProfileConfigMapper */ - private $configMapper; - - /** @var ContainerInterface */ - private $container; - - /** @var KnownUserService */ - private $knownUserService; - - /** @var IFactory */ - private $l10nFactory; - - /** @var LoggerInterface */ - private $logger; - - /** @var Coordinator */ - private $coordinator; - +class ProfileManager implements IProfileManager { /** @var ILinkAction[] */ - private $actions = []; + private array $actions = []; /** @var null|ILinkAction[] */ - private $sortedActions = null; + private ?array $sortedActions = null; /** @var CappedMemoryCache<ProfileConfig> */ private CappedMemoryCache $configCache; @@ -112,32 +86,23 @@ class ProfileManager { ]; public function __construct( - IAccountManager $accountManager, - IAppManager $appManager, - IConfig $config, - ProfileConfigMapper $configMapper, - ContainerInterface $container, - KnownUserService $knownUserService, - IFactory $l10nFactory, - LoggerInterface $logger, - Coordinator $coordinator + private IAccountManager $accountManager, + private IAppManager $appManager, + private IConfig $config, + private ProfileConfigMapper $configMapper, + private ContainerInterface $container, + private KnownUserService $knownUserService, + private IFactory $l10nFactory, + private LoggerInterface $logger, + private Coordinator $coordinator, ) { - $this->accountManager = $accountManager; - $this->appManager = $appManager; - $this->config = $config; - $this->configMapper = $configMapper; - $this->container = $container; - $this->knownUserService = $knownUserService; - $this->l10nFactory = $l10nFactory; - $this->logger = $logger; - $this->coordinator = $coordinator; $this->configCache = new CappedMemoryCache(); } /** * If no user is passed as an argument return whether profile is enabled globally in `config.php` */ - public function isProfileEnabled(?IUser $user = null): ?bool { + public function isProfileEnabled(?IUser $user = null): bool { $profileEnabledGlobally = $this->config->getSystemValueBool('profile.enabled', true); if (empty($user) || !$profileEnabledGlobally) { @@ -145,7 +110,7 @@ class ProfileManager { } $account = $this->accountManager->getAccount($user); - return filter_var( + return (bool) filter_var( $account->getProperty(IAccountManager::PROPERTY_PROFILE_ENABLED)->getValue(), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE, @@ -229,57 +194,54 @@ class ProfileManager { * Return whether the profile parameter of the target user * is visible to the visiting user */ - private function isParameterVisible(string $paramId, IUser $targetUser, ?IUser $visitingUser): bool { + public function isProfileFieldVisible(string $profileField, IUser $targetUser, ?IUser $visitingUser): bool { try { $account = $this->accountManager->getAccount($targetUser); - $scope = $account->getProperty($paramId)->getScope(); + $scope = $account->getProperty($profileField)->getScope(); } catch (PropertyDoesNotExistException $e) { // Allow the exception as not all profile parameters are account properties } - $visibility = $this->getProfileConfig($targetUser, $visitingUser)[$paramId]['visibility']; + $visibility = $this->getProfileConfig($targetUser, $visitingUser)[$profileField]['visibility']; // Handle profile visibility and account property scope - switch ($visibility) { - case ProfileConfig::VISIBILITY_HIDE: - return false; - case ProfileConfig::VISIBILITY_SHOW_USERS_ONLY: - if (!empty($scope)) { - switch ($scope) { - case IAccountManager::SCOPE_PRIVATE: - return $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID()); - case IAccountManager::SCOPE_LOCAL: - case IAccountManager::SCOPE_FEDERATED: - case IAccountManager::SCOPE_PUBLISHED: - return $visitingUser !== null; - default: - return false; - } - } + + if ($visibility === self::VISIBILITY_SHOW_USERS_ONLY) { + if (empty($scope)) { return $visitingUser !== null; - case ProfileConfig::VISIBILITY_SHOW: - if (!empty($scope)) { - switch ($scope) { - case IAccountManager::SCOPE_PRIVATE: - return $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID()); - case IAccountManager::SCOPE_LOCAL: - case IAccountManager::SCOPE_FEDERATED: - case IAccountManager::SCOPE_PUBLISHED: - return true; - default: - return false; - } - } + } + + return match ($scope) { + IAccountManager::SCOPE_PRIVATE => $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID()), + IAccountManager::SCOPE_LOCAL, + IAccountManager::SCOPE_FEDERATED, + IAccountManager::SCOPE_PUBLISHED => $visitingUser !== null, + default => false, + }; + } + + if ($visibility === self::VISIBILITY_SHOW) { + if (empty($scope)) { return true; - default: - return false; + } + + return match ($scope) { + IAccountManager::SCOPE_PRIVATE => $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID()), + IAccountManager::SCOPE_LOCAL, + IAccountManager::SCOPE_FEDERATED, + IAccountManager::SCOPE_PUBLISHED => true, + default => false, + }; } + + return false; } /** * Return the profile parameters of the target user that are visible to the visiting user * in an associative array + * @return array{userId: string, address?: string|null, biography?: string|null, displayname?: string|null, headline?: string|null, isUserAvatarVisible?: bool, organisation?: string|null, role?: string|null, actions: list<array{id: string, icon: string, title: string, target: ?string}>} */ - public function getProfileParams(IUser $targetUser, ?IUser $visitingUser): array { + public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array { $account = $this->accountManager->getAccount($targetUser); // Initialize associative array of profile parameters @@ -297,14 +259,14 @@ class ProfileManager { case IAccountManager::PROPERTY_ORGANISATION: case IAccountManager::PROPERTY_ROLE: $profileParameters[$property] = - $this->isParameterVisible($property, $targetUser, $visitingUser) + $this->isProfileFieldVisible($property, $targetUser, $visitingUser) // Explicitly set to null when value is empty string ? ($account->getProperty($property)->getValue() ?: null) : null; break; case IAccountManager::PROPERTY_AVATAR: // Add avatar visibility - $profileParameters['isUserAvatarVisible'] = $this->isParameterVisible($property, $targetUser, $visitingUser); + $profileParameters['isUserAvatarVisible'] = $this->isProfileFieldVisible($property, $targetUser, $visitingUser); break; } } @@ -324,7 +286,7 @@ class ProfileManager { array_filter( $this->getActions($targetUser, $visitingUser), function (ILinkAction $action) use ($targetUser, $visitingUser) { - return $this->isParameterVisible($action->getId(), $targetUser, $visitingUser); + return $this->isProfileFieldVisible($action->getId(), $targetUser, $visitingUser); } ), ) @@ -356,12 +318,12 @@ class ProfileManager { // Construct the default config for actions $actionsConfig = []; foreach ($this->getActions($targetUser, $visitingUser) as $action) { - $actionsConfig[$action->getId()] = ['visibility' => ProfileConfig::DEFAULT_VISIBILITY]; + $actionsConfig[$action->getId()] = ['visibility' => self::DEFAULT_VISIBILITY]; } // Construct the default config for account properties $propertiesConfig = []; - foreach (ProfileConfig::DEFAULT_PROPERTY_VISIBILITY as $property => $visibility) { + foreach (self::DEFAULT_PROPERTY_VISIBILITY as $property => $visibility) { $propertiesConfig[$property] = ['visibility' => $visibility]; } diff --git a/lib/private/Profiler/Profiler.php b/lib/private/Profiler/Profiler.php index 40050b7bf43..9cbf703c79b 100644 --- a/lib/private/Profiler/Profiler.php +++ b/lib/private/Profiler/Profiler.php @@ -27,11 +27,11 @@ declare(strict_types = 1); namespace OC\Profiler; use OC\AppFramework\Http\Request; +use OC\SystemConfig; use OCP\AppFramework\Http\Response; use OCP\DataCollector\IDataCollector; -use OCP\Profiler\IProfiler; use OCP\Profiler\IProfile; -use OC\SystemConfig; +use OCP\Profiler\IProfiler; class Profiler implements IProfiler { /** @var array<string, IDataCollector> */ @@ -44,7 +44,7 @@ class Profiler implements IProfiler { public function __construct(SystemConfig $config) { $this->enabled = $config->getValue('profiler', false); if ($this->enabled) { - $this->storage = new FileProfilerStorage($config->getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/profiler'); + $this->storage = new FileProfilerStorage($config->getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/__profiler'); } } @@ -95,7 +95,7 @@ class Profiler implements IProfiler { * @return array[] */ public function find(?string $url, ?int $limit, ?string $method, ?int $start, ?int $end, - string $statusCode = null): array { + string $statusCode = null): array { if ($this->storage) { return $this->storage->find($url, $limit, $method, $start, $end, $statusCode); } else { diff --git a/lib/private/Remote/User.php b/lib/private/Remote/User.php index 5590fcfba38..d67b279bccb 100644 --- a/lib/private/Remote/User.php +++ b/lib/private/Remote/User.php @@ -92,7 +92,7 @@ class User implements IUser { * @return string */ public function getTwitter() { - return isset($this->data['twitter']) ? $this->data['twitter'] : ''; + return $this->data['twitter'] ?? ''; } /** diff --git a/lib/private/Repair.php b/lib/private/Repair.php index 05624a2423a..b1800d6087d 100644 --- a/lib/private/Repair.php +++ b/lib/private/Repair.php @@ -34,19 +34,15 @@ */ namespace OC; -use OC\Repair\AddRemoveOldTasksBackgroundJob; -use OC\Repair\CleanUpAbandonedApps; -use OCP\AppFramework\QueryException; -use OCP\AppFramework\Utility\ITimeFactory; -use OCP\Collaboration\Resources\IManager; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\Migration\IOutput; -use OCP\Migration\IRepairStep; use OC\DB\Connection; use OC\DB\ConnectionAdapter; +use OC\Repair\AddAppConfigLazyMigration; use OC\Repair\AddBruteForceCleanupJob; use OC\Repair\AddCleanupUpdaterBackupsJob; +use OC\Repair\AddMetadataGenerationJob; +use OC\Repair\AddRemoveOldTasksBackgroundJob; use OC\Repair\CleanTags; +use OC\Repair\CleanUpAbandonedApps; use OC\Repair\ClearFrontendCaches; use OC\Repair\ClearGeneratedAvatarCache; use OC\Repair\Collation; @@ -84,30 +80,31 @@ use OC\Repair\RemoveLinkShares; use OC\Repair\RepairDavShares; use OC\Repair\RepairInvalidShares; use OC\Repair\RepairMimeTypes; -use OC\Repair\SqliteAutoincrement; use OC\Template\JSCombiner; +use OCP\AppFramework\QueryException; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Collaboration\Resources\IManager; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; use Psr\Log\LoggerInterface; use Throwable; class Repair implements IOutput { /** @var IRepairStep[] */ - private array $repairSteps; - - private IEventDispatcher $dispatcher; + private array $repairSteps = []; private string $currentStep; - private LoggerInterface $logger; + public function __construct( + private IEventDispatcher $dispatcher, + private LoggerInterface $logger + ) { + } - /** - * Creates a new repair step runner - * - * @param IRepairStep[] $repairSteps array of RepairStep instances - */ - public function __construct(array $repairSteps, IEventDispatcher $dispatcher, LoggerInterface $logger) { + /** @param IRepairStep[] $repairSteps */ + public function setRepairSteps(array $repairSteps): void { $this->repairSteps = $repairSteps; - $this->dispatcher = $dispatcher; - $this->logger = $logger; } /** @@ -212,6 +209,8 @@ class Repair implements IOutput { \OCP\Server::get(CleanUpAbandonedApps::class), \OCP\Server::get(AddMissingSecretJob::class), \OCP\Server::get(AddRemoveOldTasksBackgroundJob::class), + \OCP\Server::get(AddMetadataGenerationJob::class), + \OCP\Server::get(AddAppConfigLazyMigration::class), ]; } @@ -235,14 +234,11 @@ class Repair implements IOutput { * @return IRepairStep[] */ public static function getBeforeUpgradeRepairSteps() { - /** @var Connection $connection */ - $connection = \OC::$server->get(Connection::class); /** @var ConnectionAdapter $connectionAdapter */ $connectionAdapter = \OC::$server->get(ConnectionAdapter::class); $config = \OC::$server->getConfig(); $steps = [ new Collation(\OC::$server->getConfig(), \OC::$server->get(LoggerInterface::class), $connectionAdapter, true), - new SqliteAutoincrement($connection), new SaveAccountsTableData($connectionAdapter, $config), new DropAccountTermsTable($connectionAdapter), ]; @@ -250,6 +246,9 @@ class Repair implements IOutput { return $steps; } + public function debug(string $message): void { + } + /** * @param string $message */ diff --git a/lib/private/Repair/AddAppConfigLazyMigration.php b/lib/private/Repair/AddAppConfigLazyMigration.php new file mode 100644 index 00000000000..1f466b98b28 --- /dev/null +++ b/lib/private/Repair/AddAppConfigLazyMigration.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2024 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OC\Repair; + +use OCP\IAppConfig; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; +use Psr\Log\LoggerInterface; + +class AddAppConfigLazyMigration implements IRepairStep { + /** + * Just add config values that needs to be migrated to lazy loading + */ + private static array $lazyAppConfig = [ + 'core' => [ + 'oc.integritycheck.checker', + ], + ]; + + public function __construct( + private IAppConfig $appConfig, + private LoggerInterface $logger, + ) { + } + + public function getName() { + return 'migrate lazy config values'; + } + + public function run(IOutput $output) { + $c = 0; + foreach (self::$lazyAppConfig as $appId => $configKeys) { + foreach ($configKeys as $configKey) { + $c += (int)$this->appConfig->updateLazy($appId, $configKey, true); + } + } + + $this->logger->notice('core/BackgroundJobs/AppConfigLazyMigration: ' . $c . ' config values updated'); + } +} diff --git a/lib/private/Repair/AddMetadataGenerationJob.php b/lib/private/Repair/AddMetadataGenerationJob.php new file mode 100644 index 00000000000..72e5df03bbd --- /dev/null +++ b/lib/private/Repair/AddMetadataGenerationJob.php @@ -0,0 +1,43 @@ +<?php +/** + * @copyright Copyright (c) 2023 Louis Chmn <louis@chmn.me> + * + * @author Louis Chmn <louis@chmn.me> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OC\Repair; + +use OC\Core\BackgroundJobs\GenerateMetadataJob; +use OCP\BackgroundJob\IJobList; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class AddMetadataGenerationJob implements IRepairStep { + public function __construct( + private IJobList $jobList, + ) { + } + + public function getName() { + return 'Queue a job to generate metadata'; + } + + public function run(IOutput $output) { + $this->jobList->add(GenerateMetadataJob::class); + } +} diff --git a/lib/private/Repair/AddRemoveOldTasksBackgroundJob.php b/lib/private/Repair/AddRemoveOldTasksBackgroundJob.php index 94ae39f2183..00badbb726d 100644 --- a/lib/private/Repair/AddRemoveOldTasksBackgroundJob.php +++ b/lib/private/Repair/AddRemoveOldTasksBackgroundJob.php @@ -25,7 +25,8 @@ declare(strict_types=1); */ namespace OC\Repair; -use OC\TextProcessing\RemoveOldTasksBackgroundJob; +use OC\TextProcessing\RemoveOldTasksBackgroundJob as RemoveOldTextProcessingTasksBackgroundJob; +use OC\TextToImage\RemoveOldTasksBackgroundJob as RemoveOldTextToImageTasksBackgroundJob; use OCP\BackgroundJob\IJobList; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; @@ -38,10 +39,11 @@ class AddRemoveOldTasksBackgroundJob implements IRepairStep { } public function getName(): string { - return 'Add language model tasks cleanup job'; + return 'Add AI tasks cleanup job'; } public function run(IOutput $output) { - $this->jobList->add(RemoveOldTasksBackgroundJob::class); + $this->jobList->add(RemoveOldTextProcessingTasksBackgroundJob::class); + $this->jobList->add(RemoveOldTextToImageTasksBackgroundJob::class); } } diff --git a/lib/private/Repair/ClearFrontendCaches.php b/lib/private/Repair/ClearFrontendCaches.php index bf94e5bfbff..3661560c5f6 100644 --- a/lib/private/Repair/ClearFrontendCaches.php +++ b/lib/private/Repair/ClearFrontendCaches.php @@ -37,7 +37,7 @@ class ClearFrontendCaches implements IRepairStep { protected $jsCombiner; public function __construct(ICacheFactory $cacheFactory, - JSCombiner $JSCombiner) { + JSCombiner $JSCombiner) { $this->cacheFactory = $cacheFactory; $this->jsCombiner = $JSCombiner; } diff --git a/lib/private/Repair/ClearGeneratedAvatarCache.php b/lib/private/Repair/ClearGeneratedAvatarCache.php index fb3b42847dc..88b2b07ead5 100644 --- a/lib/private/Repair/ClearGeneratedAvatarCache.php +++ b/lib/private/Repair/ClearGeneratedAvatarCache.php @@ -25,8 +25,8 @@ namespace OC\Repair; use OC\Avatar\AvatarManager; -use OCP\IConfig; use OCP\BackgroundJob\IJobList; +use OCP\IConfig; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/private/Repair/ClearGeneratedAvatarCacheJob.php b/lib/private/Repair/ClearGeneratedAvatarCacheJob.php index e8513e7a933..5caa74638e5 100644 --- a/lib/private/Repair/ClearGeneratedAvatarCacheJob.php +++ b/lib/private/Repair/ClearGeneratedAvatarCacheJob.php @@ -20,9 +20,9 @@ */ namespace OC\Repair; -use OCP\BackgroundJob\QueuedJob; -use OCP\AppFramework\Utility\ITimeFactory; use OC\Avatar\AvatarManager; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\QueuedJob; class ClearGeneratedAvatarCacheJob extends QueuedJob { protected AvatarManager $avatarManager; diff --git a/lib/private/Repair/NC18/ResetGeneratedAvatarFlag.php b/lib/private/Repair/NC18/ResetGeneratedAvatarFlag.php index d5ae1d7ab63..185ff3be1be 100644 --- a/lib/private/Repair/NC18/ResetGeneratedAvatarFlag.php +++ b/lib/private/Repair/NC18/ResetGeneratedAvatarFlag.php @@ -37,7 +37,7 @@ class ResetGeneratedAvatarFlag implements IRepairStep { private $connection; public function __construct(IConfig $config, - IDBConnection $connection) { + IDBConnection $connection) { $this->config = $config; $this->connection = $connection; } diff --git a/lib/private/Repair/NC20/EncryptionLegacyCipher.php b/lib/private/Repair/NC20/EncryptionLegacyCipher.php index a7d008e87be..42a8778662b 100644 --- a/lib/private/Repair/NC20/EncryptionLegacyCipher.php +++ b/lib/private/Repair/NC20/EncryptionLegacyCipher.php @@ -38,7 +38,7 @@ class EncryptionLegacyCipher implements IRepairStep { private $manager; public function __construct(IConfig $config, - IManager $manager) { + IManager $manager) { $this->config = $config; $this->manager = $manager; } diff --git a/lib/private/Repair/NC20/EncryptionMigration.php b/lib/private/Repair/NC20/EncryptionMigration.php index 239a62c2718..dea51b1b57e 100644 --- a/lib/private/Repair/NC20/EncryptionMigration.php +++ b/lib/private/Repair/NC20/EncryptionMigration.php @@ -38,7 +38,7 @@ class EncryptionMigration implements IRepairStep { private $manager; public function __construct(IConfig $config, - IManager $manager) { + IManager $manager) { $this->config = $config; $this->manager = $manager; } diff --git a/lib/private/Repair/NC21/ValidatePhoneNumber.php b/lib/private/Repair/NC21/ValidatePhoneNumber.php index b3534dbeae8..51120c9d139 100644 --- a/lib/private/Repair/NC21/ValidatePhoneNumber.php +++ b/lib/private/Repair/NC21/ValidatePhoneNumber.php @@ -42,8 +42,8 @@ class ValidatePhoneNumber implements IRepairStep { private $accountManager; public function __construct(IUserManager $userManager, - IAccountManager $accountManager, - IConfig $config) { + IAccountManager $accountManager, + IConfig $config) { $this->config = $config; $this->userManager = $userManager; $this->accountManager = $accountManager; diff --git a/lib/private/Repair/Owncloud/CleanPreviews.php b/lib/private/Repair/Owncloud/CleanPreviews.php index 853a94c8adc..2020ae8bfc1 100644 --- a/lib/private/Repair/Owncloud/CleanPreviews.php +++ b/lib/private/Repair/Owncloud/CleanPreviews.php @@ -47,8 +47,8 @@ class CleanPreviews implements IRepairStep { * @param IConfig $config */ public function __construct(IJobList $jobList, - IUserManager $userManager, - IConfig $config) { + IUserManager $userManager, + IConfig $config) { $this->jobList = $jobList; $this->userManager = $userManager; $this->config = $config; diff --git a/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php b/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php index 7f4bbc35c17..a23816e4711 100644 --- a/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php +++ b/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl> * @@ -22,9 +25,9 @@ */ namespace OC\Repair\Owncloud; -use OC\BackgroundJob\QueuedJob; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\IJobList; +use OCP\BackgroundJob\QueuedJob; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; @@ -33,33 +36,14 @@ use OCP\IUserManager; use Psr\Log\LoggerInterface; class CleanPreviewsBackgroundJob extends QueuedJob { - /** @var IRootFolder */ - private $rootFolder; - - private LoggerInterface $logger; - - /** @var IJobList */ - private $jobList; - - /** @var ITimeFactory */ - private $timeFactory; - - /** @var IUserManager */ - private $userManager; - - /** - * CleanPreviewsBackgroundJob constructor. - */ - public function __construct(IRootFolder $rootFolder, - LoggerInterface $logger, - IJobList $jobList, - ITimeFactory $timeFactory, - IUserManager $userManager) { - $this->rootFolder = $rootFolder; - $this->logger = $logger; - $this->jobList = $jobList; - $this->timeFactory = $timeFactory; - $this->userManager = $userManager; + public function __construct( + private IRootFolder $rootFolder, + private LoggerInterface $logger, + private IJobList $jobList, + ITimeFactory $timeFactory, + private IUserManager $userManager, + ) { + parent::__construct($timeFactory); } public function run($arguments) { @@ -80,10 +64,9 @@ class CleanPreviewsBackgroundJob extends QueuedJob { } /** - * @param $uid - * @return bool + * @param string $uid */ - private function cleanupPreviews($uid) { + private function cleanupPreviews($uid): bool { try { $userFolder = $this->rootFolder->getUserFolder($uid); } catch (NotFoundException $e) { @@ -101,7 +84,7 @@ class CleanPreviewsBackgroundJob extends QueuedJob { $thumbnails = $thumbnailFolder->getDirectoryListing(); - $start = $this->timeFactory->getTime(); + $start = $this->time->getTime(); foreach ($thumbnails as $thumbnail) { try { $thumbnail->delete(); @@ -109,7 +92,7 @@ class CleanPreviewsBackgroundJob extends QueuedJob { // Ignore } - if (($this->timeFactory->getTime() - $start) > 15) { + if (($this->time->getTime() - $start) > 15) { return false; } } diff --git a/lib/private/Repair/Owncloud/MigrateOauthTables.php b/lib/private/Repair/Owncloud/MigrateOauthTables.php index 5bf0816d8de..ae2b46e1949 100644 --- a/lib/private/Repair/Owncloud/MigrateOauthTables.php +++ b/lib/private/Repair/Owncloud/MigrateOauthTables.php @@ -20,11 +20,11 @@ */ namespace OC\Repair\Owncloud; -use OCP\Migration\IOutput; -use OCP\Migration\IRepairStep; use OC\DB\Connection; use OC\DB\SchemaWrapper; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; class MigrateOauthTables implements IRepairStep { /** @var Connection */ diff --git a/lib/private/Repair/Owncloud/MoveAvatars.php b/lib/private/Repair/Owncloud/MoveAvatars.php index 44ba9b7643b..1ec08710b3a 100644 --- a/lib/private/Repair/Owncloud/MoveAvatars.php +++ b/lib/private/Repair/Owncloud/MoveAvatars.php @@ -41,7 +41,7 @@ class MoveAvatars implements IRepairStep { * @param IConfig $config */ public function __construct(IJobList $jobList, - IConfig $config) { + IConfig $config) { $this->jobList = $jobList; $this->config = $config; } diff --git a/lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php b/lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php index 83c78c2cba4..9f01c4051e6 100644 --- a/lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php +++ b/lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl> * @@ -23,10 +26,11 @@ */ namespace OC\Repair\Owncloud; -use OC\BackgroundJob\QueuedJob; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\QueuedJob; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; -use OCP\Files\Storage; +use OCP\Files\Storage\IStorage; use OCP\IAvatarManager; use OCP\IUser; use OCP\IUserManager; @@ -34,22 +38,16 @@ use Psr\Log\LoggerInterface; use function is_resource; class MoveAvatarsBackgroundJob extends QueuedJob { - /** @var IUserManager */ - private $userManager; - - /** @var LoggerInterface */ - private $logger; - - /** @var IAvatarManager */ - private $avatarManager; - - /** @var Storage */ - private $owncloudAvatarStorage; + private ?IStorage $owncloudAvatarStorage = null; - public function __construct(IUserManager $userManager, LoggerInterface $logger, IAvatarManager $avatarManager, IRootFolder $rootFolder) { - $this->userManager = $userManager; - $this->logger = $logger; - $this->avatarManager = $avatarManager; + public function __construct( + private IUserManager $userManager, + private LoggerInterface $logger, + private IAvatarManager $avatarManager, + private IRootFolder $rootFolder, + ITimeFactory $time, + ) { + parent::__construct($time); try { $this->owncloudAvatarStorage = $rootFolder->get('avatars')->getStorage(); } catch (\Exception $e) { @@ -69,7 +67,7 @@ class MoveAvatarsBackgroundJob extends QueuedJob { } $counter = 0; - $this->userManager->callForSeenUsers(function (IUser $user) use ($counter) { + $this->userManager->callForSeenUsers(function (IUser $user) use (&$counter) { $uid = $user->getUID(); $path = 'avatars/' . $this->buildOwnCloudAvatarPath($uid); diff --git a/lib/private/Repair/Owncloud/UpdateLanguageCodes.php b/lib/private/Repair/Owncloud/UpdateLanguageCodes.php index e08a0b55a9a..ae8e8bb0743 100644 --- a/lib/private/Repair/Owncloud/UpdateLanguageCodes.php +++ b/lib/private/Repair/Owncloud/UpdateLanguageCodes.php @@ -40,7 +40,7 @@ class UpdateLanguageCodes implements IRepairStep { * @param IConfig $config */ public function __construct(IDBConnection $connection, - IConfig $config) { + IConfig $config) { $this->connection = $connection; $this->config = $config; } diff --git a/lib/private/Repair/RemoveLinkShares.php b/lib/private/Repair/RemoveLinkShares.php index b45a1d83a56..3e47e3233a2 100644 --- a/lib/private/Repair/RemoveLinkShares.php +++ b/lib/private/Repair/RemoveLinkShares.php @@ -54,10 +54,10 @@ class RemoveLinkShares implements IRepairStep { private $timeFactory; public function __construct(IDBConnection $connection, - IConfig $config, - IGroupManager $groupManager, - IManager $notificationManager, - ITimeFactory $timeFactory) { + IConfig $config, + IGroupManager $groupManager, + IManager $notificationManager, + ITimeFactory $timeFactory) { $this->connection = $connection; $this->config = $config; $this->groupManager = $groupManager; diff --git a/lib/private/Repair/RepairMimeTypes.php b/lib/private/Repair/RepairMimeTypes.php index ee5a84ad65c..b204c27a9a2 100644 --- a/lib/private/Repair/RepairMimeTypes.php +++ b/lib/private/Repair/RepairMimeTypes.php @@ -49,7 +49,7 @@ class RepairMimeTypes implements IRepairStep { protected $folderMimeTypeId; public function __construct(IConfig $config, - IDBConnection $connection) { + IDBConnection $connection) { $this->config = $config; $this->connection = $connection; } @@ -229,6 +229,30 @@ class RepairMimeTypes implements IRepairStep { return $this->updateMimetypes($updatedMimetypes); } + private function introduceEnhancedMetafileFormatType() { + $updatedMimetypes = [ + 'emf' => 'image/emf', + ]; + + return $this->updateMimetypes($updatedMimetypes); + } + + private function introduceEmlAndMsgFormatType() { + $updatedMimetypes = [ + 'eml' => 'message/rfc822', + 'msg' => 'application/vnd.ms-outlook', + ]; + + return $this->updateMimetypes($updatedMimetypes); + } + + private function introduceAacAudioType() { + $updatedMimetypes = [ + 'aac' => 'audio/aac', + ]; + + return $this->updateMimetypes($updatedMimetypes); + } /** * Fix mime types @@ -286,5 +310,17 @@ class RepairMimeTypes implements IRepairStep { if (version_compare($ocVersionFromBeforeUpdate, '26.0.0.1', '<') && $this->introduceAsciidocType()) { $out->info('Fixed AsciiDoc mime types'); } + + if (version_compare($ocVersionFromBeforeUpdate, '28.0.0.5', '<') && $this->introduceEnhancedMetafileFormatType()) { + $out->info('Fixed Enhanced Metafile Format mime types'); + } + + if (version_compare($ocVersionFromBeforeUpdate, '29.0.0.2', '<') && $this->introduceEmlAndMsgFormatType()) { + $out->info('Fixed eml and msg mime type'); + } + + if (version_compare($ocVersionFromBeforeUpdate, '29.0.0.6', '<') && $this->introduceAacAudioType()) { + $out->info('Fixed aac mime type'); + } } } diff --git a/lib/private/Repair/SqliteAutoincrement.php b/lib/private/Repair/SqliteAutoincrement.php deleted file mode 100644 index 4a8b2a45d3f..00000000000 --- a/lib/private/Repair/SqliteAutoincrement.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <vincent@nextcloud.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ -namespace OC\Repair; - -use Doctrine\DBAL\Platforms\SqlitePlatform; -use Doctrine\DBAL\Schema\ColumnDiff; -use Doctrine\DBAL\Schema\SchemaDiff; -use Doctrine\DBAL\Schema\SchemaException; -use Doctrine\DBAL\Schema\TableDiff; -use OCP\Migration\IOutput; -use OCP\Migration\IRepairStep; - -/** - * Fixes Sqlite autoincrement by forcing the SQLite table schemas to be - * altered in order to retrigger SQL schema generation through OCSqlitePlatform. - */ -class SqliteAutoincrement implements IRepairStep { - /** - * @var \OC\DB\Connection - */ - protected $connection; - - /** - * @param \OC\DB\Connection $connection - */ - public function __construct($connection) { - $this->connection = $connection; - } - - public function getName() { - return 'Repair SQLite autoincrement'; - } - - /** - * Fix mime types - */ - public function run(IOutput $out) { - if (!$this->connection->getDatabasePlatform() instanceof SqlitePlatform) { - return; - } - - $sourceSchema = $this->connection->getSchemaManager()->createSchema(); - - $schemaDiff = new SchemaDiff(); - - foreach ($sourceSchema->getTables() as $tableSchema) { - $primaryKey = $tableSchema->getPrimaryKey(); - if (!$primaryKey) { - continue; - } - - $columnNames = $primaryKey->getColumns(); - - // add a column diff for every primary key column, - // but do not actually change anything, this will - // force the generation of SQL statements to alter - // those tables, which will then trigger the - // specific SQL code from OCSqlitePlatform - try { - $tableDiff = new TableDiff($tableSchema->getName()); - $tableDiff->fromTable = $tableSchema; - foreach ($columnNames as $columnName) { - $columnSchema = $tableSchema->getColumn($columnName); - $columnDiff = new ColumnDiff($columnSchema->getName(), $columnSchema); - $tableDiff->changedColumns[$columnSchema->getName()] = $columnDiff; - $schemaDiff->changedTables[] = $tableDiff; - } - } catch (SchemaException $e) { - // ignore - } - } - - $this->connection->beginTransaction(); - foreach ($schemaDiff->toSql($this->connection->getDatabasePlatform()) as $sql) { - $this->connection->query($sql); - } - $this->connection->commit(); - } -} diff --git a/lib/private/RichObjectStrings/Validator.php b/lib/private/RichObjectStrings/Validator.php index 4585cbfc814..d7329c945e9 100644 --- a/lib/private/RichObjectStrings/Validator.php +++ b/lib/private/RichObjectStrings/Validator.php @@ -95,7 +95,7 @@ class Validator implements IValidator { $missingKeys = array_diff($requiredParameters, array_keys($parameter)); if (!empty($missingKeys)) { - throw new InvalidObjectExeption('Object is invalid'); + throw new InvalidObjectExeption('Object is invalid, missing keys:'.json_encode($missingKeys)); } } diff --git a/lib/private/Route/Router.php b/lib/private/Route/Router.php index fe97623176d..e7e2a9f0e49 100644 --- a/lib/private/Route/Router.php +++ b/lib/private/Route/Router.php @@ -14,6 +14,7 @@ * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Roeland Jago Douma <roeland@famdouma.nl> * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Kate Döen <kate.doeen@nextcloud.com> * * @license AGPL-3.0 * @@ -32,8 +33,10 @@ */ namespace OC\Route; +use DirectoryIterator; use OC\AppFramework\Routing\RouteParser; use OCP\AppFramework\App; +use OCP\AppFramework\Http\Attribute\Route as RouteAttribute; use OCP\Diagnostics\IEventLogger; use OCP\IConfig; use OCP\IRequest; @@ -41,6 +44,9 @@ use OCP\Route\IRouter; use OCP\Util; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use ReflectionAttribute; +use ReflectionClass; +use ReflectionException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Exception\RouteNotFoundException; use Symfony\Component\Routing\Generator\UrlGenerator; @@ -150,6 +156,22 @@ class Router implements IRouter { } } $this->eventLogger->start('route:load:' . $requestedApp, 'Loading Routes for ' . $requestedApp); + + if ($requestedApp !== null) { + $routes = $this->getAttributeRoutes($requestedApp); + if (count($routes) > 0) { + $this->useCollection($requestedApp); + $this->setupRoutes($routes, $requestedApp); + $collection = $this->getCollection($requestedApp); + $this->root->addCollection($collection); + + // Also add the OCS collection + $collection = $this->getCollection($requestedApp . '.ocs'); + $collection->addPrefix('/ocsapp'); + $this->root->addCollection($collection); + } + } + foreach ($routingFiles as $app => $file) { if (!isset($this->loadedApps[$app])) { if (!\OC_App::isAppLoaded($app)) { @@ -173,6 +195,7 @@ class Router implements IRouter { if (!isset($this->loadedApps['core'])) { $this->loadedApps['core'] = true; $this->useCollection('root'); + $this->setupRoutes($this->getAttributeRoutes('core'), 'core'); require_once __DIR__ . '/../../../core/routes.php'; // Also add the OCS collection @@ -230,9 +253,9 @@ class Router implements IRouter { * @return \OC\Route\Route */ public function create($name, - $pattern, - array $defaults = [], - array $requirements = []) { + $pattern, + array $defaults = [], + array $requirements = []) { $route = new Route($pattern, $defaults, $requirements); $this->collection->add($name, $route); return $route; @@ -247,23 +270,23 @@ class Router implements IRouter { */ public function findMatchingRoute(string $url): array { $this->eventLogger->start('route:match', 'Match route'); - if (substr($url, 0, 6) === '/apps/') { + if (str_starts_with($url, '/apps/')) { // empty string / 'apps' / $app / rest of the route [, , $app,] = explode('/', $url, 4); $app = \OC_App::cleanAppId($app); \OC::$REQUESTEDAPP = $app; $this->loadRoutes($app); - } elseif (substr($url, 0, 13) === '/ocsapp/apps/') { + } elseif (str_starts_with($url, '/ocsapp/apps/')) { // empty string / 'ocsapp' / 'apps' / $app / rest of the route [, , , $app,] = explode('/', $url, 5); $app = \OC_App::cleanAppId($app); \OC::$REQUESTEDAPP = $app; $this->loadRoutes($app); - } elseif (substr($url, 0, 10) === '/settings/') { + } elseif (str_starts_with($url, '/settings/')) { $this->loadRoutes('settings'); - } elseif (substr($url, 0, 6) === '/core/') { + } elseif (str_starts_with($url, '/core/')) { \OC::$REQUESTEDAPP = $url; if (!$this->config->getSystemValueBool('maintenance') && !Util::needUpgrade()) { \OC_App::loadApps(); @@ -277,7 +300,7 @@ class Router implements IRouter { try { $parameters = $matcher->match($url); } catch (ResourceNotFoundException $e) { - if (substr($url, -1) !== '/') { + 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. @@ -354,12 +377,19 @@ class Router implements IRouter { * @return string */ public function generate($name, - $parameters = [], - $absolute = false) { + $parameters = [], + $absolute = false) { $referenceType = UrlGenerator::ABSOLUTE_URL; if ($absolute === false) { $referenceType = UrlGenerator::ABSOLUTE_PATH; } + /* + * The route name has to be lowercase, for symfony to match it correctly. + * This is required because smyfony allows mixed casing for controller names in the routes. + * To avoid breaking all the existing route names, registering and matching will only use the lowercase names. + * This is also safe on the PHP side because class and method names collide regardless of the casing. + */ + $name = strtolower($name); $name = $this->fixLegacyRootName($name); if (str_contains($name, '.')) { [$appName, $other] = explode('.', $name, 3); @@ -385,34 +415,79 @@ class Router implements IRouter { } protected function fixLegacyRootName(string $routeName): string { - if ($routeName === 'files.viewcontroller.showFile') { - return 'files.View.showFile'; + if ($routeName === 'files.viewcontroller.showfile') { + return 'files.view.showfile'; } - if ($routeName === 'files_sharing.sharecontroller.showShare') { - return 'files_sharing.Share.showShare'; + if ($routeName === 'files_sharing.sharecontroller.showshare') { + return 'files_sharing.share.showshare'; } - if ($routeName === 'files_sharing.sharecontroller.showAuthenticate') { - return 'files_sharing.Share.showAuthenticate'; + if ($routeName === 'files_sharing.sharecontroller.showauthenticate') { + return 'files_sharing.share.showauthenticate'; } if ($routeName === 'files_sharing.sharecontroller.authenticate') { - return 'files_sharing.Share.authenticate'; + return 'files_sharing.share.authenticate'; } - if ($routeName === 'files_sharing.sharecontroller.downloadShare') { - return 'files_sharing.Share.downloadShare'; + if ($routeName === 'files_sharing.sharecontroller.downloadshare') { + return 'files_sharing.share.downloadshare'; } - if ($routeName === 'files_sharing.publicpreview.directLink') { - return 'files_sharing.PublicPreview.directLink'; + if ($routeName === 'files_sharing.publicpreview.directlink') { + return 'files_sharing.publicpreview.directlink'; } - if ($routeName === 'cloud_federation_api.requesthandlercontroller.addShare') { - return 'cloud_federation_api.RequestHandler.addShare'; + if ($routeName === 'cloud_federation_api.requesthandlercontroller.addshare') { + return 'cloud_federation_api.requesthandler.addshare'; } - if ($routeName === 'cloud_federation_api.requesthandlercontroller.receiveNotification') { - return 'cloud_federation_api.RequestHandler.receiveNotification'; + if ($routeName === 'cloud_federation_api.requesthandlercontroller.receivenotification') { + return 'cloud_federation_api.requesthandler.receivenotification'; } return $routeName; } /** + * @throws ReflectionException + */ + private function getAttributeRoutes(string $app): array { + $routes = []; + + if ($app === 'core') { + $appControllerPath = __DIR__ . '/../../../core/Controller'; + $appNameSpace = 'OC\\Core'; + } else { + $appControllerPath = \OC_App::getAppPath($app) . '/lib/Controller'; + $appNameSpace = App::buildAppNamespace($app); + } + + if (!file_exists($appControllerPath)) { + return []; + } + + $dir = new DirectoryIterator($appControllerPath); + foreach ($dir as $file) { + if (!str_ends_with($file->getPathname(), 'Controller.php')) { + continue; + } + + $class = new ReflectionClass($appNameSpace . '\\Controller\\' . basename($file->getPathname(), '.php')); + + foreach ($class->getMethods() as $method) { + foreach ($method->getAttributes(RouteAttribute::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) { + $route = $attribute->newInstance(); + + $serializedRoute = $route->toArray(); + // Remove 'Controller' suffix + $serializedRoute['name'] = substr($class->getShortName(), 0, -10) . '#' . $method->getName(); + + $key = $route->getType(); + + $routes[$key] ??= []; + $routes[$key][] = $serializedRoute; + } + } + } + + return $routes; + } + + /** * To isolate the variable scope used inside the $file it is required in it's own method * * @param string $file the route file location to include diff --git a/lib/private/Search.php b/lib/private/Search.php index b1e39843e49..9f1a0323aa3 100644 --- a/lib/private/Search.php +++ b/lib/private/Search.php @@ -30,6 +30,7 @@ namespace OC; use OCP\ISearch; use OCP\Search\PagedProvider; use OCP\Search\Provider; +use Psr\Log\LoggerInterface; /** * Provide an interface to all search providers @@ -65,7 +66,7 @@ class Search implements ISearch { $results = array_merge($results, $providerResults); } } else { - \OC::$server->getLogger()->warning('Ignoring Unknown search provider', ['provider' => $provider]); + \OCP\Server::get(LoggerInterface::class)->warning('Ignoring Unknown search provider', ['provider' => $provider]); } } return $results; diff --git a/lib/private/Search/Filter/BooleanFilter.php b/lib/private/Search/Filter/BooleanFilter.php new file mode 100644 index 00000000000..a64bf17f31c --- /dev/null +++ b/lib/private/Search/Filter/BooleanFilter.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Search\Filter; + +use InvalidArgumentException; +use OCP\Search\IFilter; + +class BooleanFilter implements IFilter { + private bool $value; + + public function __construct(string $value) { + $this->value = match ($value) { + 'true', 'yes', 'y', '1' => true, + 'false', 'no', 'n', '0', '' => false, + default => throw new InvalidArgumentException('Invalid boolean value '. $value), + }; + } + + public function get(): bool { + return $this->value; + } +} diff --git a/lib/private/Search/Filter/DateTimeFilter.php b/lib/private/Search/Filter/DateTimeFilter.php new file mode 100644 index 00000000000..79abf9ad542 --- /dev/null +++ b/lib/private/Search/Filter/DateTimeFilter.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Search\Filter; + +use DateTimeImmutable; +use OCP\Search\IFilter; + +class DateTimeFilter implements IFilter { + private DateTimeImmutable $value; + + public function __construct(string $value) { + if (filter_var($value, FILTER_VALIDATE_INT)) { + $value = '@'.$value; + } + + $this->value = new DateTimeImmutable($value); + } + + public function get(): DateTimeImmutable { + return $this->value; + } +} diff --git a/lib/private/Search/Filter/FloatFilter.php b/lib/private/Search/Filter/FloatFilter.php new file mode 100644 index 00000000000..3db19ded59b --- /dev/null +++ b/lib/private/Search/Filter/FloatFilter.php @@ -0,0 +1,45 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Search\Filter; + +use InvalidArgumentException; +use OCP\Search\IFilter; + +class FloatFilter implements IFilter { + private float $value; + + public function __construct(string $value) { + $this->value = filter_var($value, FILTER_VALIDATE_FLOAT); + if ($this->value === false) { + throw new InvalidArgumentException('Invalid float value '. $value); + } + } + + public function get(): float { + return $this->value; + } +} diff --git a/lib/private/Search/Filter/GroupFilter.php b/lib/private/Search/Filter/GroupFilter.php new file mode 100644 index 00000000000..f0b34a360ca --- /dev/null +++ b/lib/private/Search/Filter/GroupFilter.php @@ -0,0 +1,51 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Search\Filter; + +use InvalidArgumentException; +use OCP\IGroup; +use OCP\IGroupManager; +use OCP\Search\IFilter; + +class GroupFilter implements IFilter { + private IGroup $group; + + public function __construct( + string $value, + IGroupManager $groupManager, + ) { + $group = $groupManager->get($value); + if ($group === null) { + throw new InvalidArgumentException('Group '.$value.' not found'); + } + $this->group = $group; + } + + public function get(): IGroup { + return $this->group; + } +} diff --git a/lib/private/Search/Filter/IntegerFilter.php b/lib/private/Search/Filter/IntegerFilter.php new file mode 100644 index 00000000000..b5b907b220e --- /dev/null +++ b/lib/private/Search/Filter/IntegerFilter.php @@ -0,0 +1,45 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Search\Filter; + +use InvalidArgumentException; +use OCP\Search\IFilter; + +class IntegerFilter implements IFilter { + private int $value; + + public function __construct(string $value) { + $this->value = filter_var($value, FILTER_VALIDATE_INT); + if ($this->value === false) { + throw new InvalidArgumentException('Invalid integer value '. $value); + } + } + + public function get(): int { + return $this->value; + } +} diff --git a/lib/private/Search/Filter/StringFilter.php b/lib/private/Search/Filter/StringFilter.php new file mode 100644 index 00000000000..8f754d12051 --- /dev/null +++ b/lib/private/Search/Filter/StringFilter.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Search\Filter; + +use InvalidArgumentException; +use OCP\Search\IFilter; + +class StringFilter implements IFilter { + public function __construct( + private string $value, + ) { + if ($value === '') { + throw new InvalidArgumentException('String filter can’t be empty'); + } + } + + public function get(): string { + return $this->value; + } +} diff --git a/lib/private/Search/Filter/StringsFilter.php b/lib/private/Search/Filter/StringsFilter.php new file mode 100644 index 00000000000..7a8d88768e8 --- /dev/null +++ b/lib/private/Search/Filter/StringsFilter.php @@ -0,0 +1,51 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Search\Filter; + +use InvalidArgumentException; +use OCP\Search\IFilter; + +class StringsFilter implements IFilter { + /** + * @var string[] + */ + private array $values; + + public function __construct(string ...$values) { + $this->values = array_unique(array_filter($values)); + if (empty($this->values)) { + throw new InvalidArgumentException('Strings filter can’t be empty'); + } + } + + /** + * @return string[] + */ + public function get(): array { + return $this->values; + } +} diff --git a/lib/private/Search/Filter/UserFilter.php b/lib/private/Search/Filter/UserFilter.php new file mode 100644 index 00000000000..963d5e123ac --- /dev/null +++ b/lib/private/Search/Filter/UserFilter.php @@ -0,0 +1,51 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Search\Filter; + +use InvalidArgumentException; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Search\IFilter; + +class UserFilter implements IFilter { + private IUser $user; + + public function __construct( + string $value, + IUserManager $userManager, + ) { + $user = $userManager->get($value); + if ($user === null) { + throw new InvalidArgumentException('User '.$value.' not found'); + } + $this->user = $user; + } + + public function get(): IUser { + return $this->user; + } +} diff --git a/lib/private/Search/FilterCollection.php b/lib/private/Search/FilterCollection.php new file mode 100644 index 00000000000..15d6695dcac --- /dev/null +++ b/lib/private/Search/FilterCollection.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OC\Search; + +use Generator; +use OCP\Search\IFilter; +use OCP\Search\IFilterCollection; + +/** + * Interface for search filters + * + * @since 28.0.0 + */ +class FilterCollection implements IFilterCollection { + /** + * @var IFilter[] + */ + private array $filters; + + public function __construct(IFilter ...$filters) { + $this->filters = $filters; + } + + public function has(string $name): bool { + return isset($this->filters[$name]); + } + + public function get(string $name): ?IFilter { + return $this->filters[$name] ?? null; + } + + public function getIterator(): Generator { + foreach ($this->filters as $k => $v) { + yield $k => $v; + } + } +} diff --git a/lib/private/Search/FilterFactory.php b/lib/private/Search/FilterFactory.php new file mode 100644 index 00000000000..3f4388f405c --- /dev/null +++ b/lib/private/Search/FilterFactory.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OC\Search; + +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\Search\FilterDefinition; +use OCP\Search\IFilter; +use RuntimeException; + +final class FilterFactory { + private const PERSON_TYPE_SEPARATOR = '/'; + + public static function get(string $type, string|array $filter): IFilter { + return match ($type) { + FilterDefinition::TYPE_BOOL => new Filter\BooleanFilter($filter), + FilterDefinition::TYPE_DATETIME => new Filter\DateTimeFilter($filter), + FilterDefinition::TYPE_FLOAT => new Filter\FloatFilter($filter), + FilterDefinition::TYPE_INT => new Filter\IntegerFilter($filter), + FilterDefinition::TYPE_NC_GROUP => new Filter\GroupFilter($filter, \OC::$server->get(IGroupManager::class)), + FilterDefinition::TYPE_NC_USER => new Filter\UserFilter($filter, \OC::$server->get(IUserManager::class)), + FilterDefinition::TYPE_PERSON => self::getPerson($filter), + FilterDefinition::TYPE_STRING => new Filter\StringFilter($filter), + FilterDefinition::TYPE_STRINGS => new Filter\StringsFilter(... (array) $filter), + default => throw new RuntimeException('Invalid filter type '. $type), + }; + } + + private static function getPerson(string $person): IFilter { + $parts = explode(self::PERSON_TYPE_SEPARATOR, $person, 2); + + return match (count($parts)) { + 1 => self::get(FilterDefinition::TYPE_NC_USER, $person), + 2 => self::get(... $parts), + }; + } +} diff --git a/lib/private/Search/SearchComposer.php b/lib/private/Search/SearchComposer.php index 4ec73ec54e9..03e84a079fe 100644 --- a/lib/private/Search/SearchComposer.php +++ b/lib/private/Search/SearchComposer.php @@ -28,14 +28,20 @@ declare(strict_types=1); namespace OC\Search; use InvalidArgumentException; -use OCP\AppFramework\QueryException; -use OCP\IServerContainer; +use OC\AppFramework\Bootstrap\Coordinator; +use OCP\IURLGenerator; use OCP\IUser; +use OCP\Search\FilterDefinition; +use OCP\Search\IFilter; +use OCP\Search\IFilteringProvider; +use OCP\Search\IInAppSearch; use OCP\Search\IProvider; use OCP\Search\ISearchQuery; use OCP\Search\SearchResult; -use OC\AppFramework\Bootstrap\Coordinator; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use RuntimeException; use function array_map; /** @@ -58,31 +64,40 @@ use function array_map; * @see IProvider::search() for the arguments of the individual search requests */ class SearchComposer { - /** @var IProvider[] */ - private $providers = []; - - /** @var Coordinator */ - private $bootstrapCoordinator; + /** + * @var array<string, array{appId: string, provider: IProvider}> + */ + private array $providers = []; - /** @var IServerContainer */ - private $container; + private array $commonFilters; + private array $customFilters = []; - private LoggerInterface $logger; + private array $handlers = []; - public function __construct(Coordinator $bootstrapCoordinator, - IServerContainer $container, - LoggerInterface $logger) { - $this->container = $container; - $this->logger = $logger; - $this->bootstrapCoordinator = $bootstrapCoordinator; + public function __construct( + private Coordinator $bootstrapCoordinator, + private ContainerInterface $container, + private IURLGenerator $urlGenerator, + private LoggerInterface $logger + ) { + $this->commonFilters = [ + IFilter::BUILTIN_TERM => new FilterDefinition(IFilter::BUILTIN_TERM, FilterDefinition::TYPE_STRING), + IFilter::BUILTIN_SINCE => new FilterDefinition(IFilter::BUILTIN_SINCE, FilterDefinition::TYPE_DATETIME), + IFilter::BUILTIN_UNTIL => new FilterDefinition(IFilter::BUILTIN_UNTIL, FilterDefinition::TYPE_DATETIME), + IFilter::BUILTIN_TITLE_ONLY => new FilterDefinition(IFilter::BUILTIN_TITLE_ONLY, FilterDefinition::TYPE_BOOL, false), + IFilter::BUILTIN_PERSON => new FilterDefinition(IFilter::BUILTIN_PERSON, FilterDefinition::TYPE_PERSON), + IFilter::BUILTIN_PLACES => new FilterDefinition(IFilter::BUILTIN_PLACES, FilterDefinition::TYPE_STRINGS, false), + IFilter::BUILTIN_PROVIDER => new FilterDefinition(IFilter::BUILTIN_PROVIDER, FilterDefinition::TYPE_STRING, false), + ]; } /** * Load all providers dynamically that were registered through `registerProvider` * + * If $targetProviderId is provided, only this provider is loaded * If a provider can't be loaded we log it but the operation continues nevertheless */ - private function loadLazyProviders(): void { + private function loadLazyProviders(?string $targetProviderId = null): void { $context = $this->bootstrapCoordinator->getRegistrationContext(); if ($context === null) { // Too early, nothing registered yet @@ -93,9 +108,20 @@ class SearchComposer { foreach ($registrations as $registration) { try { /** @var IProvider $provider */ - $provider = $this->container->query($registration->getService()); - $this->providers[$provider->getId()] = $provider; - } catch (QueryException $e) { + $provider = $this->container->get($registration->getService()); + $providerId = $provider->getId(); + if ($targetProviderId !== null && $targetProviderId !== $providerId) { + continue; + } + $this->providers[$providerId] = [ + 'appId' => $registration->getAppId(), + 'provider' => $provider, + ]; + $this->handlers[$providerId] = [$providerId]; + if ($targetProviderId !== null) { + break; + } + } catch (ContainerExceptionInterface $e) { // Log an continue. We can be fault tolerant here. $this->logger->error('Could not load search provider dynamically: ' . $e->getMessage(), [ 'exception' => $e, @@ -103,6 +129,43 @@ class SearchComposer { ]); } } + + $this->loadFilters(); + } + + private function loadFilters(): void { + foreach ($this->providers as $providerId => $providerData) { + $appId = $providerData['appId']; + $provider = $providerData['provider']; + if (!$provider instanceof IFilteringProvider) { + continue; + } + + foreach ($provider->getCustomFilters() as $filter) { + $this->registerCustomFilter($filter, $providerId); + } + foreach ($provider->getAlternateIds() as $alternateId) { + $this->handlers[$alternateId][] = $providerId; + } + foreach ($provider->getSupportedFilters() as $filterName) { + if ($this->getFilterDefinition($filterName, $providerId) === null) { + throw new InvalidArgumentException('Invalid filter '. $filterName); + } + } + } + } + + private function registerCustomFilter(FilterDefinition $filter, string $providerId): void { + $name = $filter->name(); + if (isset($this->commonFilters[$name])) { + throw new InvalidArgumentException('Filter name is already used'); + } + + if (isset($this->customFilters[$providerId])) { + $this->customFilters[$providerId][$name] = $filter; + } else { + $this->customFilters[$providerId] = [$name => $filter]; + } } /** @@ -117,26 +180,146 @@ class SearchComposer { public function getProviders(string $route, array $routeParameters): array { $this->loadLazyProviders(); - $providers = array_values( - array_map(function (IProvider $provider) use ($route, $routeParameters) { + $providers = array_map( + function (array $providerData) use ($route, $routeParameters) { + $appId = $providerData['appId']; + $provider = $providerData['provider']; + $order = $provider->getOrder($route, $routeParameters); + if ($order === null) { + return; + } + $triggers = [$provider->getId()]; + if ($provider instanceof IFilteringProvider) { + $triggers += $provider->getAlternateIds(); + $filters = $provider->getSupportedFilters(); + } else { + $filters = [IFilter::BUILTIN_TERM]; + } + return [ 'id' => $provider->getId(), + 'appId' => $appId, 'name' => $provider->getName(), - 'order' => $provider->getOrder($route, $routeParameters), + 'icon' => $this->fetchIcon($appId, $provider->getId()), + 'order' => $order, + 'triggers' => $triggers, + 'filters' => $this->getFiltersType($filters, $provider->getId()), + 'inAppSearch' => $provider instanceof IInAppSearch, ]; - }, $this->providers) + }, + $this->providers, ); + $providers = array_filter($providers); + // Sort providers by order and strip associative keys usort($providers, function ($provider1, $provider2) { return $provider1['order'] <=> $provider2['order']; }); - /** - * Return an array with the IDs, but strip the associative keys - */ return $providers; } + private function fetchIcon(string $appId, string $providerId): string { + $icons = [ + [$providerId, $providerId.'.svg'], + [$providerId, 'app.svg'], + [$appId, $providerId.'.svg'], + [$appId, $appId.'.svg'], + [$appId, 'app.svg'], + ['core', 'places/default-app-icon.svg'], + ]; + if ($appId === 'settings' && $providerId === 'users') { + // Conflict: + // the file /apps/settings/users.svg is already used in black version by top right user menu + // Override icon name here + $icons = [['settings', 'users-white.svg']]; + } + foreach ($icons as $i => $icon) { + try { + return $this->urlGenerator->imagePath(... $icon); + } catch (RuntimeException $e) { + // Ignore error + } + } + + return ''; + } + + /** + * @param $filters string[] + * @return array<string, string> + */ + private function getFiltersType(array $filters, string $providerId): array { + $filterList = []; + foreach ($filters as $filter) { + $filterList[$filter] = $this->getFilterDefinition($filter, $providerId)->type(); + } + + return $filterList; + } + + private function getFilterDefinition(string $name, string $providerId): ?FilterDefinition { + if (isset($this->commonFilters[$name])) { + return $this->commonFilters[$name]; + } + if (isset($this->customFilters[$providerId][$name])) { + return $this->customFilters[$providerId][$name]; + } + + return null; + } + + /** + * @param array<string, string> $parameters + */ + public function buildFilterList(string $providerId, array $parameters): FilterCollection { + $this->loadLazyProviders($providerId); + + $list = []; + foreach ($parameters as $name => $value) { + $filter = $this->buildFilter($name, $value, $providerId); + if ($filter === null) { + continue; + } + $list[$name] = $filter; + } + + return new FilterCollection(... $list); + } + + private function buildFilter(string $name, string $value, string $providerId): ?IFilter { + $filterDefinition = $this->getFilterDefinition($name, $providerId); + if ($filterDefinition === null) { + $this->logger->debug('Unable to find {name} definition', [ + 'name' => $name, + 'value' => $value, + ]); + + return null; + } + + if (!$this->filterSupportedByProvider($filterDefinition, $providerId)) { + // FIXME Use dedicated exception and handle it + throw new UnsupportedFilter($name, $providerId); + } + + return FilterFactory::get($filterDefinition->type(), $value); + } + + private function filterSupportedByProvider(FilterDefinition $filterDefinition, string $providerId): bool { + // Non exclusive filters can be ommited by apps + if (!$filterDefinition->exclusive()) { + return true; + } + + $provider = $this->providers[$providerId]['provider']; + $supportedFilters = $provider instanceof IFilteringProvider + ? $provider->getSupportedFilters() + : [IFilter::BUILTIN_TERM]; + + return in_array($filterDefinition->name(), $supportedFilters, true); + } + /** * Query an individual search provider for results * @@ -147,15 +330,18 @@ class SearchComposer { * @return SearchResult * @throws InvalidArgumentException when the $providerId does not correspond to a registered provider */ - public function search(IUser $user, - string $providerId, - ISearchQuery $query): SearchResult { - $this->loadLazyProviders(); + public function search( + IUser $user, + string $providerId, + ISearchQuery $query, + ): SearchResult { + $this->loadLazyProviders($providerId); - $provider = $this->providers[$providerId] ?? null; + $provider = $this->providers[$providerId]['provider'] ?? null; if ($provider === null) { throw new InvalidArgumentException("Provider $providerId is unknown"); } + return $provider->search($user, $query); } } diff --git a/lib/private/Search/SearchQuery.php b/lib/private/Search/SearchQuery.php index c89446d5970..e4295c4ab76 100644 --- a/lib/private/Search/SearchQuery.php +++ b/lib/private/Search/SearchQuery.php @@ -27,89 +27,57 @@ declare(strict_types=1); */ namespace OC\Search; +use OCP\Search\IFilter; +use OCP\Search\IFilterCollection; use OCP\Search\ISearchQuery; class SearchQuery implements ISearchQuery { public const LIMIT_DEFAULT = 5; - /** @var string */ - private $term; - - /** @var int */ - private $sortOrder; - - /** @var int */ - private $limit; - - /** @var int|string|null */ - private $cursor; - - /** @var string */ - private $route; - - /** @var array */ - private $routeParameters; - /** - * @param string $term - * @param int $sortOrder - * @param int $limit - * @param int|string|null $cursor - * @param string $route - * @param array $routeParameters + * @param string[] $params Request query + * @param string[] $routeParameters */ - public function __construct(string $term, - int $sortOrder = ISearchQuery::SORT_DATE_DESC, - int $limit = self::LIMIT_DEFAULT, - $cursor = null, - string $route = '', - array $routeParameters = []) { - $this->term = $term; - $this->sortOrder = $sortOrder; - $this->limit = $limit; - $this->cursor = $cursor; - $this->route = $route; - $this->routeParameters = $routeParameters; + public function __construct( + private IFilterCollection $filters, + private int $sortOrder = ISearchQuery::SORT_DATE_DESC, + private int $limit = self::LIMIT_DEFAULT, + private int|string|null $cursor = null, + private string $route = '', + private array $routeParameters = [], + ) { } - /** - * @inheritDoc - */ public function getTerm(): string { - return $this->term; + return $this->getFilter('term')?->get() ?? ''; + } + + public function getFilter(string $name): ?IFilter { + return $this->filters->has($name) + ? $this->filters->get($name) + : null; + } + + public function getFilters(): IFilterCollection { + return $this->filters; } - /** - * @inheritDoc - */ public function getSortOrder(): int { return $this->sortOrder; } - /** - * @inheritDoc - */ public function getLimit(): int { return $this->limit; } - /** - * @inheritDoc - */ - public function getCursor() { + public function getCursor(): int|string|null { return $this->cursor; } - /** - * @inheritDoc - */ public function getRoute(): string { return $this->route; } - /** - * @inheritDoc - */ public function getRouteParameters(): array { return $this->routeParameters; } diff --git a/lib/private/Search/UnsupportedFilter.php b/lib/private/Search/UnsupportedFilter.php new file mode 100644 index 00000000000..84b6163d2fa --- /dev/null +++ b/lib/private/Search/UnsupportedFilter.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OC\Search; + +use Exception; + +final class UnsupportedFilter extends Exception { + public function __construct(string $filerName, $providerId) { + parent::__construct('Provider '.$providerId.' doesn’t support filter '.$filerName.'.'); + } +} diff --git a/lib/private/Security/Bruteforce/Capabilities.php b/lib/private/Security/Bruteforce/Capabilities.php index b50eea0b7af..add2bb8d8b5 100644 --- a/lib/private/Security/Bruteforce/Capabilities.php +++ b/lib/private/Security/Bruteforce/Capabilities.php @@ -29,8 +29,8 @@ declare(strict_types=1); */ namespace OC\Security\Bruteforce; -use OCP\Capabilities\IPublicCapability; use OCP\Capabilities\IInitialStateExcludedCapability; +use OCP\Capabilities\IPublicCapability; use OCP\IRequest; use OCP\Security\Bruteforce\IThrottler; diff --git a/lib/private/Security/Bruteforce/CleanupJob.php b/lib/private/Security/Bruteforce/CleanupJob.php index 45cfe572acb..13628dd300d 100644 --- a/lib/private/Security/Bruteforce/CleanupJob.php +++ b/lib/private/Security/Bruteforce/CleanupJob.php @@ -32,19 +32,18 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; class CleanupJob extends TimedJob { - /** @var IDBConnection */ - private $connection; - - public function __construct(ITimeFactory $time, IDBConnection $connection) { + public function __construct( + ITimeFactory $time, + private IDBConnection $connection, + ) { parent::__construct($time); - $this->connection = $connection; // Run once a day $this->setInterval(3600 * 24); $this->setTimeSensitivity(IJob::TIME_INSENSITIVE); } - protected function run($argument) { + protected function run($argument): void { // Delete all entries more than 48 hours old $time = $this->time->getTime() - (48 * 3600); diff --git a/lib/private/Security/Bruteforce/Throttler.php b/lib/private/Security/Bruteforce/Throttler.php index 2803373e8ba..7e5f1daa28c 100644 --- a/lib/private/Security/Bruteforce/Throttler.php +++ b/lib/private/Security/Bruteforce/Throttler.php @@ -72,8 +72,8 @@ class Throttler implements IThrottler { * {@inheritDoc} */ public function registerAttempt(string $action, - string $ip, - array $metadata = []): void { + string $ip, + array $metadata = []): void { // No need to log if the bruteforce protection is disabled if (!$this->config->getSystemValueBool('auth.bruteforce.protection.enabled', true)) { return; @@ -106,9 +106,6 @@ class Throttler implements IThrottler { /** * Check if the IP is whitelisted - * - * @param string $ip - * @return bool */ public function isBypassListed(string $ip): bool { if (isset($this->ipIsWhitelisted[$ip])) { diff --git a/lib/private/Security/CSP/ContentSecurityPolicy.php b/lib/private/Security/CSP/ContentSecurityPolicy.php index e2d115cf34e..ee525af4c2a 100644 --- a/lib/private/Security/CSP/ContentSecurityPolicy.php +++ b/lib/private/Security/CSP/ContentSecurityPolicy.php @@ -34,33 +34,22 @@ namespace OC\Security\CSP; * @package OC\Security\CSP */ class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy { - /** - * @return boolean - */ public function isInlineScriptAllowed(): bool { return $this->inlineScriptAllowed; } - /** - * @param boolean $inlineScriptAllowed - */ - public function setInlineScriptAllowed(bool $inlineScriptAllowed) { + public function setInlineScriptAllowed(bool $inlineScriptAllowed): void { $this->inlineScriptAllowed = $inlineScriptAllowed; } - /** - * @return boolean - */ public function isEvalScriptAllowed(): bool { return $this->evalScriptAllowed; } /** - * @param boolean $evalScriptAllowed - * * @deprecated 17.0.0 Unsafe eval should not be used anymore. */ - public function setEvalScriptAllowed(bool $evalScriptAllowed) { + public function setEvalScriptAllowed(bool $evalScriptAllowed): void { $this->evalScriptAllowed = $evalScriptAllowed; } @@ -72,134 +61,79 @@ class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy $this->evalWasmAllowed = $evalWasmAllowed; } - /** - * @return array - */ public function getAllowedScriptDomains(): array { return $this->allowedScriptDomains; } - /** - * @param array $allowedScriptDomains - */ - public function setAllowedScriptDomains(array $allowedScriptDomains) { + public function setAllowedScriptDomains(array $allowedScriptDomains): void { $this->allowedScriptDomains = $allowedScriptDomains; } - /** - * @return boolean - */ public function isInlineStyleAllowed(): bool { return $this->inlineStyleAllowed; } - /** - * @param boolean $inlineStyleAllowed - */ - public function setInlineStyleAllowed(bool $inlineStyleAllowed) { + public function setInlineStyleAllowed(bool $inlineStyleAllowed): void { $this->inlineStyleAllowed = $inlineStyleAllowed; } - /** - * @return array - */ public function getAllowedStyleDomains(): array { return $this->allowedStyleDomains; } - /** - * @param array $allowedStyleDomains - */ - public function setAllowedStyleDomains(array $allowedStyleDomains) { + public function setAllowedStyleDomains(array $allowedStyleDomains): void { $this->allowedStyleDomains = $allowedStyleDomains; } - /** - * @return array - */ public function getAllowedImageDomains(): array { return $this->allowedImageDomains; } - /** - * @param array $allowedImageDomains - */ - public function setAllowedImageDomains(array $allowedImageDomains) { + public function setAllowedImageDomains(array $allowedImageDomains): void { $this->allowedImageDomains = $allowedImageDomains; } - /** - * @return array - */ public function getAllowedConnectDomains(): array { return $this->allowedConnectDomains; } - /** - * @param array $allowedConnectDomains - */ - public function setAllowedConnectDomains(array $allowedConnectDomains) { + public function setAllowedConnectDomains(array $allowedConnectDomains): void { $this->allowedConnectDomains = $allowedConnectDomains; } - /** - * @return array - */ public function getAllowedMediaDomains(): array { return $this->allowedMediaDomains; } - /** - * @param array $allowedMediaDomains - */ - public function setAllowedMediaDomains(array $allowedMediaDomains) { + public function setAllowedMediaDomains(array $allowedMediaDomains): void { $this->allowedMediaDomains = $allowedMediaDomains; } - /** - * @return array - */ public function getAllowedObjectDomains(): array { return $this->allowedObjectDomains; } - /** - * @param array $allowedObjectDomains - */ - public function setAllowedObjectDomains(array $allowedObjectDomains) { + public function setAllowedObjectDomains(array $allowedObjectDomains): void { $this->allowedObjectDomains = $allowedObjectDomains; } - /** - * @return array - */ public function getAllowedFrameDomains(): array { return $this->allowedFrameDomains; } - /** - * @param array $allowedFrameDomains - */ - public function setAllowedFrameDomains(array $allowedFrameDomains) { + public function setAllowedFrameDomains(array $allowedFrameDomains): void { $this->allowedFrameDomains = $allowedFrameDomains; } - /** - * @return array - */ public function getAllowedFontDomains(): array { return $this->allowedFontDomains; } - /** - * @param array $allowedFontDomains - */ - public function setAllowedFontDomains($allowedFontDomains) { + public function setAllowedFontDomains($allowedFontDomains): void { $this->allowedFontDomains = $allowedFontDomains; } /** - * @return array * @deprecated 15.0.0 use FrameDomains and WorkerSrcDomains */ public function getAllowedChildSrcDomains(): array { @@ -210,13 +144,10 @@ class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy * @param array $allowedChildSrcDomains * @deprecated 15.0.0 use FrameDomains and WorkerSrcDomains */ - public function setAllowedChildSrcDomains($allowedChildSrcDomains) { + public function setAllowedChildSrcDomains($allowedChildSrcDomains): void { $this->allowedChildSrcDomains = $allowedChildSrcDomains; } - /** - * @return array - */ public function getAllowedFrameAncestors(): array { return $this->allowedFrameAncestors; } @@ -224,7 +155,7 @@ class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy /** * @param array $allowedFrameAncestors */ - public function setAllowedFrameAncestors($allowedFrameAncestors) { + public function setAllowedFrameAncestors($allowedFrameAncestors): void { $this->allowedFrameAncestors = $allowedFrameAncestors; } @@ -232,7 +163,7 @@ class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy return $this->allowedWorkerSrcDomains; } - public function setAllowedWorkerSrcDomains(array $allowedWorkerSrcDomains) { + public function setAllowedWorkerSrcDomains(array $allowedWorkerSrcDomains): void { $this->allowedWorkerSrcDomains = $allowedWorkerSrcDomains; } @@ -249,21 +180,23 @@ class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy return $this->reportTo; } - public function setReportTo(array $reportTo) { + public function setReportTo(array $reportTo): void { $this->reportTo = $reportTo; } - /** - * @return boolean - */ public function isStrictDynamicAllowed(): bool { return $this->strictDynamicAllowed; } - /** - * @param boolean $strictDynamicAllowed - */ - public function setStrictDynamicAllowed(bool $strictDynamicAllowed) { + public function setStrictDynamicAllowed(bool $strictDynamicAllowed): void { $this->strictDynamicAllowed = $strictDynamicAllowed; } + + public function isStrictDynamicAllowedOnScripts(): bool { + return $this->strictDynamicAllowedOnScripts; + } + + public function setStrictDynamicAllowedOnScripts(bool $strictDynamicAllowedOnScripts): void { + $this->strictDynamicAllowedOnScripts = $strictDynamicAllowedOnScripts; + } } diff --git a/lib/private/Security/CSP/ContentSecurityPolicyManager.php b/lib/private/Security/CSP/ContentSecurityPolicyManager.php index 4930dcb759c..503933ef980 100644 --- a/lib/private/Security/CSP/ContentSecurityPolicyManager.php +++ b/lib/private/Security/CSP/ContentSecurityPolicyManager.php @@ -35,25 +35,21 @@ use OCP\Security\IContentSecurityPolicyManager; class ContentSecurityPolicyManager implements IContentSecurityPolicyManager { /** @var ContentSecurityPolicy[] */ - private $policies = []; + private array $policies = []; - /** @var IEventDispatcher */ - private $dispatcher; - - public function __construct(IEventDispatcher $dispatcher) { - $this->dispatcher = $dispatcher; + public function __construct( + private IEventDispatcher $dispatcher, + ) { } /** {@inheritdoc} */ - public function addDefaultPolicy(EmptyContentSecurityPolicy $policy) { + public function addDefaultPolicy(EmptyContentSecurityPolicy $policy): void { $this->policies[] = $policy; } /** * Get the configured default policy. This is not in the public namespace * as it is only supposed to be used by core itself. - * - * @return ContentSecurityPolicy */ public function getDefaultPolicy(): ContentSecurityPolicy { $event = new AddContentSecurityPolicyEvent($this); @@ -68,13 +64,11 @@ class ContentSecurityPolicyManager implements IContentSecurityPolicyManager { /** * Merges the first given policy with the second one - * - * @param ContentSecurityPolicy $defaultPolicy - * @param EmptyContentSecurityPolicy $originalPolicy - * @return ContentSecurityPolicy */ - public function mergePolicies(ContentSecurityPolicy $defaultPolicy, - EmptyContentSecurityPolicy $originalPolicy): ContentSecurityPolicy { + public function mergePolicies( + ContentSecurityPolicy $defaultPolicy, + EmptyContentSecurityPolicy $originalPolicy, + ): ContentSecurityPolicy { foreach ((object)(array)$originalPolicy as $name => $value) { $setter = 'set'.ucfirst($name); if (\is_array($value)) { diff --git a/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php b/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php index 1167b3358d2..6dbf86e5c88 100644 --- a/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php +++ b/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php @@ -38,27 +38,16 @@ use OCP\IRequest; * @package OC\Security\CSP */ class ContentSecurityPolicyNonceManager { - /** @var CsrfTokenManager */ - private $csrfTokenManager; - /** @var IRequest */ - private $request; - /** @var string */ - private $nonce = ''; + private string $nonce = ''; - /** - * @param CsrfTokenManager $csrfTokenManager - * @param IRequest $request - */ - public function __construct(CsrfTokenManager $csrfTokenManager, - IRequest $request) { - $this->csrfTokenManager = $csrfTokenManager; - $this->request = $request; + public function __construct( + private CsrfTokenManager $csrfTokenManager, + private IRequest $request, + ) { } /** - * Returns the current CSP nounce - * - * @return string + * Returns the current CSP nonce */ public function getNonce(): string { if ($this->nonce === '') { @@ -74,14 +63,13 @@ class ContentSecurityPolicyNonceManager { /** * Check if the browser supports CSP v3 - * - * @return bool */ public function browserSupportsCspV3(): bool { $browserWhitelist = [ Request::USER_AGENT_CHROME, Request::USER_AGENT_FIREFOX, Request::USER_AGENT_SAFARI, + Request::USER_AGENT_MS_EDGE, ]; if ($this->request->isUserAgent($browserWhitelist)) { diff --git a/lib/private/Security/CSRF/CsrfToken.php b/lib/private/Security/CSRF/CsrfToken.php index a76e169e5b9..45e628b3f3c 100644 --- a/lib/private/Security/CSRF/CsrfToken.php +++ b/lib/private/Security/CSRF/CsrfToken.php @@ -36,23 +36,19 @@ namespace OC\Security\CSRF; * @package OC\Security\CSRF */ class CsrfToken { - /** @var string */ - private $value; - /** @var string */ - private $encryptedValue = ''; + private string $encryptedValue = ''; /** * @param string $value Value of the token. Can be encrypted or not encrypted. */ - public function __construct(string $value) { - $this->value = $value; + public function __construct( + private string $value, + ) { } /** * Encrypted value of the token. This is used to mitigate BREACH alike * vulnerabilities. For display measures do use this functionality. - * - * @return string */ public function getEncryptedValue(): string { if ($this->encryptedValue === '') { @@ -66,8 +62,6 @@ class CsrfToken { /** * The unencrypted value of the token. Used for decrypting an already * encrypted token. - * - * @return string */ public function getDecryptedValue(): string { $token = explode(':', $this->value); diff --git a/lib/private/Security/CSRF/CsrfTokenGenerator.php b/lib/private/Security/CSRF/CsrfTokenGenerator.php index 0576fda9e06..c3d89247de1 100644 --- a/lib/private/Security/CSRF/CsrfTokenGenerator.php +++ b/lib/private/Security/CSRF/CsrfTokenGenerator.php @@ -34,21 +34,15 @@ use OCP\Security\ISecureRandom; * @package OC\Security\CSRF */ class CsrfTokenGenerator { - /** @var ISecureRandom */ - private $random; - - /** - * @param ISecureRandom $random - */ - public function __construct(ISecureRandom $random) { - $this->random = $random; + public function __construct( + private ISecureRandom $random, + ) { } /** * Generate a new CSRF token. * * @param int $length Length of the token in characters. - * @return string */ public function generateToken(int $length = 32): string { return $this->random->generate($length); diff --git a/lib/private/Security/CSRF/CsrfTokenManager.php b/lib/private/Security/CSRF/CsrfTokenManager.php index 2c6dd45866d..dceacf45e2a 100644 --- a/lib/private/Security/CSRF/CsrfTokenManager.php +++ b/lib/private/Security/CSRF/CsrfTokenManager.php @@ -34,27 +34,18 @@ use OC\Security\CSRF\TokenStorage\SessionStorage; * @package OC\Security\CSRF */ class CsrfTokenManager { - /** @var CsrfTokenGenerator */ - private $tokenGenerator; - /** @var SessionStorage */ - private $sessionStorage; - /** @var CsrfToken|null */ - private $csrfToken = null; + private SessionStorage $sessionStorage; + private ?CsrfToken $csrfToken = null; - /** - * @param CsrfTokenGenerator $tokenGenerator - * @param SessionStorage $storageInterface - */ - public function __construct(CsrfTokenGenerator $tokenGenerator, - SessionStorage $storageInterface) { - $this->tokenGenerator = $tokenGenerator; + public function __construct( + private CsrfTokenGenerator $tokenGenerator, + SessionStorage $storageInterface, + ) { $this->sessionStorage = $storageInterface; } /** * Returns the current CSRF token, if none set it will create a new one. - * - * @return CsrfToken */ public function getToken(): CsrfToken { if (!\is_null($this->csrfToken)) { @@ -74,8 +65,6 @@ class CsrfTokenManager { /** * Invalidates any current token and sets a new one. - * - * @return CsrfToken */ public function refreshToken(): CsrfToken { $value = $this->tokenGenerator->generateToken(); @@ -87,16 +76,13 @@ class CsrfTokenManager { /** * Remove the current token from the storage. */ - public function removeToken() { + public function removeToken(): void { $this->csrfToken = null; $this->sessionStorage->removeToken(); } /** * Verifies whether the provided token is valid. - * - * @param CsrfToken $token - * @return bool */ public function isTokenValid(CsrfToken $token): bool { if (!$this->sessionStorage->hasToken()) { diff --git a/lib/private/Security/CSRF/TokenStorage/SessionStorage.php b/lib/private/Security/CSRF/TokenStorage/SessionStorage.php index ab05d5b1493..0ffe043e2f9 100644 --- a/lib/private/Security/CSRF/TokenStorage/SessionStorage.php +++ b/lib/private/Security/CSRF/TokenStorage/SessionStorage.php @@ -35,27 +35,18 @@ use OCP\ISession; * @package OC\Security\CSRF\TokenStorage */ class SessionStorage { - /** @var ISession */ - private $session; - - /** - * @param ISession $session - */ - public function __construct(ISession $session) { - $this->session = $session; + public function __construct( + private ISession $session, + ) { } - /** - * @param ISession $session - */ - public function setSession(ISession $session) { + public function setSession(ISession $session): void { $this->session = $session; } /** * Returns the current token or throws an exception if none is found. * - * @return string * @throws \Exception */ public function getToken(): string { @@ -69,23 +60,20 @@ class SessionStorage { /** * Set the valid current token to $value. - * - * @param string $value */ - public function setToken(string $value) { + public function setToken(string $value): void { $this->session->set('requesttoken', $value); } /** * Removes the current token. */ - public function removeToken() { + public function removeToken(): void { $this->session->remove('requesttoken'); } + /** * Whether the storage has a storage. - * - * @return bool */ public function hasToken(): bool { return $this->session->exists('requesttoken'); diff --git a/lib/private/Security/Certificate.php b/lib/private/Security/Certificate.php index fb5b9aa8a93..759c71b2eec 100644 --- a/lib/private/Security/Certificate.php +++ b/lib/private/Security/Certificate.php @@ -30,25 +30,23 @@ namespace OC\Security; use OCP\ICertificate; class Certificate implements ICertificate { - protected $name; + protected string $name; - protected $commonName; + protected ?string $commonName; - protected $organization; + protected ?string $organization; - protected $serial; - protected $issueDate; + protected \DateTime $issueDate; - protected $expireDate; + protected \DateTime $expireDate; - protected $issuerName; + protected ?string $issuerName; - protected $issuerOrganization; + protected ?string $issuerOrganization; /** * @param string $data base64 encoded certificate - * @param string $name * @throws \Exception If the certificate could not get parsed */ public function __construct(string $data, string $name) { @@ -66,67 +64,43 @@ class Certificate implements ICertificate { throw new \Exception('Certificate could not get parsed.'); } - $this->commonName = isset($info['subject']['CN']) ? $info['subject']['CN'] : null; - $this->organization = isset($info['subject']['O']) ? $info['subject']['O'] : null; + $this->commonName = $info['subject']['CN'] ?? null; + $this->organization = $info['subject']['O'] ?? null; $this->issueDate = new \DateTime('@' . $info['validFrom_time_t'], $gmt); $this->expireDate = new \DateTime('@' . $info['validTo_time_t'], $gmt); - $this->issuerName = isset($info['issuer']['CN']) ? $info['issuer']['CN'] : null; - $this->issuerOrganization = isset($info['issuer']['O']) ? $info['issuer']['O'] : null; + $this->issuerName = $info['issuer']['CN'] ?? null; + $this->issuerOrganization = $info['issuer']['O'] ?? null; } - /** - * @return string - */ public function getName(): string { return $this->name; } - /** - * @return string|null - */ public function getCommonName(): ?string { return $this->commonName; } - /** - * @return string|null - */ public function getOrganization(): ?string { return $this->organization; } - /** - * @return \DateTime - */ public function getIssueDate(): \DateTime { return $this->issueDate; } - /** - * @return \DateTime - */ public function getExpireDate(): \DateTime { return $this->expireDate; } - /** - * @return bool - */ public function isExpired(): bool { $now = new \DateTime(); return $this->issueDate > $now or $now > $this->expireDate; } - /** - * @return string|null - */ public function getIssuerName(): ?string { return $this->issuerName; } - /** - * @return string|null - */ public function getIssuerOrganization(): ?string { return $this->issuerOrganization; } diff --git a/lib/private/Security/CertificateManager.php b/lib/private/Security/CertificateManager.php index 3a87b7f1a00..cf5f0f41d56 100644 --- a/lib/private/Security/CertificateManager.php +++ b/lib/private/Security/CertificateManager.php @@ -44,21 +44,14 @@ use Psr\Log\LoggerInterface; * Manage trusted certificates for users */ class CertificateManager implements ICertificateManager { - protected View $view; - protected IConfig $config; - protected LoggerInterface $logger; - protected ISecureRandom $random; - private ?string $bundlePath = null; - public function __construct(View $view, - IConfig $config, - LoggerInterface $logger, - ISecureRandom $random) { - $this->view = $view; - $this->config = $config; - $this->logger = $logger; - $this->random = $random; + public function __construct( + protected View $view, + protected IConfig $config, + protected LoggerInterface $logger, + protected ISecureRandom $random, + ) { } /** @@ -178,7 +171,6 @@ class CertificateManager implements ICertificateManager { * * @param string $certificate the certificate data * @param string $name the filename for the certificate - * @return \OCP\ICertificate * @throws \Exception If the certificate could not get added */ public function addCertificate(string $certificate, string $name): ICertificate { @@ -205,9 +197,6 @@ class CertificateManager implements ICertificateManager { /** * Remove the certificate and re-generate the certificate bundle - * - * @param string $name - * @return bool */ public function removeCertificate(string $name): bool { if (!Filesystem::isValidPath($name)) { @@ -225,8 +214,6 @@ class CertificateManager implements ICertificateManager { /** * Get the path to the certificate bundle - * - * @return string */ public function getCertificateBundle(): string { return $this->getPathToCertificates() . 'rootcerts.crt'; @@ -267,8 +254,6 @@ class CertificateManager implements ICertificateManager { /** * Check if we need to re-bundle the certificates because one of the sources has updated - * - * @return bool */ private function needsRebundling(): bool { $targetBundle = $this->getCertificateBundle(); @@ -282,8 +267,6 @@ class CertificateManager implements ICertificateManager { /** * get mtime of ca-bundle shipped by Nextcloud - * - * @return int */ protected function getFilemtimeOfCaBundle(): int { return filemtime(\OC::$SERVERROOT . '/resources/config/ca-bundle.crt'); diff --git a/lib/private/Security/CredentialsManager.php b/lib/private/Security/CredentialsManager.php index 0bddaeda1b0..ea59a24d646 100644 --- a/lib/private/Security/CredentialsManager.php +++ b/lib/private/Security/CredentialsManager.php @@ -40,26 +40,16 @@ use OCP\Security\ICrypto; class CredentialsManager implements ICredentialsManager { public const DB_TABLE = 'storages_credentials'; - /** @var ICrypto */ - protected $crypto; - - /** @var IDBConnection */ - protected $dbConnection; - - /** - * @param ICrypto $crypto - * @param IDBConnection $dbConnection - */ - public function __construct(ICrypto $crypto, IDBConnection $dbConnection) { - $this->crypto = $crypto; - $this->dbConnection = $dbConnection; + public function __construct( + protected ICrypto $crypto, + protected IDBConnection $dbConnection, + ) { } /** * Store a set of credentials * * @param string $userId empty string for system-wide credentials - * @param string $identifier * @param mixed $credentials */ public function store(string $userId, string $identifier, $credentials): void { @@ -77,10 +67,8 @@ class CredentialsManager implements ICredentialsManager { * Retrieve a set of credentials * * @param string $userId empty string for system-wide credentials - * @param string $identifier - * @return mixed */ - public function retrieve(string $userId, string $identifier) { + public function retrieve(string $userId, string $identifier): mixed { $qb = $this->dbConnection->getQueryBuilder(); $qb->select('credentials') ->from(self::DB_TABLE) @@ -108,7 +96,6 @@ class CredentialsManager implements ICredentialsManager { * Delete a set of credentials * * @param string $userId empty string for system-wide credentials - * @param string $identifier * @return int rows removed */ public function delete(string $userId, string $identifier): int { @@ -128,7 +115,6 @@ class CredentialsManager implements ICredentialsManager { /** * Erase all credentials stored for a user * - * @param string $userId * @return int rows removed */ public function erase(string $userId): int { diff --git a/lib/private/Security/Crypto.php b/lib/private/Security/Crypto.php index 2a7905376ef..033456f3f2e 100644 --- a/lib/private/Security/Crypto.php +++ b/lib/private/Security/Crypto.php @@ -32,7 +32,6 @@ namespace OC\Security; use Exception; use OCP\IConfig; use OCP\Security\ICrypto; -use OCP\Security\ISecureRandom; use phpseclib\Crypt\AES; use phpseclib\Crypt\Hash; @@ -47,20 +46,13 @@ use phpseclib\Crypt\Hash; * @package OC\Security */ class Crypto implements ICrypto { - /** @var AES $cipher */ - private $cipher; - /** @var int */ - private $ivLength = 16; - /** @var IConfig */ - private $config; + private AES $cipher; + private int $ivLength = 16; - /** - * @param IConfig $config - * @param ISecureRandom $random - */ - public function __construct(IConfig $config) { + public function __construct( + private IConfig $config, + ) { $this->cipher = new AES(); - $this->config = $config; } /** @@ -84,7 +76,6 @@ class Crypto implements ICrypto { /** * Encrypts a value and adds an HMAC (Encrypt-Then-MAC) * - * @param string $plaintext * @param string $password Password to encrypt, if not specified the secret from config.php will be taken * @return string Authenticated ciphertext * @throws Exception if it was not possible to gather sufficient entropy @@ -115,9 +106,7 @@ class Crypto implements ICrypto { /** * Decrypts a value and verifies the HMAC (Encrypt-Then-Mac) - * @param string $authenticatedCiphertext * @param string $password Password to encrypt, if not specified the secret from config.php will be taken - * @return string plaintext * @throws Exception If the HMAC does not match * @throws Exception If the decryption failed */ diff --git a/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php b/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php index 3aa93ac3da4..bb9fc41332f 100644 --- a/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php +++ b/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php @@ -32,13 +32,11 @@ use OCP\Security\FeaturePolicy\AddFeaturePolicyEvent; class FeaturePolicyManager { /** @var EmptyFeaturePolicy[] */ - private $policies = []; + private array $policies = []; - /** @var IEventDispatcher */ - private $dispatcher; - - public function __construct(IEventDispatcher $dispatcher) { - $this->dispatcher = $dispatcher; + public function __construct( + private IEventDispatcher $dispatcher, + ) { } public function addDefaultPolicy(EmptyFeaturePolicy $policy): void { @@ -60,8 +58,10 @@ class FeaturePolicyManager { * Merges the first given policy with the second one * */ - public function mergePolicies(FeaturePolicy $defaultPolicy, - EmptyFeaturePolicy $originalPolicy): FeaturePolicy { + public function mergePolicies( + FeaturePolicy $defaultPolicy, + EmptyFeaturePolicy $originalPolicy, + ): FeaturePolicy { foreach ((object)(array)$originalPolicy as $name => $value) { $setter = 'set' . ucfirst($name); if (\is_array($value)) { diff --git a/lib/private/Security/Hasher.php b/lib/private/Security/Hasher.php index 85f69263925..23747751053 100644 --- a/lib/private/Security/Hasher.php +++ b/lib/private/Security/Hasher.php @@ -51,19 +51,14 @@ use OCP\Security\IHasher; * @package OC\Security */ class Hasher implements IHasher { - /** @var IConfig */ - private $config; - /** @var array Options passed to password_hash and password_needs_rehash */ - private $options = []; - /** @var string Salt used for legacy passwords */ - private $legacySalt = null; - - /** - * @param IConfig $config - */ - public function __construct(IConfig $config) { - $this->config = $config; - + /** Options passed to password_hash and password_needs_rehash */ + private array $options = []; + /** Salt used for legacy passwords */ + private ?string $legacySalt = null; + + public function __construct( + private IConfig $config, + ) { if (\defined('PASSWORD_ARGON2ID') || \defined('PASSWORD_ARGON2I')) { // password_hash fails, when the minimum values are undershot. // In this case, apply minimum. @@ -106,7 +101,7 @@ class Hasher implements IHasher { * @param string $prefixedHash * @return null|array Null if the hash is not prefixed, otherwise array('version' => 1, 'hash' => 'foo') */ - protected function splitHash(string $prefixedHash) { + protected function splitHash(string $prefixedHash): ?array { $explodedString = explode('|', $prefixedHash, 2); if (\count($explodedString) === 2) { if ((int)$explodedString[0] > 0) { @@ -198,7 +193,7 @@ class Hasher implements IHasher { return password_needs_rehash($hash, $algorithm, $this->options); } - private function getPrefferedAlgorithm() { + private function getPrefferedAlgorithm(): string { $default = PASSWORD_BCRYPT; if (\defined('PASSWORD_ARGON2I')) { $default = PASSWORD_ARGON2I; diff --git a/lib/private/Security/Normalizer/IpAddress.php b/lib/private/Security/Normalizer/IpAddress.php index 98d85ce07a1..f8e55370da7 100644 --- a/lib/private/Security/Normalizer/IpAddress.php +++ b/lib/private/Security/Normalizer/IpAddress.php @@ -37,43 +37,18 @@ namespace OC\Security\Normalizer; * @package OC\Security\Normalizer */ class IpAddress { - /** @var string */ - private $ip; - /** - * @param string $ip IP to normalized + * @param string $ip IP to normalize */ - public function __construct(string $ip) { - $this->ip = $ip; + public function __construct( + private string $ip, + ) { } /** - * Return the given subnet for an IPv4 address and mask bits - * - * @param string $ip - * @param int $maskBits - * @return string - */ - private function getIPv4Subnet(string $ip, int $maskBits = 32): string { - $binary = \inet_pton($ip); - for ($i = 32; $i > $maskBits; $i -= 8) { - $j = \intdiv($i, 8) - 1; - $k = \min(8, $i - $maskBits); - $mask = (0xff - ((2 ** $k) - 1)); - $int = \unpack('C', $binary[$j]); - $binary[$j] = \pack('C', $int[1] & $mask); - } - return \inet_ntop($binary).'/'.$maskBits; - } - - /** - * Return the given subnet for an IPv6 address and mask bits - * - * @param string $ip - * @param int $maskBits - * @return string + * Return the given subnet for an IPv6 address (64 first bits) */ - private function getIPv6Subnet(string $ip, int $maskBits = 48): string { + private function getIPv6Subnet(string $ip): string { if ($ip[0] === '[' && $ip[-1] === ']') { // If IP is with brackets, for example [::1] $ip = substr($ip, 1, strlen($ip) - 2); } @@ -81,15 +56,11 @@ class IpAddress { if ($pos !== false) { $ip = substr($ip, 0, $pos - 1); } + $binary = \inet_pton($ip); - for ($i = 128; $i > $maskBits; $i -= 8) { - $j = \intdiv($i, 8) - 1; - $k = \min(8, $i - $maskBits); - $mask = (0xff - ((2 ** $k) - 1)); - $int = \unpack('C', $binary[$j]); - $binary[$j] = \pack('C', $int[1] & $mask); - } - return \inet_ntop($binary).'/'.$maskBits; + $mask = inet_pton('FFFF:FFFF:FFFF:FFFF::'); + + return inet_ntop($binary & $mask).'/64'; } /** @@ -103,58 +74,34 @@ class IpAddress { if (!$binary) { return null; } - for ($i = 0; $i <= 9; $i++) { - if (unpack('C', $binary[$i])[1] !== 0) { - return null; - } - } - for ($i = 10; $i <= 11; $i++) { - if (unpack('C', $binary[$i])[1] !== 255) { - return null; - } - } - - $binary4 = ''; - for ($i = 12; $i < 16; $i++) { - $binary4 .= $binary[$i]; + $mask = inet_pton('::FFFF:FFFF'); + if (($binary & ~$mask) !== inet_pton('::FFFF:0.0.0.0')) { + return null; } - return inet_ntop($binary4); + return inet_ntop(substr($binary, -4)); } /** * Gets either the /32 (IPv4) or the /64 (IPv6) subnet of an IP address - * - * @return string */ public function getSubnet(): string { - if (\preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $this->ip)) { - return $this->getIPv4Subnet( - $this->ip, - 32 - ); + if (filter_var($this->ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + return $this->ip.'/32'; } $ipv4 = $this->getEmbeddedIpv4($this->ip); if ($ipv4 !== null) { - return $this->getIPv4Subnet( - $ipv4, - 32 - ); + return $ipv4.'/32'; } - return $this->getIPv6Subnet( - $this->ip, - 64 - ); + return $this->getIPv6Subnet($this->ip); } /** * Returns the specified IP address - * - * @return string */ public function __toString(): string { return $this->ip; diff --git a/lib/private/Security/RateLimiting/Exception/RateLimitExceededException.php b/lib/private/Security/RateLimiting/Exception/RateLimitExceededException.php index 08091e997ca..baf74927886 100644 --- a/lib/private/Security/RateLimiting/Exception/RateLimitExceededException.php +++ b/lib/private/Security/RateLimiting/Exception/RateLimitExceededException.php @@ -27,8 +27,9 @@ namespace OC\Security\RateLimiting\Exception; use OC\AppFramework\Middleware\Security\Exceptions\SecurityException; use OCP\AppFramework\Http; +use OCP\Security\RateLimiting\IRateLimitExceededException; -class RateLimitExceededException extends SecurityException { +class RateLimitExceededException extends SecurityException implements IRateLimitExceededException { public function __construct() { parent::__construct('Rate limit exceeded', Http::STATUS_TOO_MANY_REQUESTS); } diff --git a/lib/private/Security/RateLimiting/Limiter.php b/lib/private/Security/RateLimiting/Limiter.php index c8c0e2ce101..689e7b14558 100644 --- a/lib/private/Security/RateLimiting/Limiter.php +++ b/lib/private/Security/RateLimiting/Limiter.php @@ -30,8 +30,9 @@ use OC\Security\Normalizer\IpAddress; use OC\Security\RateLimiting\Backend\IBackend; use OC\Security\RateLimiting\Exception\RateLimitExceededException; use OCP\IUser; +use OCP\Security\RateLimiting\ILimiter; -class Limiter { +class Limiter implements ILimiter { public function __construct( private IBackend $backend, ) { diff --git a/lib/private/Security/RemoteHostValidator.php b/lib/private/Security/RemoteHostValidator.php index 38129fbd81b..9cc69594c32 100644 --- a/lib/private/Security/RemoteHostValidator.php +++ b/lib/private/Security/RemoteHostValidator.php @@ -38,19 +38,12 @@ use function urldecode; * @internal */ final class RemoteHostValidator implements IRemoteHostValidator { - private IConfig $config; - private HostnameClassifier $hostnameClassifier; - private IpAddressClassifier $ipAddressClassifier; - private LoggerInterface $logger; - - public function __construct(IConfig $config, - HostnameClassifier $hostnameClassifier, - IpAddressClassifier $ipAddressClassifier, - LoggerInterface $logger) { - $this->config = $config; - $this->hostnameClassifier = $hostnameClassifier; - $this->ipAddressClassifier = $ipAddressClassifier; - $this->logger = $logger; + public function __construct( + private IConfig $config, + private HostnameClassifier $hostnameClassifier, + private IpAddressClassifier $ipAddressClassifier, + private LoggerInterface $logger, + ) { } public function isValid(string $host): bool { @@ -59,6 +52,10 @@ final class RemoteHostValidator implements IRemoteHostValidator { } $host = idn_to_utf8(strtolower(urldecode($host))); + if ($host === false) { + return false; + } + // Remove brackets from IPv6 addresses if (str_starts_with($host, '[') && str_ends_with($host, ']')) { $host = substr($host, 1, -1); diff --git a/lib/private/Security/SecureRandom.php b/lib/private/Security/SecureRandom.php index cbd1dc8db6d..f5bc5ddfb5e 100644 --- a/lib/private/Security/SecureRandom.php +++ b/lib/private/Security/SecureRandom.php @@ -44,11 +44,12 @@ class SecureRandom implements ISecureRandom { * @param int $length The length of the generated string * @param string $characters An optional list of characters to use if no character list is * specified all valid base64 characters are used. - * @return string * @throws \LengthException if an invalid length is requested */ - public function generate(int $length, - string $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'): string { + public function generate( + int $length, + string $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', + ): string { if ($length <= 0) { throw new \LengthException('Invalid length specified: ' . $length . ' must be bigger than 0'); } diff --git a/lib/private/Security/TrustedDomainHelper.php b/lib/private/Security/TrustedDomainHelper.php index ca6a5cba073..e91f230a9c9 100644 --- a/lib/private/Security/TrustedDomainHelper.php +++ b/lib/private/Security/TrustedDomainHelper.php @@ -34,19 +34,13 @@ use OCP\IConfig; use OCP\Security\ITrustedDomainHelper; class TrustedDomainHelper implements ITrustedDomainHelper { - /** @var IConfig */ - private $config; - - /** - * @param IConfig $config - */ - public function __construct(IConfig $config) { - $this->config = $config; + public function __construct( + private IConfig $config, + ) { } /** * Strips a potential port from a domain (in format domain:port) - * @param string $host * @return string $host without appended port */ private function getDomainWithoutPort(string $host): string { diff --git a/lib/private/Security/VerificationToken/CleanUpJob.php b/lib/private/Security/VerificationToken/CleanUpJob.php index 1f4af046451..9c1b27d344d 100644 --- a/lib/private/Security/VerificationToken/CleanUpJob.php +++ b/lib/private/Security/VerificationToken/CleanUpJob.php @@ -27,10 +27,10 @@ declare(strict_types=1); namespace OC\Security\VerificationToken; use OCP\AppFramework\Utility\ITimeFactory; -use OCP\IConfig; -use OCP\IUserManager; use OCP\BackgroundJob\IJobList; use OCP\BackgroundJob\Job; +use OCP\IConfig; +use OCP\IUserManager; use OCP\Security\VerificationToken\InvalidTokenException; use OCP\Security\VerificationToken\IVerificationToken; diff --git a/lib/private/Server.php b/lib/private/Server.php index e8ade23d8fe..76c73383b2e 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -68,6 +68,7 @@ use OC\Authentication\Listeners\UserLoggedInListener; use OC\Authentication\LoginCredentials\Store; use OC\Authentication\Token\IProvider; use OC\Avatar\AvatarManager; +use OC\Blurhash\Listener\GenerateBlurhashMetadata; use OC\Collaboration\Collaborators\GroupPlugin; use OC\Collaboration\Collaborators\MailPlugin; use OC\Collaboration\Collaborators\RemoteGroupPlugin; @@ -102,6 +103,7 @@ use OC\Files\Storage\StorageFactory; use OC\Files\Template\TemplateManager; use OC\Files\Type\Loader; use OC\Files\View; +use OC\FilesMetadata\FilesMetadataManager; use OC\FullTextSearch\FullTextSearchManager; use OC\Http\Client\ClientService; use OC\Http\Client\NegativeDnsCache; @@ -109,8 +111,8 @@ use OC\IntegrityCheck\Checker; use OC\IntegrityCheck\Helpers\AppLocator; use OC\IntegrityCheck\Helpers\EnvironmentHelper; use OC\IntegrityCheck\Helpers\FileAccessHelper; -use OC\LDAP\NullLDAPProviderFactory; use OC\KnownUser\KnownUserService; +use OC\LDAP\NullLDAPProviderFactory; use OC\Lock\DBLockingProvider; use OC\Lock\MemcacheLockingProvider; use OC\Lock\NoopLockingProvider; @@ -120,14 +122,15 @@ use OC\Log\PsrLoggerAdapter; use OC\Mail\Mailer; use OC\Memcache\ArrayCache; use OC\Memcache\Factory; -use OC\Metadata\Capabilities as MetadataCapabilities; -use OC\Metadata\IMetadataManager; -use OC\Metadata\MetadataManager; use OC\Notification\Manager; +use OC\OCM\Model\OCMProvider; +use OC\OCM\OCMDiscoveryService; use OC\OCS\DiscoveryService; use OC\Preview\GeneratorHelper; use OC\Preview\IMagickSupport; use OC\Preview\MimeIconProvider; +use OC\Profile\ProfileManager; +use OC\Profiler\Profiler; use OC\Remote\Api\ApiFactory; use OC\Remote\InstanceFactory; use OC\RichObjectStrings\Validator; @@ -142,27 +145,37 @@ use OC\Security\CSP\ContentSecurityPolicyNonceManager; use OC\Security\CSRF\CsrfTokenManager; use OC\Security\CSRF\TokenStorage\SessionStorage; use OC\Security\Hasher; +use OC\Security\RateLimiting\Limiter; use OC\Security\SecureRandom; use OC\Security\TrustedDomainHelper; use OC\Security\VerificationToken\VerificationToken; use OC\Session\CryptoWrapper; +use OC\Settings\DeclarativeManager; +use OC\SetupCheck\SetupCheckManager; use OC\Share20\ProviderFactory; use OC\Share20\ShareHelper; use OC\SpeechToText\SpeechToTextManager; use OC\SystemTag\ManagerFactory as SystemTagManagerFactory; use OC\Tagging\TagMapper; use OC\Talk\Broker; +use OC\Teams\TeamManager; use OC\Template\JSCombiner; use OC\Translation\TranslationManager; +use OC\User\AvailabilityCoordinator; use OC\User\DisplayNameCache; use OC\User\Listeners\BeforeUserDeletedListener; use OC\User\Listeners\UserChangedListener; use OC\User\Session; +use OCA\Files_External\Service\BackendService; +use OCA\Files_External\Service\GlobalStoragesService; +use OCA\Files_External\Service\UserGlobalStoragesService; +use OCA\Files_External\Service\UserStoragesService; use OCA\Theming\ImageManager; use OCA\Theming\ThemingDefaults; use OCA\Theming\Util; use OCP\Accounts\IAccountManager; use OCP\App\IAppManager; +use OCP\AppFramework\Utility\ITimeFactory; use OCP\Authentication\LoginCredentials\IStore; use OCP\Authentication\Token\IProvider as OCPIProvider; use OCP\BackgroundJob\IJobList; @@ -190,16 +203,17 @@ use OCP\Files\Lock\ILockManager; use OCP\Files\Mount\IMountManager; use OCP\Files\Storage\IStorageFactory; use OCP\Files\Template\ITemplateManager; +use OCP\FilesMetadata\IFilesMetadataManager; use OCP\FullTextSearch\IFullTextSearchManager; use OCP\GlobalScale\IConfig; use OCP\Group\ISubAdmin; use OCP\Http\Client\IClientService; use OCP\IAppConfig; use OCP\IAvatarManager; +use OCP\IBinaryFinder; use OCP\ICache; use OCP\ICacheFactory; use OCP\ICertificateManager; -use OCP\IBinaryFinder; use OCP\IDateTimeFormatter; use OCP\IDateTimeZone; use OCP\IDBConnection; @@ -209,6 +223,7 @@ use OCP\IInitialStateService; use OCP\IL10N; use OCP\ILogger; use OCP\INavigationManager; +use OCP\IPhoneNumberUtil; use OCP\IPreview; use OCP\IRequest; use OCP\IRequestId; @@ -227,6 +242,11 @@ use OCP\Lock\ILockingProvider; use OCP\Lockdown\ILockdownManager; use OCP\Log\ILogFactory; use OCP\Mail\IMailer; +use OCP\OCM\IOCMDiscoveryService; +use OCP\OCM\IOCMProvider; +use OCP\Preview\IMimeIconProvider; +use OCP\Profile\IProfileManager; +use OCP\Profiler\IProfiler; use OCP\Remote\Api\IApiFactory; use OCP\Remote\IInstanceFactory; use OCP\RichObjectStrings\IValidator; @@ -238,12 +258,17 @@ use OCP\Security\ICrypto; use OCP\Security\IHasher; use OCP\Security\ISecureRandom; use OCP\Security\ITrustedDomainHelper; +use OCP\Security\RateLimiting\ILimiter; use OCP\Security\VerificationToken\IVerificationToken; +use OCP\Settings\IDeclarativeManager; +use OCP\SetupCheck\ISetupCheckManager; +use OCP\Share\IProviderFactory; use OCP\Share\IShareHelper; use OCP\SpeechToText\ISpeechToTextManager; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagObjectMapper; use OCP\Talk\IBroker; +use OCP\Teams\ITeamManager; use OCP\Translation\ITranslationManager; use OCP\User\Events\BeforeUserDeletedEvent; use OCP\User\Events\BeforeUserLoggedInEvent; @@ -254,16 +279,10 @@ use OCP\User\Events\UserChangedEvent; use OCP\User\Events\UserLoggedInEvent; use OCP\User\Events\UserLoggedInWithCookieEvent; use OCP\User\Events\UserLoggedOutEvent; +use OCP\User\IAvailabilityCoordinator; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -use OCA\Files_External\Service\UserStoragesService; -use OCA\Files_External\Service\UserGlobalStoragesService; -use OCA\Files_External\Service\GlobalStoragesService; -use OCA\Files_External\Service\BackendService; -use OCP\Profiler\IProfiler; -use OC\Profiler\Profiler; -use OCP\Preview\IMimeIconProvider; /** * Class Server @@ -433,14 +452,17 @@ class Server extends ServerContainer implements IServerContainer { $this->registerService('RootFolder', function (ContainerInterface $c) { $manager = \OC\Files\Filesystem::getMountManager(); $view = new View(); + /** @var IUserSession $userSession */ + $userSession = $c->get(IUserSession::class); $root = new Root( $manager, $view, - null, + $userSession->getUser(), $c->get(IUserMountCache::class), $this->get(LoggerInterface::class), $this->get(IUserManager::class), $this->get(IEventDispatcher::class), + $this->get(ICacheFactory::class), ); $previewConnector = new \OC\Preview\WatcherConnector( @@ -455,7 +477,8 @@ class Server extends ServerContainer implements IServerContainer { return new HookConnector( $c->get(IRootFolder::class), new View(), - $c->get(IEventDispatcher::class) + $c->get(IEventDispatcher::class), + $c->get(LoggerInterface::class) ); }); @@ -701,7 +724,7 @@ class Server extends ServerContainer implements IServerContainer { $this->registerService('RedisFactory', function (Server $c) { $systemConfig = $c->get(SystemConfig::class); - return new RedisFactory($systemConfig, $c->getEventLogger()); + return new RedisFactory($systemConfig, $c->get(IEventLogger::class)); }); $this->registerService(\OCP\Activity\IManager::class, function (Server $c) { @@ -785,8 +808,8 @@ class Server extends ServerContainer implements IServerContainer { $this->registerDeprecatedAlias('Search', ISearch::class); $this->registerService(\OC\Security\RateLimiting\Backend\IBackend::class, function ($c) { - $cacheFactory = $c->get(ICacheFactory::class); - if ($cacheFactory->isAvailable()) { + $config = $c->get(\OCP\IConfig::class); + if (ltrim($config->getSystemValueString('memcache.distributed', ''), '\\') === \OC\Memcache\Redis::class) { $backend = new \OC\Security\RateLimiting\Backend\MemoryCacheBackend( $c->get(AllConfig::class), $this->get(ICacheFactory::class), @@ -829,8 +852,7 @@ class Server extends ServerContainer implements IServerContainer { if (!$factory->isValidType($type)) { throw new \OC\DatabaseException('Invalid database type'); } - $connectionParams = $factory->createConnectionParams(); - $connection = $factory->getConnection($type, $connectionParams); + $connection = $factory->getConnection($type, []); return $connection; }); /** @deprecated 19.0.0 */ @@ -874,7 +896,8 @@ class Server extends ServerContainer implements IServerContainer { $c->get(IGroupManager::class), $c->get(ICacheFactory::class), $c->get(IEventDispatcher::class), - $c->get(LoggerInterface::class) + $c->get(LoggerInterface::class), + $c->get(IURLGenerator::class), ); }); /** @deprecated 19.0.0 */ @@ -962,15 +985,16 @@ class Server extends ServerContainer implements IServerContainer { return $backend; }); - $this->registerService('IntegrityCodeChecker', function (ContainerInterface $c) { + $this->registerDeprecatedAlias('IntegrityCodeChecker', Checker::class); + $this->registerService(Checker::class, function (ContainerInterface $c) { // IConfig and IAppManager requires a working database. This code // might however be called when ownCloud is not yet setup. if (\OC::$server->get(SystemConfig::class)->getValue('installed', false)) { $config = $c->get(\OCP\IConfig::class); + $appConfig = $c->get(\OCP\IAppConfig::class); $appManager = $c->get(IAppManager::class); } else { - $config = null; - $appManager = null; + $config = $appConfig = $appManager = null; } return new Checker( @@ -978,6 +1002,7 @@ class Server extends ServerContainer implements IServerContainer { new FileAccessHelper(), new AppLocator(), $config, + $appConfig, $c->get(ICacheFactory::class), $appManager, $c->get(IMimeTypeDetector::class) @@ -1066,7 +1091,8 @@ class Server extends ServerContainer implements IServerContainer { $memcacheFactory = $c->get(ICacheFactory::class); $memcache = $memcacheFactory->createLocking('lock'); if (!($memcache instanceof \OC\Memcache\NullCache)) { - return new MemcacheLockingProvider($memcache, $ttl); + $timeFactory = $c->get(ITimeFactory::class); + return new MemcacheLockingProvider($memcache, $timeFactory, $ttl); } return new DBLockingProvider( $c->get(IDBConnection::class), @@ -1122,9 +1148,6 @@ class Server extends ServerContainer implements IServerContainer { $manager->registerCapability(function () use ($c) { return $c->get(\OC\Security\Bruteforce\Capabilities::class); }); - $manager->registerCapability(function () use ($c) { - return $c->get(MetadataCapabilities::class); - }); return $manager; }); /** @deprecated 19.0.0 */ @@ -1142,7 +1165,7 @@ class Server extends ServerContainer implements IServerContainer { $userDisplayName = $manager->getDisplayName($id); if ($userDisplayName === null) { $l = $c->get(IFactory::class)->get('core'); - return $l->t('Unknown user'); + return $l->t('Unknown account'); } return $userDisplayName; }); @@ -1161,13 +1184,13 @@ class Server extends ServerContainer implements IServerContainer { $classExists = false; } - if ($classExists && $c->get(\OCP\IConfig::class)->getSystemValueBool('installed', false) && $c->get(IAppManager::class)->isInstalled('theming') && $c->getTrustedDomainHelper()->isTrustedDomain($c->getRequest()->getInsecureServerHost())) { + if ($classExists && $c->get(\OCP\IConfig::class)->getSystemValueBool('installed', false) && $c->get(IAppManager::class)->isInstalled('theming') && $c->get(TrustedDomainHelper::class)->isTrustedDomain($c->getRequest()->getInsecureServerHost())) { $imageManager = new ImageManager( $c->get(\OCP\IConfig::class), $c->getAppDataDir('theming'), $c->get(IURLGenerator::class), $this->get(ICacheFactory::class), - $this->get(ILogger::class), + $this->get(LoggerInterface::class), $this->get(ITempManager::class) ); return new ThemingDefaults( @@ -1229,34 +1252,14 @@ class Server extends ServerContainer implements IServerContainer { /** @deprecated 19.0.0 */ $this->registerDeprecatedAlias('ContentSecurityPolicyManager', ContentSecurityPolicyManager::class); - $this->registerService(\OCP\Share\IManager::class, function (IServerContainer $c) { + $this->registerService(IProviderFactory::class, function (ContainerInterface $c) { $config = $c->get(\OCP\IConfig::class); $factoryClass = $config->getSystemValue('sharing.managerFactory', ProviderFactory::class); /** @var \OCP\Share\IProviderFactory $factory */ - $factory = new $factoryClass($this); - - $manager = new \OC\Share20\Manager( - $c->get(LoggerInterface::class), - $c->get(\OCP\IConfig::class), - $c->get(ISecureRandom::class), - $c->get(IHasher::class), - $c->get(IMountManager::class), - $c->get(IGroupManager::class), - $c->getL10N('lib'), - $c->get(IFactory::class), - $factory, - $c->get(IUserManager::class), - $c->get(IRootFolder::class), - $c->get(IMailer::class), - $c->get(IURLGenerator::class), - $c->get('ThemingDefaults'), - $c->get(IEventDispatcher::class), - $c->get(IUserSession::class), - $c->get(KnownUserService::class) - ); - - return $manager; + return new $factoryClass($this); }); + + $this->registerAlias(\OCP\Share\IManager::class, \OC\Share20\Manager::class); /** @deprecated 19.0.0 */ $this->registerDeprecatedAlias('ShareManager', \OCP\Share\IManager::class); @@ -1282,6 +1285,7 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(\OCP\Collaboration\Resources\IManager::class, \OC\Collaboration\Resources\Manager::class); $this->registerAlias(IReferenceManager::class, ReferenceManager::class); + $this->registerAlias(ITeamManager::class, TeamManager::class); $this->registerDeprecatedAlias('SettingsManager', \OC\Settings\Manager::class); $this->registerAlias(\OCP\Settings\IManager::class, \OC\Settings\Manager::class); @@ -1304,6 +1308,7 @@ class Server extends ServerContainer implements IServerContainer { $c->get(IClientService::class) ); }); + $this->registerAlias(IOCMDiscoveryService::class, OCMDiscoveryService::class); $this->registerService(ICloudIdManager::class, function (ContainerInterface $c) { return new CloudIdManager( @@ -1319,9 +1324,11 @@ class Server extends ServerContainer implements IServerContainer { $this->registerService(ICloudFederationProviderManager::class, function (ContainerInterface $c) { return new CloudFederationProviderManager( + $c->get(\OCP\IConfig::class), $c->get(IAppManager::class), $c->get(IClientService::class), $c->get(ICloudIdManager::class), + $c->get(IOCMDiscoveryService::class), $c->get(LoggerInterface::class) ); }); @@ -1385,6 +1392,7 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(\OCP\Dashboard\IManager::class, \OC\Dashboard\Manager::class); $this->registerAlias(IFullTextSearchManager::class, FullTextSearchManager::class); + $this->registerAlias(IFilesMetadataManager::class, FilesMetadataManager::class); $this->registerAlias(ISubAdmin::class, SubAdmin::class); @@ -1396,8 +1404,6 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(IBroker::class, Broker::class); - $this->registerAlias(IMetadataManager::class, MetadataManager::class); - $this->registerAlias(\OCP\Files\AppData\IAppDataFactory::class, \OC\Files\AppData\Factory::class); $this->registerAlias(IBinaryFinder::class, BinaryFinder::class); @@ -1412,6 +1418,22 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(\OCP\TextProcessing\IManager::class, \OC\TextProcessing\Manager::class); + $this->registerAlias(\OCP\TextToImage\IManager::class, \OC\TextToImage\Manager::class); + + $this->registerAlias(ILimiter::class, Limiter::class); + + $this->registerAlias(IPhoneNumberUtil::class, PhoneNumberUtil::class); + + $this->registerAlias(IOCMProvider::class, OCMProvider::class); + + $this->registerAlias(ISetupCheckManager::class, SetupCheckManager::class); + + $this->registerAlias(IProfileManager::class, ProfileManager::class); + + $this->registerAlias(IAvailabilityCoordinator::class, AvailabilityCoordinator::class); + + $this->registerAlias(IDeclarativeManager::class, DeclarativeManager::class); + $this->connectDispatcher(); } @@ -1452,6 +1474,9 @@ class Server extends ServerContainer implements IServerContainer { $eventDispatcher->addServiceListener(PostLoginEvent::class, UserLoggedInListener::class); $eventDispatcher->addServiceListener(UserChangedEvent::class, UserChangedListener::class); $eventDispatcher->addServiceListener(BeforeUserDeletedEvent::class, BeforeUserDeletedListener::class); + + FilesMetadataManager::loadListeners($eventDispatcher); + GenerateBlurhashMetadata::loadListeners($eventDispatcher); } /** @@ -1628,6 +1653,7 @@ class Server extends ServerContainer implements IServerContainer { /** * @param \OCP\ISession $session + * @return void */ public function setSession(\OCP\ISession $session) { $this->get(SessionStorage::class)->setSession($session); @@ -1691,7 +1717,7 @@ class Server extends ServerContainer implements IServerContainer { * @param string $app appid * @param string $lang * @return IL10N - * @deprecated 20.0.0 + * @deprecated 20.0.0 use DI of {@see IL10N} or {@see IFactory} instead, or {@see \OCP\Util::getL10N()} as a last resort */ public function getL10N($app, $lang = null) { return $this->get(IFactory::class)->get($app, $lang); diff --git a/lib/private/Session/CryptoSessionData.php b/lib/private/Session/CryptoSessionData.php index 1eb6987fc18..34aab2a5165 100644 --- a/lib/private/Session/CryptoSessionData.php +++ b/lib/private/Session/CryptoSessionData.php @@ -32,11 +32,14 @@ namespace OC\Session; use OCP\ISession; use OCP\Security\ICrypto; use OCP\Session\Exceptions\SessionNotAvailableException; +use function json_decode; +use function OCP\Log\logger; /** * Class CryptoSessionData * * @package OC\Session + * @template-implements \ArrayAccess<string,mixed> */ class CryptoSessionData implements \ArrayAccess, ISession { /** @var ISession */ @@ -57,8 +60,8 @@ class CryptoSessionData implements \ArrayAccess, ISession { * @param string $passphrase */ public function __construct(ISession $session, - ICrypto $crypto, - string $passphrase) { + ICrypto $crypto, + string $passphrase) { $this->crypto = $crypto; $this->session = $session; $this->passphrase = $passphrase; @@ -79,14 +82,24 @@ class CryptoSessionData implements \ArrayAccess, ISession { protected function initializeSession() { $encryptedSessionData = $this->session->get(self::encryptedSessionName) ?: ''; - try { - $this->sessionValues = json_decode( - $this->crypto->decrypt($encryptedSessionData, $this->passphrase), - true - ); - } catch (\Exception $e) { + if ($encryptedSessionData === '') { + // Nothing to decrypt $this->sessionValues = []; - $this->regenerateId(true, false); + } else { + try { + $this->sessionValues = json_decode( + $this->crypto->decrypt($encryptedSessionData, $this->passphrase), + true, + 512, + JSON_THROW_ON_ERROR, + ); + } catch (\Exception $e) { + logger('core')->critical('Could not decrypt or decode encrypted session data', [ + 'exception' => $e, + ]); + $this->sessionValues = []; + $this->regenerateId(true, false); + } } } diff --git a/lib/private/Session/CryptoWrapper.php b/lib/private/Session/CryptoWrapper.php index e98aac3b8bf..5004ebf82cf 100644 --- a/lib/private/Session/CryptoWrapper.php +++ b/lib/private/Session/CryptoWrapper.php @@ -68,9 +68,9 @@ class CryptoWrapper { * @param IRequest $request */ public function __construct(IConfig $config, - ICrypto $crypto, - ISecureRandom $random, - IRequest $request) { + ICrypto $crypto, + ISecureRandom $random, + IRequest $request) { $this->crypto = $crypto; $this->config = $config; $this->random = $random; diff --git a/lib/private/Session/Internal.php b/lib/private/Session/Internal.php index e8e2a4f2d8e..5fb9b05c5f4 100644 --- a/lib/private/Session/Internal.php +++ b/lib/private/Session/Internal.php @@ -33,8 +33,8 @@ declare(strict_types=1); */ namespace OC\Session; -use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Token\IProvider; +use OCP\Authentication\Exceptions\InvalidTokenException; use OCP\Session\Exceptions\SessionNotAvailableException; /** diff --git a/lib/private/Session/Session.php b/lib/private/Session/Session.php index b434461a335..04fc61fe610 100644 --- a/lib/private/Session/Session.php +++ b/lib/private/Session/Session.php @@ -29,6 +29,9 @@ namespace OC\Session; use OCP\ISession; +/** + * @template-implements \ArrayAccess<string,mixed> + */ abstract class Session implements \ArrayAccess, ISession { /** * @var bool diff --git a/lib/private/Settings/DeclarativeManager.php b/lib/private/Settings/DeclarativeManager.php new file mode 100644 index 00000000000..04acf984089 --- /dev/null +++ b/lib/private/Settings/DeclarativeManager.php @@ -0,0 +1,405 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com> + * + * @author Kate Döen <kate.doeen@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Settings; + +use Exception; +use OC\AppFramework\Bootstrap\Coordinator; +use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\IAppConfig; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IUser; +use OCP\Server; +use OCP\Settings\DeclarativeSettingsTypes; +use OCP\Settings\Events\DeclarativeSettingsGetValueEvent; +use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent; +use OCP\Settings\Events\DeclarativeSettingsSetValueEvent; +use OCP\Settings\IDeclarativeManager; +use OCP\Settings\IDeclarativeSettingsForm; +use Psr\Log\LoggerInterface; + +/** + * @psalm-import-type DeclarativeSettingsValueTypes from IDeclarativeSettingsForm + * @psalm-import-type DeclarativeSettingsStorageType from IDeclarativeSettingsForm + * @psalm-import-type DeclarativeSettingsSectionType from IDeclarativeSettingsForm + * @psalm-import-type DeclarativeSettingsFormSchemaWithValues from IDeclarativeSettingsForm + * @psalm-import-type DeclarativeSettingsFormSchemaWithoutValues from IDeclarativeSettingsForm + */ +class DeclarativeManager implements IDeclarativeManager { + public function __construct( + private IEventDispatcher $eventDispatcher, + private IGroupManager $groupManager, + private Coordinator $coordinator, + private IConfig $config, + private IAppConfig $appConfig, + private LoggerInterface $logger, + ) { + } + + /** + * @var array<string, list<DeclarativeSettingsFormSchemaWithoutValues>> + */ + private array $appSchemas = []; + + /** + * @inheritdoc + */ + public function registerSchema(string $app, array $schema): void { + $this->appSchemas[$app] ??= []; + + if (!$this->validateSchema($app, $schema)) { + throw new Exception('Invalid schema. Please check the logs for more details.'); + } + + foreach ($this->appSchemas[$app] as $otherSchema) { + if ($otherSchema['id'] === $schema['id']) { + throw new Exception('Duplicate form IDs detected: ' . $schema['id']); + } + } + + $fieldIDs = array_map(fn ($field) => $field['id'], $schema['fields']); + $otherFieldIDs = array_merge(...array_map(fn ($schema) => array_map(fn ($field) => $field['id'], $schema['fields']), $this->appSchemas[$app])); + $intersectionFieldIDs = array_intersect($fieldIDs, $otherFieldIDs); + if (count($intersectionFieldIDs) > 0) { + throw new Exception('Non unique field IDs detected: ' . join(', ', $intersectionFieldIDs)); + } + + $this->appSchemas[$app][] = $schema; + } + + /** + * @inheritdoc + */ + public function loadSchemas(): void { + $declarativeSettings = $this->coordinator->getRegistrationContext()->getDeclarativeSettings(); + foreach ($declarativeSettings as $declarativeSetting) { + /** @var IDeclarativeSettingsForm $declarativeSettingObject */ + $declarativeSettingObject = Server::get($declarativeSetting->getService()); + $this->registerSchema($declarativeSetting->getAppId(), $declarativeSettingObject->getSchema()); + } + + $this->eventDispatcher->dispatchTyped(new DeclarativeSettingsRegisterFormEvent($this)); + } + + /** + * @inheritdoc + */ + public function getFormIDs(IUser $user, string $type, string $section): array { + $isAdmin = $this->groupManager->isAdmin($user->getUID()); + /** @var array<string, list<string>> $formIds */ + $formIds = []; + + foreach ($this->appSchemas as $app => $schemas) { + $ids = []; + usort($schemas, [$this, 'sortSchemasByPriorityCallback']); + foreach ($schemas as $schema) { + if ($schema['section_type'] === DeclarativeSettingsTypes::SECTION_TYPE_ADMIN && !$isAdmin) { + continue; + } + if ($schema['section_type'] === $type && $schema['section_id'] === $section) { + $ids[] = $schema['id']; + } + } + + if (!empty($ids)) { + $formIds[$app] = array_merge($formIds[$app] ?? [], $ids); + } + } + + return $formIds; + } + + /** + * @inheritdoc + * @throws Exception + */ + public function getFormsWithValues(IUser $user, ?string $type, ?string $section): array { + $isAdmin = $this->groupManager->isAdmin($user->getUID()); + $forms = []; + + foreach ($this->appSchemas as $app => $schemas) { + foreach ($schemas as $schema) { + if ($type !== null && $schema['section_type'] !== $type) { + continue; + } + if ($section !== null && $schema['section_id'] !== $section) { + continue; + } + // If listing all fields skip the admin fields which a non-admin user has no access to + if ($type === null && $schema['section_type'] === 'admin' && !$isAdmin) { + continue; + } + + $s = $schema; + $s['app'] = $app; + + foreach ($s['fields'] as &$field) { + $field['value'] = $this->getValue($user, $app, $schema['id'], $field['id']); + } + unset($field); + + /** @var DeclarativeSettingsFormSchemaWithValues $s */ + $forms[] = $s; + } + } + + usort($forms, [$this, 'sortSchemasByPriorityCallback']); + + return $forms; + } + + private function sortSchemasByPriorityCallback(mixed $a, mixed $b): int { + if ($a['priority'] === $b['priority']) { + return 0; + } + return $a['priority'] > $b['priority'] ? -1 : 1; + } + + /** + * @return DeclarativeSettingsStorageType + */ + private function getStorageType(string $app, string $fieldId): string { + if (array_key_exists($app, $this->appSchemas)) { + foreach ($this->appSchemas[$app] as $schema) { + foreach ($schema['fields'] as $field) { + if ($field['id'] == $fieldId) { + if (array_key_exists('storage_type', $field)) { + return $field['storage_type']; + } + } + } + + if (array_key_exists('storage_type', $schema)) { + return $schema['storage_type']; + } + } + } + + return DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL; + } + + /** + * @return DeclarativeSettingsSectionType + * @throws Exception + */ + private function getSectionType(string $app, string $fieldId): string { + if (array_key_exists($app, $this->appSchemas)) { + foreach ($this->appSchemas[$app] as $schema) { + foreach ($schema['fields'] as $field) { + if ($field['id'] == $fieldId) { + return $schema['section_type']; + } + } + } + } + + throw new Exception('Unknown fieldId "' . $fieldId . '"'); + } + + /** + * @psalm-param DeclarativeSettingsSectionType $sectionType + * @throws NotAdminException + */ + private function assertAuthorized(IUser $user, string $sectionType): void { + if ($sectionType === 'admin' && !$this->groupManager->isAdmin($user->getUID())) { + throw new NotAdminException('Logged in user does not have permission to access these settings.'); + } + } + + /** + * @return DeclarativeSettingsValueTypes + * @throws Exception + * @throws NotAdminException + */ + private function getValue(IUser $user, string $app, string $formId, string $fieldId): mixed { + $sectionType = $this->getSectionType($app, $fieldId); + $this->assertAuthorized($user, $sectionType); + + $storageType = $this->getStorageType($app, $fieldId); + switch ($storageType) { + case DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL: + $event = new DeclarativeSettingsGetValueEvent($user, $app, $formId, $fieldId); + $this->eventDispatcher->dispatchTyped($event); + return $event->getValue(); + case DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL: + return $this->getInternalValue($user, $app, $formId, $fieldId); + default: + throw new Exception('Unknown storage type "' . $storageType . '"'); + } + } + + /** + * @inheritdoc + */ + public function setValue(IUser $user, string $app, string $formId, string $fieldId, mixed $value): void { + $sectionType = $this->getSectionType($app, $fieldId); + $this->assertAuthorized($user, $sectionType); + + $storageType = $this->getStorageType($app, $fieldId); + switch ($storageType) { + case DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL: + $this->eventDispatcher->dispatchTyped(new DeclarativeSettingsSetValueEvent($user, $app, $formId, $fieldId, $value)); + break; + case DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL: + $this->saveInternalValue($user, $app, $fieldId, $value); + break; + default: + throw new Exception('Unknown storage type "' . $storageType . '"'); + } + } + + private function getInternalValue(IUser $user, string $app, string $formId, string $fieldId): mixed { + $sectionType = $this->getSectionType($app, $fieldId); + $defaultValue = $this->getDefaultValue($app, $formId, $fieldId); + switch ($sectionType) { + case DeclarativeSettingsTypes::SECTION_TYPE_ADMIN: + return $this->config->getAppValue($app, $fieldId, $defaultValue); + case DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL: + return $this->config->getUserValue($user->getUID(), $app, $fieldId, $defaultValue); + default: + throw new Exception('Unknown section type "' . $sectionType . '"'); + } + } + + private function saveInternalValue(IUser $user, string $app, string $fieldId, mixed $value): void { + $sectionType = $this->getSectionType($app, $fieldId); + switch ($sectionType) { + case DeclarativeSettingsTypes::SECTION_TYPE_ADMIN: + $this->appConfig->setValueString($app, $fieldId, $value); + break; + case DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL: + $this->config->setUserValue($user->getUID(), $app, $fieldId, $value); + break; + default: + throw new Exception('Unknown section type "' . $sectionType . '"'); + } + } + + private function getDefaultValue(string $app, string $formId, string $fieldId): mixed { + foreach ($this->appSchemas[$app] as $schema) { + if ($schema['id'] === $formId) { + foreach ($schema['fields'] as $field) { + if ($field['id'] === $fieldId) { + if (isset($field['default'])) { + if (is_array($field['default'])) { + return json_encode($field['default']); + } + return $field['default']; + } + } + } + } + } + return null; + } + + private function validateSchema(string $appId, array $schema): bool { + if (!isset($schema['id'])) { + $this->logger->warning('Attempt to register a declarative settings schema with no id', ['app' => $appId]); + return false; + } + $formId = $schema['id']; + if (!isset($schema['section_type'])) { + $this->logger->warning('Declarative settings: missing section_type', ['app' => $appId, 'form_id' => $formId]); + return false; + } + if (!in_array($schema['section_type'], [DeclarativeSettingsTypes::SECTION_TYPE_ADMIN, DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL])) { + $this->logger->warning('Declarative settings: invalid section_type', ['app' => $appId, 'form_id' => $formId, 'section_type' => $schema['section_type']]); + return false; + } + if (!isset($schema['section_id'])) { + $this->logger->warning('Declarative settings: missing section_id', ['app' => $appId, 'form_id' => $formId]); + return false; + } + if (!isset($schema['storage_type'])) { + $this->logger->warning('Declarative settings: missing storage_type', ['app' => $appId, 'form_id' => $formId]); + return false; + } + if (!in_array($schema['storage_type'], [DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL, DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL])) { + $this->logger->warning('Declarative settings: invalid storage_type', ['app' => $appId, 'form_id' => $formId, 'storage_type' => $schema['storage_type']]); + return false; + } + if (!isset($schema['title'])) { + $this->logger->warning('Declarative settings: missing title', ['app' => $appId, 'form_id' => $formId]); + return false; + } + if (!isset($schema['fields']) || !is_array($schema['fields'])) { + $this->logger->warning('Declarative settings: missing or invalid fields', ['app' => $appId, 'form_id' => $formId]); + return false; + } + foreach ($schema['fields'] as $field) { + if (!isset($field['id'])) { + $this->logger->warning('Declarative settings: missing field id', ['app' => $appId, 'form_id' => $formId, 'field' => $field]); + return false; + } + $fieldId = $field['id']; + if (!isset($field['title'])) { + $this->logger->warning('Declarative settings: missing field title', ['app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId]); + return false; + } + if (!isset($field['type'])) { + $this->logger->warning('Declarative settings: missing field type', ['app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId]); + return false; + } + if (!in_array($field['type'], [ + DeclarativeSettingsTypes::MULTI_SELECT, DeclarativeSettingsTypes::MULTI_CHECKBOX, DeclarativeSettingsTypes::RADIO, + DeclarativeSettingsTypes::SELECT, DeclarativeSettingsTypes::CHECKBOX, + DeclarativeSettingsTypes::URL, DeclarativeSettingsTypes::EMAIL, DeclarativeSettingsTypes::NUMBER, + DeclarativeSettingsTypes::TEL, DeclarativeSettingsTypes::TEXT, DeclarativeSettingsTypes::PASSWORD, + ])) { + $this->logger->warning('Declarative settings: invalid field type', [ + 'app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId, 'type' => $field['type'], + ]); + return false; + } + if (!$this->validateField($appId, $formId, $field)) { + return false; + } + } + + return true; + } + + private function validateField(string $appId, string $formId, array $field): bool { + $fieldId = $field['id']; + if (in_array($field['type'], [ + DeclarativeSettingsTypes::MULTI_SELECT, DeclarativeSettingsTypes::MULTI_CHECKBOX, DeclarativeSettingsTypes::RADIO, + DeclarativeSettingsTypes::SELECT + ])) { + if (!isset($field['options'])) { + $this->logger->warning('Declarative settings: missing field options', ['app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId]); + return false; + } + if (!is_array($field['options'])) { + $this->logger->warning('Declarative settings: field options should be an array', ['app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId]); + return false; + } + } + return true; + } +} diff --git a/lib/private/Settings/Manager.php b/lib/private/Settings/Manager.php index 2d44ac7d3df..839d3e5ce38 100644 --- a/lib/private/Settings/Manager.php +++ b/lib/private/Settings/Manager.php @@ -12,6 +12,7 @@ * @author Roeland Jago Douma <roeland@famdouma.nl> * @author sualko <klaus@jsxc.org> * @author Carl Schwan <carl@carlschwan.eu> + * @author Kate Döen <kate.doeen@nextcloud.com> * * @license GNU AGPL version 3 or any later version * @@ -90,17 +91,14 @@ class Manager implements IManager { $this->subAdmin = $subAdmin; } - /** @var array */ + /** @var array<self::SETTINGS_*, list<class-string<IIconSection>>> */ protected $sectionClasses = []; - /** @var array */ + /** @var array<self::SETTINGS_*, array<string, IIconSection>> */ protected $sections = []; /** - * @param string $type 'admin' or 'personal' - * @param string $section Class must implement OCP\Settings\IIconSection - * - * @return void + * @inheritdoc */ public function registerSection(string $type, string $section) { if (!isset($this->sectionClasses[$type])) { @@ -111,7 +109,7 @@ class Manager implements IManager { } /** - * @param string $type 'admin' or 'personal' + * @psalm-param self::SETTINGS_* $type * * @return IIconSection[] */ @@ -149,6 +147,9 @@ class Manager implements IManager { return $this->sections[$type]; } + /** + * @inheritdoc + */ public function getSection(string $type, string $sectionId): ?IIconSection { if (isset($this->sections[$type]) && isset($this->sections[$type][$sectionId])) { return $this->sections[$type][$sectionId]; @@ -163,27 +164,23 @@ class Manager implements IManager { ], true); } - /** @var array */ + /** @var array<class-string<ISettings>, self::SETTINGS_*> */ protected $settingClasses = []; - /** @var array */ + /** @var array<self::SETTINGS_*, array<string, list<ISettings>>> */ protected $settings = []; /** - * @psam-param 'admin'|'personal' $type The type of the setting. - * @param string $setting Class must implement OCP\Settings\ISettings - * @param bool $allowedDelegation - * - * @return void + * @inheritdoc */ public function registerSetting(string $type, string $setting) { $this->settingClasses[$setting] = $type; } /** - * @param string $type 'admin' or 'personal' + * @psalm-param self::SETTINGS_* $type The type of the setting. * @param string $section - * @param Closure $filter optional filter to apply on all loaded ISettings + * @param ?Closure $filter optional filter to apply on all loaded ISettings * * @return ISettings[] */ @@ -258,7 +255,7 @@ class Manager implements IManager { /** * @inheritdoc */ - public function getAdminSettings($section, bool $subAdminOnly = false): array { + public function getAdminSettings(string $section, bool $subAdminOnly = false): array { if ($subAdminOnly) { $subAdminSettingsFilter = function (ISettings $settings) { return $settings instanceof ISubAdminSettings; @@ -329,7 +326,7 @@ class Manager implements IManager { /** * @inheritdoc */ - public function getPersonalSettings($section): array { + public function getPersonalSettings(string $section): array { $settings = []; $appSettings = $this->getSettings('personal', $section); @@ -344,6 +341,9 @@ class Manager implements IManager { return $settings; } + /** + * @inheritdoc + */ public function getAllowedAdminSettings(string $section, IUser $user): array { $isAdmin = $this->groupManager->isAdmin($user->getUID()); if ($isAdmin) { @@ -375,6 +375,9 @@ class Manager implements IManager { return $settings; } + /** + * @inheritdoc + */ public function getAllAllowedAdminSettings(IUser $user): array { $this->getSettings('admin', ''); // Make sure all the settings are loaded $settings = []; diff --git a/lib/private/Setup.php b/lib/private/Setup.php index 0993fe54f47..0b7780c5cd0 100644 --- a/lib/private/Setup.php +++ b/lib/private/Setup.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright Copyright (c) 2016, ownCloud, Inc. * @@ -53,51 +56,42 @@ use Exception; use InvalidArgumentException; use OC\Authentication\Token\PublicKeyTokenProvider; use OC\Authentication\Token\TokenCleanupJob; -use OC\TextProcessing\RemoveOldTasksBackgroundJob; use OC\Log\Rotate; use OC\Preview\BackgroundCleanupJob; +use OC\TextProcessing\RemoveOldTasksBackgroundJob; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\IJobList; use OCP\Defaults; +use OCP\IAppConfig; +use OCP\IConfig; use OCP\IGroup; +use OCP\IGroupManager; use OCP\IL10N; +use OCP\IRequest; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\L10N\IFactory as IL10NFactory; +use OCP\Migration\IOutput; use OCP\Security\ISecureRandom; +use OCP\Server; use Psr\Log\LoggerInterface; class Setup { - /** @var SystemConfig */ - protected $config; - /** @var IniGetWrapper */ - protected $iniWrapper; - /** @var IL10N */ - protected $l10n; - /** @var Defaults */ - protected $defaults; - /** @var LoggerInterface */ - protected $logger; - /** @var ISecureRandom */ - protected $random; - /** @var Installer */ - protected $installer; + protected IL10N $l10n; public function __construct( - SystemConfig $config, - IniGetWrapper $iniWrapper, - IL10N $l10n, - Defaults $defaults, - LoggerInterface $logger, - ISecureRandom $random, - Installer $installer + protected SystemConfig $config, + protected IniGetWrapper $iniWrapper, + IL10NFactory $l10nFactory, + protected Defaults $defaults, + protected LoggerInterface $logger, + protected ISecureRandom $random, + protected Installer $installer ) { - $this->config = $config; - $this->iniWrapper = $iniWrapper; - $this->l10n = $l10n; - $this->defaults = $defaults; - $this->logger = $logger; - $this->random = $random; - $this->installer = $installer; + $this->l10n = $l10nFactory->get('lib'); } - protected static $dbSetupClasses = [ + protected static array $dbSetupClasses = [ 'mysql' => \OC\Setup\MySQL::class, 'pgsql' => \OC\Setup\PostgreSQL::class, 'oci' => \OC\Setup\OCI::class, @@ -107,30 +101,22 @@ class Setup { /** * Wrapper around the "class_exists" PHP function to be able to mock it - * - * @param string $name - * @return bool */ - protected function class_exists($name) { + protected function class_exists(string $name): bool { return class_exists($name); } /** * Wrapper around the "is_callable" PHP function to be able to mock it - * - * @param string $name - * @return bool */ - protected function is_callable($name) { + protected function is_callable(string $name): bool { return is_callable($name); } /** * Wrapper around \PDO::getAvailableDrivers - * - * @return array */ - protected function getAvailableDbDriversForPdo() { + protected function getAvailableDbDriversForPdo(): array { if (class_exists(\PDO::class)) { return \PDO::getAvailableDrivers(); } @@ -140,11 +126,10 @@ class Setup { /** * Get the available and supported databases of this instance * - * @param bool $allowAllDatabases * @return array * @throws Exception */ - public function getSupportedDatabases($allowAllDatabases = false) { + public function getSupportedDatabases(bool $allowAllDatabases = false): array { $availableDatabases = [ 'sqlite' => [ 'type' => 'pdo', @@ -206,7 +191,7 @@ class Setup { * @return array of system info, including an "errors" value * in case of errors/warnings */ - public function getSystemInfo($allowAllDatabases = false) { + public function getSystemInfo(bool $allowAllDatabases = false): array { $databases = $this->getSupportedDatabases($allowAllDatabases); $dataDir = $this->config->getValue('datadirectory', \OC::$SERVERROOT . '/data'); @@ -226,7 +211,7 @@ class Setup { try { $util = new \OC_Util(); - $htAccessWorking = $util->isHtaccessWorking(\OC::$server->getConfig()); + $htAccessWorking = $util->isHtaccessWorking(Server::get(IConfig::class)); } catch (\OCP\HintException $e) { $errors[] = [ 'error' => $e->getMessage(), @@ -272,17 +257,16 @@ class Setup { } /** - * @param $options - * @return array + * @return array<string|array> errors */ - public function install($options) { + public function install(array $options, ?IOutput $output = null): array { $l = $this->l10n; $error = []; $dbType = $options['dbtype']; if (empty($options['adminlogin'])) { - $error[] = $l->t('Set an admin username.'); + $error[] = $l->t('Set an admin Login.'); } if (empty($options['adminpass'])) { $error[] = $l->t('Set an admin password.'); @@ -313,7 +297,7 @@ class Setup { return $error; } - $request = \OC::$server->getRequest(); + $request = Server::get(IRequest::class); //no errors, good if (isset($options['trusted_domains']) @@ -328,7 +312,7 @@ class Setup { $dbType = 'sqlite3'; } - //generate a random salt that is used to salt the local user passwords + //generate a random salt that is used to salt the local passwords $salt = $this->random->generate(30); // generate a secret $secret = $this->random->generate(48); @@ -349,6 +333,7 @@ class Setup { $this->config->setValues($newConfigValues); + $this->outputDebug($output, 'Configuring database'); $dbSetup->initialize($options); try { $dbSetup->setupDatabase($username); @@ -361,15 +346,17 @@ class Setup { return $error; } catch (Exception $e) { $error[] = [ - 'error' => 'Error while trying to create admin user: ' . $e->getMessage(), + 'error' => 'Error while trying to create admin account: ' . $e->getMessage(), 'exception' => $e, 'hint' => '', ]; return $error; } + + $this->outputDebug($output, 'Run server migrations'); try { // apply necessary migrations - $dbSetup->runMigrations(); + $dbSetup->runMigrations($output); } catch (Exception $e) { $error[] = [ 'error' => 'Error while trying to initialise the database: ' . $e->getMessage(), @@ -379,78 +366,89 @@ class Setup { return $error; } - //create the user and group + $this->outputDebug($output, 'Create admin account'); + + // create the admin account and group $user = null; try { - $user = \OC::$server->getUserManager()->createUser($username, $password); + $user = Server::get(IUserManager::class)->createUser($username, $password); if (!$user) { - $error[] = "User <$username> could not be created."; + $error[] = "Account <$username> could not be created."; + return $error; } } catch (Exception $exception) { $error[] = $exception->getMessage(); + return $error; } - if (empty($error)) { - $config = \OC::$server->getConfig(); - $config->setAppValue('core', 'installedat', (string)microtime(true)); - $config->setAppValue('core', 'lastupdatedat', (string)microtime(true)); + $config = Server::get(IConfig::class); + $config->setAppValue('core', 'installedat', (string)microtime(true)); + $appConfig = Server::get(IAppConfig::class); + $appConfig->setValueInt('core', 'lastupdatedat', time()); - $vendorData = $this->getVendorData(); - $config->setAppValue('core', 'vendor', $vendorData['vendor']); - if ($vendorData['channel'] !== 'stable') { - $config->setSystemValue('updater.release.channel', $vendorData['channel']); - } + $vendorData = $this->getVendorData(); + $config->setAppValue('core', 'vendor', $vendorData['vendor']); + if ($vendorData['channel'] !== 'stable') { + $config->setSystemValue('updater.release.channel', $vendorData['channel']); + } - $group = \OC::$server->getGroupManager()->createGroup('admin'); - if ($group instanceof IGroup) { - $group->addUser($user); - } + $group = Server::get(IGroupManager::class)->createGroup('admin'); + if ($group instanceof IGroup) { + $group->addUser($user); + } - // Install shipped apps and specified app bundles - Installer::installShippedApps(); + // Install shipped apps and specified app bundles + $this->outputDebug($output, 'Install default apps'); + Installer::installShippedApps(false, $output); - // create empty file in data dir, so we can later find - // out that this is indeed an ownCloud data directory - file_put_contents($config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); + // create empty file in data dir, so we can later find + // out that this is indeed an ownCloud data directory + $this->outputDebug($output, 'Setup data directory'); + file_put_contents($config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); - // Update .htaccess files - self::updateHtaccess(); - self::protectDataDirectory(); + // Update .htaccess files + self::updateHtaccess(); + self::protectDataDirectory(); - self::installBackgroundJobs(); + $this->outputDebug($output, 'Install background jobs'); + self::installBackgroundJobs(); - //and we are done - $config->setSystemValue('installed', true); - if (self::shouldRemoveCanInstallFile()) { - unlink(\OC::$configDir.'/CAN_INSTALL'); - } - - $bootstrapCoordinator = \OCP\Server::get(\OC\AppFramework\Bootstrap\Coordinator::class); - $bootstrapCoordinator->runInitialRegistration(); + //and we are done + $config->setSystemValue('installed', true); + if (self::shouldRemoveCanInstallFile()) { + unlink(\OC::$configDir.'/CAN_INSTALL'); + } - // Create a session token for the newly created user - // The token provider requires a working db, so it's not injected on setup - /* @var $userSession User\Session */ - $userSession = \OC::$server->getUserSession(); - $provider = \OCP\Server::get(PublicKeyTokenProvider::class); - $userSession->setTokenProvider($provider); - $userSession->login($username, $password); - $userSession->createSessionToken($request, $userSession->getUser()->getUID(), $username, $password); + $bootstrapCoordinator = \OCP\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); - $session = $userSession->getSession(); - $session->set('last-password-confirm', \OCP\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; } - public static function installBackgroundJobs() { - $jobList = \OC::$server->getJobList(); + public static function installBackgroundJobs(): void { + $jobList = Server::get(IJobList::class); $jobList->add(TokenCleanupJob::class); $jobList->add(Rotate::class); $jobList->add(BackgroundCleanupJob::class); @@ -460,15 +458,13 @@ class Setup { /** * @return string Absolute path to htaccess */ - private function pathToHtaccess() { + private function pathToHtaccess(): string { return \OC::$SERVERROOT . '/.htaccess'; } /** * Find webroot from config * - * @param SystemConfig $config - * @return string * @throws InvalidArgumentException when invalid value for overwrite.cli.url */ private static function findWebRoot(SystemConfig $config): string { @@ -495,8 +491,8 @@ class Setup { * @return bool True when success, False otherwise * @throws \OCP\AppFramework\QueryException */ - public static function updateHtaccess() { - $config = \OC::$server->getSystemConfig(); + public static function updateHtaccess(): bool { + $config = Server::get(SystemConfig::class); try { $webRoot = self::findWebRoot($config); @@ -504,15 +500,11 @@ class Setup { return false; } - $setupHelper = new \OC\Setup( - $config, - \OC::$server->get(IniGetWrapper::class), - \OC::$server->getL10N('lib'), - \OCP\Server::get(Defaults::class), - \OC::$server->get(LoggerInterface::class), - \OC::$server->getSecureRandom(), - \OCP\Server::get(Installer::class) - ); + $setupHelper = Server::get(\OC\Setup::class); + + if (!is_writable($setupHelper->pathToHtaccess())) { + return false; + } $htaccessContent = file_get_contents($setupHelper->pathToHtaccess()); $content = "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####\n"; @@ -531,13 +523,13 @@ class Setup { $content .= "\n Options -MultiViews"; $content .= "\n RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]"; $content .= "\n RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]"; - $content .= "\n RewriteCond %{REQUEST_FILENAME} !\\.(css|js|mjs|svg|gif|png|html|ttf|woff2?|ico|jpg|jpeg|map|webm|mp4|mp3|ogg|wav|wasm|tflite)$"; + $content .= "\n RewriteCond %{REQUEST_FILENAME} !\\.(css|js|mjs|svg|gif|png|html|ttf|woff2?|ico|jpg|jpeg|map|webm|mp4|mp3|ogg|wav|flac|wasm|tflite)$"; $content .= "\n RewriteCond %{REQUEST_FILENAME} !/core/ajax/update\\.php"; $content .= "\n RewriteCond %{REQUEST_FILENAME} !/core/img/(favicon\\.ico|manifest\\.json)$"; $content .= "\n RewriteCond %{REQUEST_FILENAME} !/(cron|public|remote|status)\\.php"; $content .= "\n RewriteCond %{REQUEST_FILENAME} !/ocs/v(1|2)\\.php"; $content .= "\n RewriteCond %{REQUEST_FILENAME} !/robots\\.txt"; - $content .= "\n RewriteCond %{REQUEST_FILENAME} !/(ocm-provider|ocs-provider|updater)/"; + $content .= "\n RewriteCond %{REQUEST_FILENAME} !/(ocs-provider|updater)/"; $content .= "\n RewriteCond %{REQUEST_URI} !^/\\.well-known/(acme-challenge|pki-validation)/.*"; $content .= "\n RewriteCond %{REQUEST_FILENAME} !/richdocumentscode(_arm64)?/proxy.php$"; $content .= "\n RewriteRule . index.php [PT,E=PATH_INFO:$1]"; @@ -551,15 +543,19 @@ class Setup { $content .= "\n</IfModule>"; } - if ($content !== '') { - //suppress errors in case we don't have permissions for it - return (bool)@file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent . $content . "\n"); + // Never write file back if disk space should be too low + if (function_exists('disk_free_space')) { + $df = disk_free_space(\OC::$SERVERROOT); + $size = strlen($content) + 10240; + if ($df !== false && $df < (float)$size) { + throw new \Exception(\OC::$SERVERROOT . " does not have enough space for writing the htaccess file! Not writing it back!"); + } } - - return false; + //suppress errors in case we don't have permissions for it + return (bool)@file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent . $content . "\n"); } - public static function protectDataDirectory() { + public static function protectDataDirectory(): void { //Require all denied $now = date('Y-m-d H:i:s'); $content = "# Generated by Nextcloud on $now\n"; @@ -587,7 +583,7 @@ class Setup { $content .= " IndexIgnore *\n"; $content .= "</IfModule>"; - $baseDir = \OC::$server->getConfig()->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data'); + $baseDir = Server::get(IConfig::class)->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data'); file_put_contents($baseDir . '/.htaccess', $content); file_put_contents($baseDir . '/index.html', ''); } @@ -603,17 +599,17 @@ class Setup { ]; } - /** - * @return bool - */ - public function shouldRemoveCanInstallFile() { + public function shouldRemoveCanInstallFile(): bool { return \OC_Util::getChannel() !== 'git' && is_file(\OC::$configDir.'/CAN_INSTALL'); } - /** - * @return bool - */ - public function canInstallFileExists() { + public function canInstallFileExists(): bool { return is_file(\OC::$configDir.'/CAN_INSTALL'); } + + protected function outputDebug(?IOutput $output, string $message): void { + if ($output instanceof IOutput) { + $output->debug($message); + } + } } diff --git a/lib/private/Setup/AbstractDatabase.php b/lib/private/Setup/AbstractDatabase.php index 9ec4137cdef..ef35ecef919 100644 --- a/lib/private/Setup/AbstractDatabase.php +++ b/lib/private/Setup/AbstractDatabase.php @@ -33,6 +33,7 @@ use OC\DB\ConnectionFactory; use OC\DB\MigrationService; use OC\SystemConfig; use OCP\IL10N; +use OCP\Migration\IOutput; use OCP\Security\ISecureRandom; use Psr\Log\LoggerInterface; @@ -70,9 +71,9 @@ abstract class AbstractDatabase { public function validate($config) { $errors = []; if (empty($config['dbuser']) && empty($config['dbname'])) { - $errors[] = $this->trans->t("Enter the database username and name for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t("Enter the database Login and name for %s", [$this->dbprettyname]); } elseif (empty($config['dbuser'])) { - $errors[] = $this->trans->t("Enter the database username for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t("Enter the database Login for %s", [$this->dbprettyname]); } elseif (empty($config['dbname'])) { $errors[] = $this->trans->t("Enter the database name for %s", [$this->dbprettyname]); } @@ -88,7 +89,7 @@ abstract class AbstractDatabase { $dbName = $config['dbname']; $dbHost = !empty($config['dbhost']) ? $config['dbhost'] : 'localhost'; $dbPort = !empty($config['dbport']) ? $config['dbport'] : ''; - $dbTablePrefix = isset($config['dbtableprefix']) ? $config['dbtableprefix'] : 'oc_'; + $dbTablePrefix = $config['dbtableprefix'] ?? 'oc_'; $createUserConfig = $this->config->getValue("setup_create_db_user", true); // accept `false` both as bool and string, since setting config values from env will result in a string @@ -139,10 +140,12 @@ abstract class AbstractDatabase { } $connectionParams['host'] = $host; } - $connectionParams = array_merge($connectionParams, $configOverwrite); + $connectionParams = array_merge($connectionParams, ['primary' => $connectionParams, 'replica' => [$connectionParams]]); $cf = new ConnectionFactory($this->config); - return $cf->getConnection($this->config->getValue('dbtype', 'sqlite'), $connectionParams); + $connection = $cf->getConnection($this->config->getValue('dbtype', 'sqlite'), $connectionParams); + $connection->ensureConnectedToPrimary(); + return $connection; } /** @@ -150,11 +153,11 @@ abstract class AbstractDatabase { */ abstract public function setupDatabase($username); - public function runMigrations() { + public function runMigrations(?IOutput $output = null) { if (!is_dir(\OC::$SERVERROOT."/core/Migrations")) { return; } - $ms = new MigrationService('core', \OC::$server->get(Connection::class)); + $ms = new MigrationService('core', \OC::$server->get(Connection::class), $output); $ms->migrate('latest', true); } } diff --git a/lib/private/Setup/MySQL.php b/lib/private/Setup/MySQL.php index 50f566728a9..29d0651cc67 100644 --- a/lib/private/Setup/MySQL.php +++ b/lib/private/Setup/MySQL.php @@ -29,10 +29,10 @@ */ namespace OC\Setup; +use Doctrine\DBAL\Platforms\MySQL80Platform; use OC\DB\ConnectionAdapter; use OC\DB\MySqlTools; use OCP\IDBConnection; -use Doctrine\DBAL\Platforms\MySQL80Platform; use OCP\Security\ISecureRandom; class MySQL extends AbstractDatabase { @@ -73,7 +73,7 @@ class MySQL extends AbstractDatabase { $this->logger->error($e->getMessage(), [ 'exception' => $e, ]); - throw new \OC\DatabaseSetupException($this->trans->t('MySQL username and/or password not valid'), + throw new \OC\DatabaseSetupException($this->trans->t('MySQL Login and/or password not valid'), $this->trans->t('You need to enter details of an existing account.'), 0, $e); } } diff --git a/lib/private/Setup/OCI.php b/lib/private/Setup/OCI.php index 477561bbe2a..8c5fa333f70 100644 --- a/lib/private/Setup/OCI.php +++ b/lib/private/Setup/OCI.php @@ -53,9 +53,9 @@ class OCI extends AbstractDatabase { public function validate($config) { $errors = []; if (empty($config['dbuser']) && empty($config['dbname'])) { - $errors[] = $this->trans->t("Enter the database username and name for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t("Enter the database Login and name for %s", [$this->dbprettyname]); } elseif (empty($config['dbuser'])) { - $errors[] = $this->trans->t("Enter the database username for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t("Enter the database Login for %s", [$this->dbprettyname]); } elseif (empty($config['dbname'])) { $errors[] = $this->trans->t("Enter the database name for %s", [$this->dbprettyname]); } @@ -75,7 +75,7 @@ class OCI extends AbstractDatabase { . ' NLS_LANG=' . getenv('NLS_LANG') . ' tnsnames.ora is ' . (is_readable(getenv('ORACLE_HOME') . '/network/admin/tnsnames.ora') ? '' : 'not ') . 'readable', 0, $e); } - throw new \OC\DatabaseSetupException($this->trans->t('Oracle username and/or password not valid'), + throw new \OC\DatabaseSetupException($this->trans->t('Oracle Login and/or password not valid'), 'Check environment: ORACLE_HOME=' . getenv('ORACLE_HOME') . ' ORACLE_SID=' . getenv('ORACLE_SID') . ' LD_LIBRARY_PATH=' . getenv('LD_LIBRARY_PATH') diff --git a/lib/private/Setup/PostgreSQL.php b/lib/private/Setup/PostgreSQL.php index 490cbba69a9..84a978eab20 100644 --- a/lib/private/Setup/PostgreSQL.php +++ b/lib/private/Setup/PostgreSQL.php @@ -114,7 +114,7 @@ class PostgreSQL extends AbstractDatabase { $this->logger->error($e->getMessage(), [ 'exception' => $e, ]); - throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), + throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL Login and/or password not valid'), $this->trans->t('You need to enter details of an existing account.'), 0, $e); } } diff --git a/lib/private/SetupCheck/SetupCheckManager.php b/lib/private/SetupCheck/SetupCheckManager.php new file mode 100644 index 00000000000..b8b6cfa11e7 --- /dev/null +++ b/lib/private/SetupCheck/SetupCheckManager.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2022 Carl Schwan <carl@carlschwan.eu> + * + * @author Carl Schwan <carl@carlschwan.eu> + * @author Côme Chilliet <come.chilliet@nextcloud.com> + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\SetupCheck; + +use OC\AppFramework\Bootstrap\Coordinator; +use OCP\Server; +use OCP\SetupCheck\ISetupCheck; +use OCP\SetupCheck\ISetupCheckManager; +use Psr\Log\LoggerInterface; + +class SetupCheckManager implements ISetupCheckManager { + public function __construct( + private Coordinator $coordinator, + private LoggerInterface $logger, + ) { + } + + public function runAll(): array { + $results = []; + $setupChecks = $this->coordinator->getRegistrationContext()->getSetupChecks(); + foreach ($setupChecks as $setupCheck) { + /** @var ISetupCheck $setupCheckObject */ + $setupCheckObject = Server::get($setupCheck->getService()); + $this->logger->debug('Running check '.get_class($setupCheckObject)); + $setupResult = $setupCheckObject->run(); + $setupResult->setName($setupCheckObject->getName()); + $category = $setupCheckObject->getCategory(); + $results[$category] ??= []; + $results[$category][$setupCheckObject::class] = $setupResult; + } + return $results; + } +} diff --git a/lib/private/Share/Share.php b/lib/private/Share/Share.php index 8d14f293e5a..54e0eb72662 100644 --- a/lib/private/Share/Share.php +++ b/lib/private/Share/Share.php @@ -36,10 +36,6 @@ namespace OC\Share; use OCA\Files_Sharing\ShareBackend\File; -use OCP\DB\Exception; -use OCP\DB\QueryBuilder\IQueryBuilder; -use OCP\IDBConnection; -use OCP\Share\IShare; use Psr\Log\LoggerInterface; /** @@ -94,161 +90,6 @@ class Share extends Constants { } /** - * Get the items of item type shared with the current user - * - * @param string $itemType - * @param int $format (optional) Format type must be defined by the backend - * @param mixed $parameters (optional) - * @param int $limit Number of items to return (optional) Returns all by default - * @param boolean $includeCollections (optional) - * @return mixed Return depends on format - * @deprecated TESTS ONLY - this methods is only used by tests - * called like this: - * \OC\Share\Share::getItemsSharedWith('folder'); (apps/files_sharing/tests/UpdaterTest.php) - */ - public static function getItemsSharedWith() { - return self::getItems('folder', null, self::$shareTypeUserAndGroups, \OC_User::getUser()); - } - - /** - * Get the items of item type shared with a user - * - * @param string $itemType - * @param string $user id for which user we want the shares - * @param int $format (optional) Format type must be defined by the backend - * @param mixed $parameters (optional) - * @param int $limit Number of items to return (optional) Returns all by default - * @param boolean $includeCollections (optional) - * @return mixed Return depends on format - * @deprecated TESTS ONLY - this methods is only used by tests - * called like this: - * \OC\Share\Share::getItemsSharedWithUser('test', $shareWith); (tests/lib/Share/Backend.php) - */ - public static function getItemsSharedWithUser($itemType, $user) { - return self::getItems('test', null, self::$shareTypeUserAndGroups, $user); - } - - /** - * Get the item of item type shared with a given user by source - * - * @param string $itemType - * @param string $itemSource - * @param ?string $user User to whom the item was shared - * @param ?string $owner Owner of the share - * @param ?int $shareType only look for a specific share type - * @return array Return list of items with file_target, permissions and expiration - * @throws Exception - */ - public static function getItemSharedWithUser(string $itemType, string $itemSource, ?string $user = null, ?string $owner = null, ?int $shareType = null) { - $shares = []; - $fileDependent = $itemType === 'file' || $itemType === 'folder'; - $qb = self::getSelectStatement(self::FORMAT_NONE, $fileDependent); - $qb->from('share', 's'); - if ($fileDependent) { - $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('file_source', 'f.fileid')); - $qb->innerJoin('s', 'storages', 'st', $qb->expr()->eq('numeric_id', 'f.storage')); - $column = 'file_source'; - } else { - $column = 'item_source'; - } - - $qb->where($qb->expr()->eq($column, $qb->createNamedParameter($itemSource))) - ->andWhere($qb->expr()->eq('item_type', $qb->createNamedParameter($itemType))); - - // for link shares $user === null - if ($user !== null) { - $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($user))); - } - - if ($shareType !== null) { - $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType, IQueryBuilder::PARAM_INT))); - } - - if ($owner !== null) { - $qb->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($owner))); - } - - $result = $qb->executeQuery(); - while ($row = $result->fetch()) { - if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) { - continue; - } - if ($fileDependent && (int)$row['file_parent'] === -1) { - // if it is a mount point we need to get the path from the mount manager - $mountManager = \OC\Files\Filesystem::getMountManager(); - $mountPoint = $mountManager->findByStorageId($row['storage_id']); - if (!empty($mountPoint)) { - $path = $mountPoint[0]->getMountPoint(); - $path = trim($path, '/'); - $path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt` - $row['path'] = $path; - } else { - \OC::$server->get(LoggerInterface::class)->warning( - 'Could not resolve mount point for ' . $row['storage_id'], - ['app' => 'OCP\Share'] - ); - } - } - $shares[] = $row; - } - $result->closeCursor(); - - // if we didn't found a result then let's look for a group share. - if (empty($shares) && $user !== null) { - $userObject = \OC::$server->getUserManager()->get($user); - $groups = []; - if ($userObject) { - $groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject); - } - - if (!empty($groups)) { - $qb = self::getSelectStatement(self::FORMAT_NONE, $fileDependent); - $qb->from('share', 's'); - - if ($fileDependent) { - $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('file_source', 'f.fileid')) - ->innerJoin('s', 'storages', 'st', $qb->expr()->eq('numeric_id', 'f.storage')); - } - - $qb->where($qb->expr()->eq($column, $qb->createNamedParameter($itemSource))) - ->andWhere($qb->expr()->eq('item_type', $qb->createNamedParameter($itemType, IQueryBuilder::PARAM_STR))) - ->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY))); - - if ($owner !== null) { - $qb->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($owner))); - } - $result = $qb->executeQuery(); - - while ($row = $result->fetch()) { - $shares[] = $row; - } - $result->closeCursor(); - } - } - - return $shares; - } - - /** - * Get the shared item of item type owned by the current user - * - * @param string $itemType - * @param string $itemSource - * @param int $format (optional) Format type must be defined by the backend - * @param mixed $parameters - * @param boolean $includeCollections - * @return mixed Return depends on format - * - * Refactoring notes: - * * defacto $parameters and $format is always the default and therefore is removed in the subsequent call - */ - public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE, - $parameters = null, $includeCollections = false) { - return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), self::FORMAT_NONE, - null, -1, $includeCollections); - } - - /** * Get the backend class for the specified item type * * @param string $itemType @@ -256,8 +97,8 @@ class Share extends Constants { * @throws \Exception */ public static function getBackend($itemType) { - $l = \OC::$server->getL10N('lib'); - $logger = \OC::$server->get(LoggerInterface::class); + $l = \OCP\Util::getL10N('lib'); + $logger = \OCP\Server::get(LoggerInterface::class); if (isset(self::$backends[$itemType])) { return self::$backends[$itemType]; } elseif (isset(self::$backendTypes[$itemType]['class'])) { @@ -303,421 +144,6 @@ class Share extends Constants { } /** - * Get a list of collection item types for the specified item type - * - * @param string $itemType - * @return array|false - */ - private static function getCollectionItemTypes(string $itemType) { - $collectionTypes = [$itemType]; - foreach (self::$backendTypes as $type => $backend) { - if (in_array($backend['collectionOf'], $collectionTypes)) { - $collectionTypes[] = $type; - } - } - // TODO Add option for collections to be collection of themselves, only 'folder' does it now... - if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) { - unset($collectionTypes[0]); - } - // Return array if collections were found or the item type is a - // collection itself - collections can be inside collections - if (count($collectionTypes) > 0) { - return $collectionTypes; - } - return false; - } - - /** - * Get shared items from the database - * - * @param string $itemType - * @param string $item Item source or target (optional) - * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique - * @param string $shareWith User or group the item is being shared with - * @param string $uidOwner User that is the owner of shared items (optional) - * @param int $format Format to convert items to with formatItems() (optional) - * @param mixed $parameters to pass to formatItems() (optional) - * @param int $limit Number of items to return, -1 to return all matches (optional) - * @param boolean $includeCollections Include collection item types (optional) - * @param boolean $itemShareWithBySource (optional) - * @param boolean $checkExpireDate - * @return array - * - * See public functions getItem(s)... for parameter usage - * - * Refactoring notes: - * * defacto $limit, $itemsShareWithBySource, $checkExpireDate, $parameters and $format is always the default and therefore is removed in the subsequent call - */ - public static function getItems($itemType, ?string $item = null, ?int $shareType = null, $shareWith = null, - $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, - $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate = true) { - if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') { - return []; - } - $fileDependent = $itemType == 'file' || $itemType == 'folder'; - $qb = self::getSelectStatement(self::FORMAT_NONE, $fileDependent, $uidOwner); - $qb->from('share', 's'); - - $backend = self::getBackend($itemType); - $collectionTypes = false; - // Get filesystem root to add it to the file target and remove from the - // file source, match file_source with the file cache - if ($fileDependent) { - if (!is_null($uidOwner)) { - $root = \OC\Files\Filesystem::getRoot(); - } else { - $root = ''; - } - if (isset($item)) { - $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('file_source', 'f.fileid')); - } else { - $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->andX( - $qb->expr()->eq('file_source', 'f.fileid'), - $qb->expr()->isNotNull('file_target') - )); - } - $qb->innerJoin('s', 'storages', 'st', $qb->expr()->eq('numeric_id', 'f.storage')); - } else { - $root = ''; - $collectionTypes = self::getCollectionItemTypes($itemType); - if ($includeCollections && !isset($item) && $collectionTypes) { - // If includeCollections is true, find collections of this item type, e.g. a music album contains songs - if (!in_array($itemType, $collectionTypes)) { - $itemTypes = array_merge([$itemType], $collectionTypes); - } else { - $itemTypes = $collectionTypes; - } - $qb->where($qb->expr()->in('item_type', $qb->createNamedParameter($itemTypes, IQueryBuilder::PARAM_STR_ARRAY))); - } else { - $qb->where($qb->expr()->eq('item_type', $qb->createNamedParameter($itemType))); - } - } - if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') { - $qb->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(IShare::TYPE_LINK, IQueryBuilder::PARAM_INT))); - } - if (isset($shareType)) { - // Include all user and group items - if ($shareType === self::$shareTypeUserAndGroups && isset($shareWith)) { - $qb->andWhere($qb->expr()->andX( - $qb->expr()->in('share_type', $qb->createNamedParameter([IShare::TYPE_USER, self::$shareTypeGroupUserUnique], IQueryBuilder::PARAM_INT_ARRAY)), - $qb->expr()->eq('share_with', $qb->createNamedParameter($shareWith)) - )); - - $user = \OC::$server->getUserManager()->get($shareWith); - $groups = []; - if ($user) { - $groups = \OC::$server->getGroupManager()->getUserGroupIds($user); - } - if (!empty($groups)) { - $qb->orWhere($qb->expr()->andX( - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP, IQueryBuilder::PARAM_INT)), - $qb->expr()->in('share_with', $qb->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)) - )); - } - - // Don't include own group shares - $qb->andWhere($qb->expr()->neq('uid_owner', $qb->createNamedParameter($shareWith))); - } else { - $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType, IQueryBuilder::PARAM_INT))); - if (isset($shareWith)) { - $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($shareWith, IQueryBuilder::PARAM_STR))); - } - } - } - if (isset($uidOwner)) { - $qb->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uidOwner))); - if (!isset($shareType)) { - // Prevent unique user targets for group shares from being selected - $qb->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(self::$shareTypeGroupUserUnique, IQueryBuilder::PARAM_INT))); - } - if ($fileDependent) { - $column = 'file_source'; - } else { - $column = 'item_source'; - } - } else { - if ($fileDependent) { - $column = 'file_target'; - } else { - $column = 'item_target'; - } - } - if (isset($item)) { - $collectionTypes = self::getCollectionItemTypes($itemType); - // If looking for own shared items, check item_source else check item_target - if (isset($uidOwner)) { - // If item type is a file, file source needs to be checked in case the item was converted - if ($fileDependent) { - $expr = $qb->expr()->eq('file_source', $qb->createNamedParameter($item)); - $column = 'file_source'; - } else { - $expr = $qb->expr()->eq('item_source', $qb->createNamedParameter($item)); - $column = 'item_source'; - } - } else { - if ($fileDependent) { - $item = \OC\Files\Filesystem::normalizePath($item); - $expr = $qb->expr()->eq('file_target', $qb->createNamedParameter($item)); - } else { - $expr = $qb->expr()->eq('item_target', $qb->createNamedParameter($item)); - } - } - if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) { - $qb->andWhere($qb->expr()->orX( - $expr, - $qb->expr()->in('item_type', $qb->createNamedParameter($collectionTypes, IQueryBuilder::PARAM_STR_ARRAY)) - )); - } else { - $qb->andWhere($expr); - } - } - $qb->orderBy('s.id', 'ASC'); - try { - $result = $qb->executeQuery(); - } catch (\Exception $e) { - \OCP\Server::get(LoggerInterface::class)->error( - 'Error while selecting shares: ' . $qb->getSQL(), - [ - 'app' => 'files_sharing', - 'exception' => $e - ]); - throw new \RuntimeException('Wrong SQL query', 500, $e); - } - - $root = strlen($root); - $items = []; - $targets = []; - $switchedItems = []; - $mounts = []; - while ($row = $result->fetch()) { - //var_dump($row); - self::transformDBResults($row); - // Filter out duplicate group shares for users with unique targets - if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) { - continue; - } - if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) { - $row['share_type'] = IShare::TYPE_GROUP; - $row['unique_name'] = true; // remember that we use a unique name for this user - $row['share_with'] = $items[$row['parent']]['share_with']; - // if the group share was unshared from the user we keep the permission, otherwise - // we take the permission from the parent because this is always the up-to-date - // permission for the group share - if ($row['permissions'] > 0) { - $row['permissions'] = $items[$row['parent']]['permissions']; - } - // Remove the parent group share - unset($items[$row['parent']]); - if ($row['permissions'] == 0) { - continue; - } - } elseif (!isset($uidOwner)) { - // Check if the same target already exists - if (isset($targets[$row['id']])) { - // Check if the same owner shared with the user twice - // through a group and user share - this is allowed - $id = $targets[$row['id']]; - if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) { - // Switch to group share type to ensure resharing conditions aren't bypassed - if ($items[$id]['share_type'] != IShare::TYPE_GROUP) { - $items[$id]['share_type'] = IShare::TYPE_GROUP; - $items[$id]['share_with'] = $row['share_with']; - } - // Switch ids if sharing permission is granted on only - // one share to ensure correct parent is used if resharing - if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE - && (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) { - $items[$row['id']] = $items[$id]; - $switchedItems[$id] = $row['id']; - unset($items[$id]); - $id = $row['id']; - } - $items[$id]['permissions'] |= (int)$row['permissions']; - } - continue; - } elseif (!empty($row['parent'])) { - $targets[$row['parent']] = $row['id']; - } - } - // Remove root from file source paths if retrieving own shared items - if (isset($uidOwner) && isset($row['path'])) { - if (isset($row['parent'])) { - $query = \OC::$server->getDatabaseConnection()->getQueryBuilder(); - $query->select('file_target') - ->from('share') - ->where($query->expr()->eq('id', $query->createNamedParameter($row['parent']))); - - $parentRow = false; - try { - $parentResult = $query->executeQuery(); - $parentRow = $parentResult->fetchOne(); - $parentResult->closeCursor(); - - $tmpPath = $parentRow['file_target']; - // find the right position where the row path continues from the target path - $pos = strrpos($row['path'], $parentRow['file_target']); - $subPath = substr($row['path'], $pos); - $splitPath = explode('/', $subPath); - foreach (array_slice($splitPath, 2) as $pathPart) { - $tmpPath = $tmpPath . '/' . $pathPart; - } - $row['path'] = $tmpPath; - } catch (Exception $e) { - \OCP\Server::get(LoggerInterface::class) - ->error('Can\'t select parent :' . $e->getMessage() . ' query=' . $query->getSQL(), [ - 'exception' => $e, - 'app' => 'core' - ]); - } - } else { - if (!isset($mounts[$row['storage']])) { - $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']); - if (is_array($mountPoints) && !empty($mountPoints)) { - $mounts[$row['storage']] = current($mountPoints); - } - } - if (!empty($mounts[$row['storage']])) { - $path = $mounts[$row['storage']]->getMountPoint() . $row['path']; - $relPath = substr($path, $root); // path relative to data/user - $row['path'] = rtrim($relPath, '/'); - } - } - } - - // Check if resharing is allowed, if not remove share permission - if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) { - $row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE; - } - // Add display names to result - $row['share_with_displayname'] = $row['share_with']; - if (isset($row['share_with']) && $row['share_with'] != '' && - $row['share_type'] === IShare::TYPE_USER) { - $shareWithUser = \OC::$server->getUserManager()->get($row['share_with']); - $row['share_with_displayname'] = $shareWithUser === null ? $row['share_with'] : $shareWithUser->getDisplayName(); - } elseif (isset($row['share_with']) && $row['share_with'] != '' && - $row['share_type'] === IShare::TYPE_REMOTE) { - $addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD'], [ - 'limit' => 1, - 'enumeration' => false, - 'fullmatch' => false, - 'strict_search' => true, - ]); - foreach ($addressBookEntries as $entry) { - foreach ($entry['CLOUD'] as $cloudID) { - if ($cloudID === $row['share_with']) { - $row['share_with_displayname'] = $entry['FN']; - } - } - } - } - if (isset($row['uid_owner']) && $row['uid_owner'] != '') { - $ownerUser = \OC::$server->getUserManager()->get($row['uid_owner']); - $row['displayname_owner'] = $ownerUser === null ? $row['uid_owner'] : $ownerUser->getDisplayName(); - } - - if ($row['permissions'] > 0) { - $items[$row['id']] = $row; - } - } - $result->closeCursor(); - - // group items if we are looking for items shared with the current user - if (isset($shareWith) && $shareWith === \OC_User::getUser()) { - $items = self::groupItems($items, $itemType); - } - - if (!empty($items)) { - $collectionItems = []; - foreach ($items as &$row) { - // Check if this is a collection of the requested item type - if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) { - if (($collectionBackend = self::getBackend($row['item_type'])) - && $collectionBackend instanceof \OCP\Share_Backend_Collection) { - // Collections can be inside collections, check if the item is a collection - if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) { - $collectionItems[] = $row; - } else { - $collection = []; - $collection['item_type'] = $row['item_type']; - if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') { - $collection['path'] = basename($row['path']); - } - $row['collection'] = $collection; - // Fetch all the children sources - $children = $collectionBackend->getChildren($row[$column]); - foreach ($children as $child) { - $childItem = $row; - $childItem['item_type'] = $itemType; - if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') { - $childItem['item_source'] = $child['source']; - $childItem['item_target'] = $child['target']; - } - if ($backend instanceof \OCP\Share_Backend_File_Dependent) { - if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') { - $childItem['file_source'] = $child['source']; - } else { // TODO is this really needed if we already know that we use the file backend? - $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']); - $childItem['file_source'] = $meta['fileid']; - } - $childItem['file_target'] = - \OC\Files\Filesystem::normalizePath($child['file_path']); - } - if (isset($item)) { - if ($childItem[$column] == $item) { - $collectionItems[] = $childItem; - } - } else { - $collectionItems[] = $childItem; - } - } - } - } - // Remove collection item - $toRemove = $row['id']; - if (array_key_exists($toRemove, $switchedItems)) { - $toRemove = $switchedItems[$toRemove]; - } - unset($items[$toRemove]); - } elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) { - // FIXME: Thats a dirty hack to improve file sharing performance, - // see github issue #10588 for more details - // Need to find a solution which works for all back-ends - $collectionBackend = self::getBackend($row['item_type']); - $sharedParents = $collectionBackend->getParents($row['item_source']); - foreach ($sharedParents as $parent) { - $collectionItems[] = $parent; - } - } - } - if (!empty($collectionItems)) { - $collectionItems = array_unique($collectionItems, SORT_REGULAR); - $items = array_merge($items, $collectionItems); - } - - // filter out invalid items, these can appear when subshare entries exist - // for a group in which the requested user isn't a member any more - $items = array_filter($items, function ($item) { - return $item['share_type'] !== self::$shareTypeGroupUserUnique; - }); - - return self::formatResult($items, $column, $backend); - } elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) { - // FIXME: Thats a dirty hack to improve file sharing performance, - // see github issue #10588 for more details - // Need to find a solution which works for all back-ends - $collectionItems = []; - $collectionBackend = self::getBackend('folder'); - $sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner); - foreach ($sharedParents as $parent) { - $collectionItems[] = $parent; - } - return self::formatResult($collectionItems, $column, $backend); - } - - return []; - } - - /** * group items with link to the same source * * @param array $items @@ -757,185 +183,6 @@ class Share extends Constants { } /** - * Construct select statement - * - * @param bool $fileDependent ist it a file/folder share or a general share - */ - private static function getSelectStatement(int $format, bool $fileDependent, ?string $uidOwner = null): IQueryBuilder { - /** @var IDBConnection $connection */ - $connection = \OC::$server->get(IDBConnection::class); - $qb = $connection->getQueryBuilder(); - if ($format == self::FORMAT_STATUSES) { - if ($fileDependent) { - return $qb->select( - 's.id', - 's.parent', - 'share_type', - 'path', - 'storage', - 'share_with', - 'uid_owner', - 'file_source', - 'stime', - 's.permissions', - 'uid_initiator' - )->selectAlias('st.id', 'storage_id') - ->selectAlias('f.parent', 'file_parent'); - } - return $qb->select('id', 'parent', 'share_type', 'share_with', 'uid_owner', 'item_source', 'stime', 's.permissions'); - } - - if (isset($uidOwner)) { - if ($fileDependent) { - return $qb->select( - 's.id', - 'item_type', - 'item_source', - 's.parent', - 'share_type', - 'share_with', - 'file_source', - 'file_target', - 'path', - 's.permissions', - 'stime', - 'expiration', - 'token', - 'storage', - 'mail_send', - 'uid_owner', - 'uid_initiator' - )->selectAlias('st.id', 'storage_id') - ->selectAlias('f.parent', 'file_parent'); - } - return $qb->select('id', 'item_type', 'item_source', 'parent', 'share_type', - 'share_with', 'uid_owner', 'file_source', 'stime', 's.permissions', - 'expiration', 'token', 'mail_send'); - } - - if ($fileDependent) { - if ($format == File::FORMAT_GET_FOLDER_CONTENTS || $format == File::FORMAT_FILE_APP_ROOT) { - return $qb->select( - 's.id', - 'item_type', - 'item_source', - 's.parent', - 'uid_owner', - 'share_type', - 'share_with', - 'file_source', - 'path', - 'file_target', - 's.permissions', - 'stime', - 'expiration', - 'storage', - 'name', - 'mtime', - 'mimepart', - 'size', - 'encrypted', - 'etag', - 'mail_send' - )->selectAlias('f.parent', 'file_parent'); - } - return $qb->select( - 's.id', - 'item_type', - 'item_source', - 'item_target', - 's.parent', - 'share_type', - 'share_with', - 'uid_owner', - 'file_source', - 'path', - 'file_target', - 's.permissions', - 'stime', - 'expiration', - 'token', - 'storage', - 'mail_send', - )->selectAlias('f.parent', 'file_parent') - ->selectAlias('st.id', 'storage_id'); - } - return $qb->select('*'); - } - - - /** - * transform db results - * - * @param array $row result - */ - private static function transformDBResults(&$row) { - if (isset($row['id'])) { - $row['id'] = (int)$row['id']; - } - if (isset($row['share_type'])) { - $row['share_type'] = (int)$row['share_type']; - } - if (isset($row['parent'])) { - $row['parent'] = (int)$row['parent']; - } - if (isset($row['file_parent'])) { - $row['file_parent'] = (int)$row['file_parent']; - } - if (isset($row['file_source'])) { - $row['file_source'] = (int)$row['file_source']; - } - if (isset($row['permissions'])) { - $row['permissions'] = (int)$row['permissions']; - } - if (isset($row['storage'])) { - $row['storage'] = (int)$row['storage']; - } - if (isset($row['stime'])) { - $row['stime'] = (int)$row['stime']; - } - if (isset($row['expiration']) && $row['share_type'] !== IShare::TYPE_LINK) { - // discard expiration date for non-link shares, which might have been - // set by ancient bugs - $row['expiration'] = null; - } - } - - /** - * format result - * - * @param array $items result - * @param string $column is it a file share or a general share ('file_target' or 'item_target') - * @param \OCP\Share_Backend $backend sharing backend - * @param int $format - * @param array $parameters additional format parameters - * @return array format result - */ - private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE, $parameters = null) { - if ($format === self::FORMAT_NONE) { - return $items; - } elseif ($format === self::FORMAT_STATUSES) { - $statuses = []; - foreach ($items as $item) { - if ($item['share_type'] === IShare::TYPE_LINK) { - if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) { - continue; - } - $statuses[$item[$column]]['link'] = true; - } elseif (!isset($statuses[$item[$column]])) { - $statuses[$item[$column]]['link'] = false; - } - if (!empty($item['file_target'])) { - $statuses[$item[$column]]['path'] = $item['path']; - } - } - return $statuses; - } else { - return $backend->formatItems($items, $format, $parameters); - } - } - - /** * remove protocol from URL * * @param string $url @@ -958,29 +205,4 @@ class Share extends Constants { public static function getExpireInterval() { return (int)\OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7'); } - - /** - * Checks whether the given path is reachable for the given owner - * - * @param string $path path relative to files - * @param string $ownerStorageId storage id of the owner - * - * @return boolean true if file is reachable, false otherwise - */ - private static function isFileReachable($path, $ownerStorageId) { - // if outside the home storage, file is always considered reachable - if (!(substr($ownerStorageId, 0, 6) === 'home::' || - substr($ownerStorageId, 0, 13) === 'object::user:' - )) { - return true; - } - - // if inside the home storage, the file has to be under "/files/" - $path = ltrim($path, '/'); - if (substr($path, 0, 6) === 'files/') { - return true; - } - - return false; - } } diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 5201cf074b1..50196402b42 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -38,12 +38,12 @@ use OC\Files\Cache\Cache; use OC\Share20\Exception\BackendError; use OC\Share20\Exception\InvalidShare; use OC\Share20\Exception\ProviderException; +use OCP\AppFramework\Utility\ITimeFactory; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Defaults; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Node; -use OCP\IConfig; use OCP\IDBConnection; use OCP\IGroupManager; use OCP\IURLGenerator; @@ -55,6 +55,7 @@ use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IAttributes; use OCP\Share\IShare; use OCP\Share\IShareProvider; +use Psr\Log\LoggerInterface; use function str_starts_with; /** @@ -90,19 +91,19 @@ class DefaultShareProvider implements IShareProvider { /** @var IURLGenerator */ private $urlGenerator; - /** @var IConfig */ - private $config; + private ITimeFactory $timeFactory; public function __construct( - IDBConnection $connection, - IUserManager $userManager, - IGroupManager $groupManager, - IRootFolder $rootFolder, - IMailer $mailer, - Defaults $defaults, - IFactory $l10nFactory, - IURLGenerator $urlGenerator, - IConfig $config) { + IDBConnection $connection, + IUserManager $userManager, + IGroupManager $groupManager, + IRootFolder $rootFolder, + IMailer $mailer, + Defaults $defaults, + IFactory $l10nFactory, + IURLGenerator $urlGenerator, + ITimeFactory $timeFactory, + ) { $this->dbConn = $connection; $this->userManager = $userManager; $this->groupManager = $groupManager; @@ -111,7 +112,7 @@ class DefaultShareProvider implements IShareProvider { $this->defaults = $defaults; $this->l10nFactory = $l10nFactory; $this->urlGenerator = $urlGenerator; - $this->config = $config; + $this->timeFactory = $timeFactory; } /** @@ -216,32 +217,22 @@ class DefaultShareProvider implements IShareProvider { } // Set the time this share was created - $qb->setValue('stime', $qb->createNamedParameter(time())); + $shareTime = $this->timeFactory->now(); + $qb->setValue('stime', $qb->createNamedParameter($shareTime->getTimestamp())); // insert the data and fetch the id of the share - $this->dbConn->beginTransaction(); - $qb->execute(); - $id = $this->dbConn->lastInsertId('*PREFIX*share'); + $qb->executeStatement(); - // Now fetch the inserted share and create a complete share object - $qb = $this->dbConn->getQueryBuilder(); - $qb->select('*') - ->from('share') - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); - - $cursor = $qb->execute(); - $data = $cursor->fetch(); - $this->dbConn->commit(); - $cursor->closeCursor(); + // Update mandatory data + $id = $qb->getLastInsertId(); + $share->setId((string)$id); + $share->setProviderId($this->identifier()); - if ($data === false) { - throw new ShareNotFound('Newly created share could not be found'); - } + $share->setShareTime(\DateTime::createFromImmutable($shareTime)); $mailSendValue = $share->getMailSend(); - $data['mail_send'] = ($mailSendValue === null) ? true : $mailSendValue; + $share->setMailSend(($mailSendValue === null) ? true : $mailSendValue); - $share = $this->createShare($data); return $share; } @@ -701,17 +692,24 @@ class DefaultShareProvider implements IShareProvider { }, $childMountNodes); $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid')); + $storageFilter = $qb->expr()->eq('f.storage', $qb->createNamedParameter($node->getMountPoint()->getNumericStorageId(), IQueryBuilder::PARAM_INT)); if ($shallow) { $qb->andWhere( $qb->expr()->orX( - $qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())), + $qb->expr()->andX( + $storageFilter, + $qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())), + ), $qb->expr()->in('f.fileid', $qb->createParameter('chunk')) ) ); } else { $qb->andWhere( $qb->expr()->orX( - $qb->expr()->like('f.path', $qb->createNamedParameter($this->dbConn->escapeLikeParameter($node->getInternalPath()) . '/%')), + $qb->expr()->andX( + $storageFilter, + $qb->expr()->like('f.path', $qb->createNamedParameter($this->dbConn->escapeLikeParameter($node->getInternalPath()) . '/%')), + ), $qb->expr()->in('f.fileid', $qb->createParameter('chunk')) ) ); @@ -1247,7 +1245,8 @@ class DefaultShareProvider implements IShareProvider { ) ); } else { - \OC::$server->getLogger()->logException(new \InvalidArgumentException('Default share provider tried to delete all shares for type: ' . $shareType)); + $e = new \InvalidArgumentException('Default share provider tried to delete all shares for type: ' . $shareType); + \OCP\Server::get(LoggerInterface::class)->error($e->getMessage(), ['exception' => $e]); return; } @@ -1374,7 +1373,7 @@ class DefaultShareProvider implements IShareProvider { $type = (int)$row['share_type']; if ($type === IShare::TYPE_USER) { $uid = $row['share_with']; - $users[$uid] = isset($users[$uid]) ? $users[$uid] : []; + $users[$uid] = $users[$uid] ?? []; $users[$uid][$row['id']] = $row; } elseif ($type === IShare::TYPE_GROUP) { $gid = $row['share_with']; @@ -1387,14 +1386,14 @@ class DefaultShareProvider implements IShareProvider { $userList = $group->getUsers(); foreach ($userList as $user) { $uid = $user->getUID(); - $users[$uid] = isset($users[$uid]) ? $users[$uid] : []; + $users[$uid] = $users[$uid] ?? []; $users[$uid][$row['id']] = $row; } } elseif ($type === IShare::TYPE_LINK) { $link = true; } elseif ($type === IShare::TYPE_USERGROUP && $currentAccess === true) { $uid = $row['share_with']; - $users[$uid] = isset($users[$uid]) ? $users[$uid] : []; + $users[$uid] = $users[$uid] ?? []; $users[$uid][$row['id']] = $row; } } diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index b03608f9872..9b54592dd1e 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -41,7 +41,6 @@ */ namespace OC\Share20; -use OCP\Cache\CappedMemoryCache; use OC\Files\Mount\MoveableMount; use OC\KnownUser\KnownUserService; use OC\Share20\Exception\ProviderException; @@ -55,6 +54,7 @@ use OCP\Files\Mount\IMountManager; use OCP\Files\Node; use OCP\HintException; use OCP\IConfig; +use OCP\IDateTimeZone; use OCP\IGroupManager; use OCP\IL10N; use OCP\IURLGenerator; @@ -106,8 +106,6 @@ class Manager implements IManager { private $userManager; /** @var IRootFolder */ private $rootFolder; - /** @var CappedMemoryCache */ - private $sharingDisabledForUsersCache; /** @var LegacyHooks */ private $legacyHooks; /** @var IMailer */ @@ -122,6 +120,8 @@ class Manager implements IManager { private $userSession; /** @var KnownUserService */ private $knownUserService; + private ShareDisableChecker $shareDisableChecker; + private IDateTimeZone $dateTimeZone; public function __construct( LoggerInterface $logger, @@ -130,7 +130,6 @@ class Manager implements IManager { IHasher $hasher, IMountManager $mountManager, IGroupManager $groupManager, - IL10N $l, IFactory $l10nFactory, IProviderFactory $factory, IUserManager $userManager, @@ -140,7 +139,9 @@ class Manager implements IManager { \OC_Defaults $defaults, IEventDispatcher $dispatcher, IUserSession $userSession, - KnownUserService $knownUserService + KnownUserService $knownUserService, + ShareDisableChecker $shareDisableChecker, + IDateTimeZone $dateTimeZone, ) { $this->logger = $logger; $this->config = $config; @@ -148,12 +149,11 @@ class Manager implements IManager { $this->hasher = $hasher; $this->mountManager = $mountManager; $this->groupManager = $groupManager; - $this->l = $l; + $this->l = $l10nFactory->get('lib'); $this->l10nFactory = $l10nFactory; $this->factory = $factory; $this->userManager = $userManager; $this->rootFolder = $rootFolder; - $this->sharingDisabledForUsersCache = new CappedMemoryCache(); // The constructor of LegacyHooks registers the listeners of share events // do not remove if those are not properly migrated $this->legacyHooks = new LegacyHooks($dispatcher); @@ -163,6 +163,8 @@ class Manager implements IManager { $this->dispatcher = $dispatcher; $this->userSession = $userSession; $this->knownUserService = $knownUserService; + $this->shareDisableChecker = $shareDisableChecker; + $this->dateTimeZone = $dateTimeZone; } /** @@ -308,8 +310,7 @@ class Manager implements IManager { $mount = $userMount->getMountPoint(); // When it's a reshare use the parent share permissions as maximum $userMountPointId = $mount->getStorageRootId(); - $userMountPoints = $userFolder->getById($userMountPointId); - $userMountPoint = array_shift($userMountPoints); + $userMountPoint = $userFolder->getFirstNodeById($userMountPointId); if ($userMountPoint === null) { throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null'); @@ -383,10 +384,10 @@ class Manager implements IManager { $expirationDate = $share->getExpirationDate(); if ($expirationDate !== null) { - //Make sure the expiration date is a date + $expirationDate->setTimezone($this->dateTimeZone->getTimeZone()); $expirationDate->setTime(0, 0, 0); - $date = new \DateTime(); + $date = new \DateTime('now', $this->dateTimeZone->getTimeZone()); $date->setTime(0, 0, 0); if ($date >= $expirationDate) { $message = $this->l->t('Expiration date is in the past'); @@ -414,9 +415,8 @@ class Manager implements IManager { $isEnforced = $this->shareApiInternalDefaultExpireDateEnforced(); } if ($fullId === null && $expirationDate === null && $defaultExpireDate) { - $expirationDate = new \DateTime(); + $expirationDate = new \DateTime('now', $this->dateTimeZone->getTimeZone()); $expirationDate->setTime(0, 0, 0); - $days = (int)$this->config->getAppValue('core', $configProp, (string)$defaultExpireDays); if ($days > $defaultExpireDays) { $days = $defaultExpireDays; @@ -430,7 +430,7 @@ class Manager implements IManager { throw new \InvalidArgumentException('Expiration date is enforced'); } - $date = new \DateTime(); + $date = new \DateTime('now', $this->dateTimeZone->getTimeZone()); $date->setTime(0, 0, 0); $date->add(new \DateInterval('P' . $defaultExpireDays . 'D')); if ($date < $expirationDate) { @@ -470,10 +470,10 @@ class Manager implements IManager { $expirationDate = $share->getExpirationDate(); if ($expirationDate !== null) { - //Make sure the expiration date is a date + $expirationDate->setTimezone($this->dateTimeZone->getTimeZone()); $expirationDate->setTime(0, 0, 0); - $date = new \DateTime(); + $date = new \DateTime('now', $this->dateTimeZone->getTimeZone()); $date->setTime(0, 0, 0); if ($date >= $expirationDate) { $message = $this->l->t('Expiration date is in the past'); @@ -490,7 +490,7 @@ class Manager implements IManager { } if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) { - $expirationDate = new \DateTime(); + $expirationDate = new \DateTime('now', $this->dateTimeZone->getTimeZone()); $expirationDate->setTime(0, 0, 0); $days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', (string)$this->shareApiLinkDefaultExpireDays()); @@ -506,7 +506,7 @@ class Manager implements IManager { throw new \InvalidArgumentException('Expiration date is enforced'); } - $date = new \DateTime(); + $date = new \DateTime('now', $this->dateTimeZone->getTimeZone()); $date->setTime(0, 0, 0); $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D')); if ($date < $expirationDate) { @@ -528,6 +528,9 @@ class Manager implements IManager { throw new \Exception($message); } + if ($expirationDate instanceof \DateTime) { + $expirationDate->setTimezone(new \DateTimeZone(date_default_timezone_get())); + } $share->setExpirationDate($expirationDate); return $share; @@ -549,6 +552,11 @@ class Manager implements IManager { $this->groupManager->getUserGroupIds($sharedBy), $this->groupManager->getUserGroupIds($sharedWith) ); + + // optional excluded groups + $excludedGroups = $this->shareWithGroupMembersOnlyExcludeGroupsList(); + $groups = array_diff($groups, $excludedGroups); + if (empty($groups)) { $message_t = $this->l->t('Sharing is only allowed with group members'); throw new \Exception($message_t); @@ -574,7 +582,7 @@ class Manager implements IManager { // Identical share already exists if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) { - $message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]); + $message = $this->l->t('Sharing %s failed, because this item is already shared with the account %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]); throw new AlreadySharedException($message, $existingShare); } @@ -585,7 +593,7 @@ class Manager implements IManager { $user = $this->userManager->get($share->getSharedWith()); if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) { - $message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]); + $message = $this->l->t('Sharing %s failed, because this item is already shared with the account %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]); throw new AlreadySharedException($message, $existingShare); } } @@ -609,7 +617,10 @@ class Manager implements IManager { if ($this->shareWithGroupMembersOnly()) { $sharedBy = $this->userManager->get($share->getSharedBy()); $sharedWith = $this->groupManager->get($share->getSharedWith()); - if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) { + + // optional excluded groups + $excludedGroups = $this->shareWithGroupMembersOnlyExcludeGroupsList(); + if (is_null($sharedWith) || in_array($share->getSharedWith(), $excludedGroups) || !$sharedWith->inGroup($sharedBy)) { throw new \Exception('Sharing is only allowed within your own groups'); } } @@ -881,12 +892,12 @@ class Manager implements IManager { * @param \DateTime|null $expiration */ protected function sendMailNotification(IL10N $l, - $filename, - $link, - $initiator, - $shareWith, - \DateTime $expiration = null, - $note = '') { + $filename, + $link, + $initiator, + $shareWith, + \DateTime $expiration = null, + $note = '') { $initiatorUser = $this->userManager->get($initiator); $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; @@ -1574,14 +1585,8 @@ class Manager implements IManager { * @return bool */ public function checkPassword(IShare $share, $password) { - $passwordProtected = $share->getShareType() !== IShare::TYPE_LINK - || $share->getShareType() !== IShare::TYPE_EMAIL - || $share->getShareType() !== IShare::TYPE_CIRCLE; - if (!$passwordProtected) { - //TODO maybe exception? - return false; - } + // if there is no password on the share object / passsword is null, there is nothing to check if ($password === null || $share->getPassword() === null) { return false; } @@ -1716,8 +1721,7 @@ class Manager implements IManager { //Get node for the owner and correct the owner in case of external storage $userFolder = $this->rootFolder->getUserFolder($owner); if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) { - $nodes = $userFolder->getById($path->getId()); - $path = array_shift($nodes); + $path = $userFolder->getFirstNodeById($path->getId()); if ($path === null || $path->getOwner() === null) { return []; } @@ -1946,6 +1950,21 @@ class Manager implements IManager { } /** + * If shareWithGroupMembersOnly is enabled, return an optional + * list of groups that must be excluded from the principle of + * belonging to the same group. + * + * @return array + */ + public function shareWithGroupMembersOnlyExcludeGroupsList() { + if (!$this->shareWithGroupMembersOnly()) { + return []; + } + $excludeGroups = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', ''); + return json_decode($excludeGroups, true) ?? []; + } + + /** * Check if users can share with groups * * @return bool @@ -2025,37 +2044,7 @@ class Manager implements IManager { * @return bool */ public function sharingDisabledForUser($userId) { - if ($userId === null) { - return false; - } - - if (isset($this->sharingDisabledForUsersCache[$userId])) { - return $this->sharingDisabledForUsersCache[$userId]; - } - - if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') { - $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', ''); - $excludedGroups = json_decode($groupsList); - if (is_null($excludedGroups)) { - $excludedGroups = explode(',', $groupsList); - $newValue = json_encode($excludedGroups); - $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue); - } - $user = $this->userManager->get($userId); - $usersGroups = $this->groupManager->getUserGroupIds($user); - if (!empty($usersGroups)) { - $remainingGroups = array_diff($usersGroups, $excludedGroups); - // if the user is only in groups which are disabled for sharing then - // sharing is also disabled for the user - if (empty($remainingGroups)) { - $this->sharingDisabledForUsersCache[$userId] = true; - return true; - } - } - } - - $this->sharingDisabledForUsersCache[$userId] = false; - return false; + return $this->shareDisableChecker->sharingDisabledForUser($userId); } /** diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php index 8c01d660915..dbf1b21dabe 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -41,6 +41,7 @@ use OCA\FederatedFileSharing\TokenHandler; use OCA\ShareByMail\Settings\SettingsManager; use OCA\ShareByMail\ShareByMailProvider; use OCA\Talk\Share\RoomShareProvider; +use OCP\AppFramework\Utility\ITimeFactory; use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; use OCP\IServerContainer; @@ -104,7 +105,7 @@ class ProviderFactory implements IProviderFactory { $this->serverContainer->query(Defaults::class), $this->serverContainer->getL10NFactory(), $this->serverContainer->getURLGenerator(), - $this->serverContainer->getConfig() + $this->serverContainer->query(ITimeFactory::class), ); } @@ -192,7 +193,7 @@ class ProviderFactory implements IProviderFactory { $this->serverContainer->getUserManager(), $this->serverContainer->getLazyRootFolder(), $this->serverContainer->getL10N('sharebymail'), - $this->serverContainer->getLogger(), + $this->serverContainer->get(LoggerInterface::class), $this->serverContainer->getMailer(), $this->serverContainer->getURLGenerator(), $this->serverContainer->getActivityManager(), diff --git a/lib/private/Share20/PublicShareTemplateFactory.php b/lib/private/Share20/PublicShareTemplateFactory.php index 222f327496a..0e9642c306e 100644 --- a/lib/private/Share20/PublicShareTemplateFactory.php +++ b/lib/private/Share20/PublicShareTemplateFactory.php @@ -27,9 +27,9 @@ use Exception; use OC\AppFramework\Bootstrap\Coordinator; use OCA\Files_Sharing\DefaultPublicShareTemplateProvider; use OCP\Server; -use OCP\Share\IShare; use OCP\Share\IPublicShareTemplateFactory; use OCP\Share\IPublicShareTemplateProvider; +use OCP\Share\IShare; class PublicShareTemplateFactory implements IPublicShareTemplateFactory { public function __construct( diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php index 0a50fa0ccfb..19b36cb60e8 100644 --- a/lib/private/Share20/Share.php +++ b/lib/private/Share20/Share.php @@ -29,8 +29,8 @@ */ namespace OC\Share20; -use OCP\Files\File; use OCP\Files\Cache\ICacheEntry; +use OCP\Files\File; use OCP\Files\FileInfo; use OCP\Files\IRootFolder; use OCP\Files\Node; @@ -188,12 +188,12 @@ class Share implements IShare { $userFolder = $this->rootFolder->getUserFolder($this->sharedBy); } - $nodes = $userFolder->getById($this->fileId); - if (empty($nodes)) { + $node = $userFolder->getFirstNodeById($this->fileId); + if (!$node) { throw new NotFoundException('Node for share not found, fileid: ' . $this->fileId); } - $this->node = $nodes[0]; + $this->node = $node; } return $this->node; @@ -211,12 +211,16 @@ class Share implements IShare { /** * @inheritdoc */ - public function getNodeId() { + public function getNodeId(): int { if ($this->fileId === null) { $this->fileId = $this->getNode()->getId(); } - return $this->fileId; + if ($this->fileId === null) { + throw new NotFoundException("Share source not found"); + } else { + return $this->fileId; + } } /** diff --git a/lib/private/Share20/ShareDisableChecker.php b/lib/private/Share20/ShareDisableChecker.php new file mode 100644 index 00000000000..9d0c2b8c2b4 --- /dev/null +++ b/lib/private/Share20/ShareDisableChecker.php @@ -0,0 +1,65 @@ +<?php + +namespace OC\Share20; + +use OCP\Cache\CappedMemoryCache; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IUserManager; + +/** + * split of from the share manager to allow using it with minimal DI + */ +class ShareDisableChecker { + private CappedMemoryCache $sharingDisabledForUsersCache; + + public function __construct( + private IConfig $config, + private IUserManager $userManager, + private IGroupManager $groupManager, + ) { + $this->sharingDisabledForUsersCache = new CappedMemoryCache(); + } + + + /** + * @param ?string $userId + * @return bool + */ + public function sharingDisabledForUser(?string $userId) { + if ($userId === null) { + return false; + } + + if (isset($this->sharingDisabledForUsersCache[$userId])) { + return $this->sharingDisabledForUsersCache[$userId]; + } + + if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') { + $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', ''); + $excludedGroups = json_decode($groupsList); + if (is_null($excludedGroups)) { + $excludedGroups = explode(',', $groupsList); + $newValue = json_encode($excludedGroups); + $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue); + } + $user = $this->userManager->get($userId); + if (!$user) { + return false; + } + $usersGroups = $this->groupManager->getUserGroupIds($user); + if (!empty($usersGroups)) { + $remainingGroups = array_diff($usersGroups, $excludedGroups); + // if the user is only in groups which are disabled for sharing then + // sharing is also disabled for the user + if (empty($remainingGroups)) { + $this->sharingDisabledForUsersCache[$userId] = true; + return true; + } + } + } + + $this->sharingDisabledForUsersCache[$userId] = false; + return false; + } +} diff --git a/lib/private/SpeechToText/SpeechToTextManager.php b/lib/private/SpeechToText/SpeechToTextManager.php index bdd04ad3651..73efe105b38 100644 --- a/lib/private/SpeechToText/SpeechToTextManager.php +++ b/lib/private/SpeechToText/SpeechToTextManager.php @@ -36,9 +36,12 @@ use OCP\Files\InvalidPathException; use OCP\Files\NotFoundException; use OCP\IConfig; use OCP\IServerContainer; +use OCP\IUserSession; use OCP\PreConditionNotMetException; use OCP\SpeechToText\ISpeechToTextManager; use OCP\SpeechToText\ISpeechToTextProvider; +use OCP\SpeechToText\ISpeechToTextProviderWithId; +use OCP\SpeechToText\ISpeechToTextProviderWithUserId; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use Psr\Log\LoggerInterface; @@ -55,6 +58,7 @@ class SpeechToTextManager implements ISpeechToTextManager { private LoggerInterface $logger, private IJobList $jobList, private IConfig $config, + private IUserSession $userSession, ) { } @@ -117,8 +121,13 @@ class SpeechToTextManager implements ISpeechToTextManager { $json = $this->config->getAppValue('core', 'ai.stt_provider', ''); if ($json !== '') { - $className = json_decode($json, true); - $provider = current(array_filter($providers, fn ($provider) => $provider::class === $className)); + $classNameOrId = json_decode($json, true); + $provider = current(array_filter($providers, function ($provider) use ($classNameOrId) { + if ($provider instanceof ISpeechToTextProviderWithId) { + return $provider->getId() === $classNameOrId; + } + return $provider::class === $classNameOrId; + })); if ($provider !== false) { $providers = [$provider]; } @@ -126,9 +135,13 @@ class SpeechToTextManager implements ISpeechToTextManager { foreach ($providers as $provider) { try { + if ($provider instanceof ISpeechToTextProviderWithUserId) { + $provider->setUserId($this->userSession->getUser()?->getUID()); + } return $provider->transcribeFile($file); } catch (\Throwable $e) { $this->logger->info('SpeechToText transcription using provider ' . $provider->getName() . ' failed', ['exception' => $e]); + throw new RuntimeException('SpeechToText transcription using provider "' . $provider->getName() . '" failed: ' . $e->getMessage()); } } diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php index 8921d52ecd1..083cd129657 100644 --- a/lib/private/SpeechToText/TranscriptionJob.php +++ b/lib/private/SpeechToText/TranscriptionJob.php @@ -65,7 +65,7 @@ class TranscriptionJob extends QueuedJob { try { \OC_Util::setupFS($owner); $userFolder = $this->rootFolder->getUserFolder($owner); - $file = current($userFolder->getById($fileId)); + $file = $userFolder->getFirstNodeById($fileId); if (!($file instanceof File)) { $this->logger->warning('Transcription of file ' . $fileId . ' failed. The file could not be found'); $this->eventDispatcher->dispatchTyped( diff --git a/lib/private/StreamImage.php b/lib/private/StreamImage.php index 33078310d27..e2f854bc233 100644 --- a/lib/private/StreamImage.php +++ b/lib/private/StreamImage.php @@ -23,8 +23,8 @@ namespace OC; -use OCP\IStreamImage; use OCP\IImage; +use OCP\IStreamImage; /** * Only useful when dealing with transferring streamed previews from an external diff --git a/lib/private/SubAdmin.php b/lib/private/SubAdmin.php index 54f14b8ab88..9f079d30e04 100644 --- a/lib/private/SubAdmin.php +++ b/lib/private/SubAdmin.php @@ -60,9 +60,9 @@ class SubAdmin extends PublicEmitter implements ISubAdmin { * @param IDBConnection $dbConn */ public function __construct(IUserManager $userManager, - IGroupManager $groupManager, - IDBConnection $dbConn, - IEventDispatcher $eventDispatcher) { + IGroupManager $groupManager, + IDBConnection $dbConn, + IEventDispatcher $eventDispatcher) { $this->userManager = $userManager; $this->groupManager = $groupManager; $this->dbConn = $dbConn; diff --git a/lib/private/Support/Subscription/Registry.php b/lib/private/Support/Subscription/Registry.php index eba76ca103e..f313574f96b 100644 --- a/lib/private/Support/Subscription/Registry.php +++ b/lib/private/Support/Subscription/Registry.php @@ -62,10 +62,10 @@ class Registry implements IRegistry { private $logger; public function __construct(IConfig $config, - IServerContainer $container, - IUserManager $userManager, - IGroupManager $groupManager, - LoggerInterface $logger) { + IServerContainer $container, + IUserManager $userManager, + IGroupManager $groupManager, + LoggerInterface $logger) { $this->config = $config; $this->container = $container; $this->userManager = $userManager; @@ -239,7 +239,7 @@ class Registry implements IRegistry { $notificationManager->notify($notification); } - $this->logger->warning('The user limit was reached and the new user was not created', ['app' => 'lib']); + $this->logger->warning('The account limit was reached and the new account was not created', ['app' => 'lib']); } protected function reIssue(): bool { diff --git a/lib/private/SystemConfig.php b/lib/private/SystemConfig.php index a18c4c2a138..f63663fbfe3 100644 --- a/lib/private/SystemConfig.php +++ b/lib/private/SystemConfig.php @@ -55,6 +55,7 @@ class SystemConfig { 'secret' => true, 'updater.secret' => true, 'trusted_proxies' => true, + 'preview_imaginary_url' => true, 'proxyuserpwd' => true, 'sentry.dsn' => true, 'sentry.public-dsn' => true, @@ -118,13 +119,14 @@ class SystemConfig { ], ], ], + 'onlyoffice' => [ + 'jwt_secret' => true, + ], ]; - /** @var Config */ - private $config; - - public function __construct(Config $config) { - $this->config = $config; + public function __construct( + private Config $config, + ) { } /** diff --git a/lib/private/SystemTag/ManagerFactory.php b/lib/private/SystemTag/ManagerFactory.php index 6670922407e..d8f7d4d772b 100644 --- a/lib/private/SystemTag/ManagerFactory.php +++ b/lib/private/SystemTag/ManagerFactory.php @@ -40,25 +40,16 @@ use OCP\SystemTag\ISystemTagObjectMapper; */ class ManagerFactory implements ISystemTagManagerFactory { /** - * Server container - * - * @var IServerContainer - */ - private $serverContainer; - - /** * Constructor for the system tag manager factory - * - * @param IServerContainer $serverContainer server container */ - public function __construct(IServerContainer $serverContainer) { - $this->serverContainer = $serverContainer; + public function __construct( + private IServerContainer $serverContainer, + ) { } /** * Creates and returns an instance of the system tag manager * - * @return ISystemTagManager * @since 9.0.0 */ public function getManager(): ISystemTagManager { @@ -73,7 +64,6 @@ class ManagerFactory implements ISystemTagManagerFactory { * Creates and returns an instance of the system tag object * mapper * - * @return ISystemTagObjectMapper * @since 9.0.0 */ public function getObjectMapper(): ISystemTagObjectMapper { diff --git a/lib/private/SystemTag/SystemTag.php b/lib/private/SystemTag/SystemTag.php index da6d4bd4b11..cd8010201d3 100644 --- a/lib/private/SystemTag/SystemTag.php +++ b/lib/private/SystemTag/SystemTag.php @@ -30,39 +30,12 @@ namespace OC\SystemTag; use OCP\SystemTag\ISystemTag; class SystemTag implements ISystemTag { - /** - * @var string - */ - private $id; - - /** - * @var string - */ - private $name; - - /** - * @var bool - */ - private $userVisible; - - /** - * @var bool - */ - private $userAssignable; - - /** - * Constructor. - * - * @param string $id tag id - * @param string $name tag name - * @param bool $userVisible whether the tag is user visible - * @param bool $userAssignable whether the tag is user assignable - */ - public function __construct(string $id, string $name, bool $userVisible, bool $userAssignable) { - $this->id = $id; - $this->name = $name; - $this->userVisible = $userVisible; - $this->userAssignable = $userAssignable; + public function __construct( + private string $id, + private string $name, + private bool $userVisible, + private bool $userAssignable, + ) { } /** @@ -97,14 +70,14 @@ class SystemTag implements ISystemTag { * {@inheritdoc} */ public function getAccessLevel(): int { - if ($this->userVisible) { - if ($this->userAssignable) { - return self::ACCESS_LEVEL_PUBLIC; - } else { - return self::ACCESS_LEVEL_RESTRICTED; - } - } else { + if (!$this->userVisible) { return self::ACCESS_LEVEL_INVISIBLE; } + + if (!$this->userAssignable) { + return self::ACCESS_LEVEL_RESTRICTED; + } + + return self::ACCESS_LEVEL_PUBLIC; } } diff --git a/lib/private/SystemTag/SystemTagManager.php b/lib/private/SystemTag/SystemTagManager.php index c52c350b6f8..67e1a7d921f 100644 --- a/lib/private/SystemTag/SystemTagManager.php +++ b/lib/private/SystemTag/SystemTagManager.php @@ -50,10 +50,8 @@ class SystemTagManager implements ISystemTagManager { /** * Prepared query for selecting tags directly - * - * @var \OCP\DB\QueryBuilder\IQueryBuilder */ - private $selectTagQuery; + private IQueryBuilder $selectTagQuery; public function __construct( protected IDBConnection $connection, @@ -219,7 +217,12 @@ class SystemTagManager implements ISystemTagManager { /** * {@inheritdoc} */ - public function updateTag(string $tagId, string $newName, bool $userVisible, bool $userAssignable) { + public function updateTag( + string $tagId, + string $newName, + bool $userVisible, + bool $userAssignable, + ): void { try { $tags = $this->getTagsByIds($tagId); } catch (TagNotFoundException $e) { @@ -271,7 +274,7 @@ class SystemTagManager implements ISystemTagManager { /** * {@inheritdoc} */ - public function deleteTags($tagIds) { + public function deleteTags($tagIds): void { if (!\is_array($tagIds)) { $tagIds = [$tagIds]; } @@ -363,14 +366,14 @@ class SystemTagManager implements ISystemTagManager { return false; } - private function createSystemTagFromRow($row) { + private function createSystemTagFromRow($row): SystemTag { return new SystemTag((string)$row['id'], $row['name'], (bool)$row['visibility'], (bool)$row['editable']); } /** * {@inheritdoc} */ - public function setTagGroups(ISystemTag $tag, array $groupIds) { + public function setTagGroups(ISystemTag $tag, array $groupIds): void { // delete relationships first $this->connection->beginTransaction(); try { diff --git a/lib/private/SystemTag/SystemTagObjectMapper.php b/lib/private/SystemTag/SystemTagObjectMapper.php index 66a21e58609..614d0274add 100644 --- a/lib/private/SystemTag/SystemTagObjectMapper.php +++ b/lib/private/SystemTag/SystemTagObjectMapper.php @@ -81,7 +81,6 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { $result->closeCursor(); } - return $mapping; } @@ -128,7 +127,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { /** * {@inheritdoc} */ - public function assignTags(string $objId, string $objectType, $tagIds) { + public function assignTags(string $objId, string $objectType, $tagIds): void { if (!\is_array($tagIds)) { $tagIds = [$tagIds]; } @@ -169,7 +168,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { /** * {@inheritdoc} */ - public function unassignTags(string $objId, string $objectType, $tagIds) { + public function unassignTags(string $objId, string $objectType, $tagIds): void { if (!\is_array($tagIds)) { $tagIds = [$tagIds]; } @@ -241,7 +240,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { * * @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist */ - private function assertTagsExist($tagIds) { + private function assertTagsExist(array $tagIds): void { $tags = $this->tagManager->getTagsByIds($tagIds); if (\count($tags) !== \count($tagIds)) { // at least one tag missing, bail out diff --git a/lib/private/SystemTag/SystemTagsInFilesDetector.php b/lib/private/SystemTag/SystemTagsInFilesDetector.php index c9f26c58c02..044322733ea 100644 --- a/lib/private/SystemTag/SystemTagsInFilesDetector.php +++ b/lib/private/SystemTag/SystemTagsInFilesDetector.php @@ -36,7 +36,9 @@ use OCP\Files\Search\ISearchBinaryOperator; use OCP\Files\Search\ISearchComparison; class SystemTagsInFilesDetector { - public function __construct(protected QuerySearchHelper $searchHelper) { + public function __construct( + protected QuerySearchHelper $searchHelper, + ) { } public function detectAssignedSystemTagsIn( diff --git a/lib/private/TagManager.php b/lib/private/TagManager.php index 82c4dd2188d..552113f89dc 100644 --- a/lib/private/TagManager.php +++ b/lib/private/TagManager.php @@ -27,6 +27,7 @@ namespace OC; use OC\Tagging\TagMapper; +use OCP\Db\Exception as DBException; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; @@ -35,7 +36,6 @@ use OCP\ITagManager; use OCP\ITags; use OCP\IUserSession; use OCP\User\Events\UserDeletedEvent; -use OCP\Db\Exception as DBException; use Psr\Log\LoggerInterface; /** diff --git a/lib/private/Tagging/TagMapper.php b/lib/private/Tagging/TagMapper.php index 1ee9c33acf7..ab227de5f7f 100644 --- a/lib/private/Tagging/TagMapper.php +++ b/lib/private/Tagging/TagMapper.php @@ -27,8 +27,8 @@ namespace OC\Tagging; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\QBMapper; -use OCP\IDBConnection; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; /** * Mapper for Tag entity diff --git a/lib/private/Tags.php b/lib/private/Tags.php index 8da1e7edc3b..5f84b692def 100644 --- a/lib/private/Tags.php +++ b/lib/private/Tags.php @@ -35,7 +35,6 @@ use OC\Tagging\TagMapper; use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; -use OCP\ILogger; use OCP\ITags; use OCP\Share_Backend; use Psr\Log\LoggerInterface; @@ -235,7 +234,7 @@ class Tags implements ITags { } if ($tagId === false) { - $l10n = \OC::$server->getL10N('core'); + $l10n = \OCP\Util::getL10N('core'); throw new \Exception( $l10n->t('Could not find category "%s"', [$tag]) ); @@ -486,11 +485,13 @@ class Tags implements ITags { try { return $this->getIdsForTag(ITags::TAG_FAVORITE); } catch (\Exception $e) { - \OC::$server->getLogger()->logException($e, [ - 'message' => __METHOD__, - 'level' => ILogger::ERROR, - 'app' => 'core', - ]); + \OCP\Server::get(LoggerInterface::class)->error( + $e->getMessage(), + [ + 'app' => 'core', + 'exception' => $e, + ] + ); return []; } } @@ -529,7 +530,7 @@ class Tags implements ITags { if (is_string($tag) && !is_numeric($tag)) { $tag = trim($tag); if ($tag === '') { - \OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG); + $this->logger->debug(__METHOD__.', Cannot add an empty tag'); return false; } if (!$this->hasTag($tag)) { @@ -549,7 +550,7 @@ class Tags implements ITags { try { $qb->executeStatement(); } catch (\Exception $e) { - \OC::$server->getLogger()->error($e->getMessage(), [ + \OCP\Server::get(LoggerInterface::class)->error($e->getMessage(), [ 'app' => 'core', 'exception' => $e, ]); @@ -569,7 +570,7 @@ class Tags implements ITags { if (is_string($tag) && !is_numeric($tag)) { $tag = trim($tag); if ($tag === '') { - \OCP\Util::writeLog('core', __METHOD__.', Tag name is empty', ILogger::DEBUG); + $this->logger->debug(__METHOD__.', Tag name is empty'); return false; } $tagId = $this->getTagId($tag); @@ -609,8 +610,7 @@ class Tags implements ITags { $names = array_map('trim', $names); array_filter($names); - \OCP\Util::writeLog('core', __METHOD__ . ', before: ' - . print_r($this->tags, true), ILogger::DEBUG); + $this->logger->debug(__METHOD__ . ', before: ' . print_r($this->tags, true)); foreach ($names as $name) { $id = null; @@ -625,8 +625,7 @@ class Tags implements ITags { unset($this->tags[$key]); $this->mapper->delete($tag); } else { - \OCP\Util::writeLog('core', __METHOD__ . 'Cannot delete tag ' . $name - . ': not found.', ILogger::ERROR); + $this->logger->error(__METHOD__ . 'Cannot delete tag ' . $name . ': not found.'); } if (!is_null($id) && $id !== false) { try { diff --git a/lib/private/Talk/Broker.php b/lib/private/Talk/Broker.php index 12e6c5fb34b..451e7822790 100644 --- a/lib/private/Talk/Broker.php +++ b/lib/private/Talk/Broker.php @@ -48,8 +48,8 @@ class Broker implements IBroker { private ?ITalkBackend $backend = null; public function __construct(Coordinator $coordinator, - IServerContainer $container, - LoggerInterface $logger) { + IServerContainer $container, + LoggerInterface $logger) { $this->coordinator = $coordinator; $this->container = $container; $this->logger = $logger; @@ -94,8 +94,8 @@ class Broker implements IBroker { } public function createConversation(string $name, - array $moderators, - IConversationOptions $options = null): IConversation { + array $moderators, + IConversationOptions $options = null): IConversation { if (!$this->hasBackend()) { throw new NoBackendException("The Talk broker has no registered backend"); } diff --git a/lib/private/Teams/TeamManager.php b/lib/private/Teams/TeamManager.php new file mode 100644 index 00000000000..6651d3ce676 --- /dev/null +++ b/lib/private/Teams/TeamManager.php @@ -0,0 +1,119 @@ +<?php +/** + * @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OC\Teams; + +use OC\AppFramework\Bootstrap\Coordinator; +use OCA\Circles\CirclesManager; +use OCA\Circles\Exceptions\CircleNotFoundException; +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Member; +use OCP\IURLGenerator; +use OCP\Server; +use OCP\Teams\ITeamManager; +use OCP\Teams\ITeamResourceProvider; +use OCP\Teams\Team; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; + +class TeamManager implements ITeamManager { + + /** @var ?ITeamResourceProvider[] */ + private ?array $providers = null; + + public function __construct( + private Coordinator $bootContext, + private IURLGenerator $urlGenerator, + private ?CirclesManager $circlesManager, + ) { + } + + public function hasTeamSupport(): bool { + return $this->circlesManager !== null; + } + + public function getProviders(): array { + if ($this->providers !== null) { + return $this->providers; + } + + $this->providers = []; + foreach ($this->bootContext->getRegistrationContext()->getTeamResourceProviders() as $providerRegistration) { + try { + /** @var ITeamResourceProvider $provider */ + $provider = Server::get($providerRegistration->getService()); + $this->providers[$provider->getId()] = $provider; + } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) { + } + } + return $this->providers; + } + + public function getProvider(string $providerId): ITeamResourceProvider { + $providers = $this->getProviders(); + if (isset($providers[$providerId])) { + return $providers[$providerId]; + } + + throw new \RuntimeException('No provider found for id ' .$providerId); + } + + public function getSharedWith(string $teamId, string $userId): array { + if ($this->getTeam($teamId, $userId) === null) { + return []; + } + + $resources = []; + + foreach ($this->getProviders() as $provider) { + array_push($resources, ...$provider->getSharedWith($teamId)); + } + + return $resources; + } + + public function getTeamsForResource(string $providerId, string $resourceId, string $userId): array { + $provider = $this->getProvider($providerId); + return array_values(array_filter(array_map(function ($teamId) use ($userId) { + $team = $this->getTeam($teamId, $userId); + if ($team === null) { + return null; + } + + return new Team( + $teamId, + $team->getDisplayName(), + $this->urlGenerator->linkToRouteAbsolute('contacts.contacts.directcircle', ['singleId' => $teamId]), + ); + }, $provider->getTeamsForResource($resourceId)))); + } + + private function getTeam(string $teamId, string $userId): ?Circle { + try { + $federatedUser = $this->circlesManager->getFederatedUser($userId, Member::TYPE_USER); + $this->circlesManager->startSession($federatedUser); + return $this->circlesManager->getCircle($teamId); + } catch (CircleNotFoundException) { + return null; + } + } +} diff --git a/lib/private/Template/JSCombiner.php b/lib/private/Template/JSCombiner.php index b87829360d5..fad69a76ae0 100644 --- a/lib/private/Template/JSCombiner.php +++ b/lib/private/Template/JSCombiner.php @@ -55,10 +55,10 @@ class JSCombiner { private $cacheFactory; public function __construct(IAppData $appData, - IURLGenerator $urlGenerator, - ICacheFactory $cacheFactory, - SystemConfig $config, - LoggerInterface $logger) { + IURLGenerator $urlGenerator, + ICacheFactory $cacheFactory, + SystemConfig $config, + LoggerInterface $logger) { $this->appData = $appData; $this->urlGenerator = $urlGenerator; $this->cacheFactory = $cacheFactory; diff --git a/lib/private/Template/JSConfigHelper.php b/lib/private/Template/JSConfigHelper.php index 9cf0838e43a..d2cd536fa9f 100644 --- a/lib/private/Template/JSConfigHelper.php +++ b/lib/private/Template/JSConfigHelper.php @@ -45,9 +45,9 @@ use OCP\IConfig; use OCP\IGroupManager; use OCP\IInitialStateService; use OCP\IL10N; +use OCP\ILogger; use OCP\ISession; use OCP\IURLGenerator; -use OCP\ILogger; use OCP\IUser; use OCP\Share\IManager as IShareManager; use OCP\User\Backend\IPasswordConfirmationBackend; @@ -70,16 +70,16 @@ class JSConfigHelper { private $excludedUserBackEnds = ['user_saml' => true, 'user_globalsiteselector' => true]; public function __construct(IL10N $l, - Defaults $defaults, - IAppManager $appManager, - ISession $session, - ?IUser $currentUser, - IConfig $config, - IGroupManager $groupManager, - IniGetWrapper $iniWrapper, - IURLGenerator $urlGenerator, - CapabilitiesManager $capabilitiesManager, - IInitialStateService $initialStateService) { + Defaults $defaults, + IAppManager $appManager, + ISession $session, + ?IUser $currentUser, + IConfig $config, + IGroupManager $groupManager, + IniGetWrapper $iniWrapper, + IURLGenerator $urlGenerator, + CapabilitiesManager $capabilitiesManager, + IInitialStateService $initialStateService) { $this->l = $l; $this->defaults = $defaults; $this->appManager = $appManager; @@ -180,7 +180,8 @@ class JSConfigHelper { 'sharing.maxAutocompleteResults' => max(0, $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT)), 'sharing.minSearchStringLength' => $this->config->getSystemValueInt('sharing.minSearchStringLength', 0), 'version' => implode('.', Util::getVersion()), - 'versionstring' => \OC_Util::getVersionString() + 'versionstring' => \OC_Util::getVersionString(), + 'enable_non-accessible_features' => $this->config->getSystemValueBool('enable_non-accessible_features', true), ]; $array = [ diff --git a/lib/private/Template/JSResourceLocator.php b/lib/private/Template/JSResourceLocator.php index b283f0b610f..c73b3efe997 100644 --- a/lib/private/Template/JSResourceLocator.php +++ b/lib/private/Template/JSResourceLocator.php @@ -51,6 +51,22 @@ class JSResourceLocator extends ResourceLocator { // Extracting the appId and the script file name $app = substr($script, 0, strpos($script, '/')); $scriptName = basename($script); + // Get the app root path + $appRoot = $this->serverroot . 'apps/'; + $appWebRoot = null; + try { + // We need the dir name as getAppPath appends the appid + $appRoot = dirname($this->appManager->getAppPath($app)); + // Only do this if $app_path is set, because an empty argument to realpath gets turned into cwd. + if ($appRoot) { + // Handle symlinks + $appRoot = realpath($appRoot); + } + // Get the app webroot + $appWebRoot = dirname($this->appManager->getAppWebPath($app)); + } catch (AppPathNotFoundException $e) { + // ignore + } if (str_contains($script, '/l10n/')) { // For language files we try to load them all, so themes can overwrite @@ -60,7 +76,7 @@ class JSResourceLocator extends ResourceLocator { $found += $this->appendScriptIfExist($this->serverroot, $theme_dir.'core/'.$script); $found += $this->appendScriptIfExist($this->serverroot, $script); $found += $this->appendScriptIfExist($this->serverroot, $theme_dir.$script); - $found += $this->appendScriptIfExist($this->serverroot, 'apps/'.$script); + $found += $this->appendScriptIfExist($appRoot, $script, $appWebRoot); $found += $this->appendScriptIfExist($this->serverroot, $theme_dir.'apps/'.$script); if ($found) { @@ -71,8 +87,9 @@ class JSResourceLocator extends ResourceLocator { || $this->appendScriptIfExist($this->serverroot, $script) || $this->appendScriptIfExist($this->serverroot, $theme_dir."dist/$app-$scriptName") || $this->appendScriptIfExist($this->serverroot, "dist/$app-$scriptName") - || $this->appendScriptIfExist($this->serverroot, 'apps/'.$script) + || $this->appendScriptIfExist($appRoot, $script, $appWebRoot) || $this->cacheAndAppendCombineJsonIfExist($this->serverroot, $script.'.json') + || $this->cacheAndAppendCombineJsonIfExist($appRoot, $script.'.json', $appWebRoot) || $this->appendScriptIfExist($this->serverroot, $theme_dir.'core/'.$script) || $this->appendScriptIfExist($this->serverroot, 'core/'.$script) || (strpos($scriptName, '/') === -1 && ($this->appendScriptIfExist($this->serverroot, $theme_dir."dist/core-$scriptName") @@ -82,43 +99,13 @@ class JSResourceLocator extends ResourceLocator { return; } - $script = substr($script, strpos($script, '/') + 1); - $app_url = null; - - try { - $app_url = $this->appManager->getAppWebPath($app); - } catch (AppPathNotFoundException) { - // pass - } - - try { - $app_path = $this->appManager->getAppPath($app); - - // Account for the possibility of having symlinks in app path. Only - // do this if $app_path is set, because an empty argument to realpath - // gets turned into cwd. - $app_path = realpath($app_path); - - // check combined files - if (!str_starts_with($script, 'l10n/') && $this->cacheAndAppendCombineJsonIfExist($app_path, $script.'.json', $app)) { - return; - } - - // fallback to plain file location - if ($this->appendScriptIfExist($app_path, $script, $app_url)) { - return; - } - } catch (AppPathNotFoundException) { - // pass (general error handling happens below) - } - // missing translations files will be ignored - if (str_starts_with($script, 'l10n/')) { + if (str_contains($script, '/l10n/')) { return; } $this->logger->error('Could not find resource {resource} to load', [ - 'resource' => $app . '/' . $script . '.js', + 'resource' => $script . '.js', 'app' => 'jsresourceloader', ]); } diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php index 658a85152bf..b4490dfe101 100644 --- a/lib/private/TemplateLayout.php +++ b/lib/private/TemplateLayout.php @@ -47,11 +47,13 @@ use OC\Search\SearchQuery; use OC\Template\CSSResourceLocator; use OC\Template\JSConfigHelper; use OC\Template\JSResourceLocator; +use OCP\App\IAppManager; use OCP\AppFramework\Http\TemplateResponse; use OCP\Defaults; use OCP\IConfig; use OCP\IInitialStateService; use OCP\INavigationManager; +use OCP\IURLGenerator; use OCP\IUserSession; use OCP\Support\Subscription\IRegistry; use OCP\Util; @@ -106,11 +108,15 @@ class TemplateLayout extends \OC_Template { $this->initialState->provideInitialState('core', 'active-app', $this->navigationManager->getActiveEntry()); $this->initialState->provideInitialState('core', 'apps', $this->navigationManager->getAll()); - $this->initialState->provideInitialState('unified-search', 'limit-default', (int)$this->config->getAppValue('core', 'unified-search.limit-default', (string)SearchQuery::LIMIT_DEFAULT)); - $this->initialState->provideInitialState('unified-search', 'min-search-length', (int)$this->config->getAppValue('core', 'unified-search.min-search-length', (string)1)); - $this->initialState->provideInitialState('unified-search', 'live-search', $this->config->getAppValue('core', 'unified-search.live-search', 'yes') === 'yes'); - Util::addScript('core', 'unified-search', 'core'); + if ($this->config->getSystemValueBool('unified_search.enabled', false) || !$this->config->getSystemValueBool('enable_non-accessible_features', true)) { + $this->initialState->provideInitialState('unified-search', 'limit-default', (int)$this->config->getAppValue('core', 'unified-search.limit-default', (string)SearchQuery::LIMIT_DEFAULT)); + $this->initialState->provideInitialState('unified-search', 'min-search-length', (int)$this->config->getAppValue('core', 'unified-search.min-search-length', (string)1)); + $this->initialState->provideInitialState('unified-search', 'live-search', $this->config->getAppValue('core', 'unified-search.live-search', 'yes') === 'yes'); + Util::addScript('core', 'legacy-unified-search', 'core'); + } else { + Util::addScript('core', 'unified-search', 'core'); + } // Set body data-theme $this->assign('enabledThemes', []); if (\OC::$server->getAppManager()->isEnabledForUser('theming') && class_exists('\OCA\Theming\Service\ThemesService')) { @@ -189,13 +195,31 @@ class TemplateLayout extends \OC_Template { $this->assign('appid', $appId); $this->assign('bodyid', 'body-public'); + // Set logo link target + $logoUrl = $this->config->getSystemValueString('logo_url', ''); + $this->assign('logoUrl', $logoUrl); + /** @var IRegistry $subscription */ $subscription = \OCP\Server::get(IRegistry::class); $showSimpleSignup = $this->config->getSystemValueBool('simpleSignUpLink.shown', true); if ($showSimpleSignup && $subscription->delegateHasValidSubscription()) { $showSimpleSignup = false; } + + $defaultSignUpLink = 'https://nextcloud.com/signup/'; + $signUpLink = $this->config->getSystemValueString('registration_link', $defaultSignUpLink); + if ($signUpLink !== $defaultSignUpLink) { + $showSimpleSignup = true; + } + + $appManager = \OCP\Server::get(IAppManager::class); + if ($appManager->isEnabledForUser('registration')) { + $urlGenerator = \OCP\Server::get(IURLGenerator::class); + $signUpLink = $urlGenerator->getAbsoluteURL('/index.php/apps/registration/'); + } + $this->assign('showSimpleSignUpLink', $showSimpleSignup); + $this->assign('signUpLink', $signUpLink); } else { parent::__construct('core', 'layout.base'); } @@ -225,7 +249,7 @@ class TemplateLayout extends \OC_Template { // this is on purpose outside of the if statement below so that the initial state is prefilled (done in the getConfig() call) // see https://github.com/nextcloud/server/pull/22636 for details $jsConfigHelper = new JSConfigHelper( - \OC::$server->getL10N('lib'), + \OCP\Util::getL10N('lib'), \OCP\Server::get(Defaults::class), \OC::$server->getAppManager(), \OC::$server->getSession(), @@ -279,7 +303,7 @@ class TemplateLayout extends \OC_Template { $web = $info[1]; $file = $info[2]; - if (substr($file, -strlen('print.css')) === 'print.css') { + if (str_ends_with($file, 'print.css')) { $this->append('printcssfiles', $web.'/'.$file . $this->getVersionHashSuffix()); } else { $suffix = $this->getVersionHashSuffix($web, $file); diff --git a/lib/private/TextProcessing/Db/Task.php b/lib/private/TextProcessing/Db/Task.php index 9c6f16d11ae..5f362d429f3 100644 --- a/lib/private/TextProcessing/Db/Task.php +++ b/lib/private/TextProcessing/Db/Task.php @@ -45,6 +45,8 @@ use OCP\TextProcessing\Task as OCPTask; * @method string getAppId() * @method setIdentifier(string $identifier) * @method string getIdentifier() + * @method setCompletionExpectedAt(null|\DateTime $completionExpectedAt) + * @method null|\DateTime getCompletionExpectedAt() */ class Task extends Entity { protected $lastUpdated; @@ -55,16 +57,17 @@ class Task extends Entity { protected $userId; protected $appId; protected $identifier; + protected $completionExpectedAt; /** * @var string[] */ - public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'identifier']; + public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'identifier', 'completion_expected_at']; /** * @var string[] */ - public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'identifier']; + public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'identifier', 'completionExpectedAt']; public function __construct() { @@ -78,6 +81,7 @@ class Task extends Entity { $this->addType('userId', 'string'); $this->addType('appId', 'string'); $this->addType('identifier', 'string'); + $this->addType('completionExpectedAt', 'datetime'); } public function toRow(): array { @@ -98,6 +102,7 @@ class Task extends Entity { 'userId' => $task->getUserId(), 'appId' => $task->getAppId(), 'identifier' => $task->getIdentifier(), + 'completionExpectedAt' => $task->getCompletionExpectedAt(), ]); return $task; } @@ -107,6 +112,7 @@ class Task extends Entity { $task->setId($this->getId()); $task->setStatus($this->getStatus()); $task->setOutput($this->getOutput()); + $task->setCompletionExpectedAt($this->getCompletionExpectedAt()); return $task; } } diff --git a/lib/private/TextProcessing/Manager.php b/lib/private/TextProcessing/Manager.php index b9cb06c298e..e62a794f228 100644 --- a/lib/private/TextProcessing/Manager.php +++ b/lib/private/TextProcessing/Manager.php @@ -27,19 +27,22 @@ namespace OC\TextProcessing; use OC\AppFramework\Bootstrap\Coordinator; use OC\TextProcessing\Db\Task as DbTask; -use OCP\IConfig; -use OCP\TextProcessing\Task; -use OCP\TextProcessing\Task as OCPTask; use OC\TextProcessing\Db\TaskMapper; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\BackgroundJob\IJobList; use OCP\Common\Exception\NotFoundException; use OCP\DB\Exception; +use OCP\IConfig; use OCP\IServerContainer; +use OCP\PreConditionNotMetException; +use OCP\TextProcessing\Exception\TaskFailureException; use OCP\TextProcessing\IManager; use OCP\TextProcessing\IProvider; -use OCP\PreConditionNotMetException; +use OCP\TextProcessing\IProviderWithExpectedRuntime; +use OCP\TextProcessing\IProviderWithId; +use OCP\TextProcessing\Task; +use OCP\TextProcessing\Task as OCPTask; use Psr\Log\LoggerInterface; use RuntimeException; use Throwable; @@ -114,26 +117,16 @@ class Manager implements IManager { if (!$this->canHandleTask($task)) { throw new PreConditionNotMetException('No text processing provider is installed that can handle this task'); } - $providers = $this->getProviders(); - $json = $this->config->getAppValue('core', 'ai.textprocessing_provider_preferences', ''); - if ($json !== '') { - $preferences = json_decode($json, true); - if (isset($preferences[$task->getType()])) { - // If a preference for this task type is set, move the preferred provider to the start - $provider = current(array_filter($providers, fn ($provider) => $provider::class === $preferences[$task->getType()])); - if ($provider !== false) { - $providers = array_filter($providers, fn ($p) => $p !== $provider); - array_unshift($providers, $provider); - } - } - } + $providers = $this->getPreferredProviders($task); foreach ($providers as $provider) { - if (!$task->canUseProvider($provider)) { - continue; - } try { $task->setStatus(OCPTask::STATUS_RUNNING); + if ($provider instanceof IProviderWithExpectedRuntime) { + $completionExpectedAt = new \DateTime('now'); + $completionExpectedAt->add(new \DateInterval('PT'.$provider->getExpectedRuntime().'S')); + $task->setCompletionExpectedAt($completionExpectedAt); + } if ($task->getId() === null) { $taskEntity = $this->taskMapper->insert(DbTask::fromPublicTask($task)); $task->setId($taskEntity->getId()); @@ -145,31 +138,37 @@ class Manager implements IManager { $task->setStatus(OCPTask::STATUS_SUCCESSFUL); $this->taskMapper->update(DbTask::fromPublicTask($task)); return $output; - } catch (\RuntimeException $e) { - $this->logger->info('LanguageModel call using provider ' . $provider->getName() . ' failed', ['exception' => $e]); - $task->setStatus(OCPTask::STATUS_FAILED); - $this->taskMapper->update(DbTask::fromPublicTask($task)); - throw $e; } catch (\Throwable $e) { $this->logger->info('LanguageModel call using provider ' . $provider->getName() . ' failed', ['exception' => $e]); $task->setStatus(OCPTask::STATUS_FAILED); $this->taskMapper->update(DbTask::fromPublicTask($task)); - throw new RuntimeException('LanguageModel call using provider ' . $provider->getName() . ' failed: ' . $e->getMessage(), 0, $e); + throw new TaskFailureException('LanguageModel call using provider ' . $provider->getName() . ' failed: ' . $e->getMessage(), 0, $e); } } - throw new RuntimeException('Could not run task'); + $task->setStatus(OCPTask::STATUS_FAILED); + $this->taskMapper->update(DbTask::fromPublicTask($task)); + throw new TaskFailureException('Could not run task'); } /** * @inheritDoc - * @throws Exception */ public function scheduleTask(OCPTask $task): void { if (!$this->canHandleTask($task)) { throw new PreConditionNotMetException('No LanguageModel provider is installed that can handle this task'); } $task->setStatus(OCPTask::STATUS_SCHEDULED); + $providers = $this->getPreferredProviders($task); + if (count($providers) === 0) { + throw new PreConditionNotMetException('No LanguageModel provider is installed that can handle this task'); + } + [$provider,] = $providers; + if ($provider instanceof IProviderWithExpectedRuntime) { + $completionExpectedAt = new \DateTime('now'); + $completionExpectedAt->add(new \DateInterval('PT'.$provider->getExpectedRuntime().'S')); + $task->setCompletionExpectedAt($completionExpectedAt); + } $taskEntity = DbTask::fromPublicTask($task); $this->taskMapper->insert($taskEntity); $task->setId($taskEntity->getId()); @@ -181,6 +180,25 @@ class Manager implements IManager { /** * @inheritDoc */ + public function runOrScheduleTask(OCPTask $task): bool { + if (!$this->canHandleTask($task)) { + throw new PreConditionNotMetException('No LanguageModel provider is installed that can handle this task'); + } + [$provider,] = $this->getPreferredProviders($task); + $maxExecutionTime = (int) ini_get('max_execution_time'); + // Offload the task to a background job if the expected runtime of the likely provider is longer than 80% of our max execution time + // or if the provider doesn't provide a getExpectedRuntime() method + if (!$provider instanceof IProviderWithExpectedRuntime || $provider->getExpectedRuntime() > $maxExecutionTime * 0.8) { + $this->scheduleTask($task); + return false; + } + $this->runTask($task); + return true; + } + + /** + * @inheritDoc + */ public function deleteTask(Task $task): void { $taskEntity = DbTask::fromPublicTask($task); $this->taskMapper->delete($taskEntity); @@ -253,4 +271,30 @@ class Manager implements IManager { throw new RuntimeException('Failure while trying to find tasks by appId and identifier: ' . $e->getMessage(), 0, $e); } } + + /** + * @param OCPTask $task + * @return IProvider[] + */ + public function getPreferredProviders(OCPTask $task): array { + $providers = $this->getProviders(); + $json = $this->config->getAppValue('core', 'ai.textprocessing_provider_preferences', ''); + if ($json !== '') { + $preferences = json_decode($json, true); + if (isset($preferences[$task->getType()])) { + // If a preference for this task type is set, move the preferred provider to the start + $provider = current(array_values(array_filter($providers, function ($provider) use ($preferences, $task) { + if ($provider instanceof IProviderWithId) { + return $provider->getId() === $preferences[$task->getType()]; + } + return $provider::class === $preferences[$task->getType()]; + }))); + if ($provider !== false) { + $providers = array_filter($providers, fn ($p) => $p !== $provider); + array_unshift($providers, $provider); + } + } + } + return array_values(array_filter($providers, fn (IProvider $provider) => $task->canUseProvider($provider))); + } } diff --git a/lib/private/TextToImage/Db/Task.php b/lib/private/TextToImage/Db/Task.php new file mode 100644 index 00000000000..96dd6e4e165 --- /dev/null +++ b/lib/private/TextToImage/Db/Task.php @@ -0,0 +1,117 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OC\TextToImage\Db; + +use DateTime; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\TextToImage\Task as OCPTask; + +/** + * @method setLastUpdated(DateTime $lastUpdated) + * @method DateTime getLastUpdated() + * @method setInput(string $type) + * @method string getInput() + * @method setResultPath(string $resultPath) + * @method string getResultPath() + * @method setStatus(int $type) + * @method int getStatus() + * @method setUserId(?string $userId) + * @method string|null getUserId() + * @method setAppId(string $type) + * @method string getAppId() + * @method setIdentifier(string $identifier) + * @method string|null getIdentifier() + * @method setNumberOfImages(int $numberOfImages) + * @method int getNumberOfImages() + * @method setCompletionExpectedAt(DateTime $at) + * @method DateTime getCompletionExpectedAt() + */ +class Task extends Entity { + protected $lastUpdated; + protected $type; + protected $input; + protected $status; + protected $userId; + protected $appId; + protected $identifier; + protected $numberOfImages; + protected $completionExpectedAt; + + /** + * @var string[] + */ + public static array $columns = ['id', 'last_updated', 'input', 'status', 'user_id', 'app_id', 'identifier', 'number_of_images', 'completion_expected_at']; + + /** + * @var string[] + */ + public static array $fields = ['id', 'lastUpdated', 'input', 'status', 'userId', 'appId', 'identifier', 'numberOfImages', 'completionExpectedAt']; + + + public function __construct() { + // add types in constructor + $this->addType('id', 'integer'); + $this->addType('lastUpdated', 'datetime'); + $this->addType('input', 'string'); + $this->addType('status', 'integer'); + $this->addType('userId', 'string'); + $this->addType('appId', 'string'); + $this->addType('identifier', 'string'); + $this->addType('numberOfImages', 'integer'); + $this->addType('completionExpectedAt', 'datetime'); + } + + public function toRow(): array { + return array_combine(self::$columns, array_map(function ($field) { + return $this->{'get'.ucfirst($field)}(); + }, self::$fields)); + } + + public static function fromPublicTask(OCPTask $task): Task { + /** @var Task $dbTask */ + $dbTask = Task::fromParams([ + 'id' => $task->getId(), + 'lastUpdated' => \OCP\Server::get(ITimeFactory::class)->getDateTime(), + 'status' => $task->getStatus(), + 'numberOfImages' => $task->getNumberOfImages(), + 'input' => $task->getInput(), + 'userId' => $task->getUserId(), + 'appId' => $task->getAppId(), + 'identifier' => $task->getIdentifier(), + 'completionExpectedAt' => $task->getCompletionExpectedAt(), + ]); + return $dbTask; + } + + public function toPublicTask(): OCPTask { + $task = new OCPTask($this->getInput(), $this->getAppId(), $this->getNumberOfImages(), $this->getuserId(), $this->getIdentifier()); + $task->setId($this->getId()); + $task->setStatus($this->getStatus()); + $task->setCompletionExpectedAt($this->getCompletionExpectedAt()); + return $task; + } +} diff --git a/lib/private/TextToImage/Db/TaskMapper.php b/lib/private/TextToImage/Db/TaskMapper.php new file mode 100644 index 00000000000..68fdd8f40de --- /dev/null +++ b/lib/private/TextToImage/Db/TaskMapper.php @@ -0,0 +1,127 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OC\TextToImage\Db; + +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Db\QBMapper; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\DB\Exception; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +/** + * @extends QBMapper<Task> + */ +class TaskMapper extends QBMapper { + public function __construct( + IDBConnection $db, + private ITimeFactory $timeFactory, + ) { + parent::__construct($db, 'text2image_tasks', Task::class); + } + + /** + * @param int $id + * @return Task + * @throws Exception + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + */ + public function find(int $id): Task { + $qb = $this->db->getQueryBuilder(); + $qb->select(Task::$columns) + ->from($this->tableName) + ->where($qb->expr()->eq('id', $qb->createPositionalParameter($id))); + return $this->findEntity($qb); + } + + /** + * @param int $id + * @param string|null $userId + * @return Task + * @throws DoesNotExistException + * @throws Exception + * @throws MultipleObjectsReturnedException + */ + public function findByIdAndUser(int $id, ?string $userId): Task { + $qb = $this->db->getQueryBuilder(); + $qb->select(Task::$columns) + ->from($this->tableName) + ->where($qb->expr()->eq('id', $qb->createPositionalParameter($id))); + if ($userId === null) { + $qb->andWhere($qb->expr()->isNull('user_id')); + } else { + $qb->andWhere($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId))); + } + return $this->findEntity($qb); + } + + /** + * @param string $userId + * @param string $appId + * @param string|null $identifier + * @return array + * @throws Exception + */ + public function findUserTasksByApp(?string $userId, string $appId, ?string $identifier = null): array { + $qb = $this->db->getQueryBuilder(); + $qb->select(Task::$columns) + ->from($this->tableName) + ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId))) + ->andWhere($qb->expr()->eq('app_id', $qb->createPositionalParameter($appId))); + if ($identifier !== null) { + $qb->andWhere($qb->expr()->eq('identifier', $qb->createPositionalParameter($identifier))); + } + return $this->findEntities($qb); + } + + /** + * @param int $timeout + * @return Task[] the deleted tasks + * @throws Exception + */ + public function deleteOlderThan(int $timeout): array { + $datetime = $this->timeFactory->getDateTime(); + $datetime->sub(new \DateInterval('PT'.$timeout.'S')); + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->tableName) + ->where($qb->expr()->lt('last_updated', $qb->createPositionalParameter($datetime, IQueryBuilder::PARAM_DATE))); + $deletedTasks = $this->findEntities($qb); + $qb = $this->db->getQueryBuilder(); + $qb->delete($this->tableName) + ->where($qb->expr()->lt('last_updated', $qb->createPositionalParameter($datetime, IQueryBuilder::PARAM_DATE))); + $qb->executeStatement(); + return $deletedTasks; + } + + public function update(Entity $entity): Entity { + $entity->setLastUpdated($this->timeFactory->getDateTime()); + return parent::update($entity); + } +} diff --git a/lib/private/TextToImage/Manager.php b/lib/private/TextToImage/Manager.php new file mode 100644 index 00000000000..b549f386b6a --- /dev/null +++ b/lib/private/TextToImage/Manager.php @@ -0,0 +1,341 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OC\TextToImage; + +use OC\AppFramework\Bootstrap\Coordinator; +use OC\TextToImage\Db\Task as DbTask; +use OC\TextToImage\Db\TaskMapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\BackgroundJob\IJobList; +use OCP\DB\Exception; +use OCP\Files\AppData\IAppDataFactory; +use OCP\Files\IAppData; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; +use OCP\IConfig; +use OCP\IServerContainer; +use OCP\PreConditionNotMetException; +use OCP\TextToImage\Exception\TaskFailureException; +use OCP\TextToImage\Exception\TaskNotFoundException; +use OCP\TextToImage\IManager; +use OCP\TextToImage\IProvider; +use OCP\TextToImage\IProviderWithUserId; +use OCP\TextToImage\Task; +use Psr\Log\LoggerInterface; +use RuntimeException; +use Throwable; + +class Manager implements IManager { + /** @var ?list<IProvider> */ + private ?array $providers = null; + private IAppData $appData; + + public function __construct( + private IServerContainer $serverContainer, + private Coordinator $coordinator, + private LoggerInterface $logger, + private IJobList $jobList, + private TaskMapper $taskMapper, + private IConfig $config, + IAppDataFactory $appDataFactory, + ) { + $this->appData = $appDataFactory->get('core'); + } + + /** + * @inheritDoc + */ + public function getProviders(): array { + $context = $this->coordinator->getRegistrationContext(); + if ($context === null) { + return []; + } + + if ($this->providers !== null) { + return $this->providers; + } + + $this->providers = []; + + foreach ($context->getTextToImageProviders() as $providerServiceRegistration) { + $class = $providerServiceRegistration->getService(); + try { + /** @var IProvider $provider */ + $provider = $this->serverContainer->get($class); + $this->providers[] = $provider; + } catch (Throwable $e) { + $this->logger->error('Failed to load Text to image provider ' . $class, [ + 'exception' => $e, + ]); + } + } + + return $this->providers; + } + + /** + * @inheritDoc + */ + public function hasProviders(): bool { + $context = $this->coordinator->getRegistrationContext(); + if ($context === null) { + return false; + } + return count($context->getTextToImageProviders()) > 0; + } + + /** + * @inheritDoc + */ + public function runTask(Task $task): void { + $this->logger->debug('Running TextToImage Task'); + if (!$this->hasProviders()) { + throw new PreConditionNotMetException('No text to image provider is installed that can handle this task'); + } + $providers = $this->getPreferredProviders(); + + foreach ($providers as $provider) { + $this->logger->debug('Trying to run Text2Image provider '.$provider::class); + try { + $task->setStatus(Task::STATUS_RUNNING); + $completionExpectedAt = new \DateTime('now'); + $completionExpectedAt->add(new \DateInterval('PT'.$provider->getExpectedRuntime().'S')); + $task->setCompletionExpectedAt($completionExpectedAt); + if ($task->getId() === null) { + $this->logger->debug('Inserting Text2Image task into DB'); + $taskEntity = $this->taskMapper->insert(DbTask::fromPublicTask($task)); + $task->setId($taskEntity->getId()); + } else { + $this->logger->debug('Updating Text2Image task in DB'); + $this->taskMapper->update(DbTask::fromPublicTask($task)); + } + try { + $folder = $this->appData->getFolder('text2image'); + } catch(NotFoundException) { + $this->logger->debug('Creating folder in appdata for Text2Image results'); + $folder = $this->appData->newFolder('text2image'); + } + try { + $folder = $folder->getFolder((string) $task->getId()); + } catch(NotFoundException) { + $this->logger->debug('Creating new folder in appdata Text2Image results folder'); + $folder = $folder->newFolder((string) $task->getId()); + } + $this->logger->debug('Creating result files for Text2Image task'); + $resources = []; + $files = []; + for ($i = 0; $i < $task->getNumberOfImages(); $i++) { + $file = $folder->newFile((string) $i); + $files[] = $file; + $resource = $file->write(); + if ($resource !== false && $resource !== true && is_resource($resource)) { + $resources[] = $resource; + } else { + throw new RuntimeException('Text2Image generation using provider "' . $provider->getName() . '" failed: Couldn\'t open file to write.'); + } + } + $this->logger->debug('Calling Text2Image provider\'s generate method'); + if ($provider instanceof IProviderWithUserId) { + $provider->setUserId($task->getUserId()); + } + $provider->generate($task->getInput(), $resources); + for ($i = 0; $i < $task->getNumberOfImages(); $i++) { + if (is_resource($resources[$i])) { + // If $resource hasn't been closed yet, we'll do that here + fclose($resources[$i]); + } + } + $task->setStatus(Task::STATUS_SUCCESSFUL); + $this->logger->debug('Updating Text2Image task in DB'); + $this->taskMapper->update(DbTask::fromPublicTask($task)); + return; + } catch (\RuntimeException|\Throwable $e) { + for ($i = 0; $i < $task->getNumberOfImages(); $i++) { + if (isset($files, $files[$i])) { + try { + $files[$i]->delete(); + } catch(NotPermittedException $e) { + $this->logger->warning('Failed to clean up Text2Image result file after error', ['exception' => $e]); + } + } + } + + $this->logger->info('Text2Image generation using provider "' . $provider->getName() . '" failed', ['exception' => $e]); + $task->setStatus(Task::STATUS_FAILED); + try { + $this->taskMapper->update(DbTask::fromPublicTask($task)); + } catch (Exception $e) { + $this->logger->warning('Failed to update database after Text2Image error', ['exception' => $e]); + } + throw new TaskFailureException('Text2Image generation using provider "' . $provider->getName() . '" failed: ' . $e->getMessage(), 0, $e); + } + } + + $task->setStatus(Task::STATUS_FAILED); + try { + $this->taskMapper->update(DbTask::fromPublicTask($task)); + } catch (Exception $e) { + $this->logger->warning('Failed to update database after Text2Image error', ['exception' => $e]); + } + throw new TaskFailureException('Could not run task'); + } + + /** + * @inheritDoc + */ + public function scheduleTask(Task $task): void { + if (!$this->hasProviders()) { + throw new PreConditionNotMetException('No text to image provider is installed that can handle this task'); + } + $this->logger->debug('Scheduling Text2Image Task'); + $task->setStatus(Task::STATUS_SCHEDULED); + $completionExpectedAt = new \DateTime('now'); + $completionExpectedAt->add(new \DateInterval('PT'.$this->getPreferredProviders()[0]->getExpectedRuntime().'S')); + $task->setCompletionExpectedAt($completionExpectedAt); + $taskEntity = DbTask::fromPublicTask($task); + $this->taskMapper->insert($taskEntity); + $task->setId($taskEntity->getId()); + $this->jobList->add(TaskBackgroundJob::class, [ + 'taskId' => $task->getId() + ]); + } + + /** + * @inheritDoc + */ + public function runOrScheduleTask(Task $task) : void { + if (!$this->hasProviders()) { + throw new PreConditionNotMetException('No text to image provider is installed that can handle this task'); + } + $providers = $this->getPreferredProviders(); + $maxExecutionTime = (int) ini_get('max_execution_time'); + // Offload the task to a background job if the expected runtime of the likely provider is longer than 80% of our max execution time + if ($providers[0]->getExpectedRuntime() > $maxExecutionTime * 0.8) { + $this->scheduleTask($task); + return; + } + $this->runTask($task); + } + + /** + * @inheritDoc + */ + public function deleteTask(Task $task): void { + $taskEntity = DbTask::fromPublicTask($task); + $this->taskMapper->delete($taskEntity); + $this->jobList->remove(TaskBackgroundJob::class, [ + 'taskId' => $task->getId() + ]); + } + + /** + * Get a task from its id + * + * @param int $id The id of the task + * @return Task + * @throws RuntimeException If the query failed + * @throws TaskNotFoundException If the task could not be found + */ + public function getTask(int $id): Task { + try { + $taskEntity = $this->taskMapper->find($id); + return $taskEntity->toPublicTask(); + } catch (DoesNotExistException $e) { + throw new TaskNotFoundException('Could not find task with the provided id'); + } catch (MultipleObjectsReturnedException $e) { + throw new RuntimeException('Could not uniquely identify task with given id', 0, $e); + } catch (Exception $e) { + throw new RuntimeException('Failure while trying to find task by id: ' . $e->getMessage(), 0, $e); + } + } + + /** + * Get a task from its user id and task id + * If userId is null, this can only get a task that was scheduled anonymously + * + * @param int $id The id of the task + * @param string|null $userId The user id that scheduled the task + * @return Task + * @throws RuntimeException If the query failed + * @throws TaskNotFoundException If the task could not be found + */ + public function getUserTask(int $id, ?string $userId): Task { + try { + $taskEntity = $this->taskMapper->findByIdAndUser($id, $userId); + return $taskEntity->toPublicTask(); + } catch (DoesNotExistException $e) { + throw new TaskNotFoundException('Could not find task with the provided id and user id'); + } catch (MultipleObjectsReturnedException $e) { + throw new RuntimeException('Could not uniquely identify task with given id and user id', 0, $e); + } catch (Exception $e) { + throw new RuntimeException('Failure while trying to find task by id and user id: ' . $e->getMessage(), 0, $e); + } + } + + /** + * Get a list of tasks scheduled by a specific user for a specific app + * and optionally with a specific identifier. + * This cannot be used to get anonymously scheduled tasks + * + * @param string $userId + * @param string $appId + * @param string|null $identifier + * @return Task[] + * @throws RuntimeException + */ + public function getUserTasksByApp(?string $userId, string $appId, ?string $identifier = null): array { + try { + $taskEntities = $this->taskMapper->findUserTasksByApp($userId, $appId, $identifier); + return array_map(static function (DbTask $taskEntity) { + return $taskEntity->toPublicTask(); + }, $taskEntities); + } catch (Exception $e) { + throw new RuntimeException('Failure while trying to find tasks by appId and identifier: ' . $e->getMessage(), 0, $e); + } + } + + /** + * @return list<IProvider> + */ + private function getPreferredProviders() { + $providers = $this->getProviders(); + $json = $this->config->getAppValue('core', 'ai.text2image_provider', ''); + if ($json !== '') { + try { + $id = json_decode($json, true, 512, JSON_THROW_ON_ERROR); + $provider = current(array_filter($providers, fn ($provider) => $provider->getId() === $id)); + if ($provider !== false && $provider !== null) { + $providers = [$provider]; + } + } catch (\JsonException $e) { + $this->logger->warning('Failed to decode Text2Image setting `ai.text2image_provider`', ['exception' => $e]); + } + } + + return $providers; + } +} diff --git a/lib/private/TextToImage/RemoveOldTasksBackgroundJob.php b/lib/private/TextToImage/RemoveOldTasksBackgroundJob.php new file mode 100644 index 00000000000..2ecebc241bf --- /dev/null +++ b/lib/private/TextToImage/RemoveOldTasksBackgroundJob.php @@ -0,0 +1,78 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +namespace OC\TextToImage; + +use OC\TextToImage\Db\TaskMapper; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\TimedJob; +use OCP\DB\Exception; +use OCP\Files\AppData\IAppDataFactory; +use OCP\Files\IAppData; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; +use Psr\Log\LoggerInterface; + +class RemoveOldTasksBackgroundJob extends TimedJob { + public const MAX_TASK_AGE_SECONDS = 60 * 50 * 24 * 7; // 1 week + + private IAppData $appData; + + public function __construct( + ITimeFactory $timeFactory, + private TaskMapper $taskMapper, + private LoggerInterface $logger, + IAppDataFactory $appDataFactory, + ) { + parent::__construct($timeFactory); + $this->appData = $appDataFactory->get('core'); + $this->setInterval(60 * 60 * 24); + } + + /** + * @param mixed $argument + * @inheritDoc + */ + protected function run($argument) { + try { + $deletedTasks = $this->taskMapper->deleteOlderThan(self::MAX_TASK_AGE_SECONDS); + $folder = $this->appData->getFolder('text2image'); + foreach ($deletedTasks as $deletedTask) { + try { + $folder->getFolder((string)$deletedTask->getId())->delete(); + } catch (NotFoundException) { + // noop + } catch (NotPermittedException $e) { + $this->logger->warning('Failed to delete stale text to image task files', ['exception' => $e]); + } + } + } catch (Exception $e) { + $this->logger->warning('Failed to delete stale text to image tasks', ['exception' => $e]); + } catch(NotFoundException) { + // noop + } + } +} diff --git a/lib/private/TextToImage/TaskBackgroundJob.php b/lib/private/TextToImage/TaskBackgroundJob.php new file mode 100644 index 00000000000..ac5cd6b59b5 --- /dev/null +++ b/lib/private/TextToImage/TaskBackgroundJob.php @@ -0,0 +1,63 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +namespace OC\TextToImage; + +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\QueuedJob; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\TextToImage\Events\TaskFailedEvent; +use OCP\TextToImage\Events\TaskSuccessfulEvent; +use OCP\TextToImage\IManager; + +class TaskBackgroundJob extends QueuedJob { + public function __construct( + ITimeFactory $timeFactory, + private IManager $text2imageManager, + private IEventDispatcher $eventDispatcher, + ) { + parent::__construct($timeFactory); + // We want to avoid overloading the machine with these jobs + // so we only allow running one job at a time + $this->setAllowParallelRuns(false); + } + + /** + * @param array{taskId: int} $argument + * @inheritDoc + */ + protected function run($argument) { + $taskId = $argument['taskId']; + $task = $this->text2imageManager->getTask($taskId); + try { + $this->text2imageManager->runTask($task); + $event = new TaskSuccessfulEvent($task); + } catch (\Throwable $e) { + $event = new TaskFailedEvent($task, $e->getMessage()); + } + $this->eventDispatcher->dispatchTyped($event); + } +} diff --git a/lib/private/Translation/TranslationManager.php b/lib/private/Translation/TranslationManager.php index 48a0e2cdebd..306275121ea 100644 --- a/lib/private/Translation/TranslationManager.php +++ b/lib/private/Translation/TranslationManager.php @@ -30,11 +30,14 @@ use InvalidArgumentException; use OC\AppFramework\Bootstrap\Coordinator; use OCP\IConfig; use OCP\IServerContainer; +use OCP\IUserSession; use OCP\PreConditionNotMetException; use OCP\Translation\CouldNotTranslateException; use OCP\Translation\IDetectLanguageProvider; use OCP\Translation\ITranslationManager; use OCP\Translation\ITranslationProvider; +use OCP\Translation\ITranslationProviderWithId; +use OCP\Translation\ITranslationProviderWithUserId; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use Psr\Log\LoggerInterface; @@ -50,6 +53,7 @@ class TranslationManager implements ITranslationManager { private Coordinator $coordinator, private LoggerInterface $logger, private IConfig $config, + private IUserSession $userSession, ) { } @@ -73,19 +77,26 @@ class TranslationManager implements ITranslationManager { $precedence = json_decode($json, true); $newProviders = []; foreach ($precedence as $className) { - $provider = current(array_filter($providers, fn ($provider) => $provider::class === $className)); + $provider = current(array_filter($providers, function ($provider) use ($className) { + return $provider instanceof ITranslationProviderWithId ? $provider->getId() === $className : $provider::class === $className; + })); if ($provider !== false) { $newProviders[] = $provider; } } // Add all providers that haven't been added so far - $newProviders += array_udiff($providers, $newProviders, fn ($a, $b) => $a::class > $b::class ? 1 : ($a::class < $b::class ? -1 : 0)); + $newProviders += array_udiff($providers, $newProviders, function ($a, $b) { + return ($a instanceof ITranslationProviderWithId ? $a->getId() : $a::class) <=> ($b instanceof ITranslationProviderWithId ? $b->getId() : $b::class); + }); $providers = $newProviders; } if ($fromLanguage === null) { foreach ($providers as $provider) { if ($provider instanceof IDetectLanguageProvider) { + if ($provider instanceof ITranslationProviderWithUserId) { + $provider->setUserId($this->userSession->getUser()?->getUID()); + } $fromLanguage = $provider->detectLanguage($text); } @@ -105,6 +116,9 @@ class TranslationManager implements ITranslationManager { foreach ($providers as $provider) { try { + if ($provider instanceof ITranslationProviderWithUserId) { + $provider->setUserId($this->userSession->getUser()?->getUID()); + } return $provider->translate($fromLanguage, $toLanguage, $text); } catch (RuntimeException $e) { $this->logger->warning("Failed to translate from {$fromLanguage} to {$toLanguage} using provider {$provider->getName()}", ['exception' => $e]); diff --git a/lib/private/URLGenerator.php b/lib/private/URLGenerator.php index 3a52b99889c..3d384de5842 100644 --- a/lib/private/URLGenerator.php +++ b/lib/private/URLGenerator.php @@ -70,10 +70,10 @@ class URLGenerator implements IURLGenerator { private ?IAppManager $appManager = null; public function __construct(IConfig $config, - IUserSession $userSession, - ICacheFactory $cacheFactory, - IRequest $request, - Router $router + IUserSession $userSession, + ICacheFactory $cacheFactory, + IRequest $request, + Router $router ) { $this->config = $config; $this->userSession = $userSession; @@ -116,16 +116,25 @@ class URLGenerator implements IURLGenerator { } public function linkToOCSRouteAbsolute(string $routeName, array $arguments = []): string { + // Returns `/subfolder/index.php/ocsapp/…` with `'htaccess.IgnoreFrontController' => false` in config.php + // And `/subfolder/ocsapp/…` with `'htaccess.IgnoreFrontController' => true` in config.php $route = $this->router->generate('ocs.'.$routeName, $arguments, false); - $indexPhpPos = strpos($route, '/index.php/'); - if ($indexPhpPos !== false) { - $route = substr($route, $indexPhpPos + 10); + // Cut off `/subfolder` + if (\OC::$WEBROOT !== '' && str_starts_with($route, \OC::$WEBROOT)) { + $route = substr($route, \strlen(\OC::$WEBROOT)); } + if (str_starts_with($route, '/index.php/')) { + $route = substr($route, 10); + } + + // Remove `ocsapp/` bit $route = substr($route, 7); + // Prefix with ocs/v2.php endpoint $route = '/ocs/v2.php' . $route; + // Turn into an absolute URL return $this->getAbsoluteURL($route); } @@ -147,7 +156,7 @@ class URLGenerator implements IURLGenerator { $app_path = $this->getAppManager()->getAppPath($appName); // Check if the app is in the app folder if (file_exists($app_path . '/' . $file)) { - if (substr($file, -3) === 'php') { + if (str_ends_with($file, 'php')) { $urlLinkTo = \OC::$WEBROOT . '/index.php/apps/' . $appName; if ($frontControllerActive) { $urlLinkTo = \OC::$WEBROOT . '/apps/' . $appName; diff --git a/lib/private/Updater.php b/lib/private/Updater.php index 5a14bb17507..09866273bb3 100644 --- a/lib/private/Updater.php +++ b/lib/private/Updater.php @@ -40,14 +40,8 @@ declare(strict_types=1); */ namespace OC; -use OCP\App\IAppManager; -use OCP\EventDispatcher\Event; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\HintException; -use OCP\IConfig; -use OCP\ILogger; -use OCP\Util; use OC\App\AppManager; +use OC\App\AppStore\Fetcher\AppFetcher; use OC\DB\Connection; use OC\DB\MigrationService; use OC\DB\MigratorExecuteSqlEvent; @@ -61,6 +55,14 @@ use OC\Repair\Events\RepairStartEvent; use OC\Repair\Events\RepairStepEvent; use OC\Repair\Events\RepairWarningEvent; use OC_App; +use OCP\App\IAppManager; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\HintException; +use OCP\IAppConfig; +use OCP\IConfig; +use OCP\ILogger; +use OCP\Util; use Psr\Log\LoggerInterface; /** @@ -73,19 +75,7 @@ use Psr\Log\LoggerInterface; * - failure(string $message) */ class Updater extends BasicEmitter { - /** @var LoggerInterface */ - private $log; - - /** @var IConfig */ - private $config; - - /** @var Checker */ - private $checker; - - /** @var Installer */ - private $installer; - - private $logLevelNames = [ + private array $logLevelNames = [ 0 => 'Debug', 1 => 'Info', 2 => 'Warning', @@ -93,14 +83,13 @@ class Updater extends BasicEmitter { 4 => 'Fatal', ]; - public function __construct(IConfig $config, - Checker $checker, - ?LoggerInterface $log, - Installer $installer) { - $this->log = $log; - $this->config = $config; - $this->checker = $checker; - $this->installer = $installer; + public function __construct( + private IConfig $config, + private IAppConfig $appConfig, + private Checker $checker, + private ?LoggerInterface $log, + private Installer $installer + ) { } /** @@ -255,7 +244,8 @@ class Updater extends BasicEmitter { file_put_contents($this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); // pre-upgrade repairs - $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->get(\OCP\EventDispatcher\IEventDispatcher::class), \OC::$server->get(LoggerInterface::class)); + $repair = \OCP\Server::get(Repair::class); + $repair->setRepairSteps(Repair::getBeforeUpgradeRepairSteps()); $repair->run(); $this->doCoreUpgrade(); @@ -272,7 +262,7 @@ class Updater extends BasicEmitter { $this->doAppUpgrade(); // Update the appfetchers version so it downloads the correct list from the appstore - \OC::$server->getAppFetcher()->setVersion($currentVersion); + \OC::$server->get(AppFetcher::class)->setVersion($currentVersion); /** @var AppManager $appManager */ $appManager = \OC::$server->getAppManager(); @@ -296,11 +286,12 @@ class Updater extends BasicEmitter { } // post-upgrade repairs - $repair = new Repair(Repair::getRepairSteps(), \OC::$server->get(\OCP\EventDispatcher\IEventDispatcher::class), \OC::$server->get(LoggerInterface::class)); + $repair = \OCP\Server::get(Repair::class); + $repair->setRepairSteps(Repair::getRepairSteps()); $repair->run(); //Invalidate update feed - $this->config->setAppValue('core', 'lastupdatedat', '0'); + $this->appConfig->setValueInt('core', 'lastupdatedat', 0); // Check for code integrity if not disabled if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) { diff --git a/lib/private/Updater/VersionCheck.php b/lib/private/Updater/VersionCheck.php index 2aab260716a..01022067d87 100644 --- a/lib/private/Updater/VersionCheck.php +++ b/lib/private/Updater/VersionCheck.php @@ -27,17 +27,21 @@ namespace OC\Updater; use OCP\Http\Client\IClientService; +use OCP\IAppConfig; use OCP\IConfig; use OCP\IUserManager; use OCP\Support\Subscription\IRegistry; use OCP\Util; +use Psr\Log\LoggerInterface; class VersionCheck { public function __construct( private IClientService $clientService, private IConfig $config, + private IAppConfig $appConfig, private IUserManager $userManager, private IRegistry $registry, + private LoggerInterface $logger, ) { } @@ -54,13 +58,13 @@ class VersionCheck { } // Look up the cache - it is invalidated all 30 minutes - if (((int)$this->config->getAppValue('core', 'lastupdatedat') + 1800) > time()) { + if (($this->appConfig->getValueInt('core', 'lastupdatedat') + 1800) > time()) { return json_decode($this->config->getAppValue('core', 'lastupdateResult'), true); } $updaterUrl = $this->config->getSystemValueString('updater.server.url', 'https://updates.nextcloud.com/updater_server/'); - $this->config->setAppValue('core', 'lastupdatedat', (string)time()); + $this->appConfig->setValueInt('core', 'lastupdatedat', time()); if ($this->config->getAppValue('core', 'installedat', '') === '') { $this->config->setAppValue('core', 'installedat', (string)microtime(true)); @@ -68,7 +72,7 @@ class VersionCheck { $version = Util::getVersion(); $version['installed'] = $this->config->getAppValue('core', 'installedat'); - $version['updated'] = $this->config->getAppValue('core', 'lastupdatedat'); + $version['updated'] = $this->appConfig->getValueInt('core', 'lastupdatedat'); $version['updatechannel'] = \OC_Util::getChannel(); $version['edition'] = ''; $version['build'] = \OC_Util::getBuild(); @@ -86,6 +90,8 @@ class VersionCheck { try { $xml = $this->getUrlContent($url); } catch (\Exception $e) { + $this->logger->info('Version could not be fetched from updater server: ' . $url, ['exception' => $e]); + return false; } @@ -123,7 +129,9 @@ class VersionCheck { */ protected function getUrlContent($url) { $client = $this->clientService->newClient(); - $response = $client->get($url); + $response = $client->get($url, [ + 'timeout' => 5, + ]); return $response->getBody(); } diff --git a/lib/private/User/AvailabilityCoordinator.php b/lib/private/User/AvailabilityCoordinator.php new file mode 100644 index 00000000000..c32c3005c32 --- /dev/null +++ b/lib/private/User/AvailabilityCoordinator.php @@ -0,0 +1,139 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * @author Richard Steinmetz <richard@steinmetz.cloud> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OC\User; + +use JsonException; +use OCA\DAV\AppInfo\Application; +use OCA\DAV\CalDAV\TimezoneService; +use OCA\DAV\Service\AbsenceService; +use OCP\ICache; +use OCP\ICacheFactory; +use OCP\IConfig; +use OCP\IUser; +use OCP\User\IAvailabilityCoordinator; +use OCP\User\IOutOfOfficeData; +use Psr\Log\LoggerInterface; + +class AvailabilityCoordinator implements IAvailabilityCoordinator { + private ICache $cache; + + public function __construct( + ICacheFactory $cacheFactory, + private IConfig $config, + private AbsenceService $absenceService, + private LoggerInterface $logger, + private TimezoneService $timezoneService, + ) { + $this->cache = $cacheFactory->createLocal('OutOfOfficeData'); + } + + public function isEnabled(): bool { + return $this->config->getAppValue(Application::APP_ID, 'hide_absence_settings', 'no') === 'no'; + } + + private function getCachedOutOfOfficeData(IUser $user): ?OutOfOfficeData { + $cachedString = $this->cache->get($user->getUID()); + if ($cachedString === null) { + return null; + } + + try { + $cachedData = json_decode($cachedString, true, 10, JSON_THROW_ON_ERROR); + } catch (JsonException $e) { + $this->logger->error('Failed to deserialize cached out-of-office data: ' . $e->getMessage(), [ + 'exception' => $e, + 'json' => $cachedString, + ]); + return null; + } + + return new OutOfOfficeData( + $cachedData['id'], + $user, + $cachedData['startDate'], + $cachedData['endDate'], + $cachedData['shortMessage'], + $cachedData['message'], + ); + } + + private function setCachedOutOfOfficeData(IOutOfOfficeData $data): void { + try { + $cachedString = json_encode([ + 'id' => $data->getId(), + 'startDate' => $data->getStartDate(), + 'endDate' => $data->getEndDate(), + 'shortMessage' => $data->getShortMessage(), + 'message' => $data->getMessage(), + ], JSON_THROW_ON_ERROR); + } catch (JsonException $e) { + $this->logger->error('Failed to serialize out-of-office data: ' . $e->getMessage(), [ + 'exception' => $e, + ]); + return; + } + + $this->cache->set($data->getUser()->getUID(), $cachedString, 300); + } + + public function getCurrentOutOfOfficeData(IUser $user): ?IOutOfOfficeData { + $timezone = $this->getCachedTimezone($user->getUID()); + if ($timezone === null) { + $timezone = $this->timezoneService->getUserTimezone($user->getUID()) ?? $this->timezoneService->getDefaultTimezone(); + $this->setCachedTimezone($user->getUID(), $timezone); + } + + $data = $this->getCachedOutOfOfficeData($user); + if ($data === null) { + $absenceData = $this->absenceService->getAbsence($user->getUID()); + if ($absenceData === null) { + return null; + } + $data = $absenceData->toOutOufOfficeData($user, $timezone); + } + + $this->setCachedOutOfOfficeData($data); + return $data; + } + + private function getCachedTimezone(string $userId): ?string { + return $this->cache->get($userId . '_timezone') ?? null; + } + + private function setCachedTimezone(string $userId, string $timezone): void { + $this->cache->set($userId . '_timezone', $timezone, 3600); + } + + public function clearCache(string $userId): void { + $this->cache->set($userId, null, 300); + $this->cache->set($userId . '_timezone', null, 3600); + } + + public function isInEffect(IOutOfOfficeData $data): bool { + return $this->absenceService->isInEffect($data); + } +} diff --git a/lib/private/User/DisplayNameCache.php b/lib/private/User/DisplayNameCache.php index 6ee74cc9f6c..a3bc69646a1 100644 --- a/lib/private/User/DisplayNameCache.php +++ b/lib/private/User/DisplayNameCache.php @@ -37,6 +37,7 @@ use OCP\User\Events\UserDeletedEvent; * This saves fetching the user from a user backend and later on fetching * their preferences. It's generally not an issue if this data is slightly * outdated. + * @template-implements IEventListener<UserChangedEvent|UserDeletedEvent> */ class DisplayNameCache implements IEventListener { private array $cache = []; diff --git a/lib/private/User/Listeners/BeforeUserDeletedListener.php b/lib/private/User/Listeners/BeforeUserDeletedListener.php index ec1f80c5413..8978c341a13 100644 --- a/lib/private/User/Listeners/BeforeUserDeletedListener.php +++ b/lib/private/User/Listeners/BeforeUserDeletedListener.php @@ -25,9 +25,9 @@ namespace OC\User\Listeners; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; -use OCP\User\Events\BeforeUserDeletedEvent; use OCP\Files\NotFoundException; use OCP\IAvatarManager; +use OCP\User\Events\BeforeUserDeletedEvent; use Psr\Log\LoggerInterface; /** diff --git a/lib/private/User/Listeners/UserChangedListener.php b/lib/private/User/Listeners/UserChangedListener.php index a561db2423d..0fa5ceeb0ed 100644 --- a/lib/private/User/Listeners/UserChangedListener.php +++ b/lib/private/User/Listeners/UserChangedListener.php @@ -25,9 +25,9 @@ namespace OC\User\Listeners; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; -use OCP\User\Events\UserChangedEvent; use OCP\Files\NotFoundException; use OCP\IAvatarManager; +use OCP\User\Events\UserChangedEvent; /** * @template-implements IEventListener<UserChangedEvent> diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index fb1afb65825..66a9529483e 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -48,13 +48,15 @@ use OCP\IUserManager; use OCP\L10N\IFactory; use OCP\Server; use OCP\Support\Subscription\IAssertion; -use OCP\User\Backend\IGetRealUIDBackend; -use OCP\User\Backend\ISearchKnownUsersBackend; use OCP\User\Backend\ICheckPasswordBackend; use OCP\User\Backend\ICountUsersBackend; +use OCP\User\Backend\IGetRealUIDBackend; +use OCP\User\Backend\IProvideEnabledStateBackend; +use OCP\User\Backend\ISearchKnownUsersBackend; use OCP\User\Events\BeforeUserCreatedEvent; use OCP\User\Events\UserCreatedEvent; use OCP\UserInterface; +use Psr\Log\LoggerInterface; /** * Class Manager @@ -96,8 +98,8 @@ class Manager extends PublicEmitter implements IUserManager { private DisplayNameCache $displayNameCache; public function __construct(IConfig $config, - ICacheFactory $cacheFactory, - IEventDispatcher $eventDispatcher) { + ICacheFactory $cacheFactory, + IEventDispatcher $eventDispatcher) { $this->config = $config; $this->cache = new WithLocalCache($cacheFactory->createDistributed('user_backend_map')); $cachedUsers = &$this->cachedUsers; @@ -234,7 +236,7 @@ class Manager extends PublicEmitter implements IUserManager { $result = $this->checkPasswordNoLogging($loginName, $password); if ($result === false) { - \OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']); + \OCP\Server::get(LoggerInterface::class)->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']); } return $result; @@ -338,6 +340,35 @@ class Manager extends PublicEmitter implements IUserManager { } /** + * @return IUser[] + */ + public function getDisabledUsers(?int $limit = null, int $offset = 0): array { + $users = $this->config->getUsersForUserValue('core', 'enabled', 'false'); + $users = array_combine( + $users, + array_map( + fn (string $uid): IUser => new LazyUser($uid, $this), + $users + ) + ); + + $tempLimit = ($limit === null ? null : $limit + $offset); + foreach ($this->backends as $backend) { + if (($tempLimit !== null) && (count($users) >= $tempLimit)) { + break; + } + if ($backend instanceof IProvideEnabledStateBackend) { + $backendUsers = $backend->getDisabledUserList(($tempLimit === null ? null : $tempLimit - count($users))); + foreach ($backendUsers as $uid) { + $users[$uid] = new LazyUser($uid, $this, null, $backend); + } + } + } + + return array_slice($users, $offset, $limit); + } + + /** * Search known users (from phonebook sync) by displayName * * @param string $searcher @@ -415,7 +446,7 @@ class Manager extends PublicEmitter implements IUserManager { * @throws \InvalidArgumentException */ public function createUserFromBackend($uid, $password, UserInterface $backend) { - $l = \OC::$server->getL10N('lib'); + $l = \OCP\Util::getL10N('lib'); $this->validateUserId($uid, true); @@ -426,7 +457,7 @@ class Manager extends PublicEmitter implements IUserManager { // Check if user already exists if ($this->userExists($uid)) { - throw new \InvalidArgumentException($l->t('The username is already being used')); + throw new \InvalidArgumentException($l->t('The Login is already being used')); } /** @deprecated 21.0.0 use BeforeUserCreatedEvent event with the IEventDispatcher instead */ @@ -434,7 +465,7 @@ class Manager extends PublicEmitter implements IUserManager { $this->eventDispatcher->dispatchTyped(new BeforeUserCreatedEvent($uid, $password)); $state = $backend->createUser($uid, $password); if ($state === false) { - throw new \InvalidArgumentException($l->t('Could not create user')); + throw new \InvalidArgumentException($l->t('Could not create account')); } $user = $this->getUserObject($uid, $backend); if ($user instanceof IUser) { @@ -704,27 +735,27 @@ class Manager extends PublicEmitter implements IUserManager { // Check the name for bad characters // Allowed are: "a-z", "A-Z", "0-9", spaces and "_.@-'" if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) { - throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:' + throw new \InvalidArgumentException($l->t('Only the following characters are allowed in an Login:' . ' "a-z", "A-Z", "0-9", spaces and "_.@-\'"')); } // No empty username if (trim($uid) === '') { - throw new \InvalidArgumentException($l->t('A valid username must be provided')); + throw new \InvalidArgumentException($l->t('A valid Login must be provided')); } // No whitespace at the beginning or at the end if (trim($uid) !== $uid) { - throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end')); + throw new \InvalidArgumentException($l->t('Login contains whitespace at the beginning or at the end')); } // Username only consists of 1 or 2 dots (directory traversal) if ($uid === '.' || $uid === '..') { - throw new \InvalidArgumentException($l->t('Username must not consist of dots only')); + throw new \InvalidArgumentException($l->t('Login must not consist of dots only')); } if (!$this->verifyUid($uid, $checkDataDirectory)) { - throw new \InvalidArgumentException($l->t('Username is invalid because files already exist for this user')); + throw new \InvalidArgumentException($l->t('Login is invalid because files already exist for this user')); } } diff --git a/lib/private/User/OutOfOfficeData.php b/lib/private/User/OutOfOfficeData.php new file mode 100644 index 00000000000..72e42afab6a --- /dev/null +++ b/lib/private/User/OutOfOfficeData.php @@ -0,0 +1,74 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OC\User; + +use OCP\IUser; +use OCP\User\IOutOfOfficeData; + +class OutOfOfficeData implements IOutOfOfficeData { + public function __construct(private string $id, + private IUser $user, + private int $startDate, + private int $endDate, + private string $shortMessage, + private string $message) { + } + + public function getId(): string { + return $this->id; + } + + public function getUser(): IUser { + return $this->user; + } + + public function getStartDate(): int { + return $this->startDate; + } + + public function getEndDate(): int { + return $this->endDate; + } + + public function getShortMessage(): string { + return $this->shortMessage; + } + + public function getMessage(): string { + return $this->message; + } + + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'userId' => $this->getUser()->getUID(), + 'startDate' => $this->getStartDate(), + 'endDate' => $this->getEndDate(), + 'shortMessage' => $this->getShortMessage(), + 'message' => $this->getMessage(), + ]; + } +} diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index 82887f8d029..ab6ec9f38d3 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -39,8 +39,6 @@ namespace OC\User; use OC; -use OC\Authentication\Exceptions\ExpiredTokenException; -use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Exceptions\PasswordLoginForbiddenException; use OC\Authentication\Token\IProvider; @@ -51,6 +49,8 @@ use OC_User; use OC_Util; use OCA\DAV\Connector\Sabre\Auth; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Authentication\Exceptions\ExpiredTokenException; +use OCP\Authentication\Exceptions\InvalidTokenException; use OCP\EventDispatcher\GenericEvent; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\NotPermittedException; @@ -120,14 +120,14 @@ class Session implements IUserSession, Emitter { private $dispatcher; public function __construct(Manager $manager, - ISession $session, - ITimeFactory $timeFactory, - ?IProvider $tokenProvider, - IConfig $config, - ISecureRandom $random, - ILockdownManager $lockdownManager, - LoggerInterface $logger, - IEventDispatcher $dispatcher + ISession $session, + ITimeFactory $timeFactory, + ?IProvider $tokenProvider, + IConfig $config, + ISecureRandom $random, + ILockdownManager $lockdownManager, + LoggerInterface $logger, + IEventDispatcher $dispatcher ) { $this->manager = $manager; $this->session = $session; @@ -367,7 +367,7 @@ class Session implements IUserSession, Emitter { if (!$user->isEnabled()) { // disabled users can not log in // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory - $message = \OC::$server->getL10N('lib')->t('User disabled'); + $message = \OCP\Util::getL10N('lib')->t('Account disabled'); throw new LoginException($message); } @@ -406,7 +406,7 @@ class Session implements IUserSession, Emitter { return true; } - $message = \OC::$server->getL10N('lib')->t('Login canceled by app'); + $message = \OCP\Util::getL10N('lib')->t('Login canceled by app'); throw new LoginException($message); } @@ -425,9 +425,9 @@ class Session implements IUserSession, Emitter { * @return boolean */ public function logClientIn($user, - $password, - IRequest $request, - IThrottler $throttler) { + $password, + IRequest $request, + IThrottler $throttler) { $remoteAddress = $request->getRemoteAddress(); $currentDelay = $throttler->sleepDelayOrThrowOnMax($remoteAddress, 'login'); @@ -456,8 +456,18 @@ class Session implements IUserSession, Emitter { $this->handleLoginFailed($throttler, $currentDelay, $remoteAddress, $user, $password); return false; } - $users = $this->manager->getByEmail($user); - if (!(\count($users) === 1 && $this->login($users[0]->getUID(), $password))) { + + if ($isTokenPassword) { + $dbToken = $this->tokenProvider->getToken($password); + $userFromToken = $this->manager->get($dbToken->getUID()); + $isValidEmailLogin = $userFromToken->getEMailAddress() === $user + && $this->validateTokenLoginName($userFromToken->getEMailAddress(), $dbToken); + } else { + $users = $this->manager->getByEmail($user); + $isValidEmailLogin = (\count($users) === 1 && $this->login($users[0]->getUID(), $password)); + } + + if (!$isValidEmailLogin) { $this->handleLoginFailed($throttler, $currentDelay, $remoteAddress, $user, $password); return false; } @@ -576,7 +586,7 @@ class Session implements IUserSession, Emitter { * @return boolean if the login was successful */ public function tryBasicAuthLogin(IRequest $request, - IThrottler $throttler) { + IThrottler $throttler) { if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) { try { if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) { @@ -783,23 +793,23 @@ class Session implements IUserSession, Emitter { try { $dbToken = $this->tokenProvider->getToken($token); } catch (InvalidTokenException $ex) { + $this->logger->debug('Session token is invalid because it does not exist', [ + 'app' => 'core', + 'user' => $user, + 'exception' => $ex, + ]); return false; } - // Check if login names match - if (!is_null($user) && $dbToken->getLoginName() !== $user) { - // TODO: this makes it impossible to use different login names on browser and client - // e.g. login by e-mail 'user@example.com' on browser for generating the token will not - // allow to use the client token with the login name 'user'. - $this->logger->error('App token login name does not match', [ - 'tokenLoginName' => $dbToken->getLoginName(), - 'sessionLoginName' => $user, - ]); - + if (!is_null($user) && !$this->validateTokenLoginName($user, $dbToken)) { return false; } if (!$this->checkTokenCredentials($dbToken, $token)) { + $this->logger->warning('Session token credentials are invalid', [ + 'app' => 'core', + 'user' => $user, + ]); return false; } @@ -812,6 +822,27 @@ class Session implements IUserSession, Emitter { } /** + * Check if login names match + */ + private function validateTokenLoginName(?string $loginName, IToken $token): bool { + if ($token->getLoginName() !== $loginName) { + // TODO: this makes it impossible to use different login names on browser and client + // e.g. login by e-mail 'user@example.com' on browser for generating the token will not + // allow to use the client token with the login name 'user'. + $this->logger->error('App token login name does not match', [ + 'tokenLoginName' => $token->getLoginName(), + 'sessionLoginName' => $loginName, + 'app' => 'core', + 'user' => $token->getUID(), + ]); + + return false; + } + + return true; + } + + /** * Tries to login the user with auth token header * * @param IRequest $request @@ -822,13 +853,16 @@ class Session implements IUserSession, Emitter { $authHeader = $request->getHeader('Authorization'); if (str_starts_with($authHeader, 'Bearer ')) { $token = substr($authHeader, 7); - } else { - // No auth header, let's try session id + } elseif ($request->getCookie($this->config->getSystemValueString('instanceid')) !== null) { + // No auth header, let's try session id, but only if this is an existing + // session and the request has a session cookie try { $token = $this->session->getId(); } catch (SessionNotAvailableException $ex) { return false; } + } else { + return false; } if (!$this->loginWithToken($token)) { @@ -875,9 +909,9 @@ class Session implements IUserSession, Emitter { $tokens = $this->config->getUserKeys($uid, 'login_token'); // test cookies token against stored tokens if (!in_array($currentToken, $tokens, true)) { - $this->logger->info('Tried to log in {uid} but could not verify token', [ + $this->logger->info('Tried to log in but could not verify token', [ 'app' => 'core', - 'uid' => $uid, + 'user' => $uid, ]); return false; } @@ -885,18 +919,31 @@ class Session implements IUserSession, Emitter { $this->config->deleteUserValue($uid, 'login_token', $currentToken); $newToken = $this->random->generate(32); $this->config->setUserValue($uid, 'login_token', $newToken, (string)$this->timeFactory->getTime()); + $this->logger->debug('Remember-me token replaced', [ + 'app' => 'core', + 'user' => $uid, + ]); try { $sessionId = $this->session->getId(); $token = $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId); + $this->logger->debug('Session token replaced', [ + 'app' => 'core', + 'user' => $uid, + ]); } catch (SessionNotAvailableException $ex) { - $this->logger->warning('Could not renew session token for {uid} because the session is unavailable', [ + $this->logger->critical('Could not renew session token for {uid} because the session is unavailable', [ 'app' => 'core', 'uid' => $uid, + 'user' => $uid, ]); return false; } catch (InvalidTokenException $ex) { - $this->logger->warning('Renewing session token failed', ['app' => 'core']); + $this->logger->error('Renewing session token failed: ' . $ex->getMessage(), [ + 'app' => 'core', + 'user' => $uid, + 'exception' => $ex, + ]); return false; } @@ -935,10 +982,17 @@ class Session implements IUserSession, Emitter { $this->manager->emit('\OC\User', 'logout', [$user]); if ($user !== null) { try { - $this->tokenProvider->invalidateToken($this->session->getId()); + $token = $this->session->getId(); + $this->tokenProvider->invalidateToken($token); + $this->logger->debug('Session token invalidated before logout', [ + 'user' => $user->getUID(), + ]); } catch (SessionNotAvailableException $ex) { } } + $this->logger->debug('Logging out', [ + 'user' => $user === null ? null : $user->getUID(), + ]); $this->setUser(null); $this->setLoginName(null); $this->setToken(null); diff --git a/lib/private/User/User.php b/lib/private/User/User.php index d1185e17aef..580c590e6eb 100644 --- a/lib/private/User/User.php +++ b/lib/private/User/User.php @@ -49,17 +49,17 @@ use OCP\IImage; use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserBackend; +use OCP\User\Backend\IGetHomeBackend; +use OCP\User\Backend\IProvideAvatarBackend; +use OCP\User\Backend\IProvideEnabledStateBackend; +use OCP\User\Backend\ISetDisplayNameBackend; +use OCP\User\Backend\ISetPasswordBackend; use OCP\User\Events\BeforePasswordUpdatedEvent; use OCP\User\Events\BeforeUserDeletedEvent; use OCP\User\Events\PasswordUpdatedEvent; use OCP\User\Events\UserChangedEvent; use OCP\User\Events\UserDeletedEvent; use OCP\User\GetQuotaEvent; -use OCP\User\Backend\ISetDisplayNameBackend; -use OCP\User\Backend\ISetPasswordBackend; -use OCP\User\Backend\IProvideAvatarBackend; -use OCP\User\Backend\IProvideEnabledStateBackend; -use OCP\User\Backend\IGetHomeBackend; use OCP\UserInterface; use function json_decode; use function json_encode; @@ -576,7 +576,7 @@ class User implements IUser { public function getAvatarImage($size) { // delay the initialization if (is_null($this->avatarManager)) { - $this->avatarManager = \OC::$server->getAvatarManager(); + $this->avatarManager = \OC::$server->get(IAvatarManager::class); } $avatar = $this->avatarManager->getAvatar($this->uid); @@ -597,7 +597,7 @@ class User implements IUser { public function getCloudId() { $uid = $this->getUID(); $server = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/'); - if (substr($server, -10) === '/index.php') { + if (str_ends_with($server, '/index.php')) { $server = substr($server, 0, -10); } $server = $this->removeProtocolFromUrl($server); diff --git a/lib/private/UserStatus/ISettableProvider.php b/lib/private/UserStatus/ISettableProvider.php index 88a107d1f86..957d3274f1d 100644 --- a/lib/private/UserStatus/ISettableProvider.php +++ b/lib/private/UserStatus/ISettableProvider.php @@ -39,8 +39,9 @@ interface ISettableProvider extends IProvider { * @param string $messageId The new message id. * @param string $status The new status. * @param bool $createBackup If true, this will store the old status so that it is possible to revert it later (e.g. after a call). + * @param string|null $customMessage */ - public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup): void; + public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup, ?string $customMessage = null): void; /** * Revert an automatically set user status. For example after leaving a call, diff --git a/lib/private/UserStatus/Manager.php b/lib/private/UserStatus/Manager.php index 89a1bb455c7..a5594158c1e 100644 --- a/lib/private/UserStatus/Manager.php +++ b/lib/private/UserStatus/Manager.php @@ -51,7 +51,7 @@ class Manager implements IManager { * @param LoggerInterface $logger */ public function __construct(IServerContainer $container, - LoggerInterface $logger) { + LoggerInterface $logger) { $this->container = $container; $this->logger = $logger; } @@ -104,13 +104,13 @@ class Manager implements IManager { $this->provider = $provider; } - public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup = false): void { + public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup = false, ?string $customMessage = null): void { $this->setupProvider(); if (!$this->provider || !($this->provider instanceof ISettableProvider)) { return; } - $this->provider->setUserStatus($userId, $messageId, $status, $createBackup); + $this->provider->setUserStatus($userId, $messageId, $status, $createBackup, $customMessage); } public function revertUserStatus(string $userId, string $messageId, string $status): void { diff --git a/lib/private/legacy/OC_API.php b/lib/private/legacy/OC_API.php index 275e02986c4..facd08c1d2f 100644 --- a/lib/private/legacy/OC_API.php +++ b/lib/private/legacy/OC_API.php @@ -130,7 +130,7 @@ class OC_API { protected static function isV2(\OCP\IRequest $request) { $script = $request->getScriptName(); - return substr($script, -11) === '/ocs/v2.php'; + return str_ends_with($script, '/ocs/v2.php'); } /** @@ -171,7 +171,7 @@ class OC_API { ], ]; if ($format == 'json') { - return OC_JSON::encode($response); + return json_encode($response, JSON_HEX_TAG); } $writer = new XMLWriter(); diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index ac449a62a4f..c652fcfb9ba 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -51,19 +51,19 @@ declare(strict_types=1); * */ -use OCP\App\Events\AppUpdateEvent; -use OCP\App\IAppManager; -use OCP\App\ManagerEvent; -use OCP\Authentication\IAlternativeLogin; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\ILogger; -use OC\AppFramework\Bootstrap\Coordinator; use OC\App\DependencyAnalyzer; use OC\App\Platform; +use OC\AppFramework\Bootstrap\Coordinator; use OC\DB\MigrationService; use OC\Installer; use OC\Repair; use OC\Repair\Events\RepairErrorEvent; +use OCP\App\Events\AppUpdateEvent; +use OCP\App\IAppManager; +use OCP\App\ManagerEvent; +use OCP\Authentication\IAlternativeLogin; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\IAppConfig; use Psr\Container\ContainerExceptionInterface; use Psr\Log\LoggerInterface; @@ -117,6 +117,8 @@ class OC_App { * exists. * * if $types is set to non-empty array, only apps of those types will be loaded + * + * @deprecated 29.0.0 use IAppManager::loadApps instead */ public static function loadApps(array $types = []): bool { if (!\OC::$server->getSystemConfig()->getValue('installed', false)) { @@ -252,7 +254,7 @@ class OC_App { * This function set an app as enabled in appconfig. */ public function enable(string $appId, - array $groups = []) { + array $groups = []) { // Check if app is already downloaded /** @var Installer $installer */ $installer = \OCP\Server::get(Installer::class); @@ -282,17 +284,15 @@ class OC_App { /** * Get the path where to install apps - * - * @return string|false */ - public static function getInstallPath() { + public static function getInstallPath(): string|null { foreach (OC::$APPSROOTS as $dir) { if (isset($dir['writable']) && $dir['writable'] === true) { return $dir['path']; } } - \OCP\Util::writeLog('core', 'No application directories are marked as writable.', ILogger::ERROR); + \OCP\Server::get(LoggerInterface::class)->error('No application directories are marked as writable.', ['app' => 'core']); return null; } @@ -391,7 +391,7 @@ class OC_App { public static function getAppVersionByPath(string $path): string { $infoFile = $path . '/appinfo/info.xml'; $appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true); - return isset($appData['version']) ? $appData['version'] : ''; + return $appData['version'] ?? ''; } /** @@ -517,7 +517,7 @@ class OC_App { foreach (OC::$APPSROOTS as $apps_dir) { if (!is_readable($apps_dir['path'])) { - \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN); + \OCP\Server::get(LoggerInterface::class)->warning('unable to read app folder : ' . $apps_dir['path'], ['app' => 'core']); continue; } $dh = opendir($apps_dir['path']); @@ -565,15 +565,15 @@ class OC_App { $supportedApps = $this->getSupportedApps(); foreach ($installedApps as $app) { - if (array_search($app, $blacklist) === false) { + if (!in_array($app, $blacklist)) { $info = $appManager->getAppInfo($app, false, $langCode); if (!is_array($info)) { - \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR); + \OCP\Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']); continue; } if (!isset($info['name'])) { - \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR); + \OCP\Server::get(LoggerInterface::class)->error('App id "' . $app . '" has no name in appinfo', ['app' => 'core']); continue; } @@ -731,8 +731,9 @@ class OC_App { static $versions; if (!$versions) { - $appConfig = \OC::$server->getAppConfig(); - $versions = $appConfig->getValues(false, 'installed_version'); + /** @var IAppConfig $appConfig */ + $appConfig = \OCP\Server::get(IAppConfig::class); + $versions = $appConfig->searchValues('installed_version'); } return $versions; } @@ -824,7 +825,7 @@ class OC_App { $dispatcher = \OC::$server->get(IEventDispatcher::class); // load the steps - $r = new Repair([], $dispatcher, \OC::$server->get(LoggerInterface::class)); + $r = \OCP\Server::get(Repair::class); foreach ($steps as $step) { try { $r->addStep($step); @@ -870,11 +871,11 @@ class OC_App { } return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId); } else { - \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR); + \OCP\Server::get(LoggerInterface::class)->error('Can\'t get app storage, app ' . $appId . ', user not logged in', ['app' => 'core']); return false; } } else { - \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR); + \OCP\Server::get(LoggerInterface::class)->error('Can\'t get app storage, app ' . $appId . ' not enabled', ['app' => 'core']); return false; } } diff --git a/lib/private/legacy/OC_EventSource.php b/lib/private/legacy/OC_EventSource.php index cd72ba1f2d5..49fde4a214f 100644 --- a/lib/private/legacy/OC_EventSource.php +++ b/lib/private/legacy/OC_EventSource.php @@ -113,13 +113,13 @@ class OC_EventSource implements \OCP\IEventSource { } if ($this->fallback) { $response = '<script type="text/javascript">window.parent.OC.EventSource.fallBackCallBack(' - . $this->fallBackId . ',"' . $type . '",' . OC_JSON::encode($data) . ')</script>' . PHP_EOL; + . $this->fallBackId . ',"' . ($type ?? '') . '",' . json_encode($data, JSON_HEX_TAG) . ')</script>' . PHP_EOL; echo $response; } else { if ($type) { echo 'event: ' . $type . PHP_EOL; } - echo 'data: ' . OC_JSON::encode($data) . PHP_EOL; + echo 'data: ' . json_encode($data, JSON_HEX_TAG) . PHP_EOL; } echo PHP_EOL; flush(); diff --git a/lib/private/legacy/OC_Files.php b/lib/private/legacy/OC_Files.php index 7bc1fab94b6..a2f47639e65 100644 --- a/lib/private/legacy/OC_Files.php +++ b/lib/private/legacy/OC_Files.php @@ -43,10 +43,10 @@ use bantu\IniGetWrapper\IniGetWrapper; use OC\Files\View; use OC\Streamer; -use OCP\Lock\ILockingProvider; -use OCP\Files\Events\BeforeZipCreatedEvent; -use OCP\Files\Events\BeforeDirectFileDownloadEvent; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Events\BeforeDirectFileDownloadEvent; +use OCP\Files\Events\BeforeZipCreatedEvent; +use OCP\Lock\ILockingProvider; /** * Class for file server access @@ -76,7 +76,6 @@ class OC_Files { private static function sendHeaders($filename, $name, array $rangeArray): void { OC_Response::setContentDispositionHeader($name, 'attachment'); header('Content-Transfer-Encoding: binary', true); - header('Pragma: public');// enable caching in IE header('Expires: 0'); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); $fileSize = \OC\Files\Filesystem::filesize($filename); @@ -230,6 +229,10 @@ class OC_Files { OC::$server->getLogger()->logException($ex); $l = \OC::$server->getL10N('lib'); \OC_Template::printErrorPage($l->t('Cannot download file'), $ex->getMessage(), 200); + } catch (\OCP\Files\ConnectionLostException $ex) { + self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); + OC::$server->getLogger()->logException($ex, ['level' => \OCP\ILogger::DEBUG]); + \OC_Template::printErrorPage('Connection lost', $ex->getMessage(), 200); } catch (\Exception $ex) { self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); OC::$server->getLogger()->logException($ex); diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php index cf39d045ae9..9a12bd50e0e 100644 --- a/lib/private/legacy/OC_Helper.php +++ b/lib/private/legacy/OC_Helper.php @@ -46,8 +46,8 @@ use bantu\IniGetWrapper\IniGetWrapper; use OC\Files\Filesystem; use OCP\Files\Mount\IMountPoint; -use OCP\ICacheFactory; use OCP\IBinaryFinder; +use OCP\ICacheFactory; use OCP\IUser; use OCP\Util; use Psr\Log\LoggerInterface; @@ -596,6 +596,11 @@ class OC_Helper { 'mountPoint' => trim($mountPoint, '/'), ]; + if ($ownerId && $path === '/') { + // If path is root, store this as last known quota usage for this user + \OCP\Server::get(\OCP\IConfig::class)->setUserValue($ownerId, 'files', 'lastSeenQuotaUsage', (string)$relative); + } + $memcache->set($cacheKey, $info, 5 * 60); return $info; diff --git a/lib/private/legacy/OC_JSON.php b/lib/private/legacy/OC_JSON.php index b9cfb8210e0..b6791fe4b85 100644 --- a/lib/private/legacy/OC_JSON.php +++ b/lib/private/legacy/OC_JSON.php @@ -114,22 +114,10 @@ class OC_JSON { } /** - * Convert OC_L10N_String to string, for use in json encodings - */ - protected static function to_string(&$value) { - if ($value instanceof \OC\L10N\L10NString) { - $value = (string)$value; - } - } - - /** * Encode JSON * @deprecated Use a AppFramework JSONResponse instead */ - public static function encode($data) { - if (is_array($data)) { - array_walk_recursive($data, ['OC_JSON', 'to_string']); - } + private static function encode($data) { return json_encode($data, JSON_HEX_TAG); } } diff --git a/lib/private/legacy/OC_Template.php b/lib/private/legacy/OC_Template.php index 974f26fa381..545d5a73a63 100644 --- a/lib/private/legacy/OC_Template.php +++ b/lib/private/legacy/OC_Template.php @@ -21,6 +21,7 @@ * @author Roeland Jago Douma <roeland@famdouma.nl> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author Vincent Petry <vincent@nextcloud.com> + * @author Richard Steinmetz <richard@steinmetz.cloud> * * @license AGPL-3.0 * @@ -38,7 +39,9 @@ * */ use OC\TemplateLayout; +use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; use OCP\AppFramework\Http\TemplateResponse; +use OCP\EventDispatcher\IEventDispatcher; require_once __DIR__.'/template/functions.php'; @@ -249,20 +252,44 @@ class OC_Template extends \OC\Template\Base { // If the hint is the same as the message there is no need to display it twice. $hint = ''; } + $errors = [['error' => $error_msg, 'hint' => $hint]]; http_response_code($statusCode); try { - $content = new \OC_Template('', 'error', 'error', false); - $errors = [['error' => $error_msg, 'hint' => $hint]]; - $content->assign('errors', $errors); - $content->printPage(); - } catch (\Exception $e) { + // Try rendering themed html error page + $response = new TemplateResponse( + '', + 'error', + ['errors' => $errors], + TemplateResponse::RENDER_AS_ERROR, + $statusCode, + ); + $event = new BeforeTemplateRenderedEvent(false, $response); + \OC::$server->get(IEventDispatcher::class)->dispatchTyped($event); + print($response->render()); + } catch (\Throwable $e1) { $logger = \OC::$server->getLogger(); - $logger->error("$error_msg $hint", ['app' => 'core']); - $logger->logException($e, ['app' => 'core']); + $logger->logException($e1, [ + 'app' => 'core', + 'message' => 'Rendering themed error page failed. Falling back to unthemed error page.' + ]); - header('Content-Type: text/plain; charset=utf-8'); - print("$error_msg $hint"); + try { + // Try rendering unthemed html error page + $content = new \OC_Template('', 'error', 'error', false); + $content->assign('errors', $errors); + $content->printPage(); + } catch (\Exception $e2) { + // If nothing else works, fall back to plain text error page + $logger->error("$error_msg $hint", ['app' => 'core']); + $logger->logException($e2, [ + 'app' => 'core', + 'message' => 'Rendering unthemed error page failed. Falling back to plain text error page.' + ]); + + header('Content-Type: text/plain; charset=utf-8'); + print("$error_msg $hint"); + } } die(); } @@ -275,8 +302,10 @@ class OC_Template extends \OC\Template\Base { * @suppress PhanAccessMethodInternal */ public static function printExceptionErrorPage($exception, $statusCode = 503) { + $debug = false; http_response_code($statusCode); try { + $debug = \OC::$server->getSystemConfig()->getValue('debug', false); $request = \OC::$server->getRequest(); $content = new \OC_Template('', 'exception', 'error', false); $content->assign('errorClass', get_class($exception)); @@ -285,7 +314,7 @@ class OC_Template extends \OC\Template\Base { $content->assign('file', $exception->getFile()); $content->assign('line', $exception->getLine()); $content->assign('exception', $exception); - $content->assign('debugMode', \OC::$server->getSystemConfig()->getValue('debug', false)); + $content->assign('debugMode', $debug); $content->assign('remoteAddr', $request->getRemoteAddress()); $content->assign('requestID', $request->getId()); $content->printPage(); @@ -296,22 +325,28 @@ class OC_Template extends \OC\Template\Base { $logger->logException($e, ['app' => 'core']); } catch (Throwable $e) { // no way to log it properly - but to avoid a white page of death we send some output - header('Content-Type: text/plain; charset=utf-8'); - print("Internal Server Error\n\n"); - print("The server encountered an internal error and was unable to complete your request.\n"); - print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n"); - print("More details can be found in the server log.\n"); + self::printPlainErrorPage($e, $debug); // and then throw it again to log it at least to the web server error log throw $e; } - header('Content-Type: text/plain; charset=utf-8'); - print("Internal Server Error\n\n"); - print("The server encountered an internal error and was unable to complete your request.\n"); - print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n"); - print("More details can be found in the server log.\n"); + self::printPlainErrorPage($e, $debug); } die(); } + + private static function printPlainErrorPage(\Throwable $exception, bool $debug = false) { + header('Content-Type: text/plain; charset=utf-8'); + print("Internal Server Error\n\n"); + print("The server encountered an internal error and was unable to complete your request.\n"); + print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n"); + print("More details can be found in the server log.\n"); + + if ($debug) { + print("\n"); + print($exception->getMessage() . ' ' . $exception->getFile() . ' at ' . $exception->getLine() . "\n"); + print($exception->getTraceAsString()); + } + } } diff --git a/lib/private/legacy/OC_User.php b/lib/private/legacy/OC_User.php index caa4f5dca65..47890fd8dda 100644 --- a/lib/private/legacy/OC_User.php +++ b/lib/private/legacy/OC_User.php @@ -38,10 +38,13 @@ use OC\User\LoginException; use OCP\EventDispatcher\IEventDispatcher; -use OCP\ILogger; +use OCP\IGroupManager; +use OCP\IUser; use OCP\IUserManager; +use OCP\Server; use OCP\User\Events\BeforeUserLoggedInEvent; use OCP\User\Events\UserLoggedInEvent; +use Psr\Log\LoggerInterface; /** * This class provides wrapper methods for user management. Multiple backends are @@ -93,7 +96,7 @@ class OC_User { case 'database': case 'mysql': case 'sqlite': - \OCP\Util::writeLog('core', 'Adding user backend ' . $backend . '.', ILogger::DEBUG); + Server::get(LoggerInterface::class)->debug('Adding user backend ' . $backend . '.', ['app' => 'core']); self::$_usedBackends[$backend] = new \OC\User\Database(); \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]); break; @@ -102,7 +105,7 @@ class OC_User { \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]); break; default: - \OCP\Util::writeLog('core', 'Adding default user backend ' . $backend . '.', ILogger::DEBUG); + Server::get(LoggerInterface::class)->debug('Adding default user backend ' . $backend . '.', ['app' => 'core']); $className = 'OC_USER_' . strtoupper($backend); self::$_usedBackends[$backend] = new $className(); \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]); @@ -138,7 +141,7 @@ class OC_User { $class = $config['class']; $arguments = $config['arguments']; if (class_exists($class)) { - if (array_search($i, self::$_setupedBackends) === false) { + if (!in_array($i, self::$_setupedBackends)) { // make a reflection object $reflectionObj = new ReflectionClass($class); @@ -147,10 +150,10 @@ class OC_User { self::useBackend($backend); self::$_setupedBackends[] = $i; } else { - \OCP\Util::writeLog('core', 'User backend ' . $class . ' already initialized.', ILogger::DEBUG); + Server::get(LoggerInterface::class)->debug('User backend ' . $class . ' already initialized.', ['app' => 'core']); } } else { - \OCP\Util::writeLog('core', 'User backend ' . $class . ' not found.', ILogger::ERROR); + Server::get(LoggerInterface::class)->error('User backend ' . $class . ' not found.', ['app' => 'core']); } } } @@ -178,7 +181,7 @@ class OC_User { $dispatcher = \OC::$server->get(IEventDispatcher::class); if ($userSession->getUser() && !$userSession->getUser()->isEnabled()) { - $message = \OC::$server->getL10N('lib')->t('User disabled'); + $message = \OC::$server->getL10N('lib')->t('Account disabled'); throw new LoginException($message); } $userSession->setLoginName($uid); @@ -303,7 +306,7 @@ class OC_User { } $user = \OC::$server->getUserSession()->getUser(); - if ($user instanceof \OCP\IUser) { + if ($user instanceof IUser) { $backend = $user->getBackend(); if ($backend instanceof \OCP\User\Backend\ICustomLogout) { return $backend->getLogoutUrl(); @@ -323,12 +326,9 @@ class OC_User { * @return bool */ public static function isAdminUser($uid) { - $group = \OC::$server->getGroupManager()->get('admin'); - $user = \OC::$server->getUserManager()->get($uid); - if ($group && $user && $group->inGroup($user) && self::$incognitoMode === false) { - return true; - } - return false; + $user = Server::get(IUserManager::class)->get($uid); + $isAdmin = $user && Server::get(IGroupManager::class)->isAdmin($user->getUID()); + return $isAdmin && self::$incognitoMode === false; } diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 9d62c46137e..42a0d9450b5 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -325,9 +325,10 @@ class OC_Util { return; } + $timestamp = filemtime(OC::$SERVERROOT . '/version.php'); require OC::$SERVERROOT . '/version.php'; /** @var int $timestamp */ - self::$versionCache['OC_Version_Timestamp'] = \OC::$VERSION_MTIME; + self::$versionCache['OC_Version_Timestamp'] = $timestamp; /** @var string $OC_Version */ self::$versionCache['OC_Version'] = $OC_Version; /** @var string $OC_VersionString */ @@ -512,15 +513,7 @@ class OC_Util { } $webServerRestart = false; - $setup = new \OC\Setup( - $config, - \OC::$server->get(IniGetWrapper::class), - \OC::$server->getL10N('lib'), - \OC::$server->get(\OCP\Defaults::class), - \OC::$server->get(LoggerInterface::class), - \OC::$server->getSecureRandom(), - \OC::$server->get(\OC\Installer::class) - ); + $setup = \OCP\Server::get(\OC\Setup::class); $urlGenerator = \OC::$server->getURLGenerator(); @@ -739,8 +732,8 @@ class OC_Util { if ($perms[2] !== '0') { $l = \OC::$server->getL10N('lib'); return [[ - 'error' => $l->t('Your data directory is readable by other users.'), - 'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other users.'), + 'error' => $l->t('Your data directory is readable by other people.'), + 'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other people.'), ]]; } } @@ -1119,8 +1112,8 @@ class OC_Util { return false; } - foreach (str_split($trimmed) as $char) { - if (str_contains(\OCP\Constants::FILENAME_INVALID_CHARS, $char)) { + foreach (\OCP\Util::getForbiddenFileNameChars() as $char) { + if (str_contains($trimmed, $char)) { return false; } } diff --git a/lib/public/Accounts/IAccountManager.php b/lib/public/Accounts/IAccountManager.php index 68eca469ad9..fbf2d831513 100644 --- a/lib/public/Accounts/IAccountManager.php +++ b/lib/public/Accounts/IAccountManager.php @@ -72,6 +72,7 @@ interface IAccountManager { /** * Contact details only visible locally * + * @since 15.0.0 * @deprecated 21.0.1 */ public const VISIBILITY_PRIVATE = 'private'; @@ -79,6 +80,7 @@ interface IAccountManager { /** * Contact details visible on trusted federated servers. * + * @since 15.0.0 * @deprecated 21.0.1 */ public const VISIBILITY_CONTACTS_ONLY = 'contacts'; @@ -86,6 +88,7 @@ interface IAccountManager { /** * Contact details visible on trusted federated servers and in the public lookup server. * + * @since 15.0.0 * @deprecated 21.0.1 */ public const VISIBILITY_PUBLIC = 'public'; @@ -105,14 +108,49 @@ interface IAccountManager { self::VISIBILITY_PUBLIC, ]; + /** + * @since 15.0.0 + */ public const PROPERTY_AVATAR = 'avatar'; + + /** + * @since 15.0.0 + */ public const PROPERTY_DISPLAYNAME = 'displayname'; + + /** + * @since 27.0.0 + */ public const PROPERTY_DISPLAYNAME_LEGACY = 'display-name'; + + /** + * @since 15.0.0 + */ public const PROPERTY_PHONE = 'phone'; + + /** + * @since 15.0.0 + */ public const PROPERTY_EMAIL = 'email'; + + /** + * @since 15.0.0 + */ public const PROPERTY_WEBSITE = 'website'; + + /** + * @since 15.0.0 + */ public const PROPERTY_ADDRESS = 'address'; + + /** + * @since 15.0.0 + */ public const PROPERTY_TWITTER = 'twitter'; + + /** + * @since 26.0.0 + */ public const PROPERTY_FEDIVERSE = 'fediverse'; /** @@ -161,10 +199,25 @@ interface IAccountManager { self::PROPERTY_PROFILE_ENABLED, ]; + + /** + * @since 22.0.0 + */ public const COLLECTION_EMAIL = 'additional_mail'; + /** + * @since 15.0.0 + */ public const NOT_VERIFIED = '0'; + + /** + * @since 15.0.0 + */ public const VERIFICATION_IN_PROGRESS = '1'; + + /** + * @since 15.0.0 + */ public const VERIFIED = '2'; /** diff --git a/lib/public/Activity/IExtension.php b/lib/public/Activity/IExtension.php index e02347f0373..23d96380c87 100644 --- a/lib/public/Activity/IExtension.php +++ b/lib/public/Activity/IExtension.php @@ -31,13 +31,43 @@ namespace OCP\Activity; * @since 8.0.0 */ interface IExtension { + /** + * @since 8.0.0 + */ public const METHOD_STREAM = 'stream'; + + /** + * @since 8.0.0 + */ public const METHOD_MAIL = 'email'; + + /** + * @since 20.0.0 + */ public const METHOD_NOTIFICATION = 'notification'; + /** + * @since 8.0.0 + */ public const PRIORITY_VERYLOW = 10; + + /** + * @since 8.0.0 + */ public const PRIORITY_LOW = 20; + + /** + * @since 8.0.0 + */ public const PRIORITY_MEDIUM = 30; + + /** + * @since 8.0.0 + */ public const PRIORITY_HIGH = 40; + + /** + * @since 8.0.0 + */ public const PRIORITY_VERYHIGH = 50; } diff --git a/lib/public/App/IAppManager.php b/lib/public/App/IAppManager.php index 2497544dcbe..142e8bb8515 100644 --- a/lib/public/App/IAppManager.php +++ b/lib/public/App/IAppManager.php @@ -45,8 +45,8 @@ interface IAppManager { /** * Returns the app information from "appinfo/info.xml". * - * @param string $appId - * @return mixed + * @param string|null $lang + * @return array|null * @since 14.0.0 */ public function getAppInfo(string $appId, bool $path = false, $lang = null); @@ -62,10 +62,20 @@ interface IAppManager { public function getAppVersion(string $appId, bool $useCache = true): string; /** + * Returns the app icon or null if none is found + * + * @param string $appId + * @param bool $dark Enable to request a dark icon variant, default is a white icon + * @return string|null + * @since 29.0.0 + */ + public function getAppIcon(string $appId, bool $dark = false): string|null; + + /** * Check if an app is enabled for user * * @param string $appId - * @param \OCP\IUser $user (optional) if not defined, the currently loggedin user will be used + * @param \OCP\IUser|null $user (optional) if not defined, the currently loggedin user will be used * @return bool * @since 8.0.0 */ @@ -248,7 +258,30 @@ interface IAppManager { * * If `user` is not passed, the currently logged in user will be used * + * @param ?IUser $user User to query default app for + * @param bool $withFallbacks Include fallback values if no default app was configured manually + * Before falling back to predefined default apps, + * the user defined app order is considered and the first app would be used as the fallback. + * * @since 25.0.6 + * @since 28.0.0 Added optional $withFallbacks parameter + */ + public function getDefaultAppForUser(?IUser $user = null, bool $withFallbacks = true): string; + + /** + * Get the global default apps with fallbacks + * + * @return string[] The default applications + * @since 28.0.0 + */ + public function getDefaultApps(): array; + + /** + * Set the global default apps with fallbacks + * + * @param string[] $appId + * @throws \InvalidArgumentException If any of the apps is not installed + * @since 28.0.0 */ - public function getDefaultAppForUser(?IUser $user = null): string; + public function setDefaultApps(array $defaultApps): void; } diff --git a/lib/public/App/ManagerEvent.php b/lib/public/App/ManagerEvent.php index 0069e57db42..0853ce7981d 100644 --- a/lib/public/App/ManagerEvent.php +++ b/lib/public/App/ManagerEvent.php @@ -32,16 +32,19 @@ use OCP\EventDispatcher\Event; */ class ManagerEvent extends Event { /** + * @since 9.0.0 * @deprecated 22.0.0 */ public const EVENT_APP_ENABLE = 'OCP\App\IAppManager::enableApp'; /** + * @since 9.0.0 * @deprecated 22.0.0 */ public const EVENT_APP_ENABLE_FOR_GROUPS = 'OCP\App\IAppManager::enableAppForGroups'; /** + * @since 9.0.0 * @deprecated 22.0.0 */ public const EVENT_APP_DISABLE = 'OCP\App\IAppManager::disableApp'; diff --git a/lib/public/AppFramework/ApiController.php b/lib/public/AppFramework/ApiController.php index 66c278e62d8..9505af0b2e2 100644 --- a/lib/public/AppFramework/ApiController.php +++ b/lib/public/AppFramework/ApiController.php @@ -52,10 +52,10 @@ abstract class ApiController extends Controller { * @since 7.0.0 */ public function __construct($appName, - IRequest $request, - $corsMethods = 'PUT, POST, GET, DELETE, PATCH', - $corsAllowedHeaders = 'Authorization, Content-Type, Accept', - $corsMaxAge = 1728000) { + IRequest $request, + $corsMethods = 'PUT, POST, GET, DELETE, PATCH', + $corsAllowedHeaders = 'Authorization, Content-Type, Accept', + $corsMaxAge = 1728000) { parent::__construct($appName, $request); $this->corsMethods = $corsMethods; $this->corsAllowedHeaders = $corsAllowedHeaders; diff --git a/lib/public/AppFramework/App.php b/lib/public/AppFramework/App.php index 4d6e9177b78..f62c464ea55 100644 --- a/lib/public/AppFramework/App.php +++ b/lib/public/AppFramework/App.php @@ -38,6 +38,7 @@ use OC\AppFramework\Routing\RouteConfig; use OC\Route\Router; use OC\ServerContainer; use OCP\Route\IRouter; +use Psr\Log\LoggerInterface; /** * Class App @@ -98,8 +99,9 @@ class App { } if (!$setUpViaQuery && $applicationClassName !== \OCP\AppFramework\App::class) { - \OC::$server->getLogger()->logException($e, [ + \OCP\Server::get(LoggerInterface::class)->error($e->getMessage(), [ 'app' => $appName, + 'exception' => $e, ]); } } diff --git a/lib/public/AppFramework/AuthPublicShareController.php b/lib/public/AppFramework/AuthPublicShareController.php index 78dd45551ed..847f1823db8 100644 --- a/lib/public/AppFramework/AuthPublicShareController.php +++ b/lib/public/AppFramework/AuthPublicShareController.php @@ -57,9 +57,9 @@ abstract class AuthPublicShareController extends PublicShareController { * @since 14.0.0 */ public function __construct(string $appName, - IRequest $request, - ISession $session, - IURLGenerator $urlGenerator) { + IRequest $request, + ISession $session, + IURLGenerator $urlGenerator) { parent::__construct($appName, $request, $session); $this->urlGenerator = $urlGenerator; diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index 720803a78d1..09bc703e0a4 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -37,10 +37,11 @@ use OCP\Collaboration\Reference\IReferenceProvider; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Template\ICustomTemplateProvider; use OCP\IContainer; -use OCP\TextProcessing\IProvider as ITextProcessingProvider; use OCP\Notification\INotifier; use OCP\Preview\IProviderV2; use OCP\SpeechToText\ISpeechToTextProvider; +use OCP\TextProcessing\IProvider as ITextProcessingProvider; +use OCP\TextToImage\IProvider as ITextToImageProvider; use OCP\Translation\ITranslationProvider; /** @@ -129,7 +130,7 @@ interface IRegistrationContext { * @param string $event preferably the fully-qualified class name of the Event sub class to listen for * @psalm-param string|class-string<T> $event preferably the fully-qualified class name of the Event sub class to listen for * @param string $listener fully qualified class name (or ::class notation) of a \OCP\EventDispatcher\IEventListener that can be built by the DI container - * @psalm-param class-string<\OCP\EventDispatcher\IEventListener> $listener fully qualified class name that can be built by the DI container + * @psalm-param class-string<\OCP\EventDispatcher\IEventListener<T>> $listener fully qualified class name that can be built by the DI container * @param int $priority The higher this value, the earlier an event * listener will be triggered in the chain (defaults to 0) * @@ -231,6 +232,16 @@ interface IRegistrationContext { public function registerTextProcessingProvider(string $providerClass): void; /** + * Register a custom text2image provider class that provides the possibility to generate images + * through the OCP\TextToImage APIs + * + * @param string $providerClass + * @psalm-param class-string<ITextToImageProvider> $providerClass + * @since 28.0.0 + */ + public function registerTextToImageProvider(string $providerClass): void; + + /** * Register a custom template provider class that is able to inject custom templates * in addition to the user defined ones * @@ -341,6 +352,14 @@ interface IRegistrationContext { public function registerCalendarRoomBackend(string $class): void; /** + * @param string $class + * @psalm-param class-string<\OCP\Calendar\Room\IBackend> $actionClass + * @return void + * @since 29.0.0 + */ + public function registerTeamResourceProvider(string $class): void; + + /** * Register an implementation of \OCP\UserMigration\IMigrator that * will handle the implementation of a migrator * @@ -371,4 +390,24 @@ interface IRegistrationContext { * @since 26.0.0 */ public function registerPublicShareTemplateProvider(string $class): void; + + /** + * Register an implementation of \OCP\SetupCheck\ISetupCheck that + * will handle the implementation of a setup check + * + * @param class-string<\OCP\SetupCheck\ISetupCheck> $setupCheckClass + * @since 28.0.0 + */ + public function registerSetupCheck(string $setupCheckClass): void; + + /** + * Register an implementation of \OCP\Settings\IDeclarativeSettings that + * will handle the implementation of declarative settings + * + * @param string $declarativeSettingsClass + * @psalm-param class-string<\OCP\Settings\IDeclarativeSettingsForm> $declarativeSettingsClass + * @return void + * @since 29.0.0 + */ + public function registerDeclarativeSettings(string $declarativeSettingsClass): void; } diff --git a/lib/public/AppFramework/Controller.php b/lib/public/AppFramework/Controller.php index e8500d5ae1a..12e1c31626b 100644 --- a/lib/public/AppFramework/Controller.php +++ b/lib/public/AppFramework/Controller.php @@ -65,7 +65,7 @@ abstract class Controller { * @since 6.0.0 - parameter $appName was added in 7.0.0 - parameter $app was removed in 7.0.0 */ public function __construct($appName, - IRequest $request) { + IRequest $request) { $this->appName = $appName; $this->request = $request; diff --git a/lib/public/AppFramework/Http.php b/lib/public/AppFramework/Http.php index 8b3cde6875e..64e7fb689e5 100644 --- a/lib/public/AppFramework/Http.php +++ b/lib/public/AppFramework/Http.php @@ -29,63 +29,298 @@ namespace OCP\AppFramework; * @since 6.0.0 */ class Http { + /** + * @since 6.0.0 + */ public const STATUS_CONTINUE = 100; + + /** + * @since 6.0.0 + */ public const STATUS_SWITCHING_PROTOCOLS = 101; + + /** + * @since 6.0.0 + */ public const STATUS_PROCESSING = 102; + + /** + * @since 6.0.0 + */ public const STATUS_OK = 200; + + /** + * @since 6.0.0 + */ public const STATUS_CREATED = 201; + + /** + * @since 6.0.0 + */ public const STATUS_ACCEPTED = 202; + + /** + * @since 6.0.0 + */ public const STATUS_NON_AUTHORATIVE_INFORMATION = 203; + + /** + * @since 6.0.0 + */ public const STATUS_NO_CONTENT = 204; + + /** + * @since 6.0.0 + */ public const STATUS_RESET_CONTENT = 205; + + /** + * @since 6.0.0 + */ public const STATUS_PARTIAL_CONTENT = 206; + + /** + * @since 6.0.0 + */ public const STATUS_MULTI_STATUS = 207; + + /** + * @since 6.0.0 + */ public const STATUS_ALREADY_REPORTED = 208; + + /** + * @since 6.0.0 + */ public const STATUS_IM_USED = 226; + + /** + * @since 6.0.0 + */ public const STATUS_MULTIPLE_CHOICES = 300; + + /** + * @since 6.0.0 + */ public const STATUS_MOVED_PERMANENTLY = 301; + + /** + * @since 6.0.0 + */ public const STATUS_FOUND = 302; + + /** + * @since 6.0.0 + */ public const STATUS_SEE_OTHER = 303; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_MODIFIED = 304; + + /** + * @since 6.0.0 + */ public const STATUS_USE_PROXY = 305; + + /** + * @since 6.0.0 + */ public const STATUS_RESERVED = 306; + + /** + * @since 6.0.0 + */ public const STATUS_TEMPORARY_REDIRECT = 307; + + /** + * @since 6.0.0 + */ public const STATUS_BAD_REQUEST = 400; + + /** + * @since 6.0.0 + */ public const STATUS_UNAUTHORIZED = 401; + + /** + * @since 6.0.0 + */ public const STATUS_PAYMENT_REQUIRED = 402; + + /** + * @since 6.0.0 + */ public const STATUS_FORBIDDEN = 403; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_FOUND = 404; + + /** + * @since 6.0.0 + */ public const STATUS_METHOD_NOT_ALLOWED = 405; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_ACCEPTABLE = 406; + + /** + * @since 6.0.0 + */ public const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_TIMEOUT = 408; + + /** + * @since 6.0.0 + */ public const STATUS_CONFLICT = 409; + + /** + * @since 6.0.0 + */ public const STATUS_GONE = 410; + + /** + * @since 6.0.0 + */ public const STATUS_LENGTH_REQUIRED = 411; + + /** + * @since 6.0.0 + */ public const STATUS_PRECONDITION_FAILED = 412; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_URI_TOO_LONG = 414; + + /** + * @since 6.0.0 + */ public const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_RANGE_NOT_SATISFIABLE = 416; + + /** + * @since 6.0.0 + */ public const STATUS_EXPECTATION_FAILED = 417; + + /** + * @since 6.0.0 + */ public const STATUS_IM_A_TEAPOT = 418; + + /** + * @since 6.0.0 + */ public const STATUS_UNPROCESSABLE_ENTITY = 422; + + /** + * @since 6.0.0 + */ public const STATUS_LOCKED = 423; + + /** + * @since 6.0.0 + */ public const STATUS_FAILED_DEPENDENCY = 424; + + /** + * @since 6.0.0 + */ public const STATUS_UPGRADE_REQUIRED = 426; + + /** + * @since 6.0.0 + */ public const STATUS_PRECONDITION_REQUIRED = 428; + + /** + * @since 6.0.0 + */ public const STATUS_TOO_MANY_REQUESTS = 429; + + /** + * @since 6.0.0 + */ public const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; + + /** + * @since 6.0.0 + */ public const STATUS_INTERNAL_SERVER_ERROR = 500; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_IMPLEMENTED = 501; + + /** + * @since 6.0.0 + */ public const STATUS_BAD_GATEWAY = 502; + + /** + * @since 6.0.0 + */ public const STATUS_SERVICE_UNAVAILABLE = 503; + + /** + * @since 6.0.0 + */ public const STATUS_GATEWAY_TIMEOUT = 504; + + /** + * @since 6.0.0 + */ public const STATUS_HTTP_VERSION_NOT_SUPPORTED = 505; + + /** + * @since 6.0.0 + */ public const STATUS_VARIANT_ALSO_NEGOTIATES = 506; + + /** + * @since 6.0.0 + */ public const STATUS_INSUFFICIENT_STORAGE = 507; + + /** + * @since 6.0.0 + */ public const STATUS_LOOP_DETECTED = 508; + + /** + * @since 6.0.0 + */ public const STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509; + + /** + * @since 6.0.0 + */ public const STATUS_NOT_EXTENDED = 510; + + /** + * @since 6.0.0 + */ public const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511; } diff --git a/lib/public/AppFramework/Http/Attribute/ApiRoute.php b/lib/public/AppFramework/Http/Attribute/ApiRoute.php new file mode 100644 index 00000000000..0b566082521 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/ApiRoute.php @@ -0,0 +1,63 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2024 Kate Döen <kate.doeen@nextcloud.com> + * + * @author Kate Döen <kate.doeen@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * This attribute can be used to define API routes on controller methods. + * + * It works in addition to the traditional routes.php method and has the same parameters + * (except for the `name` parameter which is not needed). + * + * @since 29.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class ApiRoute extends Route { + /** + * @inheritDoc + * + * @since 29.0.0 + */ + public function __construct( + protected string $verb, + protected string $url, + protected ?array $requirements = null, + protected ?array $defaults = null, + protected ?string $root = null, + protected ?string $postfix = null, + ) { + parent::__construct( + Route::TYPE_API, + $verb, + $url, + $requirements, + $defaults, + $root, + $postfix, + ); + } +} diff --git a/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php b/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php new file mode 100644 index 00000000000..ac08513a2a9 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php @@ -0,0 +1,63 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2024 Kate Döen <kate.doeen@nextcloud.com> + * + * @author Kate Döen <kate.doeen@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * This attribute can be used to define Frontpage routes on controller methods. + * + * It works in addition to the traditional routes.php method and has the same parameters + * (except for the `name` parameter which is not needed). + * + * @since 29.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class FrontpageRoute extends Route { + /** + * @inheritDoc + * + * @since 29.0.0 + */ + public function __construct( + protected string $verb, + protected string $url, + protected ?array $requirements = null, + protected ?array $defaults = null, + protected ?string $root = null, + protected ?string $postfix = null, + ) { + parent::__construct( + Route::TYPE_FRONTPAGE, + $verb, + $url, + $requirements, + $defaults, + $root, + $postfix, + ); + } +} diff --git a/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php b/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php index 31ccd014321..4802ea5f1fd 100644 --- a/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php +++ b/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php @@ -31,6 +31,7 @@ use Attribute; * Attribute for controller methods that should be ignored when generating OpenAPI documentation * * @since 28.0.0 + * @deprecated 28.0.0 Use {@see OpenAPI} with {@see OpenAPI::SCOPE_IGNORE} instead: `#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]` */ #[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)] class IgnoreOpenAPI { diff --git a/lib/public/AppFramework/Http/Attribute/OpenAPI.php b/lib/public/AppFramework/Http/Attribute/OpenAPI.php new file mode 100644 index 00000000000..c5b3bcf5dda --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/OpenAPI.php @@ -0,0 +1,99 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * With this attribute a controller or a method can be moved into a different + * scope or tag. Scopes should be seen as API consumers, tags can be used to group + * different routes inside the same scope. + * + * @since 28.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +class OpenAPI { + /** + * APIs used for normal user facing interaction with your app, + * e.g. when you would implement a mobile client or standalone frontend. + * + * @since 28.0.0 + */ + public const SCOPE_DEFAULT = 'default'; + + /** + * APIs used to administrate your app's configuration on an administrative level. + * Will be set automatically when admin permissions are required to access the route. + * + * @since 28.0.0 + */ + public const SCOPE_ADMINISTRATION = 'administration'; + + /** + * APIs used by servers to federate with each other. + * + * @since 28.0.0 + */ + public const SCOPE_FEDERATION = 'federation'; + + /** + * Ignore this controller or method in all generated OpenAPI specifications. + * + * @since 28.0.0 + */ + public const SCOPE_IGNORE = 'ignore'; + + /** + * @param self::SCOPE_*|string $scope Scopes are used to define different clients. + * It is recommended to go with the scopes available as self::SCOPE_* constants, + * but in exotic cases other APIs might need documentation as well, + * then a free string can be provided (but it should be `a-z` only). + * @param ?list<string> $tags Tags can be used to group routes inside a scope + * for easier implementation and reviewing of the API specification. + * It defaults to the controller name in snake_case (should be `a-z` and underscore only). + * @since 28.0.0 + */ + public function __construct( + protected string $scope = self::SCOPE_DEFAULT, + protected ?array $tags = null, + ) { + } + + /** + * @since 28.0.0 + */ + public function getScope(): string { + return $this->scope; + } + + /** + * @return ?list<string> + * @since 28.0.0 + */ + public function getTags(): ?array { + return $this->tags; + } +} diff --git a/lib/public/AppFramework/Http/Attribute/Route.php b/lib/public/AppFramework/Http/Attribute/Route.php new file mode 100644 index 00000000000..58579c1f956 --- /dev/null +++ b/lib/public/AppFramework/Http/Attribute/Route.php @@ -0,0 +1,161 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2024 Kate Döen <kate.doeen@nextcloud.com> + * + * @author Kate Döen <kate.doeen@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\AppFramework\Http\Attribute; + +use Attribute; + +/** + * This attribute can be used to define routes on controller methods. + * + * It works in addition to the traditional routes.php method and has the same parameters + * (except for the `name` parameter which is not needed). + * + * @since 29.0.0 + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +class Route { + + /** + * Corresponds to the `ocs` key in routes.php + * + * @see ApiRoute + * @since 29.0.0 + */ + public const TYPE_API = 'ocs'; + + /** + * Corresponds to the `routes` key in routes.php + * + * @see FrontpageRoute + * @since 29.0.0 + */ + public const TYPE_FRONTPAGE = 'routes'; + + /** + * @param string $type Either Route::TYPE_API or Route::TYPE_FRONTPAGE. + * @psalm-param Route::TYPE_* $type + * @param string $verb HTTP method of the route. + * @psalm-param 'GET'|'HEAD'|'POST'|'PUT'|'DELETE'|'OPTIONS'|'PATCH' $verb + * @param string $url The path of the route. + * @param ?array<string, string> $requirements Array of regexes mapped to the path parameters. + * @param ?array<string, mixed> $defaults Array of default values mapped to the path parameters. + * @param ?string $root Custom root. For OCS all apps are allowed, but for index.php only some can use it. + * @param ?string $postfix Postfix for the route name. + * @since 29.0.0 + */ + public function __construct( + protected string $type, + protected string $verb, + protected string $url, + protected ?array $requirements = null, + protected ?array $defaults = null, + protected ?string $root = null, + protected ?string $postfix = null, + ) { + } + + /** + * @return array{ + * verb: string, + * url: string, + * requirements?: array<string, string>, + * defaults?: array<string, mixed>, + * root?: string, + * postfix?: string, + * } + * @since 29.0.0 + */ + public function toArray() { + $route = [ + 'verb' => $this->verb, + 'url' => $this->url, + ]; + + if ($this->requirements !== null) { + $route['requirements'] = $this->requirements; + } + if ($this->defaults !== null) { + $route['defaults'] = $this->defaults; + } + if ($this->root !== null) { + $route['root'] = $this->root; + } + if ($this->postfix !== null) { + $route['postfix'] = $this->postfix; + } + + return $route; + } + + /** + * @since 29.0.0 + */ + public function getType(): string { + return $this->type; + } + + /** + * @since 29.0.0 + */ + public function getVerb(): string { + return $this->verb; + } + + /** + * @since 29.0.0 + */ + public function getUrl(): string { + return $this->url; + } + + /** + * @since 29.0.0 + */ + public function getRequirements(): ?array { + return $this->requirements; + } + + /** + * @since 29.0.0 + */ + public function getDefaults(): ?array { + return $this->defaults; + } + + /** + * @since 29.0.0 + */ + public function getRoot(): ?string { + return $this->root; + } + + /** + * @since 29.0.0 + */ + public function getPostfix(): ?string { + return $this->postfix; + } +} diff --git a/lib/public/AppFramework/Http/ContentSecurityPolicy.php b/lib/public/AppFramework/Http/ContentSecurityPolicy.php index f17dd9bd270..7f93f7004d9 100644 --- a/lib/public/AppFramework/Http/ContentSecurityPolicy.php +++ b/lib/public/AppFramework/Http/ContentSecurityPolicy.php @@ -48,6 +48,8 @@ class ContentSecurityPolicy extends EmptyContentSecurityPolicy { protected ?bool $evalWasmAllowed = false; /** @var bool Whether strict-dynamic should be set */ protected $strictDynamicAllowed = false; + /** @var bool Whether strict-dynamic should be set for 'script-src-elem' */ + protected $strictDynamicAllowedOnScripts = true; /** @var array Domains from which scripts can get loaded */ protected $allowedScriptDomains = [ '\'self\'', diff --git a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php index 7e1de2ef2eb..6662a302d7f 100644 --- a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php +++ b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php @@ -37,10 +37,12 @@ namespace OCP\AppFramework\Http; * @since 9.0.0 */ class EmptyContentSecurityPolicy { - /** @var string Whether JS nonces should be used */ - protected $useJsNonce = null; + /** @var ?string JS nonce to be used */ + protected ?string $jsNonce = null; /** @var bool Whether strict-dynamic should be used */ protected $strictDynamicAllowed = null; + /** @var bool Whether strict-dynamic should be used on script-src-elem */ + protected $strictDynamicAllowedOnScripts = null; /** * @var bool Whether eval in JS scripts is allowed * TODO: Disallow per default @@ -94,6 +96,18 @@ class EmptyContentSecurityPolicy { } /** + * In contrast to `useStrictDynamic` this only sets strict-dynamic on script-src-elem + * Meaning only grants trust to all imports of scripts that were loaded in `<script>` tags, and thus weakens less the CSP. + * @param bool $state + * @return EmptyContentSecurityPolicy + * @since 28.0.0 + */ + public function useStrictDynamicOnScripts(bool $state = false): self { + $this->strictDynamicAllowedOnScripts = $state; + return $this; + } + + /** * Use the according JS nonce * This method is only for CSPMiddleware, custom values are ignored in mergePolicies of ContentSecurityPolicyManager * @@ -102,7 +116,7 @@ class EmptyContentSecurityPolicy { * @since 11.0.0 */ public function useJsNonce($nonce) { - $this->useJsNonce = $nonce; + $this->jsNonce = $nonce; return $this; } @@ -446,29 +460,37 @@ class EmptyContentSecurityPolicy { $policy .= "base-uri 'none';"; $policy .= "manifest-src 'self';"; - if (!empty($this->allowedScriptDomains) || $this->evalScriptAllowed || $this->evalWasmAllowed) { + if (!empty($this->allowedScriptDomains) || $this->evalScriptAllowed || $this->evalWasmAllowed || is_string($this->jsNonce)) { $policy .= 'script-src '; - if (is_string($this->useJsNonce)) { + $scriptSrc = ''; + if (is_string($this->jsNonce)) { if ($this->strictDynamicAllowed) { - $policy .= '\'strict-dynamic\' '; + $scriptSrc .= '\'strict-dynamic\' '; } - $policy .= '\'nonce-'.base64_encode($this->useJsNonce).'\''; + $scriptSrc .= '\'nonce-'.base64_encode($this->jsNonce).'\''; $allowedScriptDomains = array_flip($this->allowedScriptDomains); unset($allowedScriptDomains['\'self\'']); $this->allowedScriptDomains = array_flip($allowedScriptDomains); if (count($allowedScriptDomains) !== 0) { - $policy .= ' '; + $scriptSrc .= ' '; } } if (is_array($this->allowedScriptDomains)) { - $policy .= implode(' ', $this->allowedScriptDomains); + $scriptSrc .= implode(' ', $this->allowedScriptDomains); } if ($this->evalScriptAllowed) { - $policy .= ' \'unsafe-eval\''; + $scriptSrc .= ' \'unsafe-eval\''; } if ($this->evalWasmAllowed) { - $policy .= ' \'wasm-unsafe-eval\''; + $scriptSrc .= ' \'wasm-unsafe-eval\''; } + $policy .= $scriptSrc . ';'; + } + + // We only need to set this if 'strictDynamicAllowed' is not set because otherwise we can simply fall back to script-src + if ($this->strictDynamicAllowedOnScripts && is_string($this->jsNonce) && !$this->strictDynamicAllowed) { + $policy .= 'script-src-elem \'strict-dynamic\' '; + $policy .= $scriptSrc ?? ''; $policy .= ';'; } diff --git a/lib/public/AppFramework/Http/ParameterOutOfRangeException.php b/lib/public/AppFramework/Http/ParameterOutOfRangeException.php new file mode 100644 index 00000000000..22518d8eddf --- /dev/null +++ b/lib/public/AppFramework/Http/ParameterOutOfRangeException.php @@ -0,0 +1,79 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\AppFramework\Http; + +/** + * @since 29.0.0 + */ +class ParameterOutOfRangeException extends \OutOfRangeException { + /** + * @since 29.0.0 + */ + public function __construct( + protected string $parameterName, + protected int $actualValue, + protected int $minValue, + protected int $maxValue, + ) { + parent::__construct( + sprintf( + 'Parameter %s must be between %d and %d', + $this->parameterName, + $this->minValue, + $this->maxValue, + ) + ); + } + + /** + * @since 29.0.0 + */ + public function getParameterName(): string { + return $this->parameterName; + } + + /** + * @since 29.0.0 + */ + public function getActualValue(): int { + return $this->actualValue; + } + + /** + * @since 29.0.0 + */ + public function getMinValue(): int { + return $this->minValue; + } + + /** + * @since 29.0.0 + */ + public function getMaxValue(): int { + return $this->maxValue; + } +} diff --git a/lib/public/AppFramework/Http/Response.php b/lib/public/AppFramework/Http/Response.php index dd4f2c53418..d28f45f4c60 100644 --- a/lib/public/AppFramework/Http/Response.php +++ b/lib/public/AppFramework/Http/Response.php @@ -112,9 +112,8 @@ class Response { */ public function cacheFor(int $cacheSeconds, bool $public = false, bool $immutable = false) { if ($cacheSeconds > 0) { - $pragma = $public ? 'public' : 'private'; - $this->addHeader('Cache-Control', sprintf('%s, max-age=%s, %s', $pragma, $cacheSeconds, ($immutable ? 'immutable' : 'must-revalidate'))); - $this->addHeader('Pragma', $pragma); + $cacheStore = $public ? 'public' : 'private'; + $this->addHeader('Cache-Control', sprintf('%s, max-age=%s, %s', $cacheStore, $cacheSeconds, ($immutable ? 'immutable' : 'must-revalidate'))); // Set expires header $expires = new \DateTime(); @@ -125,7 +124,7 @@ class Response { $this->addHeader('Expires', $expires->format(\DateTimeInterface::RFC2822)); } else { $this->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); - unset($this->headers['Expires'], $this->headers['Pragma']); + unset($this->headers['Expires']); } return $this; diff --git a/lib/public/AppFramework/Http/TooManyRequestsResponse.php b/lib/public/AppFramework/Http/TooManyRequestsResponse.php index 043ae0161e9..688fb6cc385 100644 --- a/lib/public/AppFramework/Http/TooManyRequestsResponse.php +++ b/lib/public/AppFramework/Http/TooManyRequestsResponse.php @@ -26,8 +26,8 @@ declare(strict_types=1); */ namespace OCP\AppFramework\Http; -use OCP\Template; use OCP\AppFramework\Http; +use OCP\Template; /** * A generic 429 response showing an 404 error page as well to the end-user diff --git a/lib/public/AppFramework/OCSController.php b/lib/public/AppFramework/OCSController.php index 51c71ad4e64..e7dd817b0aa 100644 --- a/lib/public/AppFramework/OCSController.php +++ b/lib/public/AppFramework/OCSController.php @@ -36,9 +36,24 @@ use OCP\IRequest; * @since 8.1.0 */ abstract class OCSController extends ApiController { + /** + * @since 22.0.0 + */ public const RESPOND_UNAUTHORISED = 997; + + /** + * @since 22.0.0 + */ public const RESPOND_SERVER_ERROR = 996; + + /** + * @since 22.0.0 + */ public const RESPOND_NOT_FOUND = 998; + + /** + * @since 22.0.0 + */ public const RESPOND_UNKNOWN_ERROR = 999; /** @var int */ @@ -59,10 +74,10 @@ abstract class OCSController extends ApiController { * @since 8.1.0 */ public function __construct($appName, - IRequest $request, - $corsMethods = 'PUT, POST, GET, DELETE, PATCH', - $corsAllowedHeaders = 'Authorization, Content-Type, Accept, OCS-APIRequest', - $corsMaxAge = 1728000) { + IRequest $request, + $corsMethods = 'PUT, POST, GET, DELETE, PATCH', + $corsAllowedHeaders = 'Authorization, Content-Type, Accept, OCS-APIRequest', + $corsMaxAge = 1728000) { parent::__construct($appName, $request, $corsMethods, $corsAllowedHeaders, $corsMaxAge); $this->registerResponder('json', function ($data) { diff --git a/lib/public/AppFramework/PublicShareController.php b/lib/public/AppFramework/PublicShareController.php index 52acbe841b4..cbcb9343198 100644 --- a/lib/public/AppFramework/PublicShareController.php +++ b/lib/public/AppFramework/PublicShareController.php @@ -53,8 +53,8 @@ abstract class PublicShareController extends Controller { * @since 14.0.0 */ public function __construct(string $appName, - IRequest $request, - ISession $session) { + IRequest $request, + ISession $session) { parent::__construct($appName, $request); $this->session = $session; @@ -86,7 +86,7 @@ abstract class PublicShareController extends Controller { * * @since 14.0.0 */ - abstract protected function getPasswordHash(): string; + abstract protected function getPasswordHash(): ?string; /** * Is the provided token a valid token diff --git a/lib/public/AppFramework/Services/IAppConfig.php b/lib/public/AppFramework/Services/IAppConfig.php index baac2946e3c..9340fdd3c32 100644 --- a/lib/public/AppFramework/Services/IAppConfig.php +++ b/lib/public/AppFramework/Services/IAppConfig.php @@ -5,6 +5,7 @@ declare(strict_types=1); /** * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl> * + * @author Maxence Lange <maxence@artificial-owl.com> * @author Roeland Jago Douma <roeland@famdouma.nl> * * @license GNU AGPL version 3 or any later version @@ -25,6 +26,8 @@ declare(strict_types=1); */ namespace OCP\AppFramework\Services; +use OCP\Exceptions\AppConfigUnknownKeyException; + /** * Wrapper for AppConfig for the AppFramework * @@ -37,7 +40,58 @@ interface IAppConfig { * @return string[] the keys stored for the app * @since 20.0.0 */ - public function getAppKeys(): array ; + public function getAppKeys(): array; + + /** + * Check if a key exists in the list of stored config values. + * + * @param string $key config key + * @param bool $lazy search within lazy loaded config + * + * @return bool TRUE if key exists + * @since 29.0.0 + */ + public function hasAppKey(string $key, ?bool $lazy = false): bool; + + /** + * best way to see if a value is set as sensitive (not displayed in report) + * + * @param string $key config key + * @param bool|null $lazy search within lazy loaded config + * + * @return bool TRUE if value is sensitive + * @throws AppConfigUnknownKeyException if config key is not known + * @since 29.0.0 + */ + public function isSensitive(string $key, ?bool $lazy = false): bool; + + /** + * Returns if the config key stored in database is lazy loaded + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @param string $key config key + * + * @return bool TRUE if config is lazy loaded + * @throws AppConfigUnknownKeyException if config key is not known + * @see IAppConfig for details about lazy loading + * @since 29.0.0 + */ + public function isLazy(string $key): bool; + + /** + * List all config values from an app with config key starting with $key. + * Returns an array with config key as key, stored value as value. + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @param string $key config keys prefix to search, can be empty. + * @param bool $filtered filter sensitive config values + * + * @return array<string, string> [configKey => configValue] + * @since 29.0.0 + */ + public function getAllAppValues(string $key = '', bool $filtered = false): array; /** * Writes a new app wide value @@ -46,20 +100,197 @@ interface IAppConfig { * @param string $value the value that should be stored * @return void * @since 20.0.0 + * @deprecated 29.0.0 use {@see setAppValueString()} */ public function setAppValue(string $key, string $value): void; /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param string $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueString(string $key, string $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * Store a config key and its value in database + * + * When handling huge value around and/or above 2,147,483,647, a debug log will be generated + * on 64bits system, as php int type reach its limit (and throw an exception) on 32bits when using huge numbers. + * + * When using huge numbers, it is advised to use {@see \OCP\Util::numericToNumber()} and {@see setValueString()} + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param int $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueInt(string $key, int $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * Store a config key and its value in database. + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param float $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueFloat(string $key, float $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param bool $value config value + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueBool(string $key, bool $value, bool $lazy = false): bool; + + /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $key config key + * @param array $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function setAppValueArray(string $key, array $value, bool $lazy = false, bool $sensitive = false): bool; + + /** * Looks up an app wide defined value * * @param string $key the key of the value, under which it was saved * @param string $default the default value to be returned if the value isn't set + * * @return string the saved value * @since 20.0.0 + * @deprecated 29.0.0 use {@see getAppValueString()} */ public function getAppValue(string $key, string $default = ''): string; /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param string $default default value + * @param bool $lazy search within lazy loaded config + * + * @return string stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueString(string $key, string $default = '', bool $lazy = false): string; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param int $default default value + * @param bool $lazy search within lazy loaded config + * + * @return int stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueInt(string $key, int $default = 0, bool $lazy = false): int; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param float $default default value + * @param bool $lazy search within lazy loaded config + * + * @return float stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueFloat(string $key, float $default = 0, bool $lazy = false): float; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param bool $default default value + * @param bool $lazy search within lazy loaded config + * + * @return bool stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueBool(string $key, bool $default = false, bool $lazy = false): bool; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $key config key + * @param array $default default value + * @param bool $lazy search within lazy loaded config + * + * @return array stored config value or $default if not set in database + * @since 29.0.0 + * @see \OCP\IAppConfig for explanation about lazy loading + */ + public function getAppValueArray(string $key, array $default = [], bool $lazy = false): array; + + /** * Delete an app wide defined value * * @param string $key the key of the value, under which it was saved diff --git a/lib/public/AppFramework/Utility/ITimeFactory.php b/lib/public/AppFramework/Utility/ITimeFactory.php index d4f74c9d107..be1b80ff617 100644 --- a/lib/public/AppFramework/Utility/ITimeFactory.php +++ b/lib/public/AppFramework/Utility/ITimeFactory.php @@ -33,7 +33,7 @@ use Psr\Clock\ClockInterface; * Use this to get a timestamp or DateTime object in code to remain testable * * @since 8.0.0 - * @since 26.0.0 Extends the \Psr\Clock\ClockInterface interface + * @since 27.0.0 Extends the \Psr\Clock\ClockInterface interface * @ref https://www.php-fig.org/psr/psr-20/#21-clockinterface */ @@ -58,4 +58,12 @@ interface ITimeFactory extends ClockInterface { * @since 26.0.0 */ public function withTimeZone(\DateTimeZone $timezone): static; + + /** + * @param string|null $timezone + * @return \DateTimeZone Requested timezone if provided, UTC otherwise + * @throws \Exception + * @since 29.0.0 + */ + public function getTimeZone(?string $timezone = null): \DateTimeZone; } diff --git a/lib/public/Authentication/Exceptions/ExpiredTokenException.php b/lib/public/Authentication/Exceptions/ExpiredTokenException.php new file mode 100644 index 00000000000..5c1f4a30541 --- /dev/null +++ b/lib/public/Authentication/Exceptions/ExpiredTokenException.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Authentication\Exceptions; + +use OCP\Authentication\Token\IToken; + +/** + * @since 28.0.0 + */ +class ExpiredTokenException extends InvalidTokenException { + /** + * @since 28.0.0 + */ + public function __construct( + private IToken $token, + ) { + parent::__construct(); + } + + /** + * @since 28.0.0 + */ + public function getToken(): IToken { + return $this->token; + } +} diff --git a/lib/private/BackgroundJob/QueuedJob.php b/lib/public/Authentication/Exceptions/InvalidTokenException.php index 28d86481e62..4869cbd6465 100644 --- a/lib/private/BackgroundJob/QueuedJob.php +++ b/lib/public/Authentication/Exceptions/InvalidTokenException.php @@ -1,11 +1,11 @@ <?php + +declare(strict_types=1); + /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> * * @license AGPL-3.0 * @@ -22,28 +22,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/> * */ -namespace OC\BackgroundJob; +namespace OCP\Authentication\Exceptions; -use OCP\ILogger; +use Exception; /** - * Class QueuedJob - * - * create a background job that is to be executed once - * - * @package OC\BackgroundJob - * - * @deprecated internal class, use \OCP\BackgroundJob\QueuedJob + * @since 28.0.0 */ -abstract class QueuedJob extends Job { - /** - * run the job, then remove it from the joblist - * - * @param JobList $jobList - * @param ILogger|null $logger - */ - public function execute($jobList, ILogger $logger = null) { - $jobList->remove($this, $this->argument); - parent::execute($jobList, $logger); - } +class InvalidTokenException extends Exception { } diff --git a/lib/public/Authentication/Exceptions/WipeTokenException.php b/lib/public/Authentication/Exceptions/WipeTokenException.php new file mode 100644 index 00000000000..81ea2dc57ad --- /dev/null +++ b/lib/public/Authentication/Exceptions/WipeTokenException.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Authentication\Exceptions; + +use OCP\Authentication\Token\IToken; + +/** + * @since 28.0.0 + */ +class WipeTokenException extends InvalidTokenException { + /** + * @since 28.0.0 + */ + public function __construct( + private IToken $token, + ) { + parent::__construct(); + } + + /** + * @since 28.0.0 + */ + public function getToken(): IToken { + return $this->token; + } +} diff --git a/lib/public/Authentication/Token/IProvider.php b/lib/public/Authentication/Token/IProvider.php index da2e400eb79..59d2b8f3649 100644 --- a/lib/public/Authentication/Token/IProvider.php +++ b/lib/public/Authentication/Token/IProvider.php @@ -24,6 +24,10 @@ declare(strict_types=1); */ namespace OCP\Authentication\Token; +use OCP\Authentication\Exceptions\ExpiredTokenException; +use OCP\Authentication\Exceptions\InvalidTokenException; +use OCP\Authentication\Exceptions\WipeTokenException; + /** * @since 24.0.8 */ @@ -38,4 +42,15 @@ interface IProvider { * @return void */ public function invalidateTokensOfUser(string $uid, ?string $clientName); + + /** + * Get a token by token string id + * + * @since 28.0.0 + * @throws InvalidTokenException + * @throws ExpiredTokenException + * @throws WipeTokenException + * @return IToken + */ + public function getToken(string $tokenId): IToken; } diff --git a/lib/public/Authentication/Token/IToken.php b/lib/public/Authentication/Token/IToken.php new file mode 100644 index 00000000000..7b6ce8327c6 --- /dev/null +++ b/lib/public/Authentication/Token/IToken.php @@ -0,0 +1,139 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2016, ownCloud, Inc. + * + * @author Christoph Wurst <christoph@winzerhof-wurst.at> + * @author Robin Appelman <robin@icewind.nl> + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ +namespace OCP\Authentication\Token; + +use JsonSerializable; + +/** + * @since 28.0.0 + */ +interface IToken extends JsonSerializable { + /** + * @since 28.0.0 + */ + public const TEMPORARY_TOKEN = 0; + /** + * @since 28.0.0 + */ + public const PERMANENT_TOKEN = 1; + /** + * @since 28.0.0 + */ + public const WIPE_TOKEN = 2; + /** + * @since 28.0.0 + */ + public const DO_NOT_REMEMBER = 0; + /** + * @since 28.0.0 + */ + public const REMEMBER = 1; + + /** + * Get the token ID + * @since 28.0.0 + */ + public function getId(): int; + + /** + * Get the user UID + * @since 28.0.0 + */ + public function getUID(): string; + + /** + * Get the login name used when generating the token + * @since 28.0.0 + */ + public function getLoginName(): string; + + /** + * Get the (encrypted) login password + * @since 28.0.0 + */ + public function getPassword(): ?string; + + /** + * Get the timestamp of the last password check + * @since 28.0.0 + */ + public function getLastCheck(): int; + + /** + * Set the timestamp of the last password check + * @since 28.0.0 + */ + public function setLastCheck(int $time): void; + + /** + * Get the authentication scope for this token + * @since 28.0.0 + */ + public function getScope(): string; + + /** + * Get the authentication scope for this token + * @since 28.0.0 + */ + public function getScopeAsArray(): array; + + /** + * Set the authentication scope for this token + * @since 28.0.0 + */ + public function setScope(array $scope): void; + + /** + * Get the name of the token + * @since 28.0.0 + */ + public function getName(): string; + + /** + * Get the remember state of the token + * @since 28.0.0 + */ + public function getRemember(): int; + + /** + * Set the token + * @since 28.0.0 + */ + public function setToken(string $token): void; + + /** + * Set the password + * @since 28.0.0 + */ + public function setPassword(string $password): void; + + /** + * Set the expiration time of the token + * @since 28.0.0 + */ + public function setExpires(?int $expires): void; +} diff --git a/lib/public/Authentication/TwoFactorAuth/IRegistry.php b/lib/public/Authentication/TwoFactorAuth/IRegistry.php index 0f164902f67..19010e5e5bf 100644 --- a/lib/public/Authentication/TwoFactorAuth/IRegistry.php +++ b/lib/public/Authentication/TwoFactorAuth/IRegistry.php @@ -39,11 +39,13 @@ use OCP\IUser; */ interface IRegistry { /** + * @since 15.0.0 * @deprecated 22.0.0 */ public const EVENT_PROVIDER_ENABLED = self::class . '::enable'; /** + * @since 15.0.0 * @deprecated 22.0.0 */ public const EVENT_PROVIDER_DISABLED = self::class . '::disable'; diff --git a/lib/public/BackgroundJob/IJobList.php b/lib/public/BackgroundJob/IJobList.php index 65e2f5b6250..07b5ebcf48b 100644 --- a/lib/public/BackgroundJob/IJobList.php +++ b/lib/public/BackgroundJob/IJobList.php @@ -32,8 +32,8 @@ namespace OCP\BackgroundJob; * This interface provides functions to register background jobs * * To create a new background job create a new class that inherits from either - * \OC\BackgroundJob\Job, \OC\BackgroundJob\QueuedJob or - * \OC\BackgroundJob\TimedJob and register it using ->add($job, $argument), + * \OCP\BackgroundJob\Job, \OCP\BackgroundJob\QueuedJob or + * \OCP\BackgroundJob\TimedJob and register it using ->add($job, $argument), * $argument will be passed to the run() function of the job when the job is * executed. * @@ -58,6 +58,19 @@ interface IJobList { public function add($job, $argument = null): void; /** + * Add a job to the list but only run it after the given timestamp + * + * For cron background jobs this means the job will likely run shortly after the timestamp + * has been reached. For ajax background jobs the job might only run when users are active + * on the instance again. + * + * @param class-string<IJob> $job + * @param mixed $argument The serializable argument to be passed to $job->run() when the job is executed + * @since 28.0.0 + */ + public function scheduleAfter(string $job, int $runAfter, $argument = null): void; + + /** * Remove a job from the list * * @param IJob|class-string<IJob> $job @@ -147,7 +160,8 @@ interface IJobList { public function resetBackgroundJob(IJob $job): void; /** - * Checks whether a job of the passed class is reserved to run + * Checks whether a job of the passed class was reserved to run + * in the last 6h * * @param string|null $className * @return bool diff --git a/lib/public/BackgroundJob/Job.php b/lib/public/BackgroundJob/Job.php index a574e90e1a0..3d1a117ac9e 100644 --- a/lib/public/BackgroundJob/Job.php +++ b/lib/public/BackgroundJob/Job.php @@ -44,7 +44,6 @@ abstract class Job implements IJob, IParallelAwareJob { protected $argument; protected ITimeFactory $time; protected bool $allowParallelRuns = true; - private ?ILogger $logger = null; /** * @since 15.0.0 @@ -56,14 +55,13 @@ abstract class Job implements IJob, IParallelAwareJob { /** * The function to prepare the execution of the job. * - * - * @param IJobList $jobList - * @param ILogger|null $logger + * @return void * * @since 15.0.0 + * @deprecated since 25.0.0 Use start() instead. This method will be removed + * with the ILogger interface */ - public function execute(IJobList $jobList, ILogger $logger = null) { - $this->logger = $logger; + public function execute(IJobList $jobList, ?ILogger $logger = null) { $this->start($jobList); } @@ -73,19 +71,20 @@ abstract class Job implements IJob, IParallelAwareJob { */ public function start(IJobList $jobList): void { $jobList->setLastRun($this); - $logger = $this->logger ?? \OCP\Server::get(LoggerInterface::class); + $logger = \OCP\Server::get(LoggerInterface::class); try { + $jobDetails = get_class($this) . ' (id: ' . $this->getId() . ', arguments: ' . json_encode($this->getArgument()) . ')'; $jobStartTime = $this->time->getTime(); - $logger->debug('Run ' . get_class($this) . ' job with ID ' . $this->getId(), ['app' => 'cron']); + $logger->debug('Starting job ' . $jobDetails, ['app' => 'cron']); $this->run($this->argument); $timeTaken = $this->time->getTime() - $jobStartTime; - $logger->debug('Finished ' . get_class($this) . ' job with ID ' . $this->getId() . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']); + $logger->debug('Finished job ' . $jobDetails . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']); $jobList->setExecutionTime($this, $timeTaken); } catch (\Throwable $e) { if ($logger) { - $logger->error('Error while running background job (class: ' . get_class($this) . ', arguments: ' . print_r($this->argument, true) . ')', [ + $logger->error('Error while running background job ' . $jobDetails, [ 'app' => 'core', 'exception' => $e, ]); @@ -158,6 +157,7 @@ abstract class Job implements IJob, IParallelAwareJob { * The actual function that is called to run the job * * @param $argument + * @return void * * @since 15.0.0 */ diff --git a/lib/public/Cache/CappedMemoryCache.php b/lib/public/Cache/CappedMemoryCache.php index 6699600d42c..c92f68044ba 100644 --- a/lib/public/Cache/CappedMemoryCache.php +++ b/lib/public/Cache/CappedMemoryCache.php @@ -30,6 +30,7 @@ use OCP\ICache; * * @since 25.0.0 * @template T + * @template-implements \ArrayAccess<string,T> */ class CappedMemoryCache implements ICache, \ArrayAccess { private int $capacity; diff --git a/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php b/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php index 5206dc37115..23879b93fa1 100644 --- a/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php +++ b/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php @@ -29,6 +29,7 @@ use OCP\EventDispatcher\GenericEvent; /** * @since 16.0.0 + * @deprecated Use {@see AutoCompleteFilterEvent} instead */ class AutoCompleteEvent extends GenericEvent { /** diff --git a/lib/public/Collaboration/AutoComplete/AutoCompleteFilterEvent.php b/lib/public/Collaboration/AutoComplete/AutoCompleteFilterEvent.php new file mode 100644 index 00000000000..fd1bec42abf --- /dev/null +++ b/lib/public/Collaboration/AutoComplete/AutoCompleteFilterEvent.php @@ -0,0 +1,107 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Collaboration\AutoComplete; + +use OCP\EventDispatcher\Event; + +/** + * @since 28.0.0 + */ +class AutoCompleteFilterEvent extends Event { + /** + * @since 28.0.0 + */ + public function __construct( + protected array $results, + protected string $search, + protected ?string $itemType, + protected ?string $itemId, + protected ?string $sorter, + protected array $shareTypes, + protected int $limit, + ) { + parent::__construct(); + } + + /** + * @since 28.0.0 + */ + public function getResults(): array { + return $this->results; + } + + /** + * @param array $results + * @since 28.0.0 + */ + public function setResults(array $results): void { + $this->results = $results; + } + + /** + * @since 28.0.0 + */ + public function getSearchTerm(): string { + return $this->search; + } + + /** + * @return int[] List of `\OCP\Share\IShare::TYPE_*` constants + * @since 28.0.0 + */ + public function getShareTypes(): array { + return $this->shareTypes; + } + + /** + * @since 28.0.0 + */ + public function getItemType(): ?string { + return $this->itemType; + } + + /** + * @since 28.0.0 + */ + public function getItemId(): ?string { + return $this->itemId; + } + + /** + * @return ?string List of desired sort identifiers, top priority first. When multiple are given they are joined with a pipe: `commenters|share-recipients` + * @since 28.0.0 + */ + public function getSorter(): ?string { + return $this->sorter; + } + + /** + * @since 28.0.0 + */ + public function getLimit(): int { + return $this->limit; + } +} diff --git a/lib/public/Collaboration/Reference/IReference.php b/lib/public/Collaboration/Reference/IReference.php index 1b9157fd9b1..c0cfa72c36d 100644 --- a/lib/public/Collaboration/Reference/IReference.php +++ b/lib/public/Collaboration/Reference/IReference.php @@ -126,4 +126,11 @@ interface IReference extends JsonSerializable { * @since 25.0.0 */ public function getOpenGraphObject(): array; + + /** + * @return array{richObjectType: string, richObject: array<string, mixed>, openGraphObject: array{id: string, name: string, description: ?string, thumb: ?string, link: string}, accessible: bool} + * + * @since 25.0.0 + */ + public function jsonSerialize(): array; } diff --git a/lib/public/Collaboration/Reference/LinkReferenceProvider.php b/lib/public/Collaboration/Reference/LinkReferenceProvider.php new file mode 100644 index 00000000000..d41c1160c7c --- /dev/null +++ b/lib/public/Collaboration/Reference/LinkReferenceProvider.php @@ -0,0 +1,221 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * @author Anupam Kumar <kyteinsky@gmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\Collaboration\Reference; + +use Fusonic\OpenGraph\Consumer; +use GuzzleHttp\Exception\GuzzleException; +use GuzzleHttp\Psr7\LimitStream; +use GuzzleHttp\Psr7\Utils; +use OC\Security\RateLimiting\Exception\RateLimitExceededException; +use OC\Security\RateLimiting\Limiter; +use OC\SystemConfig; +use OCP\Files\AppData\IAppDataFactory; +use OCP\Files\NotFoundException; +use OCP\Http\Client\IClientService; +use OCP\IRequest; +use OCP\IURLGenerator; +use OCP\IUserSession; +use Psr\Log\LoggerInterface; + +/** + * @since 29.0.0 + */ +class LinkReferenceProvider implements IReferenceProvider { + + /** + * for image size and webpage header + * @since 29.0.0 + */ + public const MAX_CONTENT_LENGTH = 5 * 1024 * 1024; + + /** + * @since 29.0.0 + */ + public const ALLOWED_CONTENT_TYPES = [ + 'image/png', + 'image/jpg', + 'image/jpeg', + 'image/gif', + 'image/svg+xml', + 'image/webp' + ]; + + /** + * @since 29.0.0 + */ + public function __construct( + private IClientService $clientService, + private LoggerInterface $logger, + private SystemConfig $systemConfig, + private IAppDataFactory $appDataFactory, + private IURLGenerator $urlGenerator, + private Limiter $limiter, + private IUserSession $userSession, + private IRequest $request, + ) { + } + + /** + * @inheritDoc + * @since 29.0.0 + */ + public function matchReference(string $referenceText): bool { + if ($this->systemConfig->getValue('reference_opengraph', true) !== true) { + return false; + } + + return (bool)preg_match(IURLGenerator::URL_REGEX, $referenceText); + } + + /** + * @inheritDoc + * @since 29.0.0 + */ + public function resolveReference(string $referenceText): ?IReference { + if ($this->matchReference($referenceText)) { + $reference = new Reference($referenceText); + $this->fetchReference($reference); + return $reference; + } + + return null; + } + + /** + * Populates the reference with OpenGraph data + * + * @param Reference $reference + * @since 29.0.0 + */ + private function fetchReference(Reference $reference): void { + try { + $user = $this->userSession->getUser(); + if ($user) { + $this->limiter->registerUserRequest('opengraph', 10, 120, $user); + } else { + $this->limiter->registerAnonRequest('opengraph', 10, 120, $this->request->getRemoteAddress()); + } + } catch (RateLimitExceededException $e) { + return; + } + + $client = $this->clientService->newClient(); + try { + $headResponse = $client->head($reference->getId(), [ 'timeout' => 10 ]); + } catch (\Exception $e) { + $this->logger->debug('Failed to perform HEAD request to get target metadata', ['exception' => $e]); + return; + } + + $linkContentLength = $headResponse->getHeader('Content-Length'); + if (is_numeric($linkContentLength) && (int) $linkContentLength > self::MAX_CONTENT_LENGTH) { + $this->logger->debug('Skip resolving links pointing to content length > 5 MiB'); + return; + } + + $linkContentType = $headResponse->getHeader('Content-Type'); + $expectedContentTypeRegex = '/^text\/html;?/i'; + + // check the header begins with the expected content type + if (!preg_match($expectedContentTypeRegex, $linkContentType)) { + $this->logger->debug('Skip resolving links pointing to content type that is not "text/html"'); + return; + } + + try { + $response = $client->get($reference->getId(), [ 'timeout' => 10 ]); + } catch (\Exception $e) { + $this->logger->debug('Failed to fetch link for obtaining open graph data', ['exception' => $e]); + return; + } + + $responseBody = (string)$response->getBody(); + + // OpenGraph handling + $consumer = new Consumer(); + $consumer->useFallbackMode = true; + $object = $consumer->loadHtml($responseBody); + + $reference->setUrl($reference->getId()); + + if ($object->title) { + $reference->setTitle($object->title); + } + + if ($object->description) { + $reference->setDescription($object->description); + } + + if ($object->images) { + try { + $host = parse_url($object->images[0]->url, PHP_URL_HOST); + if ($host === false || $host === null) { + $this->logger->warning('Could not detect host of open graph image URI for ' . $reference->getId()); + return; + } + + $appData = $this->appDataFactory->get('core'); + try { + $folder = $appData->getFolder('opengraph'); + } catch (NotFoundException $e) { + $folder = $appData->newFolder('opengraph'); + } + + $response = $client->get($object->images[0]->url, ['timeout' => 10]); + $contentType = $response->getHeader('Content-Type'); + $contentLength = $response->getHeader('Content-Length'); + + if (in_array($contentType, self::ALLOWED_CONTENT_TYPES, true) && $contentLength < self::MAX_CONTENT_LENGTH) { + $stream = Utils::streamFor($response->getBody()); + $bodyStream = new LimitStream($stream, self::MAX_CONTENT_LENGTH, 0); + $reference->setImageContentType($contentType); + $folder->newFile(md5($reference->getId()), $bodyStream->getContents()); + $reference->setImageUrl($this->urlGenerator->linkToRouteAbsolute('core.Reference.preview', ['referenceId' => md5($reference->getId())])); + } + } catch (GuzzleException $e) { + $this->logger->info('Failed to fetch and store the open graph image for ' . $reference->getId(), ['exception' => $e]); + } catch (\Throwable $e) { + $this->logger->error('Failed to fetch and store the open graph image for ' . $reference->getId(), ['exception' => $e]); + } + } + } + + /** + * @inheritDoc + * @since 29.0.0 + */ + public function getCachePrefix(string $referenceId): string { + return $referenceId; + } + + /** + * @inheritDoc + * @since 29.0.0 + */ + public function getCacheKey(string $referenceId): ?string { + return null; + } +} diff --git a/lib/public/Collaboration/Reference/Reference.php b/lib/public/Collaboration/Reference/Reference.php index 0dcb665713c..8dc88edbeac 100644 --- a/lib/public/Collaboration/Reference/Reference.php +++ b/lib/public/Collaboration/Reference/Reference.php @@ -242,7 +242,7 @@ class Reference implements IReference { * @since 25.0.0 * @return array{richObjectType: string, richObject: array<string, mixed>, openGraphObject: OpenGraphObject, accessible: bool} */ - public function jsonSerialize() { + public function jsonSerialize(): array { return [ 'richObjectType' => $this->getRichObjectType(), 'richObject' => $this->getRichObject(), diff --git a/lib/public/Comments/CommentsEntityEvent.php b/lib/public/Comments/CommentsEntityEvent.php index 3336b80d6b5..fd43a5539ff 100644 --- a/lib/public/Comments/CommentsEntityEvent.php +++ b/lib/public/Comments/CommentsEntityEvent.php @@ -33,6 +33,7 @@ use OCP\EventDispatcher\Event; */ class CommentsEntityEvent extends Event { /** + * @since 9.1.0 * @deprecated 22.0.0 - Listen to the typed event instead. */ public const EVENT_ENTITY = 'OCP\Comments\ICommentsManager::registerEntity'; diff --git a/lib/public/Comments/CommentsEvent.php b/lib/public/Comments/CommentsEvent.php index 1793a1e3a86..b04b5c2e6f9 100644 --- a/lib/public/Comments/CommentsEvent.php +++ b/lib/public/Comments/CommentsEvent.php @@ -32,21 +32,25 @@ use OCP\EventDispatcher\Event; */ class CommentsEvent extends Event { /** + * @since 11.0.0 * @deprecated 22.0.0 */ public const EVENT_ADD = 'OCP\Comments\ICommentsManager::addComment'; /** + * @since 11.0.0 * @deprecated 22.0.0 */ public const EVENT_PRE_UPDATE = 'OCP\Comments\ICommentsManager::preUpdateComment'; /** + * @since 11.0.0 * @deprecated 22.0.0 */ public const EVENT_UPDATE = 'OCP\Comments\ICommentsManager::updateComment'; /** + * @since 11.0.0 * @deprecated 22.0.0 */ public const EVENT_DELETE = 'OCP\Comments\ICommentsManager::deleteComment'; diff --git a/lib/public/Comments/IComment.php b/lib/public/Comments/IComment.php index eb696fa5f06..8182bcd15d0 100644 --- a/lib/public/Comments/IComment.php +++ b/lib/public/Comments/IComment.php @@ -33,6 +33,9 @@ namespace OCP\Comments; * @since 9.0.0 */ interface IComment { + /** + * @since 9.0.0 + */ public const MAX_MESSAGE_LENGTH = 1000; /** @@ -280,6 +283,25 @@ interface IComment { public function setReferenceId(?string $referenceId): IComment; /** + * Returns the metadata of the comment + * + * @return array|null + * @since 29.0.0 + */ + public function getMetaData(): ?array; + + /** + * Sets (overwrites) the metadata of the comment + * Data as a json encoded array + * + * @param array|null $metaData + * @return IComment + * @throws \JsonException When the metadata can not be converted to a json encoded string + * @since 29.0.0 + */ + public function setMetaData(?array $metaData): IComment; + + /** * Returns the reactions array if exists * * The keys is the emoji of reaction and the value is the total. diff --git a/lib/public/Comments/ICommentsManager.php b/lib/public/Comments/ICommentsManager.php index 8d7ffd164b3..3d47be3d951 100644 --- a/lib/public/Comments/ICommentsManager.php +++ b/lib/public/Comments/ICommentsManager.php @@ -114,11 +114,11 @@ interface ICommentsManager { * @since 9.0.0 */ public function getForObject( - $objectType, - $objectId, - $limit = 0, - $offset = 0, - \DateTime $notOlderThan = null + $objectType, + $objectId, + $limit = 0, + $offset = 0, + \DateTime $notOlderThan = null ); /** @@ -271,6 +271,7 @@ interface ICommentsManager { * @param IUser $user * @return array [$fileId => $unreadCount] * @since 12.0.0 + * @deprecated 29.0.0 use getNumberOfUnreadCommentsForObjects instead */ public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user); diff --git a/lib/public/Console/ConsoleEvent.php b/lib/public/Console/ConsoleEvent.php index 99f42d2895f..2ab2521527c 100644 --- a/lib/public/Console/ConsoleEvent.php +++ b/lib/public/Console/ConsoleEvent.php @@ -32,6 +32,7 @@ use OCP\EventDispatcher\Event; */ class ConsoleEvent extends Event { /** + * @since 9.0.0 * @deprecated 22.0.0 */ public const EVENT_RUN = 'OC\Console\Application::run'; diff --git a/lib/public/Constants.php b/lib/public/Constants.php index 6a38190e167..8bae05b51e8 100644 --- a/lib/public/Constants.php +++ b/lib/public/Constants.php @@ -43,10 +43,30 @@ class Constants { * @since 8.0.0 */ public const PERMISSION_CREATE = 4; + + /** + * @since 8.0.0 + */ public const PERMISSION_READ = 1; + + /** + * @since 8.0.0 + */ public const PERMISSION_UPDATE = 2; + + /** + * @since 8.0.0 + */ public const PERMISSION_DELETE = 8; + + /** + * @since 8.0.0 + */ public const PERMISSION_SHARE = 16; + + /** + * @since 8.0.0 + */ public const PERMISSION_ALL = 31; /** diff --git a/lib/public/Contacts/ContactsMenu/IBulkProvider.php b/lib/public/Contacts/ContactsMenu/IBulkProvider.php new file mode 100644 index 00000000000..43d727e2ec3 --- /dev/null +++ b/lib/public/Contacts/ContactsMenu/IBulkProvider.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Contacts\ContactsMenu; + +/** + * Process contacts menu entries in bulk + * + * @since 28.0 + */ +interface IBulkProvider { + /** + * @since 28.0 + * @param list<IEntry> $entries + * @return void + */ + public function process(array $entries): void; +} diff --git a/lib/public/Contacts/ContactsMenu/IEntry.php b/lib/public/Contacts/ContactsMenu/IEntry.php index 9d78b0c8f57..1307e2c74f7 100644 --- a/lib/public/Contacts/ContactsMenu/IEntry.php +++ b/lib/public/Contacts/ContactsMenu/IEntry.php @@ -54,6 +54,20 @@ interface IEntry extends JsonSerializable { public function addAction(IAction $action): void; /** + * Set the (system) contact's user status + * + * @since 28.0 + * @param string $status + * @param string $statusMessage + * @param string|null $icon + * @return void + */ + public function setStatus(string $status, + string $statusMessage = null, + int $statusMessageTimestamp = null, + string $icon = null): void; + + /** * Get an arbitrary property from the contact * * @since 12.0 diff --git a/lib/public/Contacts/ContactsMenu/IProvider.php b/lib/public/Contacts/ContactsMenu/IProvider.php index c05f2707c18..200ee0b1fea 100644 --- a/lib/public/Contacts/ContactsMenu/IProvider.php +++ b/lib/public/Contacts/ContactsMenu/IProvider.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> * @@ -23,6 +26,10 @@ namespace OCP\Contacts\ContactsMenu; /** + * Process contacts menu entries + * + * @see IBulkProvider for providers that work with the full dataset at once + * * @since 12.0 */ interface IProvider { diff --git a/lib/public/Contacts/IManager.php b/lib/public/Contacts/IManager.php index 6ca349b95d0..97fa2e61529 100644 --- a/lib/public/Contacts/IManager.php +++ b/lib/public/Contacts/IManager.php @@ -107,22 +107,22 @@ interface IManager { * This function can be used to delete the contact identified by the given id * * @param int $id the unique identifier to a contact - * @param string $address_book_key identifier of the address book in which the contact shall be deleted + * @param string $addressBookKey identifier of the address book in which the contact shall be deleted * @return bool successful or not * @since 6.0.0 */ - public function delete($id, $address_book_key); + public function delete($id, $addressBookKey); /** * This function is used to create a new contact if 'id' is not given or not present. * Otherwise the contact will be updated by replacing the entire data set. * * @param array $properties this array if key-value-pairs defines a contact - * @param string $address_book_key identifier of the address book in which the contact shall be created or updated - * @return array an array representing the contact just created or updated + * @param string $addressBookKey identifier of the address book in which the contact shall be created or updated + * @return ?array an array representing the contact just created or updated * @since 6.0.0 */ - public function createOrUpdate($properties, $address_book_key); + public function createOrUpdate($properties, $addressBookKey); /** * Check if contacts are available (e.g. contacts app enabled) @@ -135,20 +135,19 @@ interface IManager { /** * Registers an address book * - * @param \OCP\IAddressBook $address_book * @return void * @since 6.0.0 */ - public function registerAddressBook(\OCP\IAddressBook $address_book); + public function registerAddressBook(\OCP\IAddressBook $addressBook); /** * Unregisters an address book * - * @param \OCP\IAddressBook $address_book + * @param \OCP\IAddressBook $addressBook * @return void * @since 6.0.0 */ - public function unregisterAddressBook(\OCP\IAddressBook $address_book); + public function unregisterAddressBook(\OCP\IAddressBook $addressBook); /** * In order to improve lazy loading a closure can be registered which will be called in case diff --git a/lib/public/DB/Events/AddMissingIndicesEvent.php b/lib/public/DB/Events/AddMissingIndicesEvent.php index dc942f3d63e..8b6d2a07a0c 100644 --- a/lib/public/DB/Events/AddMissingIndicesEvent.php +++ b/lib/public/DB/Events/AddMissingIndicesEvent.php @@ -39,6 +39,9 @@ class AddMissingIndicesEvent extends \OCP\EventDispatcher\Event { /** @var array<array-key, array{tableName: string, indexName: string, columns: string[], options: array{}, dropUnnamedIndex: bool, uniqueIndex: bool}> */ private array $missingIndices = []; + /** @var array<array-key, array{tableName: string, oldIndexNames: array, newIndexName: string, columns: string[], uniqueIndex: bool, options: array{}}> */ + private array $toReplaceIndices = []; + /** * @param string[] $columns * @since 28.0.0 @@ -75,4 +78,42 @@ class AddMissingIndicesEvent extends \OCP\EventDispatcher\Event { public function getMissingIndices(): array { return $this->missingIndices; } + + /** + * Replace one or more existing indices with a new one. Can be used to make an index unique afterwards or merge two indices into a multicolumn index. + * + * Note: Make sure to not use the same index name for the new index as for old indices. + * + * Example: + * + * <code> + * $event->replaceIndex( + * 'my_table', + * ['old_index_col_a', 'old_index_col_b'], + * 'new_index_col_a_b', + * ['column_a', 'column_b'], + * false + * ); + * </code> + * + * @since 29.0.0 + */ + public function replaceIndex(string $tableName, array $oldIndexNames, string $newIndexName, array $columns, bool $unique, array $options = []): void { + $this->toReplaceIndices[] = [ + 'tableName' => $tableName, + 'oldIndexNames' => $oldIndexNames, + 'newIndexName' => $newIndexName, + 'columns' => $columns, + 'uniqueIndex' => $unique, + 'options' => $options, + ]; + } + + /** + * @since 29.0.0 + * @return array<array-key, array{tableName: string, oldIndexNames: array, newIndexName: string, columns: string[], uniqueIndex: bool, options: array{}}> + */ + public function getIndicesToReplace(): array { + return $this->toReplaceIndices; + } } diff --git a/lib/public/DB/QueryBuilder/IQueryBuilder.php b/lib/public/DB/QueryBuilder/IQueryBuilder.php index 63fdfb65971..dba5f390d6e 100644 --- a/lib/public/DB/QueryBuilder/IQueryBuilder.php +++ b/lib/public/DB/QueryBuilder/IQueryBuilder.php @@ -27,6 +27,7 @@ */ namespace OCP\DB\QueryBuilder; +use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\Connection; use Doctrine\DBAL\ParameterType; use OCP\DB\Exception; @@ -72,11 +73,11 @@ interface IQueryBuilder { /** * @since 9.0.0 */ - public const PARAM_INT_ARRAY = Connection::PARAM_INT_ARRAY; + public const PARAM_INT_ARRAY = ArrayParameterType::INTEGER; /** * @since 9.0.0 */ - public const PARAM_STR_ARRAY = Connection::PARAM_STR_ARRAY; + public const PARAM_STR_ARRAY = ArrayParameterType::STRING; /** * @since 24.0.0 Indicates how many rows can be deleted at once with MySQL @@ -907,7 +908,7 @@ interface IQueryBuilder { * @link http://www.zetacomponents.org * * @param mixed $value - * @param mixed $type + * @param self::PARAM_* $type * @param string $placeHolder The name to bind with. The string must start with a colon ':'. * * @return IParameter @@ -935,7 +936,7 @@ interface IQueryBuilder { * </code> * * @param mixed $value - * @param integer $type + * @param self::PARAM_* $type * * @return IParameter * @since 8.2.0 diff --git a/lib/public/Dashboard/IManager.php b/lib/public/Dashboard/IManager.php index 77bff7b34ff..135fd4b4514 100644 --- a/lib/public/Dashboard/IManager.php +++ b/lib/public/Dashboard/IManager.php @@ -40,7 +40,7 @@ interface IManager { /** * @since 20.0.0 * - * @return IWidget[] + * @return array<string, IWidget> */ public function getWidgets(): array; } diff --git a/lib/public/Dashboard/Model/WidgetButton.php b/lib/public/Dashboard/Model/WidgetButton.php index 480249b539f..57ea06ec6b1 100644 --- a/lib/public/Dashboard/Model/WidgetButton.php +++ b/lib/public/Dashboard/Model/WidgetButton.php @@ -29,8 +29,19 @@ namespace OCP\Dashboard\Model; * @since 25.0.0 */ class WidgetButton { + /** + * @since 25.0.0 + */ public const TYPE_NEW = 'new'; + + /** + * @since 25.0.0 + */ public const TYPE_MORE = 'more'; + + /** + * @since 25.0.0 + */ public const TYPE_SETUP = 'setup'; private string $type; diff --git a/lib/public/Dashboard/Model/WidgetItem.php b/lib/public/Dashboard/Model/WidgetItem.php index 1c54d2bd426..22235053b5d 100644 --- a/lib/public/Dashboard/Model/WidgetItem.php +++ b/lib/public/Dashboard/Model/WidgetItem.php @@ -70,11 +70,11 @@ final class WidgetItem implements JsonSerializable { * @since 22.0.0 */ public function __construct(string $title = '', - string $subtitle = '', - string $link = '', - string $iconUrl = '', - string $sinceId = '', - string $overlayIconUrl = '') { + string $subtitle = '', + string $link = '', + string $iconUrl = '', + string $sinceId = '', + string $overlayIconUrl = '') { $this->title = $title; $this->subtitle = $subtitle; $this->iconUrl = $iconUrl; diff --git a/lib/public/EventDispatcher/IEventDispatcher.php b/lib/public/EventDispatcher/IEventDispatcher.php index 0a96fa799d4..a84e0fe2f3b 100644 --- a/lib/public/EventDispatcher/IEventDispatcher.php +++ b/lib/public/EventDispatcher/IEventDispatcher.php @@ -71,6 +71,15 @@ interface IEventDispatcher { /** * @template T of \OCP\EventDispatcher\Event + * @param string $eventName preferably the fully-qualified class name of the Event sub class + * + * @return bool TRUE if event has registered listeners + * @since 29.0.0 + */ + public function hasListeners(string $eventName): bool; + + /** + * @template T of \OCP\EventDispatcher\Event * @param string $eventName * @psalm-param string|class-string<T> $eventName * @param Event $event diff --git a/lib/public/Exceptions/AbortedEventException.php b/lib/public/Exceptions/AbortedEventException.php new file mode 100644 index 00000000000..5a3b797e386 --- /dev/null +++ b/lib/public/Exceptions/AbortedEventException.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Exceptions; + +use Exception; + +/** + * @since 29.0.0 + */ +class AbortedEventException extends Exception { +} diff --git a/lib/public/Exceptions/AppConfigException.php b/lib/public/Exceptions/AppConfigException.php new file mode 100644 index 00000000000..73c91d9f018 --- /dev/null +++ b/lib/public/Exceptions/AppConfigException.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Exceptions; + +use Exception; + +/** + * @since 29.0.0 + */ +class AppConfigException extends Exception { +} diff --git a/lib/public/Exceptions/AppConfigIncorrectTypeException.php b/lib/public/Exceptions/AppConfigIncorrectTypeException.php new file mode 100644 index 00000000000..1284e4b193e --- /dev/null +++ b/lib/public/Exceptions/AppConfigIncorrectTypeException.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Exceptions; + +/** + * @since 29.0.0 + */ +class AppConfigIncorrectTypeException extends AppConfigException { +} diff --git a/lib/public/Exceptions/AppConfigTypeConflictException.php b/lib/public/Exceptions/AppConfigTypeConflictException.php new file mode 100644 index 00000000000..599fed0cb3b --- /dev/null +++ b/lib/public/Exceptions/AppConfigTypeConflictException.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Exceptions; + +/** + * @since 29.0.0 + */ +class AppConfigTypeConflictException extends AppConfigException { +} diff --git a/lib/public/Exceptions/AppConfigUnknownKeyException.php b/lib/public/Exceptions/AppConfigUnknownKeyException.php new file mode 100644 index 00000000000..e2b9d7fd3dc --- /dev/null +++ b/lib/public/Exceptions/AppConfigUnknownKeyException.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Exceptions; + +/** + * @since 29.0.0 + */ +class AppConfigUnknownKeyException extends AppConfigException { +} diff --git a/lib/public/Federation/Exceptions/ActionNotSupportedException.php b/lib/public/Federation/Exceptions/ActionNotSupportedException.php index e5f8d50fd99..a7dcda15fe5 100644 --- a/lib/public/Federation/Exceptions/ActionNotSupportedException.php +++ b/lib/public/Federation/Exceptions/ActionNotSupportedException.php @@ -38,7 +38,7 @@ class ActionNotSupportedException extends HintException { * */ public function __construct($action) { - $l = \OC::$server->getL10N('federation'); + $l = \OCP\Util::getL10N('federation'); $message = 'Action "' . $action . '" not supported or implemented.'; $hint = $l->t('Action "%s" not supported or implemented.', [$action]); parent::__construct($message, $hint); diff --git a/lib/public/Federation/Exceptions/AuthenticationFailedException.php b/lib/public/Federation/Exceptions/AuthenticationFailedException.php index 2bd3e361edd..63c8f63ab85 100644 --- a/lib/public/Federation/Exceptions/AuthenticationFailedException.php +++ b/lib/public/Federation/Exceptions/AuthenticationFailedException.php @@ -38,7 +38,7 @@ class AuthenticationFailedException extends HintException { * */ public function __construct() { - $l = \OC::$server->getL10N('federation'); + $l = \OCP\Util::getL10N('federation'); $message = 'Authentication failed, wrong token or provider ID given'; $hint = $l->t('Authentication failed, wrong token or provider ID given'); parent::__construct($message, $hint); diff --git a/lib/public/Federation/Exceptions/BadRequestException.php b/lib/public/Federation/Exceptions/BadRequestException.php index bc8b5c7b724..fbd781aee43 100644 --- a/lib/public/Federation/Exceptions/BadRequestException.php +++ b/lib/public/Federation/Exceptions/BadRequestException.php @@ -45,7 +45,7 @@ class BadRequestException extends HintException { * @param array $missingParameters */ public function __construct(array $missingParameters) { - $l = \OC::$server->getL10N('federation'); + $l = \OCP\Util::getL10N('federation'); $this->parameterList = $missingParameters; $parameterList = implode(',', $missingParameters); $message = 'Parameters missing in order to complete the request. Missing Parameters: ' . $parameterList; diff --git a/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php b/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php index d30d81eca27..cb0a8e8d51f 100644 --- a/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php +++ b/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php @@ -42,7 +42,7 @@ class ProviderAlreadyExistsException extends HintException { * @param string $existingProviderName name of cloud federation provider which already use the same ID */ public function __construct($newProviderId, $existingProviderName) { - $l = \OC::$server->getL10N('federation'); + $l = \OCP\Util::getL10N('federation'); $message = 'ID "' . $newProviderId . '" already used by cloud federation provider "' . $existingProviderName . '"'; $hint = $l->t('ID "%1$s" already used by cloud federation provider "%2$s"', [$newProviderId, $existingProviderName]); parent::__construct($message, $hint); diff --git a/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php b/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php index 849209da22d..0594bb6875b 100644 --- a/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php +++ b/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php @@ -39,7 +39,7 @@ class ProviderDoesNotExistsException extends HintException { * @param string $providerId cloud federation provider ID */ public function __construct($providerId) { - $l = \OC::$server->getL10N('federation'); + $l = \OCP\Util::getL10N('federation'); $message = 'Cloud Federation Provider with ID: "' . $providerId . '" does not exist.'; $hint = $l->t('Cloud Federation Provider with ID: "%s" does not exist.', [$providerId]); parent::__construct($message, $hint); diff --git a/lib/public/Federation/ICloudFederationNotification.php b/lib/public/Federation/ICloudFederationNotification.php index 2b51b2bc8db..26a98027d5e 100644 --- a/lib/public/Federation/ICloudFederationNotification.php +++ b/lib/public/Federation/ICloudFederationNotification.php @@ -34,8 +34,8 @@ interface ICloudFederationNotification { * * @param string $notificationType (e.g. SHARE_ACCEPTED) * @param string $resourceType (e.g. file, calendar, contact,...) - * @param $providerId id of the share - * @param array $notification , payload of the notification + * @param string $providerId id of the share + * @param array $notification payload of the notification * * @since 14.0.0 */ diff --git a/lib/public/Federation/ICloudFederationProviderManager.php b/lib/public/Federation/ICloudFederationProviderManager.php index 7272653b14d..14ac59f3b0b 100644 --- a/lib/public/Federation/ICloudFederationProviderManager.php +++ b/lib/public/Federation/ICloudFederationProviderManager.php @@ -23,6 +23,9 @@ */ namespace OCP\Federation; +use OCP\Http\Client\IResponse; +use OCP\OCM\Exceptions\OCMProviderException; + /** * Class ICloudFederationProviderManager * @@ -80,10 +83,19 @@ interface ICloudFederationProviderManager { * @return mixed * * @since 14.0.0 + * @deprecated 29.0.0 - Use {@see sendCloudShare()} instead and handle errors manually */ public function sendShare(ICloudFederationShare $share); /** + * @param ICloudFederationShare $share + * @return IResponse + * @throws OCMProviderException + * @since 29.0.0 + */ + public function sendCloudShare(ICloudFederationShare $share): IResponse; + + /** * send notification about existing share * * @param string $url @@ -91,10 +103,20 @@ interface ICloudFederationProviderManager { * @return array|false * * @since 14.0.0 + * @deprecated 29.0.0 - Use {@see sendCloudNotification()} instead and handle errors manually */ public function sendNotification($url, ICloudFederationNotification $notification); /** + * @param string $url + * @param ICloudFederationNotification $notification + * @return IResponse + * @throws OCMProviderException + * @since 29.0.0 + */ + public function sendCloudNotification(string $url, ICloudFederationNotification $notification): IResponse; + + /** * check if the new cloud federation API is ready to be used * * @return bool diff --git a/lib/public/Files/Cache/ICache.php b/lib/public/Files/Cache/ICache.php index 1934cc24bd4..0a08673d6c3 100644 --- a/lib/public/Files/Cache/ICache.php +++ b/lib/public/Files/Cache/ICache.php @@ -38,9 +38,24 @@ use OCP\Files\Search\ISearchQuery; * @since 9.0.0 */ interface ICache { + /** + * @since 9.0.0 + */ public const NOT_FOUND = 0; + + /** + * @since 9.0.0 + */ public const PARTIAL = 1; //only partial data available, file not cached in the database + + /** + * @since 9.0.0 + */ public const SHALLOW = 2; //folder in cache, but not all child files are completely scanned + + /** + * @since 9.0.0 + */ public const COMPLETE = 3; /** diff --git a/lib/public/Files/Cache/ICacheEntry.php b/lib/public/Files/Cache/ICacheEntry.php index e1e8129394c..581d5aa6731 100644 --- a/lib/public/Files/Cache/ICacheEntry.php +++ b/lib/public/Files/Cache/ICacheEntry.php @@ -28,12 +28,16 @@ use ArrayAccess; * meta data for a file or folder * * @since 9.0.0 + * @template-extends ArrayAccess<string,mixed> * * This interface extends \ArrayAccess since v21.0.0, previous versions only * implemented it in the private implementation. Hence php would allow using the * object as array, while strictly speaking it didn't support this. */ interface ICacheEntry extends ArrayAccess { + /** + * @since 9.0.0 + */ public const DIRECTORY_MIMETYPE = 'httpd/unix-directory'; /** @@ -123,8 +127,8 @@ interface ICacheEntry extends ArrayAccess { public function getEtag(); /** - * Get the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE - * \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE + * Get the permissions for the file stored as bitwise combination of \OCP\Constants::PERMISSION_READ, \OCP\Constants::PERMISSION_CREATE + * \OCP\Constants::PERMISSION_UPDATE, \OCP\Constants::PERMISSION_DELETE and \OCP\Constants::PERMISSION_SHARE * * @return int * @since 9.0.0 diff --git a/lib/public/Files/Cache/IScanner.php b/lib/public/Files/Cache/IScanner.php index 8a45bfa6de7..e6ee4ef435f 100644 --- a/lib/public/Files/Cache/IScanner.php +++ b/lib/public/Files/Cache/IScanner.php @@ -28,12 +28,34 @@ namespace OCP\Files\Cache; * @since 9.0.0 */ interface IScanner { + /** + * @since 9.0.0 + */ public const SCAN_RECURSIVE_INCOMPLETE = 2; // only recursive into not fully scanned folders + + /** + * @since 9.0.0 + */ public const SCAN_RECURSIVE = true; + + /** + * @since 9.0.0 + */ public const SCAN_SHALLOW = false; + /** + * @since 12.0.0 + */ public const REUSE_NONE = 0; + + /** + * @since 9.0.0 + */ public const REUSE_ETAG = 1; + + /** + * @since 9.0.0 + */ public const REUSE_SIZE = 2; /** diff --git a/lib/public/Files/Cache/IUpdater.php b/lib/public/Files/Cache/IUpdater.php index 5a776d4be7e..625bc91c5a7 100644 --- a/lib/public/Files/Cache/IUpdater.php +++ b/lib/public/Files/Cache/IUpdater.php @@ -53,7 +53,7 @@ interface IUpdater { * @param int $time * @since 9.0.0 */ - public function update($path, $time = null); + public function update($path, $time = null, ?int $sizeDifference = null); /** * Remove $path from the cache and update the size, etag and mtime of the parent folders diff --git a/lib/public/Files/Cache/IWatcher.php b/lib/public/Files/Cache/IWatcher.php index f70024247d5..eca09507167 100644 --- a/lib/public/Files/Cache/IWatcher.php +++ b/lib/public/Files/Cache/IWatcher.php @@ -28,8 +28,19 @@ namespace OCP\Files\Cache; * @since 9.0.0 */ interface IWatcher { + /** + * @since 9.0.0 + */ public const CHECK_NEVER = 0; // never check the underlying filesystem for updates + + /** + * @since 9.0.0 + */ public const CHECK_ONCE = 1; // check the underlying filesystem for updates once every request for each file + + /** + * @since 9.0.0 + */ public const CHECK_ALWAYS = 2; // always check the underlying filesystem for updates /** diff --git a/lib/public/Files/Config/ICachedMountInfo.php b/lib/public/Files/Config/ICachedMountInfo.php index dafd2423fdc..78a92874275 100644 --- a/lib/public/Files/Config/ICachedMountInfo.php +++ b/lib/public/Files/Config/ICachedMountInfo.php @@ -84,4 +84,12 @@ interface ICachedMountInfo { * @since 24.0.0 */ public function getMountProvider(): string; + + /** + * Get a key that uniquely identifies the mount + * + * @return string + * @since 28.0.0 + */ + public function getKey(): string; } diff --git a/lib/public/Files/ConnectionLostException.php b/lib/public/Files/ConnectionLostException.php new file mode 100644 index 00000000000..8e5deb99b46 --- /dev/null +++ b/lib/public/Files/ConnectionLostException.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2016, ownCloud, Inc. + * + * @author Côme Chilliet <come.chilliet@nextcloud.com> + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\Files; + +/** + * Exception for lost connection with the + * @since 25.0.11 + */ +class ConnectionLostException extends \RuntimeException { +} diff --git a/lib/public/Files/Events/FileCacheUpdated.php b/lib/public/Files/Events/FileCacheUpdated.php index 18d6318f2f4..2669c51088e 100644 --- a/lib/public/Files/Events/FileCacheUpdated.php +++ b/lib/public/Files/Events/FileCacheUpdated.php @@ -44,7 +44,7 @@ class FileCacheUpdated extends Event { * @since 18.0.0 */ public function __construct(IStorage $storage, - string $path) { + string $path) { parent::__construct(); $this->storage = $storage; $this->path = $path; diff --git a/lib/public/Files/Events/Node/AbstractNodeEvent.php b/lib/public/Files/Events/Node/AbstractNodeEvent.php index d6c1c6d0f95..768c0eda2d5 100644 --- a/lib/public/Files/Events/Node/AbstractNodeEvent.php +++ b/lib/public/Files/Events/Node/AbstractNodeEvent.php @@ -32,14 +32,12 @@ use OCP\Files\Node; * @since 20.0.0 */ abstract class AbstractNodeEvent extends Event { - /** @var Node */ - private $node; - /** * @since 20.0.0 */ - public function __construct(Node $node) { - $this->node = $node; + public function __construct( + private Node $node + ) { } /** diff --git a/lib/public/Files/Events/Node/AbstractNodesEvent.php b/lib/public/Files/Events/Node/AbstractNodesEvent.php index 6bd9bc32a88..d736ebf1635 100644 --- a/lib/public/Files/Events/Node/AbstractNodesEvent.php +++ b/lib/public/Files/Events/Node/AbstractNodesEvent.php @@ -32,17 +32,13 @@ use OCP\Files\Node; * @since 20.0.0 */ abstract class AbstractNodesEvent extends Event { - /** @var Node */ - private $source; - /** @var Node */ - private $target; - /** * @since 20.0.0 */ - public function __construct(Node $source, Node $target) { - $this->source = $source; - $this->target = $target; + public function __construct( + private Node $source, + private Node $target + ) { } /** diff --git a/lib/public/Files/Events/Node/BeforeNodeDeletedEvent.php b/lib/public/Files/Events/Node/BeforeNodeDeletedEvent.php index 316a30fadd8..c0226a9b527 100644 --- a/lib/public/Files/Events/Node/BeforeNodeDeletedEvent.php +++ b/lib/public/Files/Events/Node/BeforeNodeDeletedEvent.php @@ -25,8 +25,17 @@ declare(strict_types=1); */ namespace OCP\Files\Events\Node; +use OCP\Exceptions\AbortedEventException; + /** * @since 20.0.0 */ class BeforeNodeDeletedEvent extends AbstractNodeEvent { + /** + * @since 28.0.0 + * @deprecated 29.0.0 - use OCP\Exceptions\AbortedEventException instead + */ + public function abortOperation(\Throwable $ex = null) { + throw new AbortedEventException($ex?->getMessage() ?? 'Operation aborted'); + } } diff --git a/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php b/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php index efbef03e383..4c2c566c8c6 100644 --- a/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php +++ b/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php @@ -25,8 +25,17 @@ declare(strict_types=1); */ namespace OCP\Files\Events\Node; +use OCP\Exceptions\AbortedEventException; + /** * @since 20.0.0 */ class BeforeNodeRenamedEvent extends AbstractNodesEvent { + /** + * @since 28.0.0 + * @deprecated 29.0.0 - use OCP\Exceptions\AbortedEventException instead + */ + public function abortOperation(\Throwable $ex = null) { + throw new AbortedEventException($ex?->getMessage() ?? 'Operation aborted'); + } } diff --git a/lib/public/Files/Events/NodeAddedToCache.php b/lib/public/Files/Events/NodeAddedToCache.php index 6986b4b5989..3a1947e7a16 100644 --- a/lib/public/Files/Events/NodeAddedToCache.php +++ b/lib/public/Files/Events/NodeAddedToCache.php @@ -44,7 +44,7 @@ class NodeAddedToCache extends Event { * @since 18.0.0 */ public function __construct(IStorage $storage, - string $path) { + string $path) { parent::__construct(); $this->storage = $storage; $this->path = $path; diff --git a/lib/public/Files/Events/NodeRemovedFromCache.php b/lib/public/Files/Events/NodeRemovedFromCache.php index 9f67cb71371..83c4bd16531 100644 --- a/lib/public/Files/Events/NodeRemovedFromCache.php +++ b/lib/public/Files/Events/NodeRemovedFromCache.php @@ -44,7 +44,7 @@ class NodeRemovedFromCache extends Event { * @since 18.0.0 */ public function __construct(IStorage $storage, - string $path) { + string $path) { parent::__construct(); $this->storage = $storage; $this->path = $path; diff --git a/lib/public/Files/FileInfo.php b/lib/public/Files/FileInfo.php index 83ae4adef92..817b03dfc65 100644 --- a/lib/public/Files/FileInfo.php +++ b/lib/public/Files/FileInfo.php @@ -6,6 +6,7 @@ * @author Felix Heidecke <felix@heidecke.me> * @author Joas Schilling <coding@schilljs.com> * @author Julius Härtl <jus@bitgrid.net> + * @author Maxence Lange <maxence@artificial-owl.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Roeland Jago Douma <roeland@famdouma.nl> @@ -299,4 +300,21 @@ interface FileInfo { * @since 18.0.0 */ public function getUploadTime(): int; + + /** + * Get the fileid or the parent folder + * or -1 if this item has no parent folder (because it is the root) + * + * @return int + * @since 28.0.0 + */ + public function getParentId(): int; + + /** + * Get the metadata, if available + * + * @return array<string, int|string|bool|float|string[]|int[]> + * @since 28.0.0 + */ + public function getMetadata(): array; } diff --git a/lib/public/Files/Folder.php b/lib/public/Files/Folder.php index eb81a2098ec..945df48a13e 100644 --- a/lib/public/Files/Folder.php +++ b/lib/public/Files/Folder.php @@ -152,11 +152,13 @@ interface Folder extends Node { public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0); /** - * get a file or folder inside the folder by it's internal id + * get a file or folder inside the folder by its internal id * * This method could return multiple entries. For example once the file/folder * is shared or mounted (files_external) to the user multiple times. * + * Note that the different entries can have different permissions. + * * @param int $id * @return \OCP\Files\Node[] * @since 6.0.0 @@ -164,6 +166,24 @@ interface Folder extends Node { public function getById($id); /** + * get a file or folder inside the folder by its internal id + * + * Unlike getById, this method only returns a single node even if the user has + * access to the file with the requested id multiple times. + * + * This method provides no guarantee about which of the nodes in returned and the + * returned node might, for example, have less permissions than other nodes for the same file + * + * Apps that require accurate information about the users access to the file should use getById + * instead of pick the correct node out of the result. + * + * @param int $id + * @return Node|null + * @since 29.0.0 + */ + public function getFirstNodeById(int $id): ?Node; + + /** * Get the amount of free space inside the folder * * @return int diff --git a/lib/public/Files/IHomeStorage.php b/lib/public/Files/IHomeStorage.php index 7eb3ffc4a24..1fea80f2d87 100644 --- a/lib/public/Files/IHomeStorage.php +++ b/lib/public/Files/IHomeStorage.php @@ -27,6 +27,7 @@ namespace OCP\Files; use OCP\Files\Storage\IStorage; +use OCP\IUser; /** * Interface IHomeStorage @@ -34,4 +35,11 @@ use OCP\Files\Storage\IStorage; * @since 7.0.0 */ interface IHomeStorage extends IStorage { + /** + * Get the user for this home storage + * + * @return IUser + * @since 28.0.0 + */ + public function getUser(): IUser; } diff --git a/lib/public/Files/IMimeTypeLoader.php b/lib/public/Files/IMimeTypeLoader.php index d4f2767bc17..39a5db85c1a 100644 --- a/lib/public/Files/IMimeTypeLoader.php +++ b/lib/public/Files/IMimeTypeLoader.php @@ -35,7 +35,7 @@ interface IMimeTypeLoader { * @return string|null * @since 8.2.0 */ - public function getMimetypeById($id); + public function getMimetypeById(int $id): ?string; /** * Get a mimetype ID, adding the mimetype to the DB if it does not exist @@ -44,7 +44,7 @@ interface IMimeTypeLoader { * @return int * @since 8.2.0 */ - public function getId($mimetype); + public function getId(string $mimetype): int; /** * Test if a mimetype exists in the database @@ -53,12 +53,12 @@ interface IMimeTypeLoader { * @return bool * @since 8.2.0 */ - public function exists($mimetype); + public function exists(string $mimetype): bool; /** * Clear all loaded mimetypes, allow for re-loading * * @since 8.2.0 */ - public function reset(); + public function reset(): void; } diff --git a/lib/public/Files/IRootFolder.php b/lib/public/Files/IRootFolder.php index 1fee0b3595e..c1c0e6e8c72 100644 --- a/lib/public/Files/IRootFolder.php +++ b/lib/public/Files/IRootFolder.php @@ -26,7 +26,9 @@ namespace OCP\Files; use OC\Hooks\Emitter; use OC\User\NoUserException; +use OCP\Files\Cache\ICacheEntry; use OCP\Files\Mount\IMountPoint; +use OCP\Files\Node as INode; /** * Interface IRootFolder @@ -58,6 +60,24 @@ interface IRootFolder extends Folder, Emitter { public function getByIdInPath(int $id, string $path); /** + * get a file or folder inside the folder by its internal id + * + * Unlike getByIdInPath, this method only returns a single node even if the user has + * access to the file with the requested id multiple times. + * + * This method provides no guarantee about which of the nodes in returned and the + * returned node might, for example, have less permissions than other nodes for the same file + * + * Apps that require accurate information about the users access to the file should use getByIdInPath + * instead of pick the correct node out of the result. + * + * @param int $id + * @return Node|null + * @since 29.0.0 + */ + public function getFirstNodeByIdInPath(int $id, string $path): ?Node; + + /** * @return IMountPoint[] * * @since 28.0.0 @@ -65,6 +85,16 @@ interface IRootFolder extends Folder, Emitter { public function getMountsIn(string $mountPoint): array; /** + * Create a `Node` for a file or folder from the cache entry and mountpoint + * + * @param ICacheEntry $cacheEntry + * @param IMountPoint $mountPoint + * @return Node + * @since 28.0.0 + */ + public function getNodeFromCacheEntryAndMount(ICacheEntry $cacheEntry, IMountPoint $mountPoint): INode; + + /** * @since 28.0.0 */ public function getMount(string $mountPoint): IMountPoint; diff --git a/lib/public/Files/LockNotAcquiredException.php b/lib/public/Files/LockNotAcquiredException.php index 4a26878cedf..2cf8ea20acf 100644 --- a/lib/public/Files/LockNotAcquiredException.php +++ b/lib/public/Files/LockNotAcquiredException.php @@ -43,7 +43,7 @@ class LockNotAcquiredException extends \Exception { * @since 7.0.0 */ public function __construct($path, $lockType, $code = 0, \Exception $previous = null) { - $message = \OC::$server->getL10N('core')->t('Could not obtain lock type %d on "%s".', [$lockType, $path]); + $message = \OCP\Util::getL10N('core')->t('Could not obtain lock type %d on "%s".', [$lockType, $path]); parent::__construct($message, $code, $previous); } diff --git a/lib/public/Files/Mount/IMountManager.php b/lib/public/Files/Mount/IMountManager.php index a55e5758199..df2cc4c6209 100644 --- a/lib/public/Files/Mount/IMountManager.php +++ b/lib/public/Files/Mount/IMountManager.php @@ -26,6 +26,8 @@ declare(strict_types=1); */ namespace OCP\Files\Mount; +use OCP\Files\Config\ICachedMountInfo; + /** * Interface IMountManager * @@ -106,4 +108,14 @@ interface IMountManager { * @since 8.2.0 */ public function findByNumericId(int $id): array; + + /** + * Return the mount matching a cached mount info (or mount file info) + * + * @param ICachedMountInfo $info + * + * @return IMountPoint|null + * @since 28.0.0 + */ + public function getMountFromMountInfo(ICachedMountInfo $info): ?IMountPoint; } diff --git a/lib/public/Files/Node.php b/lib/public/Files/Node.php index b49b4a0f83d..ecf1427fa1a 100644 --- a/lib/public/Files/Node.php +++ b/lib/public/Files/Node.php @@ -30,8 +30,8 @@ namespace OCP\Files; -use OCP\Lock\LockedException; use OCP\Files\Storage\IStorage; +use OCP\Lock\LockedException; /** * Interface Node diff --git a/lib/public/Files/Notify/IChange.php b/lib/public/Files/Notify/IChange.php index 2a4f806be46..d8fd61b1a47 100644 --- a/lib/public/Files/Notify/IChange.php +++ b/lib/public/Files/Notify/IChange.php @@ -29,9 +29,24 @@ namespace OCP\Files\Notify; * @since 12.0.0 */ interface IChange { + /** + * @since 12.0.0 + */ public const ADDED = 1; + + /** + * @since 12.0.0 + */ public const REMOVED = 2; + + /** + * @since 12.0.0 + */ public const MODIFIED = 3; + + /** + * @since 12.0.0 + */ public const RENAMED = 4; /** diff --git a/lib/public/Files/Search/ISearchBinaryOperator.php b/lib/public/Files/Search/ISearchBinaryOperator.php index 4b3bbfd21fc..6e088fd4c2c 100644 --- a/lib/public/Files/Search/ISearchBinaryOperator.php +++ b/lib/public/Files/Search/ISearchBinaryOperator.php @@ -27,8 +27,19 @@ namespace OCP\Files\Search; * @since 12.0.0 */ interface ISearchBinaryOperator extends ISearchOperator { + /** + * @since 12.0.0 + */ public const OPERATOR_AND = 'and'; + + /** + * @since 12.0.0 + */ public const OPERATOR_OR = 'or'; + + /** + * @since 12.0.0 + */ public const OPERATOR_NOT = 'not'; /** diff --git a/lib/public/Files/Search/ISearchComparison.php b/lib/public/Files/Search/ISearchComparison.php index 8ebaeced304..eb93ef70bf6 100644 --- a/lib/public/Files/Search/ISearchComparison.php +++ b/lib/public/Files/Search/ISearchComparison.php @@ -3,6 +3,7 @@ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> * * @author Christoph Wurst <christoph@winzerhof-wurst.at> + * @author Maxence Lange <maxence@artificial-owl.com> * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version @@ -25,16 +26,59 @@ namespace OCP\Files\Search; /** * @since 12.0.0 + * + * @psalm-type ParamSingleValue = \DateTime|int|string|bool + * @psalm-type ParamValue = ParamSingleValue|list<ParamSingleValue> */ interface ISearchComparison extends ISearchOperator { + /** + * @since 12.0.0 + */ public const COMPARE_EQUAL = 'eq'; + + /** + * @since 12.0.0 + */ public const COMPARE_GREATER_THAN = 'gt'; + + /** + * @since 12.0.0 + */ public const COMPARE_GREATER_THAN_EQUAL = 'gte'; + + /** + * @since 12.0.0 + */ public const COMPARE_LESS_THAN = 'lt'; + + /** + * @since 12.0.0 + */ public const COMPARE_LESS_THAN_EQUAL = 'lte'; + + /** + * @since 12.0.0 + */ public const COMPARE_LIKE = 'like'; + + /** + * @since 23.0.0 + */ public const COMPARE_LIKE_CASE_SENSITIVE = 'clike'; + /** + * @since 28.0.0 + */ + public const COMPARE_DEFINED = 'is-defined'; + + /** + * @since 29.0.0 + */ + public const COMPARE_IN = 'in'; + + /** + * @since 23.0.0 + */ public const HINT_PATH_EQ_HASH = 'path_eq_hash'; // transform `path = "$path"` into `path_hash = md5("$path")`, on by default /** @@ -43,7 +87,7 @@ interface ISearchComparison extends ISearchOperator { * @return string * @since 12.0.0 */ - public function getType(); + public function getType(): string; /** * Get the name of the field to compare with @@ -53,13 +97,21 @@ interface ISearchComparison extends ISearchOperator { * @return string * @since 12.0.0 */ - public function getField(); + public function getField(): string; + + /** + * extra means data are not related to the main files table + * + * @return string + * @since 28.0.0 + */ + public function getExtra(): string; /** * Get the value to compare the field with * - * @return string|integer|\DateTime + * @return ParamValue * @since 12.0.0 */ - public function getValue(); + public function getValue(): string|int|bool|\DateTime|array; } diff --git a/lib/public/Files/Search/ISearchOrder.php b/lib/public/Files/Search/ISearchOrder.php index 3b9e6e6713a..978668907ad 100644 --- a/lib/public/Files/Search/ISearchOrder.php +++ b/lib/public/Files/Search/ISearchOrder.php @@ -3,6 +3,7 @@ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> * * @author Christoph Wurst <christoph@winzerhof-wurst.at> + * @author Maxence Lange <maxence@artificial-owl.com> * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version @@ -29,7 +30,14 @@ use OCP\Files\FileInfo; * @since 12.0.0 */ interface ISearchOrder { + /** + * @since 12.0.0 + */ public const DIRECTION_ASCENDING = 'asc'; + + /** + * @since 12.0.0 + */ public const DIRECTION_DESCENDING = 'desc'; /** @@ -38,7 +46,7 @@ interface ISearchOrder { * @return string * @since 12.0.0 */ - public function getDirection(); + public function getDirection(): string; /** * The field to sort on @@ -46,7 +54,15 @@ interface ISearchOrder { * @return string * @since 12.0.0 */ - public function getField(); + public function getField(): string; + + /** + * extra means data are not related to the main files table + * + * @return string + * @since 28.0.0 + */ + public function getExtra(): string; /** * Apply the sorting on 2 FileInfo objects diff --git a/lib/public/Files/Storage/INotifyStorage.php b/lib/public/Files/Storage/INotifyStorage.php index 18bcf3c6adc..6b1dacc564a 100644 --- a/lib/public/Files/Storage/INotifyStorage.php +++ b/lib/public/Files/Storage/INotifyStorage.php @@ -31,9 +31,24 @@ use OCP\Files\Notify\INotifyHandler; * @since 9.1.0 */ interface INotifyStorage { + /** + * @since 9.1.0 + */ public const NOTIFY_ADDED = 1; + + /** + * @since 9.1.0 + */ public const NOTIFY_REMOVED = 2; + + /** + * @since 9.1.0 + */ public const NOTIFY_MODIFIED = 3; + + /** + * @since 9.1.0 + */ public const NOTIFY_RENAMED = 4; /** diff --git a/lib/public/Files/StorageAuthException.php b/lib/public/Files/StorageAuthException.php index 5fce191b57e..bc39f8e27f5 100644 --- a/lib/public/Files/StorageAuthException.php +++ b/lib/public/Files/StorageAuthException.php @@ -36,7 +36,7 @@ class StorageAuthException extends StorageNotAvailableException { * @since 9.0.0 */ public function __construct($message = '', \Exception $previous = null) { - $l = \OC::$server->getL10N('core'); + $l = \OCP\Util::getL10N('core'); parent::__construct($l->t('Storage unauthorized. %s', [$message]), self::STATUS_UNAUTHORIZED, $previous); } } diff --git a/lib/public/Files/StorageBadConfigException.php b/lib/public/Files/StorageBadConfigException.php index 0e16a24daa8..36d7329d4b5 100644 --- a/lib/public/Files/StorageBadConfigException.php +++ b/lib/public/Files/StorageBadConfigException.php @@ -36,7 +36,7 @@ class StorageBadConfigException extends StorageNotAvailableException { * @since 9.0.0 */ public function __construct($message = '', \Exception $previous = null) { - $l = \OC::$server->getL10N('core'); + $l = \OCP\Util::getL10N('core'); parent::__construct($l->t('Storage incomplete configuration. %s', [$message]), self::STATUS_INCOMPLETE_CONF, $previous); } } diff --git a/lib/public/Files/StorageConnectionException.php b/lib/public/Files/StorageConnectionException.php index 9113faf72a1..d29398172e6 100644 --- a/lib/public/Files/StorageConnectionException.php +++ b/lib/public/Files/StorageConnectionException.php @@ -36,7 +36,7 @@ class StorageConnectionException extends StorageNotAvailableException { * @since 9.0.0 */ public function __construct($message = '', \Exception $previous = null) { - $l = \OC::$server->getL10N('core'); + $l = \OCP\Util::getL10N('core'); parent::__construct($l->t('Storage connection error. %s', [$message]), self::STATUS_NETWORK_ERROR, $previous); } } diff --git a/lib/public/Files/StorageNotAvailableException.php b/lib/public/Files/StorageNotAvailableException.php index f600ef80808..78b004f8518 100644 --- a/lib/public/Files/StorageNotAvailableException.php +++ b/lib/public/Files/StorageNotAvailableException.php @@ -36,15 +36,43 @@ use OCP\HintException; /** * Storage is temporarily not available - * @since 6.0.0 - since 8.2.1 based on HintException + * @since 6.0.0 + * @since 8.2.1 based on HintException */ class StorageNotAvailableException extends HintException { + /** + * @since 8.2.0 + */ public const STATUS_SUCCESS = 0; + + /** + * @since 8.2.0 + */ public const STATUS_ERROR = 1; + + /** + * @since 8.2.0 + */ public const STATUS_INDETERMINATE = 2; + + /** + * @since 8.2.0 + */ public const STATUS_INCOMPLETE_CONF = 3; + + /** + * @since 8.2.0 + */ public const STATUS_UNAUTHORIZED = 4; + + /** + * @since 8.2.0 + */ public const STATUS_TIMEOUT = 5; + + /** + * @since 8.2.0 + */ public const STATUS_NETWORK_ERROR = 6; /** @@ -56,7 +84,7 @@ class StorageNotAvailableException extends HintException { * @since 6.0.0 */ public function __construct($message = '', $code = self::STATUS_ERROR, \Exception $previous = null) { - $l = \OC::$server->getL10N('core'); + $l = \OCP\Util::getL10N('core'); parent::__construct($message, $l->t('Storage is temporarily not available'), $code, $previous); } diff --git a/lib/public/Files/StorageTimeoutException.php b/lib/public/Files/StorageTimeoutException.php index bad88ad35e0..c20711d4181 100644 --- a/lib/public/Files/StorageTimeoutException.php +++ b/lib/public/Files/StorageTimeoutException.php @@ -36,7 +36,7 @@ class StorageTimeoutException extends StorageNotAvailableException { * @since 9.0.0 */ public function __construct($message = '', \Exception $previous = null) { - $l = \OC::$server->getL10N('core'); + $l = \OCP\Util::getL10N('core'); parent::__construct($l->t('Storage connection timeout. %s', [$message]), self::STATUS_TIMEOUT, $previous); } } diff --git a/lib/public/Files/Template/TemplateFileCreator.php b/lib/public/Files/Template/TemplateFileCreator.php index 43e96b6f21b..0c2f7a115a2 100644 --- a/lib/public/Files/Template/TemplateFileCreator.php +++ b/lib/public/Files/Template/TemplateFileCreator.php @@ -42,6 +42,7 @@ final class TemplateFileCreator implements \JsonSerializable { protected $order = 100; /** * @since 27.0.0 + * @deprecated 28.0.0 */ protected string $actionLabel = ''; diff --git a/lib/public/FilesMetadata/AMetadataEvent.php b/lib/public/FilesMetadata/AMetadataEvent.php new file mode 100644 index 00000000000..8cb8ea8d1b8 --- /dev/null +++ b/lib/public/FilesMetadata/AMetadataEvent.php @@ -0,0 +1,68 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata; + +use OCP\EventDispatcher\Event; +use OCP\Files\Node; +use OCP\FilesMetadata\Model\IFilesMetadata; + +/** + * @since 28.0.0 + */ +abstract class AMetadataEvent extends Event { + /** + * @param Node $node + * @param IFilesMetadata $metadata + * @since 28.0.0 + */ + public function __construct( + protected Node $node, + protected IFilesMetadata $metadata + ) { + parent::__construct(); + } + + /** + * returns related node + * + * @return Node + * @since 28.0.0 + */ + public function getNode(): Node { + return $this->node; + } + + /** + * returns metadata. if known, it already contains data from the database. + * If the object is modified using its setters, changes are stored in database at the end of the event. + * + * @return IFilesMetadata + * @since 28.0.0 + */ + public function getMetadata(): IFilesMetadata { + return $this->metadata; + } +} diff --git a/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php b/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php new file mode 100644 index 00000000000..3d175994c32 --- /dev/null +++ b/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata\Event; + +use OCP\FilesMetadata\AMetadataEvent; + +/** + * MetadataBackgroundEvent is an event similar to MetadataLiveEvent but dispatched + * on a background thread instead of live thread. Meaning there is no limit to + * the time required for the generation of your metadata. + * + * @see AMetadataEvent::getMetadata() + * @see AMetadataEvent::getNode() + * @since 28.0.0 + */ +class MetadataBackgroundEvent extends AMetadataEvent { +} diff --git a/lib/public/FilesMetadata/Event/MetadataLiveEvent.php b/lib/public/FilesMetadata/Event/MetadataLiveEvent.php new file mode 100644 index 00000000000..a89692fde92 --- /dev/null +++ b/lib/public/FilesMetadata/Event/MetadataLiveEvent.php @@ -0,0 +1,67 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata\Event; + +use OCP\FilesMetadata\AMetadataEvent; + +/** + * MetadataLiveEvent is an event initiated when a file is created or updated. + * The app contains the Node related to the created/updated file, and a FilesMetadata that already + * contains the currently known metadata. + * + * Setting new metadata, or modifying already existing metadata with different value, will trigger + * the save of the metadata in the database. + * + * @see AMetadataEvent::getMetadata() + * @see AMetadataEvent::getNode() + * @see MetadataLiveEvent::requestBackgroundJob() + * @since 28.0.0 + */ +class MetadataLiveEvent extends AMetadataEvent { + private bool $runAsBackgroundJob = false; + + /** + * For heavy process, call this method if your app prefers to update metadata on a + * background/cron job, instead of the live process. + * A similar MetadataBackgroundEvent will be broadcast on next cron tick. + * + * @return void + * @since 28.0.0 + */ + public function requestBackgroundJob(): void { + $this->runAsBackgroundJob = true; + } + + /** + * return true if any app that catch this event requested a re-run as background job + * + * @return bool + * @since 28.0.0 + */ + public function isRunAsBackgroundJobRequested(): bool { + return $this->runAsBackgroundJob; + } +} diff --git a/lib/public/FilesMetadata/Event/MetadataNamedEvent.php b/lib/public/FilesMetadata/Event/MetadataNamedEvent.php new file mode 100644 index 00000000000..f8cfcf9bd01 --- /dev/null +++ b/lib/public/FilesMetadata/Event/MetadataNamedEvent.php @@ -0,0 +1,74 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata\Event; + +use OCP\Files\Node; +use OCP\FilesMetadata\AMetadataEvent; +use OCP\FilesMetadata\Model\IFilesMetadata; + +/** + * MetadataNamedEvent is an event similar to MetadataBackgroundEvent completed with a target name, + * used to limit the refresh of metadata only listeners capable of filtering themselves out. + * + * Meaning that when using this event, your app must implement a filter on the event's registered + * name returned by getName() + * + * This event is mostly triggered when a registered name is added to the files scan + * i.e. ./occ files:scan --generate-metadata [name] + * + * @see AMetadataEvent::getMetadata() + * @see AMetadataEvent::getNode() + * @see MetadataNamedEvent::getName() + * @since 28.0.0 + */ +class MetadataNamedEvent extends AMetadataEvent { + /** + * @param Node $node + * @param IFilesMetadata $metadata + * @param string $name name assigned to the event + * + * @since 28.0.0 + */ + public function __construct( + Node $node, + IFilesMetadata $metadata, + private string $name = '' + ) { + parent::__construct($node, $metadata); + } + + /** + * get the assigned name for the event. + * This is used to know if your app is the called one when running the + * ./occ files:scan --generate-metadata [name] + * + * @return string + * @since 28.0.0 + */ + public function getName(): string { + return $this->name; + } +} diff --git a/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php b/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php new file mode 100644 index 00000000000..e3f75a7a7af --- /dev/null +++ b/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata\Exceptions; + +use Exception; + +/** + * @since 28.0.0 + */ +class FilesMetadataException extends Exception { +} diff --git a/lib/public/FilesMetadata/Exceptions/FilesMetadataKeyFormatException.php b/lib/public/FilesMetadata/Exceptions/FilesMetadataKeyFormatException.php new file mode 100644 index 00000000000..0083e985a5e --- /dev/null +++ b/lib/public/FilesMetadata/Exceptions/FilesMetadataKeyFormatException.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata\Exceptions; + +/** + * @since 28.0.0 + */ +class FilesMetadataKeyFormatException extends FilesMetadataException { +} diff --git a/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php b/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php new file mode 100644 index 00000000000..9c03c5ba370 --- /dev/null +++ b/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata\Exceptions; + +/** + * @since 28.0.0 + */ +class FilesMetadataNotFoundException extends FilesMetadataException { +} diff --git a/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php b/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php new file mode 100644 index 00000000000..1d134c67ecf --- /dev/null +++ b/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata\Exceptions; + +/** + * @since 28.0.0 + */ +class FilesMetadataTypeException extends FilesMetadataException { +} diff --git a/lib/public/FilesMetadata/IFilesMetadataManager.php b/lib/public/FilesMetadata/IFilesMetadataManager.php new file mode 100644 index 00000000000..55feefc4f12 --- /dev/null +++ b/lib/public/FilesMetadata/IFilesMetadataManager.php @@ -0,0 +1,169 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata; + +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\Node; +use OCP\FilesMetadata\Exceptions\FilesMetadataException; +use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; +use OCP\FilesMetadata\Model\IFilesMetadata; +use OCP\FilesMetadata\Model\IMetadataValueWrapper; + +/** + * Manager for FilesMetadata; manage files' metadata. + * + * @since 28.0.0 + */ +interface IFilesMetadataManager { + /** @since 28.0.0 */ + public const PROCESS_LIVE = 1; + /** @since 28.0.0 */ + public const PROCESS_BACKGROUND = 2; + /** @since 28.0.0 */ + public const PROCESS_NAMED = 4; + + /** + * initiate the process of refreshing the metadata in relation to a node + * usually, this process: + * - get current metadata from database, if available, or create a new one + * - dispatch a MetadataLiveEvent, + * - save new metadata in database, if metadata have been changed during the event + * - refresh metadata indexes if needed, + * - prep a new cronjob if an app request it during the event, + * + * @param Node $node related node + * @param int $process type of process + * @param string $namedEvent limit process to a named event + * + * @return IFilesMetadata + * @see self::PROCESS_BACKGROUND + * @see self::PROCESS_LIVE + * @see self::PROCESS_NAMED + * @since 28.0.0 + */ + public function refreshMetadata( + Node $node, + int $process = self::PROCESS_LIVE, + string $namedEvent = '' + ): IFilesMetadata; + + /** + * returns metadata of a file id + * + * @param int $fileId file id + * @param boolean $generate Generate if metadata does not exist + * + * @return IFilesMetadata + * @throws FilesMetadataNotFoundException if not found + * @since 28.0.0 + */ + public function getMetadata(int $fileId, bool $generate = false): IFilesMetadata; + + /** + * returns metadata of multiple file ids + * + * @param int[] $fileIds file ids + * + * @return array File ID is the array key, files without metadata are not returned in the array + * @psalm-return array<int, IFilesMetadata> + * @since 28.0.0 + */ + public function getMetadataForFiles(array $fileIds): array; + + /** + * save metadata to database and refresh indexes. + * metadata are saved if new data are available. + * on update, a check on syncToken is done to avoid conflict (race condition) + * + * @param IFilesMetadata $filesMetadata + * + * @throws FilesMetadataException if metadata seems malformed + * @since 28.0.0 + */ + public function saveMetadata(IFilesMetadata $filesMetadata): void; + + /** + * delete metadata and its indexes + * + * @param int $fileId file id + * + * @return void + * @since 28.0.0 + */ + public function deleteMetadata(int $fileId): void; + + /** + * generate and return a MetadataQuery to help building sql queries + * + * @param IQueryBuilder $qb + * @param string $fileTableAlias alias of the table that contains data about files + * @param string $fileIdField alias of the field that contains file ids + * + * @return IMetadataQuery|null NULL if table are not set yet or never used + * @see IMetadataQuery + * @since 28.0.0 + */ + public function getMetadataQuery( + IQueryBuilder $qb, + string $fileTableAlias, + string $fileIdField + ): ?IMetadataQuery; + + /** + * returns all type of metadata currently available. + * The list is stored in a IFilesMetadata with null values but correct type. + * + * @return IFilesMetadata + * @since 28.0.0 + */ + public function getKnownMetadata(): IFilesMetadata; + + /** + * initiate a metadata key with its type. + * The call is mandatory before using the metadata property in a webdav request. + * It is not needed to only use this method when the app is enabled: the method can be + * called each time during the app loading as the metadata will only be initiated if not known + * + * @param string $key metadata key + * @param string $type metadata type + * @param bool $indexed TRUE if metadata can be search + * @param int $editPermission remote edit permission via Webdav PROPPATCH + * + * @see IMetadataValueWrapper::TYPE_INT + * @see IMetadataValueWrapper::TYPE_FLOAT + * @see IMetadataValueWrapper::TYPE_BOOL + * @see IMetadataValueWrapper::TYPE_ARRAY + * @see IMetadataValueWrapper::TYPE_STRING_LIST + * @see IMetadataValueWrapper::TYPE_INT_LIST + * @see IMetadataValueWrapper::TYPE_STRING + * @see IMetadataValueWrapper::EDIT_FORBIDDEN + * @see IMetadataValueWrapper::EDIT_REQ_OWNERSHIP + * @see IMetadataValueWrapper::EDIT_REQ_WRITE_PERMISSION + * @see IMetadataValueWrapper::EDIT_REQ_READ_PERMISSION + * @since 28.0.0 + */ + public function initMetadata(string $key, string $type, bool $indexed, int $editPermission): void; +} diff --git a/lib/public/FilesMetadata/IMetadataQuery.php b/lib/public/FilesMetadata/IMetadataQuery.php new file mode 100644 index 00000000000..c1c649ac243 --- /dev/null +++ b/lib/public/FilesMetadata/IMetadataQuery.php @@ -0,0 +1,92 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata; + +use OCP\FilesMetadata\Model\IFilesMetadata; + +/** + * Model that help building queries with metadata and metadata indexes + * + * @since 28.0.0 + */ +interface IMetadataQuery { + /** @since 28.0.0 */ + public const EXTRA = 'metadata'; + + /** + * Add metadata linked to file id to the query + * + * @see self::extractMetadata() + * @since 28.0.0 + */ + public function retrieveMetadata(): void; + + /** + * extract metadata from a result row + * + * @param array $row result row + * + * @return IFilesMetadata metadata + * @see self::retrieveMetadata() + * @since 28.0.0 + */ + public function extractMetadata(array $row): IFilesMetadata; + + /** + * join the metadata_index table, based on a metadataKey. + * This will prep the query for condition based on this specific metadataKey. + * If a link to the metadataKey already exists, returns known alias. + * + * TODO: investigate how to support a search done on multiple values for same key (AND). + * + * @param string $metadataKey metadata key + * @param bool $enforce limit the request only to existing metadata + * + * @return string generated table alias + * @since 28.0.0 + */ + public function joinIndex(string $metadataKey, bool $enforce = false): string; + + /** + * returns the name of the field for metadata key to be used in query expressions + * + * @param string $metadataKey metadata key + * + * @return string table field + * @since 28.0.0 + */ + public function getMetadataKeyField(string $metadataKey): string; + + /** + * returns the name of the field for metadata string value to be used in query expressions + * + * @param string $metadataKey metadata key + * + * @return string table field + * @since 28.0.0 + */ + public function getMetadataValueField(string $metadataKey): string; +} diff --git a/lib/public/FilesMetadata/Model/IFilesMetadata.php b/lib/public/FilesMetadata/Model/IFilesMetadata.php new file mode 100644 index 00000000000..024b21039bc --- /dev/null +++ b/lib/public/FilesMetadata/Model/IFilesMetadata.php @@ -0,0 +1,386 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata\Model; + +use JsonSerializable; +use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; +use OCP\FilesMetadata\Exceptions\FilesMetadataTypeException; + +/** + * Model that represent metadata linked to a specific file. + * + * Example of json stored in the database + * { + * "mymeta": { + * "value": "this is a test", + * "type": "string", + * "etag": "abcd1234", + * "indexed": false, + * "editPermission": 1 + * }, + * "myapp-anothermeta": { + * "value": 42, + * "type": "int", + * "etag": "0987zyxw", + * "indexed": true, + * "editPermission": 0 + * } + * } + * + * @see IMetadataValueWrapper + * @since 28.0.0 + */ +interface IFilesMetadata extends JsonSerializable { + /** + * returns the file id linked to this metadata + * + * @return int related file id + * @since 28.0.0 + */ + public function getFileId(): int; + + /** + * returns last time metadata were updated in the database + * + * @return int timestamp + * @since 28.0.0 + */ + public function lastUpdateTimestamp(): int; + + /** + * returns the token known at the time the metadata were extracted from database + * + * @return string token + * @since 28.0.0 + */ + public function getSyncToken(): string; + + /** + * returns all current metadata keys + * + * @return string[] list of keys + * @since 28.0.0 + */ + public function getKeys(): array; + + /** + * returns true if search metadata key exists + * + * @param string $needle metadata key to search + * + * @return bool TRUE if key exist + * @since 28.0.0 + */ + public function hasKey(string $needle): bool; + + /** + * return the list of metadata keys set as indexed + * + * @return string[] list of indexes + * @since 28.0.0 + */ + public function getIndexes(): array; + + /** + * returns true if key exists and is set as indexed + * + * @param string $key metadata key + * + * @return bool + * @since 28.0.0 + */ + public function isIndex(string $key): bool; + + /** + * returns file etag stored during the last update of the metadata key + * + * @param string $key metadata key + * @return string + * @since 29.0.0 + */ + public function getEtag(string $key): string; + + /** + * set file etag + * + * @param string $key metadata key + * @since 29.0.0 + */ + public function setEtag(string $key, string $etag): void; + + /** + * set remote edit permission + * (Webdav PROPPATCH) + * + * @param string $key metadata key + * @param int $permission remote edit permission + * + * @since 28.0.0 + */ + public function setEditPermission(string $key, int $permission): void; + + /** + * returns remote edit permission + * (Webdav PROPPATCH) + * + * @param string $key metadata key + * + * @return int + * @since 28.0.0 + */ + public function getEditPermission(string $key): int; + + /** + * returns string value for a metadata key + * + * @param string $key metadata key + * + * @return string metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getString(string $key): string; + + /** + * returns int value for a metadata key + * + * @param string $key metadata key + * + * @return int metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getInt(string $key): int; + + /** + * returns float value for a metadata key + * + * @param string $key metadata key + * + * @return float metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getFloat(string $key): float; + + /** + * returns bool value for a metadata key + * + * @param string $key metadata key + * + * @return bool metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getBool(string $key): bool; + + /** + * returns array for a metadata key + * + * @param string $key metadata key + * + * @return array metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getArray(string $key): array; + + /** + * returns string[] value for a metadata key + * + * @param string $key metadata key + * + * @return string[] metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getStringList(string $key): array; + + /** + * returns int[] value for a metadata key + * + * @param string $key metadata key + * + * @return int[] metadata value + * @throws FilesMetadataNotFoundException + * @throws FilesMetadataTypeException + * @since 28.0.0 + */ + public function getIntList(string $key): array; + + /** + * returns the value type of the metadata (string, int, ...) + * + * @param string $key metadata key + * + * @return string value type + * @throws FilesMetadataNotFoundException + * @see IMetadataValueWrapper::TYPE_STRING + * @see IMetadataValueWrapper::TYPE_INT + * @see IMetadataValueWrapper::TYPE_FLOAT + * @see IMetadataValueWrapper::TYPE_BOOL + * @see IMetadataValueWrapper::TYPE_ARRAY + * @see IMetadataValueWrapper::TYPE_STRING_LIST + * @see IMetadataValueWrapper::TYPE_INT_LIST + * @since 28.0.0 + */ + public function getType(string $key): string; + + /** + * set a metadata key/value pair for string value + * + * @param string $key metadata key + * @param string $value metadata value + * @param bool $index set TRUE if value must be indexed + * + * @return self + * @since 28.0.0 + */ + public function setString(string $key, string $value, bool $index = false): self; + + /** + * set a metadata key/value pair for int value + * + * @param string $key metadata key + * @param int $value metadata value + * @param bool $index set TRUE if value must be indexed + * + * @return self + * @since 28.0.0 + */ + public function setInt(string $key, int $value, bool $index = false): self; + + /** + * set a metadata key/value pair for float value + * + * @param string $key metadata key + * @param float $value metadata value + * + * @return self + * @since 28.0.0 + */ + public function setFloat(string $key, float $value): self; + + /** + * set a metadata key/value pair for bool value + * + * @param string $key metadata key + * @param bool $value metadata value + * @param bool $index set TRUE if value must be indexed + * + * @return self + * @since 28.0.0 + */ + public function setBool(string $key, bool $value, bool $index = false): self; + + /** + * set a metadata key/value pair for array + * + * @param string $key metadata key + * @param array $value metadata value + * + * @return self + * @since 28.0.0 + */ + public function setArray(string $key, array $value): self; + + /** + * set a metadata key/value pair for list of string + * + * @param string $key metadata key + * @param string[] $value metadata value + * @param bool $index set TRUE if each values from the list must be indexed + * + * @return self + * @since 28.0.0 + */ + public function setStringList(string $key, array $value, bool $index = false): self; + + /** + * set a metadata key/value pair for list of int + * + * @param string $key metadata key + * @param int[] $value metadata value + * @param bool $index set TRUE if each values from the list must be indexed + * + * @return self + * @since 28.0.0 + */ + public function setIntList(string $key, array $value, bool $index = false): self; + + /** + * unset a metadata + * + * @param string $key metadata key + * + * @return self + * @since 28.0.0 + */ + public function unset(string $key): self; + + /** + * unset metadata with key starting with prefix + * + * @param string $keyPrefix metadata key prefix + * + * @return self + * @since 28.0.0 + */ + public function removeStartsWith(string $keyPrefix): self; + + /** + * returns true if object have been updated since last import + * + * @return bool TRUE if metadata have been modified + * @since 28.0.0 + */ + public function updated(): bool; + + /** + * returns metadata in a simple array with METADATA_KEY => METADATA_VALUE + * + * @return array metadata + * @since 28.0.0 + */ + public function asArray(): array; + + /** + * deserialize the object from a json + * + * @param array $data serialized version of the object + * + * @return self + * @see jsonSerialize + * @since 28.0.0 + */ + public function import(array $data): self; +} diff --git a/lib/public/FilesMetadata/Model/IMetadataValueWrapper.php b/lib/public/FilesMetadata/Model/IMetadataValueWrapper.php new file mode 100644 index 00000000000..6c551efea81 --- /dev/null +++ b/lib/public/FilesMetadata/Model/IMetadataValueWrapper.php @@ -0,0 +1,352 @@ +<?php + +declare(strict_types=1); +/** + * @copyright 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\FilesMetadata\Model; + +use JsonSerializable; +use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException; +use OCP\FilesMetadata\Exceptions\FilesMetadataTypeException; + +/** + * Model that store the value of a single metadata. + * It stores the value, its type and the index status. + * + * @see IFilesMetadata + * @since 28.0.0 + */ +interface IMetadataValueWrapper extends JsonSerializable { + /** @since 28.0.0 */ + public const TYPE_STRING = 'string'; + /** @since 28.0.0 */ + public const TYPE_INT = 'int'; + /** @since 28.0.0 */ + public const TYPE_FLOAT = 'float'; + /** @since 28.0.0 */ + public const TYPE_BOOL = 'bool'; + /** @since 28.0.0 */ + public const TYPE_ARRAY = 'array'; + /** @since 28.0.0 */ + public const TYPE_STRING_LIST = 'string[]'; + /** @since 28.0.0 */ + public const TYPE_INT_LIST = 'int[]'; + + /** @since 28.0.0 */ + public const EDIT_FORBIDDEN = 0; + /** @since 28.0.0 */ + public const EDIT_REQ_OWNERSHIP = 1; + /** @since 28.0.0 */ + public const EDIT_REQ_WRITE_PERMISSION = 2; + /** @since 28.0.0 */ + public const EDIT_REQ_READ_PERMISSION = 3; + + + /** + * Unless a call of import() to deserialize an object is expected, a valid value type is needed here. + * + * @param string $type value type + * + * @see self::TYPE_INT + * @see self::TYPE_FLOAT + * @see self::TYPE_BOOL + * @see self::TYPE_ARRAY + * @see self::TYPE_STRING_LIST + * @see self::TYPE_INT_LIST + * @see self::TYPE_STRING + * @since 28.0.0 + */ + public function __construct(string $type); + + /** + * returns the value type + * + * @return string value type + * @see self::TYPE_INT + * @see self::TYPE_FLOAT + * @see self::TYPE_BOOL + * @see self::TYPE_ARRAY + * @see self::TYPE_STRING_LIST + * @see self::TYPE_INT_LIST + * @see self::TYPE_STRING + * @since 28.0.0 + */ + public function getType(): string; + + /** + * returns if the set value type is the one expected + * + * @param string $type value type + * + * @return bool + * @see self::TYPE_INT + * @see self::TYPE_FLOAT + * @see self::TYPE_BOOL + * @see self::TYPE_ARRAY + * @see self::TYPE_STRING_LIST + * @see self::TYPE_INT_LIST + * @see self::TYPE_STRING + * @since 28.0.0 + */ + public function isType(string $type): bool; + + /** + * throws an exception if the type is not correctly set + * + * @param string $type value type + * + * @return self + * @throws FilesMetadataTypeException if type cannot be confirmed + * @see self::TYPE_INT + * @see self::TYPE_BOOL + * @see self::TYPE_ARRAY + * @see self::TYPE_STRING_LIST + * @see self::TYPE_INT_LIST + * @see self::TYPE_STRING + * @see self::TYPE_FLOAT + * @since 28.0.0 + */ + public function assertType(string $type): self; + + /** + * set a string value + * + * @param string $value string to be set as value + * + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store a string + * @since 28.0.0 + */ + public function setValueString(string $value): self; + + /** + * set a int value + * + * @param int $value int to be set as value + * + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store an int + * @since 28.0.0 + */ + public function setValueInt(int $value): self; + + /** + * set a float value + * + * @param float $value float to be set as value + * + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store a float + * @since 28.0.0 + */ + public function setValueFloat(float $value): self; + + /** + * set a bool value + * + * @param bool $value bool to be set as value + * + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store a bool + * @since 28.0.0 + */ + public function setValueBool(bool $value): self; + + /** + * set an array value + * + * @param array $value array to be set as value + * + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store an array + * @since 28.0.0 + */ + public function setValueArray(array $value): self; + + /** + * set a string list value + * + * @param string[] $value string list to be set as value + * + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store a string list + * @since 28.0.0 + */ + public function setValueStringList(array $value): self; + + /** + * set an int list value + * + * @param int[] $value int list to be set as value + * + * @return self + * @throws FilesMetadataTypeException if wrapper was not set to store an int list + * @since 28.0.0 + */ + public function setValueIntList(array $value): self; + + + /** + * get stored value + * + * @return string set value + * @throws FilesMetadataTypeException if wrapper was not set to store a string + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueString(): string; + + /** + * get stored value + * + * @return int set value + * @throws FilesMetadataTypeException if wrapper was not set to store an int + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueInt(): int; + + /** + * get stored value + * + * @return float set value + * @throws FilesMetadataTypeException if wrapper was not set to store a float + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueFloat(): float; + + /** + * get stored value + * + * @return bool set value + * @throws FilesMetadataTypeException if wrapper was not set to store a bool + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueBool(): bool; + + /** + * get stored value + * + * @return array set value + * @throws FilesMetadataTypeException if wrapper was not set to store an array + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueArray(): array; + + /** + * get stored value + * + * @return string[] set value + * @throws FilesMetadataTypeException if wrapper was not set to store a string list + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueStringList(): array; + + /** + * get stored value + * + * @return int[] set value + * @throws FilesMetadataTypeException if wrapper was not set to store an int list + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueIntList(): array; + + /** + * get stored value + * + * @return string|int|float|bool|array|string[]|int[] set value + * @throws FilesMetadataNotFoundException if value is not set + * @since 28.0.0 + */ + public function getValueAny(): mixed; + + /** + * get stored etag value + * + * @return string stored etag + * @since 29.0.0 + */ + public function getEtag(): string; + + /** + * set etag value + * + * @param string $etag etag value + * + * @return self + * @since 29.0.0 + */ + public function setEtag(string $etag): self; + + /** + * @param bool $indexed TRUE to set the stored value as an indexed value + * + * @return self + * @since 28.0.0 + */ + public function setIndexed(bool $indexed): self; + + /** + * returns if value is an indexed value + * + * @return bool TRUE if value is an indexed value + * @since 28.0.0 + */ + public function isIndexed(): bool; + + /** + * set remote edit permission + * (Webdav PROPPATCH) + * + * @param int $permission edit permission + * + * @return self + * @since 28.0.0 + */ + public function setEditPermission(int $permission): self; + + /** + * get remote edit permission + * (Webdav PROPPATCH) + * + * @return int edit permission + * @since 28.0.0 + */ + public function getEditPermission(): int; + + /** + * deserialize the object from a json + * + * @param array $data serialized version of the object + * + * @return self + * @see jsonSerialize + * @since 28.0.0 + */ + public function import(array $data): self; +} diff --git a/lib/public/FullTextSearch/Exceptions/FullTextSearchIndexNotAvailableException.php b/lib/public/FullTextSearch/Exceptions/FullTextSearchIndexNotAvailableException.php new file mode 100644 index 00000000000..cf3c5905135 --- /dev/null +++ b/lib/public/FullTextSearch/Exceptions/FullTextSearchIndexNotAvailableException.php @@ -0,0 +1,35 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023, Faraz Samapoor <f.samapoor@gmail.com> + * + * @author Faraz Samapoor <f.samapoor@gmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\FullTextSearch\Exceptions; + +/** + * @since 28.0.0 + * + * Class FullTextSearchIndexNotAvailableException + * + */ +class FullTextSearchIndexNotAvailableException extends \Exception { +} diff --git a/lib/public/FullTextSearch/Model/IIndex.php b/lib/public/FullTextSearch/Model/IIndex.php index dad10c934de..6403d408a80 100644 --- a/lib/public/FullTextSearch/Model/IIndex.php +++ b/lib/public/FullTextSearch/Model/IIndex.php @@ -43,24 +43,84 @@ namespace OCP\FullTextSearch\Model; * */ interface IIndex { + /** + * @since 15.0.0 + */ public const INDEX_OK = 1; + + /** + * @since 15.0.0 + */ public const INDEX_IGNORE = 2; + /** + * @since 15.0.0 + */ public const INDEX_META = 4; + + /** + * @since 15.0.0 + */ public const INDEX_CONTENT = 8; + + /** + * @since 16.0.0 + */ public const INDEX_PARTS = 16; + + /** + * @since 15.0.0 + */ public const INDEX_FULL = 28; + + /** + * @since 15.0.0 + */ public const INDEX_REMOVE = 32; + + /** + * @since 15.0.0 + */ public const INDEX_DONE = 64; + + /** + * @since 15.0.0 + */ public const INDEX_FAILED = 128; + /** + * @since 15.0.0 + */ public const ERROR_FAILED = 1; + + /** + * @since 15.0.0 + */ public const ERROR_FAILED2 = 2; + + /** + * @since 15.0.0 + */ public const ERROR_FAILED3 = 4; + /** + * @since 15.0.0 + */ public const ERROR_SEV_1 = 1; + + /** + * @since 15.0.0 + */ public const ERROR_SEV_2 = 2; + + /** + * @since 15.0.0 + */ public const ERROR_SEV_3 = 3; + + /** + * @since 15.0.0 + */ public const ERROR_SEV_4 = 4; diff --git a/lib/public/FullTextSearch/Model/IIndexDocument.php b/lib/public/FullTextSearch/Model/IIndexDocument.php index b659c2b33f1..b043c7d8bb1 100644 --- a/lib/public/FullTextSearch/Model/IIndexDocument.php +++ b/lib/public/FullTextSearch/Model/IIndexDocument.php @@ -41,7 +41,14 @@ namespace OCP\FullTextSearch\Model; * @since 15.0.0 */ interface IIndexDocument { + /** + * @since 15.0.0 + */ public const NOT_ENCODED = 0; + + /** + * @since 15.0.0 + */ public const ENCODED_BASE64 = 1; diff --git a/lib/public/FullTextSearch/Model/IRunner.php b/lib/public/FullTextSearch/Model/IRunner.php index c03126500cb..09782e27275 100644 --- a/lib/public/FullTextSearch/Model/IRunner.php +++ b/lib/public/FullTextSearch/Model/IRunner.php @@ -40,8 +40,19 @@ namespace OCP\FullTextSearch\Model; * */ interface IRunner { + /** + * @since 15.0.0 + */ public const RESULT_TYPE_SUCCESS = 1; + + /** + * @since 15.0.0 + */ public const RESULT_TYPE_WARNING = 4; + + /** + * @since 15.0.0 + */ public const RESULT_TYPE_FAIL = 9; diff --git a/lib/public/FullTextSearch/Model/ISearchRequestSimpleQuery.php b/lib/public/FullTextSearch/Model/ISearchRequestSimpleQuery.php index 91f3c6dfe1b..15c5f98d7b8 100644 --- a/lib/public/FullTextSearch/Model/ISearchRequestSimpleQuery.php +++ b/lib/public/FullTextSearch/Model/ISearchRequestSimpleQuery.php @@ -38,16 +38,59 @@ namespace OCP\FullTextSearch\Model; * */ interface ISearchRequestSimpleQuery { + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_TEXT = 1; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_KEYWORD = 2; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_INT_EQ = 3; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_INT_GTE = 4; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_INT_GT = 5; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_INT_LTE = 6; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_INT_LT = 7; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_BOOL = 8; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_ARRAY = 9; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_REGEX = 10; + + /** + * @since 17.0.0 + */ public const COMPARE_TYPE_WILDCARD = 11; diff --git a/lib/public/Group/Backend/ABackend.php b/lib/public/Group/Backend/ABackend.php index 7f5cf732335..274b98655e4 100644 --- a/lib/public/Group/Backend/ABackend.php +++ b/lib/public/Group/Backend/ABackend.php @@ -6,6 +6,7 @@ declare(strict_types=1); * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl> * * @author Roeland Jago Douma <roeland@famdouma.nl> + * @author Carl Schwan <carl@carlschwan.eu> * * @license GNU AGPL version 3 or any later version * @@ -30,7 +31,7 @@ use OCP\GroupInterface; /** * @since 14.0.0 */ -abstract class ABackend implements GroupInterface { +abstract class ABackend implements GroupInterface, IBatchMethodsBackend { /** * @deprecated 14.0.0 * @since 14.0.0 @@ -65,4 +66,29 @@ abstract class ABackend implements GroupInterface { return (bool)($actions & $implements); } + + /** + * @since 28.0.0 + */ + public function groupsExists(array $gids): array { + return array_values(array_filter( + $gids, + fn (string $gid): bool => $this->groupExists($gid), + )); + } + + /** + * @since 28.0.0 + */ + public function getGroupsDetails(array $gids): array { + if (!($this instanceof IGroupDetailsBackend || $this->implementsActions(GroupInterface::GROUP_DETAILS))) { + throw new \Exception("Should not have been called"); + } + /** @var IGroupDetailsBackend $this */ + $groupData = []; + foreach ($gids as $gid) { + $groupData[$gid] = $this->getGroupDetails($gid); + } + return $groupData; + } } diff --git a/lib/public/Group/Backend/IBatchMethodsBackend.php b/lib/public/Group/Backend/IBatchMethodsBackend.php new file mode 100644 index 00000000000..2af00e42825 --- /dev/null +++ b/lib/public/Group/Backend/IBatchMethodsBackend.php @@ -0,0 +1,61 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * @author Carl Schwan <carl@carlschwan.eu> + * @author Côme Chilliet <come.chilliet@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Group\Backend; + +/** + * @brief Optional interface for group backends + * @since 28.0.0 + */ +interface IBatchMethodsBackend { + /** + * @brief Batch method to check if a list of groups exists + * + * The default implementation in ABackend will just call groupExists in + * a loop. But a GroupBackend implementation should provides a more optimized + * override this method to provide a more optimized way to execute this operation. + * + * @param list<string> $gids + * @return list<string> the list of group that exists + * @since 28.0.0 + */ + public function groupsExists(array $gids): array; + + /** + * @brief Batch method to get the group details of a list of groups + * + * The default implementation in ABackend will just call getGroupDetails in + * a loop. But a GroupBackend implementation should override this method + * to provide a more optimized way to execute this operation. + * + * @throw \RuntimeException if called on a backend that doesn't implements IGroupDetailsBackend + * + * @return array<string, array{displayName?: string}> + * @since 28.0.0 + */ + public function getGroupsDetails(array $gids): array; +} diff --git a/lib/public/Group/Backend/IGroupDetailsBackend.php b/lib/public/Group/Backend/IGroupDetailsBackend.php index 4852f978195..851c10388e0 100644 --- a/lib/public/Group/Backend/IGroupDetailsBackend.php +++ b/lib/public/Group/Backend/IGroupDetailsBackend.php @@ -6,6 +6,7 @@ declare(strict_types=1); * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl> * * @author Roeland Jago Douma <roeland@famdouma.nl> + * @author Carl Schwan <carl@carlschwan.eu> * * @license GNU AGPL version 3 or any later version * @@ -26,10 +27,17 @@ declare(strict_types=1); namespace OCP\Group\Backend; /** + * @brief Optional interface for group backends * @since 14.0.0 */ interface IGroupDetailsBackend { /** + * @brief Get additional details for a group, for example the display name. + * + * The array returned can be empty when no additional information is available + * for the group. + * + * @return array{displayName?: string} * @since 14.0.0 */ public function getGroupDetails(string $gid): array; diff --git a/lib/public/GroupInterface.php b/lib/public/GroupInterface.php index a18d38df002..764c810f986 100644 --- a/lib/public/GroupInterface.php +++ b/lib/public/GroupInterface.php @@ -38,15 +38,44 @@ namespace OCP; interface GroupInterface { /** * actions that user backends can define + * + * @since 12.0.0 */ public const CREATE_GROUP = 0x00000001; + + /** + * @since 12.0.0 + */ public const DELETE_GROUP = 0x00000010; + + /** + * @since 12.0.0 + */ public const ADD_TO_GROUP = 0x00000100; + + /** + * @since 12.0.0 + * @deprecated 29.0.0 + */ public const REMOVE_FROM_GOUP = 0x00001000; // oops + + /** + * @since 12.0.0 + */ public const REMOVE_FROM_GROUP = 0x00001000; + //OBSOLETE const GET_DISPLAYNAME = 0x00010000; + + /** + * @since 12.0.0 + */ public const COUNT_USERS = 0x00100000; + + /** + * @since 12.0.0 + */ public const GROUP_DETAILS = 0x01000000; + /** * @since 13.0.0 */ @@ -86,7 +115,8 @@ interface GroupInterface { public function getUserGroups($uid); /** - * get a list of all groups + * @brief Get a list of all groups + * * @param string $search * @param int $limit * @param int $offset @@ -98,7 +128,8 @@ interface GroupInterface { public function getGroups(string $search = '', int $limit = -1, int $offset = 0); /** - * check if a group exists + * @brief Check if a group exists + * * @param string $gid * @return bool * @since 4.5.0 diff --git a/lib/public/Http/Client/IClient.php b/lib/public/Http/Client/IClient.php index fb1760c25f2..c6b7cafe73f 100644 --- a/lib/public/Http/Client/IClient.php +++ b/lib/public/Http/Client/IClient.php @@ -208,6 +208,47 @@ interface IClient { public function options(string $uri, array $options = []): IResponse; /** + * Get the response of a Throwable thrown by the request methods when possible + * + * @param \Throwable $e + * @return IResponse + * @throws \Throwable When $e did not have a response + * @since 29.0.0 + */ + public function getResponseFromThrowable(\Throwable $e): IResponse; + + /** + * Sends a HTTP request + * @param string $method The HTTP method to use + * @param string $uri + * @param array $options Array such as + * 'query' => [ + * 'field' => 'abc', + * 'other_field' => '123', + * 'file_name' => fopen('/path/to/file', 'r'), + * ], + * 'headers' => [ + * 'foo' => 'bar', + * ], + * 'cookies' => [ + * 'foo' => 'bar', + * ], + * 'allow_redirects' => [ + * 'max' => 10, // allow at most 10 redirects. + * 'strict' => true, // use "strict" RFC compliant redirects. + * 'referer' => true, // add a Referer header + * 'protocols' => ['https'] // only allow https URLs + * ], + * 'sink' => '/path/to/file', // save to a file or a stream + * 'verify' => true, // bool or string to CA file + * 'debug' => true, + * @return IResponse + * @throws \Exception If the request could not get completed + * @since 29.0.0 + */ + public function request(string $method, string $uri, array $options = []): IResponse; + + /** * Sends an asynchronous GET request * @param string $uri * @param array $options Array such as diff --git a/lib/public/Http/WellKnown/JrdResponse.php b/lib/public/Http/WellKnown/JrdResponse.php index 7a25f8fe0c3..077b58dc1d9 100644 --- a/lib/public/Http/WellKnown/JrdResponse.php +++ b/lib/public/Http/WellKnown/JrdResponse.php @@ -127,10 +127,10 @@ final class JrdResponse implements IResponse { * @since 21.0.0 */ public function addLink(string $rel, - ?string $type, - ?string $href, - ?array $titles = [], - ?array $properties = []): self { + ?string $type, + ?string $href, + ?array $titles = [], + ?array $properties = []): self { $this->links[] = array_filter([ 'rel' => $rel, 'type' => $type, diff --git a/lib/public/IAppConfig.php b/lib/public/IAppConfig.php index cf387a8a44c..afcdf67f92c 100644 --- a/lib/public/IAppConfig.php +++ b/lib/public/IAppConfig.php @@ -1,9 +1,12 @@ <?php + +declare(strict_types=1); /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Bart Visscher <bartv@thisnet.nl> * @author Joas Schilling <coding@schilljs.com> + * @author Maxence Lange <maxence@artificial-owl.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Robin McCorkell <robin@mccorkell.me.uk> @@ -26,28 +29,486 @@ */ namespace OCP; +use OCP\Exceptions\AppConfigUnknownKeyException; + /** * This class provides an easy way for apps to store config values in the * database. + * + * **Note:** since 29.0.0, it supports **lazy loading** + * + * ### What is lazy loading ? + * In order to avoid loading useless config values into memory for each request, + * only non-lazy values are now loaded. + * + * Once a value that is lazy is requested, all lazy values will be loaded. + * + * Similarly, some methods from this class are marked with a warning about ignoring + * lazy loading. Use them wisely and only on parts of the code that are called + * during specific requests or actions to avoid loading the lazy values all the time. + * * @since 7.0.0 + * @since 29.0.0 - Supporting types and lazy loading */ interface IAppConfig { + /** @since 29.0.0 */ + public const VALUE_SENSITIVE = 1; + /** @since 29.0.0 */ + public const VALUE_MIXED = 2; + /** @since 29.0.0 */ + public const VALUE_STRING = 4; + /** @since 29.0.0 */ + public const VALUE_INT = 8; + /** @since 29.0.0 */ + public const VALUE_FLOAT = 16; + /** @since 29.0.0 */ + public const VALUE_BOOL = 32; + /** @since 29.0.0 */ + public const VALUE_ARRAY = 64; + /** - * check if a key is set in the appconfig - * @param string $app - * @param string $key - * @return bool + * Get list of all apps that have at least one config value stored in database + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @return string[] list of app ids * @since 7.0.0 */ - public function hasKey($app, $key); + public function getApps(): array; + + /** + * Returns all keys stored in database, related to an app. + * Please note that the values are not returned. + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @param string $app id of the app + * + * @return string[] list of stored config keys + * @since 29.0.0 + */ + public function getKeys(string $app): array; + + /** + * Check if a key exists in the list of stored config values. + * + * @param string $app id of the app + * @param string $key config key + * @param bool $lazy search within lazy loaded config + * + * @return bool TRUE if key exists + * @since 29.0.0 Added the $lazy argument + * @since 7.0.0 + */ + public function hasKey(string $app, string $key, ?bool $lazy = false): bool; + + /** + * best way to see if a value is set as sensitive (not displayed in report) + * + * @param string $app id of the app + * @param string $key config key + * @param bool|null $lazy search within lazy loaded config + * + * @return bool TRUE if value is sensitive + * @throws AppConfigUnknownKeyException if config key is not known + * @since 29.0.0 + */ + public function isSensitive(string $app, string $key, ?bool $lazy = false): bool; + + /** + * Returns if the config key stored in database is lazy loaded + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @param string $app id of the app + * @param string $key config key + * + * @return bool TRUE if config is lazy loaded + * @throws AppConfigUnknownKeyException if config key is not known + * @see IAppConfig for details about lazy loading + * @since 29.0.0 + */ + public function isLazy(string $app, string $key): bool; + + /** + * List all config values from an app with config key starting with $key. + * Returns an array with config key as key, stored value as value. + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @param string $app id of the app + * @param string $prefix config keys prefix to search, can be empty. + * @param bool $filtered filter sensitive config values + * + * @return array<string, string> [configKey => configValue] + * @since 29.0.0 + */ + public function getAllValues(string $app, string $prefix = '', bool $filtered = false): array; + + /** + * List all apps storing a specific config key and its stored value. + * Returns an array with appId as key, stored value as value. + * + * @param string $key config key + * @param bool $lazy search within lazy loaded config + * + * @return array<string, string|int|float|bool|array> [appId => configValue] + * @since 29.0.0 + */ + public function searchValues(string $key, bool $lazy = false): array; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $app id of the app + * @param string $key config key + * @param string $default default value + * @param bool $lazy search within lazy loaded config + * + * @return string stored config value or $default if not set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see getValueInt() + * @see getValueFloat() + * @see getValueBool() + * @see getValueArray() + */ + public function getValueString(string $app, string $key, string $default = '', bool $lazy = false): string; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $app id of the app + * @param string $key config key + * @param int $default default value + * @param bool $lazy search within lazy loaded config + * + * @return int stored config value or $default if not set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see getValueString() + * @see getValueFloat() + * @see getValueBool() + * @see getValueArray() + */ + public function getValueInt(string $app, string $key, int $default = 0, bool $lazy = false): int; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $app id of the app + * @param string $key config key + * @param float $default default value + * @param bool $lazy search within lazy loaded config + * + * @return float stored config value or $default if not set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see getValueString() + * @see getValueInt() + * @see getValueBool() + * @see getValueArray() + */ + public function getValueFloat(string $app, string $key, float $default = 0, bool $lazy = false): float; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $app id of the app + * @param string $key config key + * @param bool $default default value + * @param bool $lazy search within lazy loaded config + * + * @return bool stored config value or $default if not set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see getValueString() + * @see getValueInt() + * @see getValueFloat() + * @see getValueArray() + */ + public function getValueBool(string $app, string $key, bool $default = false, bool $lazy = false): bool; + + /** + * Get config value assigned to a config key. + * If config key is not found in database, default value is returned. + * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE. + * + * @param string $app id of the app + * @param string $key config key + * @param array $default default value + * @param bool $lazy search within lazy loaded config + * + * @return array stored config value or $default if not set in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see getValueString() + * @see getValueInt() + * @see getValueFloat() + * @see getValueBool() + */ + public function getValueArray(string $app, string $key, array $default = [], bool $lazy = false): array; + + /** + * returns the type of config value + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @param string $app id of the app + * @param string $key config key + * + * @return int + * @throws AppConfigUnknownKeyException + * @since 29.0.0 + * @see VALUE_STRING + * @see VALUE_INT + * @see VALUE_FLOAT + * @see VALUE_BOOL + * @see VALUE_ARRAY + */ + public function getValueType(string $app, string $key): int; + + /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $app id of the app + * @param string $key config key + * @param string $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see setValueInt() + * @see setValueFloat() + * @see setValueBool() + * @see setValueArray() + */ + public function setValueString(string $app, string $key, string $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * Store a config key and its value in database + * + * When handling huge value around and/or above 2,147,483,647, a debug log will be generated + * on 64bits system, as php int type reach its limit (and throw an exception) on 32bits when using huge numbers. + * + * When using huge numbers, it is advised to use {@see \OCP\Util::numericToNumber()} and {@see setValueString()} + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $app id of the app + * @param string $key config key + * @param int $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see setValueString() + * @see setValueFloat() + * @see setValueBool() + * @see setValueArray() + */ + public function setValueInt(string $app, string $key, int $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * Store a config key and its value in database. + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $app id of the app + * @param string $key config key + * @param float $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see setValueString() + * @see setValueInt() + * @see setValueBool() + * @see setValueArray() + */ + public function setValueFloat(string $app, string $key, float $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $app id of the app + * @param string $key config key + * @param bool $value config value + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see setValueString() + * @see setValueInt() + * @see setValueFloat() + * @see setValueArray() + */ + public function setValueBool(string $app, string $key, bool $value, bool $lazy = false): bool; + + /** + * Store a config key and its value in database + * + * If config key is already known with the exact same config value, the database is not updated. + * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded. + * + * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first + * + * @param string $app id of the app + * @param string $key config key + * @param array $value config value + * @param bool $sensitive if TRUE value will be hidden when listing config values. + * @param bool $lazy set config as lazy loaded + * + * @return bool TRUE if value was different, therefor updated in database + * @since 29.0.0 + * @see IAppConfig for explanation about lazy loading + * @see setValueString() + * @see setValueInt() + * @see setValueFloat() + * @see setValueBool() + */ + public function setValueArray(string $app, string $key, array $value, bool $lazy = false, bool $sensitive = false): bool; + + /** + * switch sensitive status of a config value + * + * **WARNING:** ignore lazy filtering, all config values are loaded from database + * + * @param string $app id of the app + * @param string $key config key + * @param bool $sensitive TRUE to set as sensitive, FALSE to unset + * + * @return bool TRUE if database update were necessary + * @since 29.0.0 + */ + public function updateSensitive(string $app, string $key, bool $sensitive): bool; + + /** + * switch lazy loading status of a config value + * + * @param string $app id of the app + * @param string $key config key + * @param bool $lazy TRUE to set as lazy loaded, FALSE to unset + * + * @return bool TRUE if database update was necessary + * @since 29.0.0 + */ + public function updateLazy(string $app, string $key, bool $lazy): bool; + + /** + * returns an array contains details about a config value + * + * ``` + * [ + * "app" => "myapp", + * "key" => "mykey", + * "value" => "its_value", + * "lazy" => false, + * "type" => 4, + * "typeString" => "string", + * 'sensitive' => true + * ] + * ``` + * + * @param string $app id of the app + * @param string $key config key + * + * @return array + * @throws AppConfigUnknownKeyException if config key is not known in database + * @since 29.0.0 + */ + public function getDetails(string $app, string $key): array; + + /** + * Convert string like 'string', 'integer', 'float', 'bool' or 'array' to + * to bitflag {@see VALUE_STRING}, {@see VALUE_INT}, {@see VALUE_FLOAT}, + * {@see VALUE_BOOL} and {@see VALUE_ARRAY} + * + * @param string $type + * + * @return int + * @since 29.0.0 + */ + public function convertTypeToInt(string $type): int; + + /** + * Convert bitflag {@see VALUE_STRING}, {@see VALUE_INT}, {@see VALUE_FLOAT}, + * {@see VALUE_BOOL} and {@see VALUE_ARRAY} to human-readable string + * + * @param int $type + * + * @return string + * @since 29.0.0 + */ + public function convertTypeToString(int $type): string; + + /** + * Delete single config key from database. + * + * @param string $app id of the app + * @param string $key config key + * @since 29.0.0 + */ + public function deleteKey(string $app, string $key): void; + + /** + * delete all config keys linked to an app + * + * @param string $app id of the app + * @since 29.0.0 + */ + public function deleteApp(string $app): void; + + /** + * Clear the cache. + * + * The cache will be rebuilt only the next time a config value is requested. + * + * @param bool $reload set to TRUE to refill cache instantly after clearing it + * @since 29.0.0 + */ + public function clearCache(bool $reload = false): void; /** * get multiply values, either the app or key can be used as wildcard by setting it to false * * @param string|false $key * @param string|false $app + * * @return array|false * @since 7.0.0 + * @deprecated 29.0.0 Use {@see getAllValues()} or {@see searchValues()} */ public function getValues($app, $key); @@ -55,18 +516,10 @@ interface IAppConfig { * get all values of the app or and filters out sensitive data * * @param string $app + * * @return array * @since 12.0.0 + * @deprecated 29.0.0 Use {@see getAllValues()} or {@see searchValues()} */ public function getFilteredValues($app); - - /** - * Get all apps using the config - * @return string[] an array of app ids - * - * This function returns a list of all apps that have at least one - * entry in the appconfig table. - * @since 7.0.0 - */ - public function getApps(); } diff --git a/lib/public/ICacheFactory.php b/lib/public/ICacheFactory.php index d70a836aa52..70ad955849d 100644 --- a/lib/public/ICacheFactory.php +++ b/lib/public/ICacheFactory.php @@ -75,4 +75,20 @@ interface ICacheFactory { * @since 13.0.0 */ public function createLocal(string $prefix = ''): ICache; + + /** + * Create an in-memory cache instance + * + * Useful for remembering values inside one process. Cache memory is cleared + * when the object is garbage-collected. Implementation may also expire keys + * earlier when the TTL is reached or too much memory is consumed. + * + * Cache keys are local to the cache object. When building two in-memory + * caches, there is no data exchange between the instances. + * + * @param int $capacity maximum number of cache keys + * @return ICache + * @since 28.0.0 + */ + public function createInMemory(int $capacity = 512): ICache; } diff --git a/lib/public/IConfig.php b/lib/public/IConfig.php index 0e7a7523218..706e4776221 100644 --- a/lib/public/IConfig.php +++ b/lib/public/IConfig.php @@ -126,6 +126,7 @@ interface IConfig { * @param string $appName the appName that we stored the value under * @return string[] the keys stored for the app * @since 8.0.0 + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function getAppKeys($appName); @@ -137,6 +138,7 @@ interface IConfig { * @param string $value the value that should be stored * @return void * @since 6.0.0 + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function setAppValue($appName, $key, $value); @@ -146,8 +148,10 @@ interface IConfig { * @param string $appName the appName that we stored the value under * @param string $key the key of the value, under which it was saved * @param string $default the default value to be returned if the value isn't set + * * @return string the saved value * @since 6.0.0 - parameter $default was added in 7.0.0 + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function getAppValue($appName, $key, $default = ''); @@ -157,6 +161,7 @@ interface IConfig { * @param string $appName the appName that we stored the value under * @param string $key the key of the value, under which it was saved * @since 8.0.0 + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function deleteAppValue($appName, $key); @@ -165,6 +170,7 @@ interface IConfig { * * @param string $appName the appName the configs are stored under * @since 8.0.0 + * @deprecated 29.0.0 Use {@see IAppConfig} directly */ public function deleteAppValues($appName); diff --git a/lib/public/IDBConnection.php b/lib/public/IDBConnection.php index fe0267facc5..5613aa3743b 100644 --- a/lib/public/IDBConnection.php +++ b/lib/public/IDBConnection.php @@ -46,6 +46,26 @@ use OCP\DB\QueryBuilder\IQueryBuilder; */ interface IDBConnection { /** + * @since 28.0.0 + */ + public const PLATFORM_MYSQL = 'mysql'; + + /** + * @since 28.0.0 + */ + public const PLATFORM_ORACLE = 'oracle'; + + /** + * @since 28.0.0 + */ + public const PLATFORM_POSTGRES = 'postgres'; + + /** + * @since 28.0.0 + */ + public const PLATFORM_SQLITE = 'sqlite'; + + /** * Gets the QueryBuilder for the connection. * * @return \OCP\DB\QueryBuilder\IQueryBuilder @@ -339,4 +359,12 @@ interface IDBConnection { * @since 13.0.0 */ public function migrateToSchema(Schema $toSchema): void; + + /** + * Returns the database provider name + * @link https://github.com/nextcloud/server/issues/30877 + * @since 28.0.0 + * @return IDBConnection::PLATFORM_* + */ + public function getDatabaseProvider(): string; } diff --git a/lib/public/IGroup.php b/lib/public/IGroup.php index ec26cc55b69..51417641e26 100644 --- a/lib/public/IGroup.php +++ b/lib/public/IGroup.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright Copyright (c) 2016, ownCloud, Inc. * @@ -38,7 +41,7 @@ interface IGroup { * @return string * @since 8.0.0 */ - public function getGID(); + public function getGID(): string; /** * Returns the group display name @@ -46,7 +49,7 @@ interface IGroup { * @return string * @since 12.0.0 */ - public function getDisplayName(); + public function getDisplayName(): string; /** * Set the group display name @@ -60,43 +63,47 @@ interface IGroup { /** * get all users in the group * - * @return \OCP\IUser[] + * @return IUser[] * @since 8.0.0 */ - public function getUsers(); + public function getUsers(): array; /** * check if a user is in the group * - * @param \OCP\IUser $user + * @param IUser $user + * * @return bool * @since 8.0.0 */ - public function inGroup(IUser $user); + public function inGroup(IUser $user): bool; /** * add a user to the group * - * @param \OCP\IUser $user + * @param IUser $user + * * @since 8.0.0 */ - public function addUser(IUser $user); + public function addUser(IUser $user): void; /** - * remove a user from the group + * Remove a user from the group + * + * @param IUser $user * - * @param \OCP\IUser $user * @since 8.0.0 */ - public function removeUser($user); + public function removeUser(IUser $user): void; /** * search for users in the group by userid * * @param string $search - * @param int $limit - * @param int $offset - * @return \OCP\IUser[] + * @param int|null $limit + * @param int|null $offset + * + * @return IUser[] * @since 8.0.0 */ public function searchUsers(string $search, ?int $limit = null, ?int $offset = null): array; @@ -108,7 +115,7 @@ interface IGroup { * @return int|bool * @since 8.0.0 */ - public function count($search = ''); + public function count(string $search = ''): int|bool; /** * returns the number of disabled users @@ -116,18 +123,19 @@ interface IGroup { * @return int|bool * @since 14.0.0 */ - public function countDisabled(); + public function countDisabled(): int|bool; /** - * search for users in the group by displayname + * Search for users in the group by displayname * * @param string $search - * @param int $limit - * @param int $offset - * @return \OCP\IUser[] + * @param int|null $limit + * @param int|null $offset + * + * @return IUser[] * @since 8.0.0 */ - public function searchDisplayName($search, $limit = null, $offset = null); + public function searchDisplayName(string $search, int $limit = null, int $offset = null): array; /** * Get the names of the backends the group is connected to @@ -135,27 +143,27 @@ interface IGroup { * @return string[] * @since 22.0.0 */ - public function getBackendNames(); + public function getBackendNames(): array; /** - * delete the group + * Delete the group * * @return bool * @since 8.0.0 */ - public function delete(); + public function delete(): bool; /** * @return bool * @since 14.0.0 */ - public function canRemoveUser(); + public function canRemoveUser(): bool; /** * @return bool * @since 14.0.0 */ - public function canAddUser(); + public function canAddUser(): bool; /** * @return bool diff --git a/lib/public/IMemcacheTTL.php b/lib/public/IMemcacheTTL.php index 8424e5b2bfa..250e727308b 100644 --- a/lib/public/IMemcacheTTL.php +++ b/lib/public/IMemcacheTTL.php @@ -35,5 +35,22 @@ interface IMemcacheTTL extends IMemcache { * @param int $ttl time to live in seconds * @since 8.2.2 */ - public function setTTL($key, $ttl); + public function setTTL(string $key, int $ttl); + + /** + * Get the ttl for an existing value, in seconds till expiry + * + * @return int|false + * @since 27 + */ + public function getTTL(string $key): int|false; + /** + * Set the ttl for an existing value if the value matches + * + * @param string $key + * @param mixed $value + * @param int $ttl time to live in seconds + * @since 27 + */ + public function compareSetTTL(string $key, $value, int $ttl): bool; } diff --git a/lib/public/INavigationManager.php b/lib/public/INavigationManager.php index 710cbd1248d..36f80c3293f 100644 --- a/lib/public/INavigationManager.php +++ b/lib/public/INavigationManager.php @@ -33,6 +33,10 @@ namespace OCP; /** + * @psalm-type NavigationEntry = array{id: string, order: int, href: string, name: string, app?: string, icon?: string, classes?: string, type?: string} + */ + +/** * Manages the ownCloud navigation * @since 6.0.0 */ @@ -58,9 +62,11 @@ interface INavigationManager { /** * Creates a new navigation entry * - * @param array|\Closure $entry Array containing: id, name, order, icon and href key + * @param array array|\Closure $entry Array containing: id, name, order, icon and href key + * If a menu entry (type = 'link') is added, you shall also set app to the app that added the entry. * The use of a closure is preferred, because it will avoid * loading the routing of your app, unless required. + * @psalm-param NavigationEntry|callable():NavigationEntry $entry * @return void * @since 6.0.0 */ diff --git a/lib/public/IPhoneNumberUtil.php b/lib/public/IPhoneNumberUtil.php new file mode 100644 index 00000000000..733de0e35a6 --- /dev/null +++ b/lib/public/IPhoneNumberUtil.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); +/** + * + * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP; + +/** + * @since 28.0.0 + */ +interface IPhoneNumberUtil { + /** + * Returns the country code for a specific region + * + * For example, this would be `41` for Switzerland and `49` for Germany. + * Returns null when the region is invalid. + * + * @param string $regionCode Two-letter region code of ISO 3166-1 + * @return int|null Null when invalid/unsupported, the phone country code otherwise + * @since 28.0.0 + */ + public function getCountryCodeForRegion(string $regionCode): ?int; + + /** + * Converts a given input into an E164 formatted phone number + * + * E164 is the international format without any formatting characters or spaces. + * E.g. +41446681800 where +41 is the region code. + * + * @param string $input Input phone number can contain formatting spaces, slashes and dashes + * @param string|null $defaultRegion Two-letter region code of ISO 3166-1 + * @return string|null Null when the input is invalid for the given region or requires a region. + * @since 28.0.0 + */ + public function convertToStandardFormat(string $input, ?string $defaultRegion = null): ?string; +} diff --git a/lib/public/IPreview.php b/lib/public/IPreview.php index 2758eba8d63..d8e17b5b029 100644 --- a/lib/public/IPreview.php +++ b/lib/public/IPreview.php @@ -38,7 +38,14 @@ use OCP\Files\SimpleFS\ISimpleFile; * @since 6.0.0 */ interface IPreview { + /** + * @since 11.0.0 + */ public const MODE_FILL = 'fill'; + + /** + * @since 11.0.0 + */ public const MODE_COVER = 'cover'; /** diff --git a/lib/public/IURLGenerator.php b/lib/public/IURLGenerator.php index 8229d51f231..396867e22b3 100644 --- a/lib/public/IURLGenerator.php +++ b/lib/public/IURLGenerator.php @@ -41,6 +41,7 @@ interface IURLGenerator { * This is a copy of the frontend regex in core/src/OCP/comments.js, make sure to adjust both when changing * * @since 25.0.0 + * @since 29.0.0 changed to match localhost and hostnames with ports */ public const URL_REGEX = '/' . self::URL_REGEX_NO_MODIFIERS . '/mi'; @@ -50,8 +51,9 @@ interface IURLGenerator { * This is a copy of the frontend regex in core/src/OCP/comments.js, make sure to adjust both when changing * * @since 25.0.0 + * @since 29.0.0 changed to match localhost and hostnames with ports */ - public const URL_REGEX_NO_MODIFIERS = '(\s|\n|^)(https?:\/\/)((?:[-A-Z0-9+_]+\.)+[-A-Z]+(?:\/[-A-Z0-9+&@#%?=~_|!:,.;()]*)*)(\s|\n|$)'; + public const URL_REGEX_NO_MODIFIERS = '(\s|\n|^)(https?:\/\/)([-A-Z0-9+_.]+(?::[0-9]+)?(?:\/[-A-Z0-9+&@#%?=~_|!:,.;()]*)*)(\s|\n|$)'; /** * Returns the URL for a route @@ -95,6 +97,7 @@ interface IURLGenerator { * @param string $appName the name of the app * @param string $file the name of the file * @return string the url + * @throws \RuntimeException If the image does not exist * @since 6.0.0 */ public function imagePath(string $appName, string $file): string; diff --git a/lib/public/IUserManager.php b/lib/public/IUserManager.php index 1efb3d5f0c2..0a94c5ad928 100644 --- a/lib/public/IUserManager.php +++ b/lib/public/IUserManager.php @@ -140,6 +140,12 @@ interface IUserManager { public function searchDisplayName($pattern, $limit = null, $offset = null); /** + * @return IUser[] + * @since 28.0.0 + */ + public function getDisabledUsers(?int $limit = null, int $offset = 0): array; + + /** * Search known users (from phonebook sync) by displayName * * @param string $searcher diff --git a/lib/public/Log/Audit/CriticalActionPerformedEvent.php b/lib/public/Log/Audit/CriticalActionPerformedEvent.php index 79c67e5b8bd..45786a5c980 100644 --- a/lib/public/Log/Audit/CriticalActionPerformedEvent.php +++ b/lib/public/Log/Audit/CriticalActionPerformedEvent.php @@ -49,8 +49,8 @@ class CriticalActionPerformedEvent extends Event { * @since 22.0.0 */ public function __construct(string $logMessage, - array $parameters = [], - bool $obfuscateParameters = false) { + array $parameters = [], + bool $obfuscateParameters = false) { parent::__construct(); $this->logMessage = $logMessage; $this->parameters = $parameters; diff --git a/lib/public/Log/ILogFactory.php b/lib/public/Log/ILogFactory.php index e0128d6b11c..e51a674afbd 100644 --- a/lib/public/Log/ILogFactory.php +++ b/lib/public/Log/ILogFactory.php @@ -24,7 +24,6 @@ */ namespace OCP\Log; -use OCP\ILogger; use Psr\Log\LoggerInterface; /** @@ -42,15 +41,6 @@ interface ILogFactory { /** * @param string $path - * @return ILogger - * @since 14.0.0 - * @deprecated 22.0.0 Use \OCP\Log\ILogFactory::getCustomPsrLogger - * @see \OCP\Log\ILogFactory::getCustomPsrLogger - */ - public function getCustomLogger(string $path): ILogger; - - /** - * @param string $path * @param string $type * @param string $tag * @return LoggerInterface diff --git a/lib/public/Migration/IOutput.php b/lib/public/Migration/IOutput.php index 70fb56b6bdd..97b0e15b9b5 100644 --- a/lib/public/Migration/IOutput.php +++ b/lib/public/Migration/IOutput.php @@ -32,6 +32,13 @@ interface IOutput { /** * @param string $message * @return void + * @since 28.0.0 + */ + public function debug(string $message): void; + + /** + * @param string $message + * @return void * @since 9.1.0 */ public function info($message); diff --git a/lib/public/OCM/Events/ResourceTypeRegisterEvent.php b/lib/public/OCM/Events/ResourceTypeRegisterEvent.php new file mode 100644 index 00000000000..1048d8d0d49 --- /dev/null +++ b/lib/public/OCM/Events/ResourceTypeRegisterEvent.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); +/* + * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\OCM\Events; + +use OCP\EventDispatcher\Event; +use OCP\OCM\IOCMProvider; + +/** + * Use this event to register additional OCM resources before the API returns + * them in the OCM provider list and capability + * + * @since 28.0.0 + */ +class ResourceTypeRegisterEvent extends Event { + /** + * @param IOCMProvider $provider + * @since 28.0.0 + */ + public function __construct( + protected IOCMProvider $provider, + ) { + parent::__construct(); + } + + /** + * @param string $name + * @param list<string> $shareTypes List of supported share recipients, e.g. 'user', 'group', … + * @param array<string, string> $protocols List of supported protocols and their location, + * e.g. ['webdav' => '/remote.php/webdav/'] + * @since 28.0.0 + */ + public function registerResourceType(string $name, array $shareTypes, array $protocols): void { + $resourceType = $this->provider->createNewResourceType(); + $resourceType->setName($name) + ->setShareTypes($shareTypes) + ->setProtocols($protocols); + $this->provider->addResourceType($resourceType); + } +} diff --git a/lib/public/OCM/Exceptions/OCMArgumentException.php b/lib/public/OCM/Exceptions/OCMArgumentException.php new file mode 100644 index 00000000000..e3abd7bf26b --- /dev/null +++ b/lib/public/OCM/Exceptions/OCMArgumentException.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023, Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\OCM\Exceptions; + +use Exception; + +/** + * @since 28.0.0 + */ +class OCMArgumentException extends Exception { +} diff --git a/lib/public/OCM/Exceptions/OCMProviderException.php b/lib/public/OCM/Exceptions/OCMProviderException.php new file mode 100644 index 00000000000..32dab10dc68 --- /dev/null +++ b/lib/public/OCM/Exceptions/OCMProviderException.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023, Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\OCM\Exceptions; + +use Exception; + +/** + * @since 28.0.0 + */ +class OCMProviderException extends Exception { +} diff --git a/lib/public/OCM/IOCMDiscoveryService.php b/lib/public/OCM/IOCMDiscoveryService.php new file mode 100644 index 00000000000..2407e7b24e8 --- /dev/null +++ b/lib/public/OCM/IOCMDiscoveryService.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\OCM; + +use OCP\OCM\Exceptions\OCMProviderException; + +/** + * Discover remote OCM services + * + * @since 28.0.0 + */ +interface IOCMDiscoveryService { + /** + * Discover remote OCM services + * + * @param string $remote address of the remote provider + * @param bool $skipCache ignore cache, refresh data + * + * @return IOCMProvider + * @throws OCMProviderException if no valid discovery data can be returned + * @since 28.0.0 + */ + public function discover(string $remote, bool $skipCache = false): IOCMProvider; +} diff --git a/lib/public/OCM/IOCMProvider.php b/lib/public/OCM/IOCMProvider.php new file mode 100644 index 00000000000..6df7eed370c --- /dev/null +++ b/lib/public/OCM/IOCMProvider.php @@ -0,0 +1,165 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\OCM; + +use JsonSerializable; +use OCP\OCM\Exceptions\OCMArgumentException; +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 + */ +interface IOCMProvider extends JsonSerializable { + /** + * enable OCM + * + * @param bool $enabled + * + * @return $this + * @since 28.0.0 + */ + public function setEnabled(bool $enabled): static; + + /** + * is set as enabled ? + * + * @return bool + * @since 28.0.0 + */ + public function isEnabled(): bool; + + /** + * get set API Version + * + * @param string $apiVersion + * + * @return $this + * @since 28.0.0 + */ + public function setApiVersion(string $apiVersion): static; + + /** + * returns API version + * + * @return string + * @since 28.0.0 + */ + public function getApiVersion(): string; + + /** + * configure endpoint + * + * @param string $endPoint + * + * @return $this + * @since 28.0.0 + */ + public function setEndPoint(string $endPoint): static; + + /** + * get configured endpoint + * + * @return string + * @since 28.0.0 + */ + public function getEndPoint(): string; + + /** + * create a new resource to later add it with {@see addResourceType()} + * @return IOCMResource + * @since 28.0.0 + */ + public function createNewResourceType(): IOCMResource; + + /** + * add a single resource to the object + * + * @param IOCMResource $resource + * + * @return $this + * @since 28.0.0 + */ + public function addResourceType(IOCMResource $resource): static; + + /** + * set resources + * + * @param IOCMResource[] $resourceTypes + * + * @return $this + * @since 28.0.0 + */ + public function setResourceTypes(array $resourceTypes): static; + + /** + * get all set resources + * + * @return IOCMResource[] + * @since 28.0.0 + */ + public function getResourceTypes(): array; + + /** + * extract a specific string value from the listing of protocols, based on resource-name and protocol-name + * + * @param string $resourceName + * @param string $protocol + * + * @return string + * @throws OCMArgumentException + * @since 28.0.0 + */ + public function extractProtocolEntry(string $resourceName, string $protocol): string; + + /** + * import data from an array + * + * @param array<string, int|string|bool|array> $data + * + * @return $this + * @throws OCMProviderException in case a descent provider cannot be generated from data + * @since 28.0.0 + */ + public function import(array $data): static; + + /** + * @return array{ + * enabled: bool, + * apiVersion: string, + * endPoint: string, + * resourceTypes: array{ + * name: string, + * shareTypes: string[], + * protocols: array<string, string> + * }[] + * } + * @since 28.0.0 + */ + public function jsonSerialize(): array; +} diff --git a/lib/public/OCM/IOCMResource.php b/lib/public/OCM/IOCMResource.php new file mode 100644 index 00000000000..242c77116f1 --- /dev/null +++ b/lib/public/OCM/IOCMResource.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Maxence Lange <maxence@artificial-owl.com> + * + * @author Maxence Lange <maxence@artificial-owl.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\OCM; + +use JsonSerializable; + +/** + * Model based on the Open Cloud Mesh Discovery API + * + * @link https://github.com/cs3org/OCM-API/ + * @since 28.0.0 + */ +interface IOCMResource extends JsonSerializable { + /** + * set name of the resource + * + * @param string $name + * + * @return $this + * @since 28.0.0 + */ + public function setName(string $name): static; + + /** + * get name of the resource + * + * @return string + * @since 28.0.0 + */ + public function getName(): string; + + /** + * set share types + * + * @param string[] $shareTypes + * + * @return $this + * @since 28.0.0 + */ + public function setShareTypes(array $shareTypes): static; + + /** + * get share types + * + * @return string[] + * @since 28.0.0 + */ + public function getShareTypes(): array; + + /** + * set available protocols + * + * @param array<string, string> $protocols + * + * @return $this + * @since 28.0.0 + */ + public function setProtocols(array $protocols): static; + + /** + * get configured protocols + * + * @return array<string, string> + * @since 28.0.0 + */ + public function getProtocols(): array; + + /** + * import data from an array + * + * @param array $data + * + * @return $this + * @since 28.0.0 + */ + public function import(array $data): static; + + /** + * @return array{ + * name: string, + * shareTypes: string[], + * protocols: array<string, string> + * } + * @since 28.0.0 + */ + public function jsonSerialize(): array; +} diff --git a/lib/public/Profile/IProfileManager.php b/lib/public/Profile/IProfileManager.php new file mode 100644 index 00000000000..996e49d116e --- /dev/null +++ b/lib/public/Profile/IProfileManager.php @@ -0,0 +1,106 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Profile; + +use OCP\Accounts\IAccountManager; +use OCP\IUser; + +/** + * @since 28.0.0 + */ +interface IProfileManager { + /** + * Visible to users, guests, and public access + * + * @since 28.0.0 + */ + public const VISIBILITY_SHOW = 'show'; + + /** + * Visible to users and guests + * + * @since 28.0.0 + */ + public const VISIBILITY_SHOW_USERS_ONLY = 'show_users_only'; + + /** + * Visible to nobody + * + * @since 28.0.0 + */ + public const VISIBILITY_HIDE = 'hide'; + + /** + * Default account property visibility + * + * @since 28.0.0 + */ + public const DEFAULT_PROPERTY_VISIBILITY = [ + IAccountManager::PROPERTY_ADDRESS => self::VISIBILITY_SHOW_USERS_ONLY, + IAccountManager::PROPERTY_AVATAR => self::VISIBILITY_SHOW, + IAccountManager::PROPERTY_BIOGRAPHY => self::VISIBILITY_SHOW, + IAccountManager::PROPERTY_DISPLAYNAME => self::VISIBILITY_SHOW, + IAccountManager::PROPERTY_HEADLINE => self::VISIBILITY_SHOW, + IAccountManager::PROPERTY_ORGANISATION => self::VISIBILITY_SHOW, + IAccountManager::PROPERTY_ROLE => self::VISIBILITY_SHOW, + IAccountManager::PROPERTY_EMAIL => self::VISIBILITY_SHOW_USERS_ONLY, + IAccountManager::PROPERTY_PHONE => self::VISIBILITY_SHOW_USERS_ONLY, + IAccountManager::PROPERTY_TWITTER => self::VISIBILITY_SHOW, + IAccountManager::PROPERTY_WEBSITE => self::VISIBILITY_SHOW, + ]; + + /** + * Default visibility + * + * @since 28.0.0 + */ + public const DEFAULT_VISIBILITY = self::VISIBILITY_SHOW_USERS_ONLY; + + /** + * If no user is passed as an argument return whether profile is enabled globally in `config.php` + * + * @since 28.0.0 + */ + public function isProfileEnabled(?IUser $user = null): bool; + + /** + * Return whether the profile parameter of the target user + * is visible to the visiting user + * + * @since 28.0.0 + */ + public function isProfileFieldVisible(string $profileField, IUser $targetUser, ?IUser $visitingUser): bool; + + /** + * Return the profile parameters of the target user that are visible to the visiting user + * in an associative array + * + * @return array{userId: string, address?: ?string, biography?: ?string, displayname?: ?string, headline?: ?string, isUserAvatarVisible?: bool, organisation?: ?string, role?: ?string, actions: list<array{id: string, icon: string, title: string, target: ?string}>} + * @since 28.0.0 + */ + public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array; +} diff --git a/lib/public/Search/FilterDefinition.php b/lib/public/Search/FilterDefinition.php new file mode 100644 index 00000000000..c1e23cd3cd3 --- /dev/null +++ b/lib/public/Search/FilterDefinition.php @@ -0,0 +1,136 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Search; + +use InvalidArgumentException; + +/** + * Filter definition + * + * Describe filter attributes + * + * @since 28.0.0 + */ +class FilterDefinition { + /** + * @since 28.0.0 + */ + public const TYPE_BOOL = 'bool'; + + /** + * @since 28.0.0 + */ + public const TYPE_INT = 'int'; + + /** + * @since 28.0.0 + */ + public const TYPE_FLOAT = 'float'; + + /** + * @since 28.0.0 + */ + public const TYPE_STRING = 'string'; + + /** + * @since 28.0.0 + */ + public const TYPE_STRINGS = 'strings'; + + /** + * @since 28.0.0 + */ + public const TYPE_DATETIME = 'datetime'; + + /** + * @since 28.0.0 + */ + public const TYPE_PERSON = 'person'; + + /** + * @since 28.0.0 + */ + public const TYPE_NC_USER = 'nc-user'; + + /** + * @since 28.0.0 + */ + public const TYPE_NC_GROUP = 'nc-group'; + + /** + * Build filter definition + * + * @param self::TYPE_* $type + * @param bool $exclusive If true, all providers not supporting this filter will be ignored when this filter is provided + * @throw InvalidArgumentException in case of invalid name. Allowed characters are -, 0-9, a-z. + * @since 28.0.0 + */ + public function __construct( + private string $name, + private string $type = self::TYPE_STRING, + private bool $exclusive = true, + ) { + if (!preg_match('/[-0-9a-z]+/Au', $name)) { + throw new InvalidArgumentException('Invalid filter name. Allowed characters are [-0-9a-z]'); + } + } + + /** + * Filter name + * + * Name is used in query string and for advanced syntax `name: <value>` + * + * @since 28.0.0 + */ + public function name(): string { + return $this->name; + } + + /** + * Filter type + * + * Expected type of value for the filter + * + * @return self::TYPE_* + * @since 28.0.0 + */ + public function type(): string { + return $this->type; + } + + /** + * Is filter exclusive? + * + * If exclusive, only provider with support for this filter will receive the query. + * Example: if an exclusive filter `mimetype` is declared, a search with this term will not + * be send to providers like `settings` that doesn't support it. + * + * @since 28.0.0 + */ + public function exclusive(): bool { + return $this->exclusive; + } +} diff --git a/lib/public/Search/IFilter.php b/lib/public/Search/IFilter.php new file mode 100644 index 00000000000..6065622cb71 --- /dev/null +++ b/lib/public/Search/IFilter.php @@ -0,0 +1,55 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Search; + +/** + * Interface for search filters + * + * @since 28.0.0 + */ +interface IFilter { + /** @since 28.0.0 */ + public const BUILTIN_TERM = 'term'; + /** @since 28.0.0 */ + public const BUILTIN_SINCE = 'since'; + /** @since 28.0.0 */ + public const BUILTIN_UNTIL = 'until'; + /** @since 28.0.0 */ + public const BUILTIN_PERSON = 'person'; + /** @since 28.0.0 */ + public const BUILTIN_TITLE_ONLY = 'title-only'; + /** @since 28.0.0 */ + public const BUILTIN_PLACES = 'places'; + /** @since 28.0.0 */ + public const BUILTIN_PROVIDER = 'provider'; + + /** + * Get filter value + * + * @since 28.0.0 + */ + public function get(): mixed; +} diff --git a/lib/public/Search/IFilterCollection.php b/lib/public/Search/IFilterCollection.php new file mode 100644 index 00000000000..6ca53a1c628 --- /dev/null +++ b/lib/public/Search/IFilterCollection.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Search; + +use IteratorAggregate; + +/** + * Interface for search filters + * + * @since 28.0.0 + * @extends IteratorAggregate<string, \OCP\Search\IFilter> + */ +interface IFilterCollection extends IteratorAggregate { + /** + * Check if a filter exits + * + * @since 28.0.0 + */ + public function has(string $name): bool; + + /** + * Get a filter by name + * + * @since 28.0.0 + */ + public function get(string $name): ?IFilter; + + /** + * Return Iterator of filters + * + * @since 28.0.0 + */ + public function getIterator(): \Traversable; +} diff --git a/lib/public/Search/IFilteringProvider.php b/lib/public/Search/IFilteringProvider.php new file mode 100644 index 00000000000..dbe1044a539 --- /dev/null +++ b/lib/public/Search/IFilteringProvider.php @@ -0,0 +1,72 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Search; + +/** + * Interface for advanced search providers + * + * These providers will be implemented in apps, so they can participate in the + * global search results of Nextcloud. If an app provides more than one type of + * resource, e.g. contacts and address books in Nextcloud Contacts, it should + * register one provider per group. + * + * @since 28.0.0 + */ +interface IFilteringProvider extends IProvider { + /** + * Return the names of filters supported by the application + * + * If a filter sent by client is not in this list, + * the current provider will be ignored. + * Example: + * array('term', 'since', 'custom-filter'); + * + * @since 28.0.0 + * @return string[] Name of supported filters (default or defined by application) + */ + public function getSupportedFilters(): array; + + /** + * Get alternate IDs handled by this provider + * + * A search provider can complete results from other search providers. + * For example, files and full-text-search can search in files. + * If you use `in:files` in a search, provider files will be invoked, + * with all other providers declaring `files` in this method + * + * @since 28.0.0 + * @return string[] IDs + */ + public function getAlternateIds(): array; + + /** + * Allows application to declare custom filters + * + * @since 28.0.0 + * @return list<FilterDefinition> + */ + public function getCustomFilters(): array; +} diff --git a/lib/public/Search/IInAppSearch.php b/lib/public/Search/IInAppSearch.php new file mode 100644 index 00000000000..9e1e294bf4d --- /dev/null +++ b/lib/public/Search/IInAppSearch.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\Search; + +/** + * Interface for search providers supporting in-app search + * + * @since 28.0.0 + */ +interface IInAppSearch extends IProvider { +} diff --git a/lib/public/Search/IProvider.php b/lib/public/Search/IProvider.php index 61655c47367..95d7a1b163a 100644 --- a/lib/public/Search/IProvider.php +++ b/lib/public/Search/IProvider.php @@ -68,15 +68,17 @@ interface IProvider { /** * Get the search provider order * The lower the int, the higher it will be sorted (0 will be before 10) + * If null, the search provider will be hidden in the UI and the API not called * * @param string $route the route the user is currently at, e.g. files.view.index * @param array $routeParameters the parameters of the route the user is currently at, e.g. [fileId = 982, dir = "/"] * - * @return int + * @return int|null * * @since 20.0.0 + * @since 28.0.0 Can return null */ - public function getOrder(string $route, array $routeParameters): int; + public function getOrder(string $route, array $routeParameters): ?int; /** * Find matching search entries in an app diff --git a/lib/public/Search/ISearchQuery.php b/lib/public/Search/ISearchQuery.php index a545d1dbccb..75d95b45c4c 100644 --- a/lib/public/Search/ISearchQuery.php +++ b/lib/public/Search/ISearchQuery.php @@ -52,6 +52,20 @@ interface ISearchQuery { public function getTerm(): string; /** + * Get a single request filter + * + * @since 28.0.0 + */ + public function getFilter(string $name): ?IFilter; + + /** + * Get request filters + * + * @since 28.0.0 + */ + public function getFilters(): IFilterCollection; + + /** * Get the sort order of results as defined as SORT_* constants on this interface * * @return int diff --git a/lib/public/Search/SearchResult.php b/lib/public/Search/SearchResult.php index 9ac8b28fb8b..892c60777b3 100644 --- a/lib/public/Search/SearchResult.php +++ b/lib/public/Search/SearchResult.php @@ -54,9 +54,9 @@ final class SearchResult implements JsonSerializable { * @since 20.0.0 */ private function __construct(string $name, - bool $isPaginated, - array $entries, - $cursor = null) { + bool $isPaginated, + array $entries, + $cursor = null) { $this->name = $name; $this->isPaginated = $isPaginated; $this->entries = $entries; @@ -87,8 +87,8 @@ final class SearchResult implements JsonSerializable { * @since 20.0.0 */ public static function paginated(string $name, - array $entries, - $cursor): self { + array $entries, + $cursor): self { return new self( $name, true, diff --git a/lib/public/Search/SearchResultEntry.php b/lib/public/Search/SearchResultEntry.php index 86a3f08cfe6..f4ff1ec2a5c 100644 --- a/lib/public/Search/SearchResultEntry.php +++ b/lib/public/Search/SearchResultEntry.php @@ -98,11 +98,11 @@ class SearchResultEntry implements JsonSerializable { * @since 20.0.0 */ public function __construct(string $thumbnailUrl, - string $title, - string $subline, - string $resourceUrl, - string $icon = '', - bool $rounded = false) { + string $title, + string $subline, + string $resourceUrl, + string $icon = '', + bool $rounded = false) { $this->thumbnailUrl = $thumbnailUrl; $this->title = $title; $this->subline = $subline; diff --git a/lib/public/Security/ISecureRandom.php b/lib/public/Security/ISecureRandom.php index 3634ebf99f7..530befb0257 100644 --- a/lib/public/Security/ISecureRandom.php +++ b/lib/public/Security/ISecureRandom.php @@ -41,17 +41,36 @@ namespace OCP\Security; interface ISecureRandom { /** * Flags for characters that can be used for <code>generate($length, $characters)</code> + * @since 8.0.0 */ public const CHAR_UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + /** + * @since 8.0.0 + */ public const CHAR_LOWER = 'abcdefghijklmnopqrstuvwxyz'; + + /** + * @since 8.0.0 + */ public const CHAR_DIGITS = '0123456789'; + + /** + * @since 8.0.0 + */ public const CHAR_SYMBOLS = '!\"#$%&\\\'()*+,-./:;<=>?@[\]^_`{|}~'; + + /** + * @since 12.0.0 + */ public const CHAR_ALPHANUMERIC = self::CHAR_UPPER . self::CHAR_LOWER . self::CHAR_DIGITS; /** * Characters that can be used for <code>generate($length, $characters)</code>, to - * generate human readable random strings. Lower- and upper-case characters and digits + * generate human-readable random strings. Lower- and upper-case characters and digits * are included. Characters which are ambiguous are excluded, such as I, l, and 1 and so on. + * + * @since 23.0.0 */ public const CHAR_HUMAN_READABLE = 'abcdefgijkmnopqrstwxyzABCDEFGHJKLMNPQRSTWXYZ23456789'; @@ -64,5 +83,5 @@ interface ISecureRandom { * @since 8.0.0 */ public function generate(int $length, - string $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'): string; + string $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'): string; } diff --git a/lib/public/Security/RateLimiting/ILimiter.php b/lib/public/Security/RateLimiting/ILimiter.php new file mode 100644 index 00000000000..cfc7387664d --- /dev/null +++ b/lib/public/Security/RateLimiting/ILimiter.php @@ -0,0 +1,72 @@ +<?php + +declare(strict_types=1); + +/* + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\Security\RateLimiting; + +use OCP\AppFramework\Http\Attribute\AnonRateLimit; +use OCP\AppFramework\Http\Attribute\UserRateLimit; +use OCP\IUser; + +/** + * Programmatic rate limiter for web requests that are not handled by an app framework controller + * + * @see AnonRateLimit + * @see UserRateLimit + * + * @since 28.0.0 + */ +interface ILimiter { + /** + * Registers attempt for an anonymous request + * + * @param string $identifier + * @param int $anonLimit + * @param int $anonPeriod in seconds + * @param string $ip + * @throws IRateLimitExceededException if limits are reached, which should cause a HTTP 429 response + * @since 28.0.0 + * + */ + public function registerAnonRequest(string $identifier, + int $anonLimit, + int $anonPeriod, + string $ip): void; + + /** + * Registers attempt for an authenticated request + * + * @param string $identifier + * @param int $userLimit + * @param int $userPeriod in seconds + * @param IUser $user the acting user + * @throws IRateLimitExceededException if limits are reached, which should cause a HTTP 429 response + * @since 28.0.0 + * + */ + public function registerUserRequest(string $identifier, + int $userLimit, + int $userPeriod, + IUser $user): void; +} diff --git a/lib/public/Security/RateLimiting/IRateLimitExceededException.php b/lib/public/Security/RateLimiting/IRateLimitExceededException.php new file mode 100644 index 00000000000..9bc8c22a67c --- /dev/null +++ b/lib/public/Security/RateLimiting/IRateLimitExceededException.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +/* + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\Security\RateLimiting; + +use Throwable; + +/** + * Thrown if the (anonymous) user has exceeded a rate limit + * + * @since 28.0.0 + */ +interface IRateLimitExceededException extends Throwable { +} diff --git a/lib/public/Settings/DeclarativeSettingsTypes.php b/lib/public/Settings/DeclarativeSettingsTypes.php new file mode 100644 index 00000000000..01e20ee7cc9 --- /dev/null +++ b/lib/public/Settings/DeclarativeSettingsTypes.php @@ -0,0 +1,145 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Andrey Borysenko <andrey.borysenko@nextcloud.com> + * + * @author Andrey Borysenko <andrey.borysenko@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Settings; + +/** + * Declarative settings types supported in the IDeclarativeSettingsForm forms + * + * @since 29.0.0 + */ +final class DeclarativeSettingsTypes { + /** + * IDeclarativeSettingsForm section_type which is determines where the form is displayed + * + * @since 29.0.0 + */ + public const SECTION_TYPE_ADMIN = 'admin'; + + /** + * IDeclarativeSettingsForm section_type which is determines where the form is displayed + * + * @since 29.0.0 + */ + public const SECTION_TYPE_PERSONAL = 'personal'; + + /** + * IDeclarativeSettingsForm storage_type which is determines where and how the config value is stored + * + * + * For `external` storage_type the app implementing \OCP\Settings\SetDeclarativeSettingsValueEvent and \OCP\Settings\GetDeclarativeSettingsValueEvent events is responsible for storing and retrieving the config value. + * + * @since 29.0.0 + */ + public const STORAGE_TYPE_EXTERNAL = 'external'; + + /** + * IDeclarativeSettingsForm storage_type which is determines where and how the config value is stored + * + * For `internal` storage_type the config value is stored in default `appconfig` and `preferences` tables. + * For `external` storage_type the app implementing \OCP\Settings\SetDeclarativeSettingsValueEvent and \OCP\Settings\GetDeclarativeSettingsValueEvent events is responsible for storing and retrieving the config value. + * + * @since 29.0.0 + */ + public const STORAGE_TYPE_INTERNAL = 'internal'; + + /** + * NcInputField type text + * + * @since 29.0.0 + */ + public const TEXT = 'text'; + + /** + * NcInputField type password + * + * @since 29.0.0 + */ + public const PASSWORD = 'password'; + + /** + * NcInputField type email + * + * @since 29.0.0 + */ + public const EMAIL = 'email'; + + /** + * NcInputField type tel + * + * @since 29.0.0 + */ + public const TEL = 'tel'; + + /** + * NcInputField type url + * + * @since 29.0.0 + */ + public const URL = 'url'; + + /** + * NcInputField type number + * + * @since 29.0.0 + */ + public const NUMBER = 'number'; + + /** + * NcCheckboxRadioSwitch type checkbox + * + * @since 29.0.0 + */ + public const CHECKBOX = 'checkbox'; + + /** + * Multiple NcCheckboxRadioSwitch type checkbox representing a one config value (saved as JSON object) + * + * @since 29.0.0 + */ + public const MULTI_CHECKBOX = 'multi-checkbox'; + + /** + * NcCheckboxRadioSwitch type radio + * + * @since 29.0.0 + */ + public const RADIO = 'radio'; + + /** + * NcSelect + * + * @since 29.0.0 + */ + public const SELECT = 'select'; + + /** + * Multiple NcSelect representing a one config value (saved as JSON array) + * + * @since 29.0.0 + */ + public const MULTI_SELECT = 'multi-select'; +} diff --git a/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php b/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php new file mode 100644 index 00000000000..925bf9fe711 --- /dev/null +++ b/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php @@ -0,0 +1,105 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com> + * + * @author Kate Döen <kate.doeen@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Settings\Events; + +use Exception; +use OCP\EventDispatcher\Event; +use OCP\IUser; +use OCP\Settings\IDeclarativeSettingsForm; + +/** + * @psalm-import-type DeclarativeSettingsValueTypes from IDeclarativeSettingsForm + * + * @since 29.0.0 + */ +class DeclarativeSettingsGetValueEvent extends Event { + /** + * @var ?DeclarativeSettingsValueTypes + */ + private mixed $value = null; + + /** + * @since 29.0.0 + */ + public function __construct( + private IUser $user, + private string $app, + private string $formId, + private string $fieldId, + ) { + parent::__construct(); + } + + /** + * @since 29.0.0 + */ + public function getUser(): IUser { + return $this->user; + } + + /** + * @since 29.0.0 + */ + public function getApp(): string { + return $this->app; + } + + /** + * @since 29.0.0 + */ + public function getFormId(): string { + return $this->formId; + } + + /** + * @since 29.0.0 + */ + public function getFieldId(): string { + return $this->fieldId; + } + + /** + * @since 29.0.0 + */ + public function setValue(mixed $value): void { + $this->value = $value; + } + + /** + * @return DeclarativeSettingsValueTypes + * @throws Exception + * + * @since 29.0.0 + */ + public function getValue(): mixed { + if ($this->value === null) { + throw new Exception('Value not set'); + } + + return $this->value; + } +} diff --git a/lib/public/Dashboard/RegisterWidgetEvent.php b/lib/public/Settings/Events/DeclarativeSettingsRegisterFormEvent.php index f0bf049571a..a9ea399fc20 100644 --- a/lib/public/Dashboard/RegisterWidgetEvent.php +++ b/lib/public/Settings/Events/DeclarativeSettingsRegisterFormEvent.php @@ -3,9 +3,9 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com> * - * @author Julius Härtl <jus@bitgrid.net> + * @author Kate Döen <kate.doeen@nextcloud.com> * * @license GNU AGPL version 3 or any later version * @@ -23,39 +23,31 @@ declare(strict_types=1); * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -namespace OCP\Dashboard; + +namespace OCP\Settings\Events; use OCP\EventDispatcher\Event; +use OCP\Settings\IDeclarativeManager; +use OCP\Settings\IDeclarativeSettingsForm; /** - * Class RegisterPanelEvent - * - * This event is dispatched to allow apps supporting older Nextcloud versions to - * still register their dashboard panels so that they are only constructed when - * they are needed. Deprecated right away so we can drop it again after 19 is EOL - * and backward compatible apps can use OCP\AppFramework\Bootstrap\IBootstrap + * @psalm-import-type DeclarativeSettingsFormSchemaWithoutValues from IDeclarativeSettingsForm * - * @since 20.0.0 - * @deprecated 20.0.0 + * @since 29.0.0 */ -class RegisterWidgetEvent extends Event { - private $manager; - +class DeclarativeSettingsRegisterFormEvent extends Event { /** - * @param IManager $manager - * @since 20.0.0 + * @since 29.0.0 */ - public function __construct(IManager $manager) { + public function __construct(private IDeclarativeManager $manager) { parent::__construct(); - - $this->manager = $manager; } /** - * @param string $panelClass - * @since 20.0.0 + * @param DeclarativeSettingsFormSchemaWithoutValues $schema + * @since 29.0.0 */ - public function registerWidget(string $panelClass) { - $this->manager->lazyRegisterWidget($panelClass); + public function registerSchema(string $app, array $schema): void { + $this->manager->registerSchema($app, $schema); } } diff --git a/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php b/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php new file mode 100644 index 00000000000..f94c17681a8 --- /dev/null +++ b/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php @@ -0,0 +1,87 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com> + * + * @author Kate Döen <kate.doeen@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Settings\Events; + +use OCP\EventDispatcher\Event; +use OCP\IUser; +use OCP\Settings\IDeclarativeSettingsForm; + +/** + * @psalm-import-type DeclarativeSettingsValueTypes from IDeclarativeSettingsForm + * + * @since 29.0.0 + */ +class DeclarativeSettingsSetValueEvent extends Event { + /** + * @param DeclarativeSettingsValueTypes $value + * @since 29.0.0 + */ + public function __construct( + private IUser $user, + private string $app, + private string $formId, + private string $fieldId, + private mixed $value, + ) { + parent::__construct(); + } + + /** + * @since 29.0.0 + */ + public function getUser(): IUser { + return $this->user; + } + + /** + * @since 29.0.0 + */ + public function getApp(): string { + return $this->app; + } + + /** + * @since 29.0.0 + */ + public function getFormId(): string { + return $this->formId; + } + + /** + * @since 29.0.0 + */ + public function getFieldId(): string { + return $this->fieldId; + } + + /** + * @since 29.0.0 + */ + public function getValue(): mixed { + return $this->value; + } +} diff --git a/lib/public/Settings/IDeclarativeManager.php b/lib/public/Settings/IDeclarativeManager.php new file mode 100644 index 00000000000..ac5bef6ed26 --- /dev/null +++ b/lib/public/Settings/IDeclarativeManager.php @@ -0,0 +1,92 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com> + * + * @author Kate Döen <kate.doeen@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Settings; + +use Exception; +use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException; +use OCP\IUser; + +/** + * @since 29.0.0 + * + * @psalm-import-type DeclarativeSettingsValueTypes from IDeclarativeSettingsForm + * @psalm-import-type DeclarativeSettingsSectionType from IDeclarativeSettingsForm + * @psalm-import-type DeclarativeSettingsFormSchemaWithValues from IDeclarativeSettingsForm + * @psalm-import-type DeclarativeSettingsFormSchemaWithoutValues from IDeclarativeSettingsForm + */ +interface IDeclarativeManager { + /** + * Registers a new declarative settings schema. + * + * @param DeclarativeSettingsFormSchemaWithoutValues $schema + * @since 29.0.0 + */ + public function registerSchema(string $app, array $schema): void; + + /** + * Load all schemas from the registration context and events. + * + * @since 29.0.0 + */ + public function loadSchemas(): void; + + /** + * Gets the IDs of the forms for the given type and section. + * + * @param DeclarativeSettingsSectionType $type + * @param string $section + * @return array<string, list<string>> + * + * @since 29.0.0 + */ + public function getFormIDs(IUser $user, string $type, string $section): array; + + /** + * Gets the forms including the field values for the given type and section. + * + * @param IUser $user Used for reading values from the personal section or for authorization for the admin section. + * @param ?DeclarativeSettingsSectionType $type If it is null the forms will not be filtered by type. + * @param ?string $section If it is null the forms will not be filtered by section. + * @return list<DeclarativeSettingsFormSchemaWithValues> + * + * @since 29.0.0 + */ + public function getFormsWithValues(IUser $user, ?string $type, ?string $section): array; + + /** + * Sets a value for the given field ID. + * + * @param IUser $user Used for storing values in the personal section or for authorization for the admin section. + * @param DeclarativeSettingsValueTypes $value + * + * @throws Exception + * @throws NotAdminException + * + * @since 29.0.0 + */ + public function setValue(IUser $user, string $app, string $formId, string $fieldId, mixed $value): void; +} diff --git a/lib/public/Settings/IDeclarativeSettingsForm.php b/lib/public/Settings/IDeclarativeSettingsForm.php new file mode 100644 index 00000000000..7513af8217c --- /dev/null +++ b/lib/public/Settings/IDeclarativeSettingsForm.php @@ -0,0 +1,81 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com> + * + * @author Kate Döen <kate.doeen@nextcloud.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Settings; + +/** + * @since 29.0.0 + * + * @psalm-type DeclarativeSettingsSectionType = 'admin'|'personal' + * + * @psalm-type DeclarativeSettingsStorageType = 'internal'|'external' + * + * @psalm-type DeclarativeSettingsValueTypes = string|int|float|bool|list<string> + * + * @psalm-type DeclarativeSettingsFormField = array{ + * id: string, + * title: string, + * description?: string, + * type: 'text'|'password'|'email'|'tel'|'url'|'number'|'checkbox'|'multi-checkbox'|'radio'|'select'|'multi-select', + * placeholder?: string, + * label?: string, + * default: mixed, + * options?: list<string|array{name: string, value: mixed}>, + * } + * + * @psalm-type DeclarativeSettingsFormFieldWithValue = DeclarativeSettingsFormField&array{ + * value: DeclarativeSettingsValueTypes, + * } + * + * @psalm-type DeclarativeSettingsFormSchema = array{ + * id: string, + * priority: int, + * section_type: DeclarativeSettingsSectionType, + * section_id: string, + * storage_type: DeclarativeSettingsStorageType, + * title: string, + * description?: string, + * doc_url?: string, + * } + * + * @psalm-type DeclarativeSettingsFormSchemaWithValues = DeclarativeSettingsFormSchema&array{ + * app: string, + * fields: list<DeclarativeSettingsFormFieldWithValue>, + * } + * + * @psalm-type DeclarativeSettingsFormSchemaWithoutValues = DeclarativeSettingsFormSchema&array{ + * fields: list<DeclarativeSettingsFormField>, + * } + */ +interface IDeclarativeSettingsForm { + /** + * Gets the schema that defines the declarative settings form + * + * @return DeclarativeSettingsFormSchemaWithoutValues + * @since 29.0.0 + */ + public function getSchema(): array; +} diff --git a/lib/public/Settings/IManager.php b/lib/public/Settings/IManager.php index 10de596dbea..dbbbf3f57e4 100644 --- a/lib/public/Settings/IManager.php +++ b/lib/public/Settings/IManager.php @@ -6,6 +6,7 @@ * @author Christoph Wurst <christoph@winzerhof-wurst.at> * @author Joas Schilling <coding@schilljs.com> * @author Lukas Reschke <lukas@statuscode.ch> + * @author Kate Döen <kate.doeen@nextcloud.com> * * @license GNU AGPL version 3 or any later version * @@ -34,34 +35,48 @@ use OCP\IUser; interface IManager { /** * @since 9.1.0 + * @deprecated 29.0.0 Use {@see self::SETTINGS_ADMIN} instead */ public const KEY_ADMIN_SETTINGS = 'admin'; /** * @since 9.1.0 + * @deprecated 29.0.0 Use {@see self::SETTINGS_ADMIN} instead */ public const KEY_ADMIN_SECTION = 'admin-section'; /** * @since 13.0.0 + * @deprecated 29.0.0 Use {@see self::SETTINGS_PERSONAL} instead */ public const KEY_PERSONAL_SETTINGS = 'personal'; /** * @since 13.0.0 + * @deprecated 29.0.0 Use {@see self::SETTINGS_PERSONAL} instead */ public const KEY_PERSONAL_SECTION = 'personal-section'; /** - * @param string $type 'admin-section' or 'personal-section' - * @param string $section Class must implement OCP\Settings\ISection + * @since 29.0.0 + */ + public const SETTINGS_ADMIN = 'admin'; + + /** + * @since 29.0.0 + */ + public const SETTINGS_PERSONAL = 'personal'; + + /** + * @psalm-param self::SETTINGS_* $type + * @param class-string<IIconSection> $section * @since 14.0.0 */ public function registerSection(string $type, string $section); /** - * @param string $type 'admin' or 'personal' - * @param string $setting Class must implement OCP\Settings\ISettings + * @psalm-param self::SETTINGS_* $type + * @param class-string<ISettings> $setting * @since 14.0.0 */ public function registerSetting(string $type, string $setting); @@ -69,7 +84,7 @@ interface IManager { /** * returns a list of the admin sections * - * @return array<int, array<int, IIconSection>> array from IConSection[] where key is the priority + * @return array<int, list<IIconSection>> list of sections with priority as key * @since 9.1.0 */ public function getAdminSections(): array; @@ -77,7 +92,7 @@ interface IManager { /** * returns a list of the personal sections * - * @return array array of ISection[] where key is the priority + * @return array<int, list<IIconSection>> list of sections with priority as key * @since 13.0.0 */ public function getPersonalSections(): array; @@ -87,10 +102,10 @@ interface IManager { * * @param string $section the section id for which to load the settings * @param bool $subAdminOnly only return settings sub admins are supposed to see (since 17.0.0) - * @return array<int, array<int, ISettings>> array of ISettings[] where key is the priority + * @return array<int, list<ISettings>> list of settings with priority as key * @since 9.1.0 */ - public function getAdminSettings($section, bool $subAdminOnly = false): array; + public function getAdminSettings(string $section, bool $subAdminOnly = false): array; /** * Returns a list of admin settings that the given user can use for the give section @@ -103,7 +118,7 @@ interface IManager { /** * Returns a list of admin settings that the given user can use. * - * @return array<int, list<ISettings>> The array of admin settings there admin delegation is allowed. + * @return list<ISettings> The array of admin settings there admin delegation is allowed. * @since 23.0.0 */ public function getAllAllowedAdminSettings(IUser $user): array; @@ -112,13 +127,14 @@ interface IManager { * returns a list of the personal settings * * @param string $section the section id for which to load the settings - * @return array array of ISettings[] where key is the priority + * @return array<int, list<ISettings>> list of settings with priority as key * @since 13.0.0 */ - public function getPersonalSettings($section): array; + public function getPersonalSettings(string $section): array; /** * Get a specific section by type and id + * @psalm-param self::SETTINGS_* $type * @since 25.0.0 */ public function getSection(string $type, string $sectionId): ?IIconSection; diff --git a/lib/public/SetupCheck/ISetupCheck.php b/lib/public/SetupCheck/ISetupCheck.php new file mode 100644 index 00000000000..96eb6ddd7da --- /dev/null +++ b/lib/public/SetupCheck/ISetupCheck.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2022 Carl Schwan <carl@carlschwan.eu> + * + * @author Carl Schwan <carl@carlschwan.eu> + * @author Côme Chilliet <come.chilliet@nextcloud.com> + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\SetupCheck; + +/** + * This interface needs to be implemented if you want to provide custom + * setup checks in your application. The results of these checks will them + * be displayed in the admin overview. + * + * @since 28.0.0 + */ +interface ISetupCheck { + /** + * @since 28.0.0 + * @return string Category id, one of security/system/accounts, or a custom one which will be merged in system + */ + public function getCategory(): string; + + /** + * @since 28.0.0 + * @return string Translated name to display to the user + */ + public function getName(): string; + + /** + * @since 28.0.0 + */ + public function run(): SetupResult; +} diff --git a/lib/private/Metadata/Capabilities.php b/lib/public/SetupCheck/ISetupCheckManager.php index 2fa0006f581..4b963e7c6b8 100644 --- a/lib/private/Metadata/Capabilities.php +++ b/lib/public/SetupCheck/ISetupCheckManager.php @@ -3,8 +3,11 @@ declare(strict_types=1); /** - * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu> - * @license AGPL-3.0-or-later + * @copyright Copyright (c) 2023 Côme Chilliet <come.chilliet@nextcloud.com> + * + * @author Côme Chilliet <come.chilliet@nextcloud.com> + * + * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, @@ -20,25 +23,15 @@ declare(strict_types=1); * */ -namespace OC\Metadata; - -use OCP\Capabilities\IPublicCapability; -use OCP\IConfig; - -class Capabilities implements IPublicCapability { - private IMetadataManager $manager; - private IConfig $config; +namespace OCP\SetupCheck; - public function __construct(IMetadataManager $manager, IConfig $config) { - $this->manager = $manager; - $this->config = $config; - } - - public function getCapabilities() { - if ($this->config->getSystemValueBool('enable_file_metadata', true)) { - return ['metadataAvailable' => $this->manager->getCapabilities()]; - } - - return []; - } +/** + * @since 28.0.0 + */ +interface ISetupCheckManager { + /** + * @since 28.0.0 + * @return array<string,array<string,SetupResult>> Result of each check, first level key is category, second level key is title + */ + public function runAll(): array; } diff --git a/lib/public/SetupCheck/SetupResult.php b/lib/public/SetupCheck/SetupResult.php new file mode 100644 index 00000000000..7ae4cfcba24 --- /dev/null +++ b/lib/public/SetupCheck/SetupResult.php @@ -0,0 +1,204 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2022 Carl Schwan <carl@carlschwan.eu> + * + * @author Carl Schwan <carl@carlschwan.eu> + * @author Côme Chilliet <come.chilliet@nextcloud.com> + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\SetupCheck; + +use OCP\RichObjectStrings\IValidator; + +/** + * @brief This class is used for storing the result of a setup check + * + * @since 28.0.0 + */ +class SetupResult implements \JsonSerializable { + /** + * @since 28.0.0 + */ + public const SUCCESS = 'success'; + + /** + * @since 28.0.0 + */ + public const INFO = 'info'; + + /** + * @since 28.0.0 + */ + public const WARNING = 'warning'; + + /** + * @since 28.0.0 + */ + public const ERROR = 'error'; + + /** + * @param string $name Translated name to display to the user + */ + private ?string $name = null; + + /** + * @brief Private constructor, use success()/info()/warning()/error() instead + * @param self::SUCCESS|self::INFO|self::WARNING|self::ERROR $severity + * @throws \OCP\RichObjectStrings\InvalidObjectExeption + * @since 28.0.0 + * @since 28.0.2 Optional parameter ?array $descriptionParameters + * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption + */ + private function __construct( + private string $severity, + private ?string $description = null, + private ?array $descriptionParameters = null, + private ?string $linkToDoc = null, + ) { + if ($description !== null && $descriptionParameters !== null) { + \OCP\Server::get(IValidator::class)->validate($description, $descriptionParameters); + } + } + + /** + * @brief Create a success result object + * @param ?string $description Translated detailed description to display to the user + * @param ?string $linkToDoc URI of related relevent documentation, be it from Nextcloud or another project + * @throws \OCP\RichObjectStrings\InvalidObjectExeption + * @since 28.0.0 + * @since 28.0.2 Optional parameter ?array $descriptionParameters + * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption + */ + public static function success(?string $description = null, ?string $linkToDoc = null, ?array $descriptionParameters = null): self { + return new self(self::SUCCESS, $description, $descriptionParameters, $linkToDoc); + } + + /** + * @brief Create an info result object + * @param ?string $description Translated detailed description to display to the user + * @param ?string $linkToDoc URI of related relevent documentation, be it from Nextcloud or another project + * @throws \OCP\RichObjectStrings\InvalidObjectExeption + * @since 28.0.0 + * @since 28.0.2 Optional parameter ?array $descriptionParameters + * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption + */ + public static function info(?string $description = null, ?string $linkToDoc = null, ?array $descriptionParameters = null): self { + return new self(self::INFO, $description, $descriptionParameters, $linkToDoc); + } + + /** + * @brief Create a warning result object + * @param ?string $description Translated detailed description to display to the user + * @param ?string $linkToDoc URI of related relevent documentation, be it from Nextcloud or another project + * @throws \OCP\RichObjectStrings\InvalidObjectExeption + * @since 28.0.0 + * @since 28.0.2 Optional parameter ?array $descriptionParameters + * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption + */ + public static function warning(?string $description = null, ?string $linkToDoc = null, ?array $descriptionParameters = null): self { + return new self(self::WARNING, $description, $descriptionParameters, $linkToDoc); + } + + /** + * @brief Create an error result object + * @param ?string $description Translated detailed description to display to the user + * @param ?string $linkToDoc URI of related relevent documentation, be it from Nextcloud or another project + * @throws \OCP\RichObjectStrings\InvalidObjectExeption + * @since 28.0.0 + * @since 28.0.2 Optional parameter ?array $descriptionParameters + * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption + */ + public static function error(?string $description = null, ?string $linkToDoc = null, ?array $descriptionParameters = null): self { + return new self(self::ERROR, $description, $descriptionParameters, $linkToDoc); + } + + /** + * @brief Get the severity for the setup check result + * + * @return self::SUCCESS|self::INFO|self::WARNING|self::ERROR + * @since 28.0.0 + */ + public function getSeverity(): string { + return $this->severity; + } + + /** + * @brief Get the description for the setup check result + * + * @since 28.0.0 + */ + public function getDescription(): ?string { + return $this->description; + } + + /** + * @brief Get the description parameters for the setup check result + * + * If this returns null, description must not be treated as rich text + * + * @since 28.0.2 + */ + public function getDescriptionParameters(): ?array { + return $this->descriptionParameters; + } + + /** + * @brief Get the name for the setup check + * + * @since 28.0.0 + */ + public function getName(): ?string { + return $this->name; + } + + /** + * @brief Set the name from the setup check + * + * @since 28.0.0 + */ + public function setName(string $name): void { + $this->name = $name; + } + + /** + * @brief Get a link to the doc for the explanation. + * + * @since 28.0.0 + */ + public function getLinkToDoc(): ?string { + return $this->linkToDoc; + } + + /** + * @brief Get an array representation of the result for API responses + * + * @since 28.0.0 + */ + public function jsonSerialize(): array { + return [ + 'name' => $this->name, + 'severity' => $this->severity, + 'description' => $this->description, + 'descriptionParameters' => $this->descriptionParameters, + 'linkToDoc' => $this->linkToDoc, + ]; + } +} diff --git a/lib/public/Share.php b/lib/public/Share.php index 9499cdb14b6..2004f77cf0a 100644 --- a/lib/public/Share.php +++ b/lib/public/Share.php @@ -33,8 +33,7 @@ namespace OCP; /** - * This class provides the ability for apps to share their content between users. - * Apps must create a backend class that implements OCP\Share_Backend and register it with this class. + * This class remains only for use with the ::class namespace used for various hooks * * It provides the following hooks: * - post_shared @@ -42,95 +41,4 @@ namespace OCP; * @deprecated 17.0.0 */ class Share extends \OC\Share\Constants { - /** - * Get the item of item type shared with a given user by source - * @param string $itemType - * @param string $itemSource - * @param string $user User to whom the item was shared - * @param string $owner Owner of the share - * @return array Return list of items with file_target, permissions and expiration - * @since 6.0.0 - parameter $owner was added in 8.0.0 - * @deprecated 17.0.0 - */ - public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null) { - return \OC\Share\Share::getItemSharedWithUser($itemType, $itemSource, $user, $owner); - } - - /** - * Get the item of item type shared with the current user by source - * @param string $itemType - * @param string $itemSource - * @param int $format (optional) Format type must be defined by the backend - * @param mixed $parameters - * @param bool $includeCollections - * @return void - * @since 5.0.0 - * @deprecated 17.0.0 - */ - public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE, - $parameters = null, $includeCollections = false) { - // not used by any app - only here to not break apps syntax - } - - /** - * Based on the given token the share information will be returned - password protected shares will be verified - * @param string $token - * @param bool $checkPasswordProtection - * @return void - * @since 5.0.0 - parameter $checkPasswordProtection was added in 7.0.0 - * @deprecated 17.0.0 - */ - public static function getShareByToken($token, $checkPasswordProtection = true) { - // not used by any app - only here to not break apps syntax - } - - - /** - * Get the shared items of item type owned by the current user - * @param string $itemType - * @param int $format (optional) Format type must be defined by the backend - * @param mixed $parameters - * @param int $limit Number of items to return (optional) Returns all by default - * @param bool $includeCollections - * @return void - * @since 5.0.0 - * @deprecated 17.0.0 - */ - public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null, - $limit = -1, $includeCollections = false) { - // only used by AppVNCSafe app (https://github.com/vnc-biz/nextcloud-appvncsafe/issues/2) - only here to not break apps syntax - } - - /** - * Get the shared item of item type owned by the current user - * @param string $itemType - * @param string $itemSource - * @param int $format (optional) Format type must be defined by the backend - * @param mixed $parameters - * @param bool $includeCollections - * @return mixed Return depends on format - * @since 5.0.0 - * @deprecated 17.0.0 - * - * Refactoring notes: - * * defacto $parameters and $format is always the default and therefore is removed in the subsequent call - */ - public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE, - $parameters = null, $includeCollections = false) { - return \OC\Share\Share::getItemShared($itemType, $itemSource, self::FORMAT_NONE, null, $includeCollections); - } - - /** - * sent status if users got informed by mail about share - * @param string $itemType - * @param string $itemSource - * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK - * @param string $recipient with whom was the item shared - * @param bool $status - * @since 6.0.0 - parameter $originIsSource was added in 8.0.0 - * @deprecated 17.0.0 - */ - public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) { - // not used by any app - only here to not break apps syntax - } } diff --git a/lib/public/Share/Events/VerifyMountPointEvent.php b/lib/public/Share/Events/VerifyMountPointEvent.php index 650f4ad2245..af71314930b 100644 --- a/lib/public/Share/Events/VerifyMountPointEvent.php +++ b/lib/public/Share/Events/VerifyMountPointEvent.php @@ -44,8 +44,8 @@ class VerifyMountPointEvent extends Event { * @since 19.0.0 */ public function __construct(IShare $share, - View $view, - string $parent) { + View $view, + string $parent) { parent::__construct(); $this->share = $share; diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php index 9ac224ed7ef..07517dd7eb5 100644 --- a/lib/public/Share/IManager.php +++ b/lib/public/Share/IManager.php @@ -416,6 +416,15 @@ interface IManager { public function shareWithGroupMembersOnly(); /** + * If shareWithGroupMembersOnly is enabled, return an optional + * list of groups that must be excluded from the principle of + * belonging to the same group. + * @return array + * @since 27.0.0 + */ + public function shareWithGroupMembersOnlyExcludeGroupsList(); + + /** * Check if users can share with groups * @return bool * @since 9.0.1 diff --git a/lib/public/Share/IShare.php b/lib/public/Share/IShare.php index 40548c6c73d..a059696a75e 100644 --- a/lib/public/Share/IShare.php +++ b/lib/public/Share/IShare.php @@ -213,7 +213,7 @@ interface IShare { * @since 9.0.0 * @throws NotFoundException */ - public function getNodeId(); + public function getNodeId(): int; /** * Set the type of node (file/folder) @@ -394,7 +394,7 @@ interface IShare { /** * Get the expiration date * - * @return \DateTime + * @return null|\DateTime * @since 9.0.0 */ public function getExpirationDate(); @@ -474,7 +474,7 @@ interface IShare { * If this share is obtained via a shareprovider the password is * hashed. * - * @return string + * @return string|null * @since 9.0.0 */ public function getPassword(); diff --git a/lib/public/Share/IShareProvider.php b/lib/public/Share/IShareProvider.php index b6e0c4ba38b..2a37508d449 100644 --- a/lib/public/Share/IShareProvider.php +++ b/lib/public/Share/IShareProvider.php @@ -70,7 +70,7 @@ interface IShareProvider { * @return IShare The share object * @since 17.0.0 */ -// public function acceptShare(IShare $share, string $recipient): IShare; + // public function acceptShare(IShare $share, string $recipient): IShare; /** * Delete a share diff --git a/lib/public/SpeechToText/ISpeechToTextProviderWithId.php b/lib/public/SpeechToText/ISpeechToTextProviderWithId.php new file mode 100644 index 00000000000..0fb337f4602 --- /dev/null +++ b/lib/public/SpeechToText/ISpeechToTextProviderWithId.php @@ -0,0 +1,14 @@ +<?php + +namespace OCP\SpeechToText; + +/** + * @since 28.0.0 + */ +interface ISpeechToTextProviderWithId extends ISpeechToTextProvider { + + /** + * @since 28.0.0 + */ + public function getId(): string; +} diff --git a/lib/public/SpeechToText/ISpeechToTextProviderWithUserId.php b/lib/public/SpeechToText/ISpeechToTextProviderWithUserId.php new file mode 100644 index 00000000000..2a9b667171d --- /dev/null +++ b/lib/public/SpeechToText/ISpeechToTextProviderWithUserId.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2024 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +namespace OCP\SpeechToText; + +/** + * @since 29.0.0 + */ +interface ISpeechToTextProviderWithUserId extends ISpeechToTextProvider { + /** + * @since 29.0.0 + */ + public function setUserId(?string $userId): void; +} diff --git a/lib/public/SystemTag/ManagerEvent.php b/lib/public/SystemTag/ManagerEvent.php index 704aecd4536..48bd651f7a3 100644 --- a/lib/public/SystemTag/ManagerEvent.php +++ b/lib/public/SystemTag/ManagerEvent.php @@ -37,16 +37,19 @@ use OCP\EventDispatcher\Event; */ class ManagerEvent extends Event { /** + * @since 9.0.0 * @deprecated 22.0.0 */ public const EVENT_CREATE = 'OCP\SystemTag\ISystemTagManager::createTag'; /** + * @since 9.0.0 * @deprecated 22.0.0 */ public const EVENT_UPDATE = 'OCP\SystemTag\ISystemTagManager::updateTag'; /** + * @since 9.0.0 * @deprecated 22.0.0 */ public const EVENT_DELETE = 'OCP\SystemTag\ISystemTagManager::deleteTag'; diff --git a/lib/public/SystemTag/MapperEvent.php b/lib/public/SystemTag/MapperEvent.php index 6aa0ea77000..cbd1b2ff2db 100644 --- a/lib/public/SystemTag/MapperEvent.php +++ b/lib/public/SystemTag/MapperEvent.php @@ -36,11 +36,13 @@ use OCP\EventDispatcher\Event; */ class MapperEvent extends Event { /** + * @since 9.0.0 * @deprecated 22.0.0 */ public const EVENT_ASSIGN = 'OCP\SystemTag\ISystemTagObjectMapper::assignTags'; /** + * @since 9.0.0 * @deprecated 22.0.0 */ public const EVENT_UNASSIGN = 'OCP\SystemTag\ISystemTagObjectMapper::unassignTags'; diff --git a/lib/public/SystemTag/SystemTagsEntityEvent.php b/lib/public/SystemTag/SystemTagsEntityEvent.php index 0ce679a3a43..252029e6ba2 100644 --- a/lib/public/SystemTag/SystemTagsEntityEvent.php +++ b/lib/public/SystemTag/SystemTagsEntityEvent.php @@ -37,6 +37,7 @@ use OCP\EventDispatcher\Event; */ class SystemTagsEntityEvent extends Event { /** + * @since 9.1.0 * @deprecated 22.0.0 Listen to the typed event instead */ public const EVENT_ENTITY = 'OCP\SystemTag\ISystemTagManager::registerEntity'; diff --git a/lib/public/Talk/IBroker.php b/lib/public/Talk/IBroker.php index d3b6e1429e6..f2b512ea4a8 100644 --- a/lib/public/Talk/IBroker.php +++ b/lib/public/Talk/IBroker.php @@ -68,8 +68,8 @@ interface IBroker { * @since 24.0.0 */ public function createConversation(string $name, - array $moderators, - IConversationOptions $options = null): IConversation; + array $moderators, + IConversationOptions $options = null): IConversation; /** * Delete a conversation by id diff --git a/lib/public/Talk/ITalkBackend.php b/lib/public/Talk/ITalkBackend.php index 3ee995576a4..a2f4d962019 100644 --- a/lib/public/Talk/ITalkBackend.php +++ b/lib/public/Talk/ITalkBackend.php @@ -46,8 +46,8 @@ interface ITalkBackend { * @since 24.0.0 */ public function createConversation(string $name, - array $moderators, - IConversationOptions $options): IConversation; + array $moderators, + IConversationOptions $options): IConversation; /** * Delete a conversation by id diff --git a/lib/public/Teams/ITeamManager.php b/lib/public/Teams/ITeamManager.php new file mode 100644 index 00000000000..51d8a1feb5a --- /dev/null +++ b/lib/public/Teams/ITeamManager.php @@ -0,0 +1,58 @@ +<?php +/** + * @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\Teams; + +/** + * @since 29.0.0 + */ +interface ITeamManager { + /** + * Get all providers that have registered as a team resource provider + * + * @return ITeamResourceProvider[] + * @since 29.0.0 + */ + public function getProviders(): array; + + /** + * Get a specific team resource provider by its id + * + * @since 29.0.0 + */ + public function getProvider(string $providerId): ITeamResourceProvider; + + /** + * Returns all team resources for a given team and user + * + * @return TeamResource[] + * @since 29.0.0 + */ + public function getSharedWith(string $teamId, string $userId): array; + + /** + * Returns all teams for a given resource and user + * + * @since 29.0.0 + */ + public function getTeamsForResource(string $providerId, string $resourceId, string $userId): array; +} diff --git a/lib/public/Teams/ITeamResourceProvider.php b/lib/public/Teams/ITeamResourceProvider.php new file mode 100644 index 00000000000..722c877555e --- /dev/null +++ b/lib/public/Teams/ITeamResourceProvider.php @@ -0,0 +1,76 @@ +<?php +/** + * @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\Teams; + +/** + * Implement a provider of resources that are shared or owned by a team + * + * @since 29.0.0 + */ +interface ITeamResourceProvider { + + /** + * Unique identifier used to identify the provider (app id) + * + * @since 29.0.0 + */ + public function getId(): string; + + /** + * User visible name of the provider (app name) + * + * @since 29.0.0 + */ + public function getName(): string; + + /** + * Svg icon to show next to the provider (app icon) + * + * @since 29.0.0 + */ + public function getIconSvg(): string; + + /** + * Return all resources that are shared to the given team id for the current provider + * + * @param string $teamId + * @return TeamResource[] + * @since 29.0.0 + */ + public function getSharedWith(string $teamId): array; + + /** + * Check if a resource is shared with the given team + * + * @since 29.0.0 + */ + public function isSharedWithTeam(string $teamId, string $resourceId): bool; + + /** + * Return team ids that a resource is shared with or owned by + * + * @return string[] + * @since 29.0.0 + */ + public function getTeamsForResource(string $resourceId): array; +} diff --git a/lib/public/Teams/Team.php b/lib/public/Teams/Team.php new file mode 100644 index 00000000000..d3d6c2d143d --- /dev/null +++ b/lib/public/Teams/Team.php @@ -0,0 +1,73 @@ +<?php +/** + * @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\Teams; + +/** + * Simple abstraction to represent a team in the public API + * + * In the backend a team is a circle identified by the circles singleId + * + * @since 29.0.0 + */ +class Team implements \JsonSerializable { + + /** + * @since 29.0.0 + */ + public function __construct(private string $teamId, private string $displayName, private ?string $link) { + } + + /** + * Unique identifier of the team (singleId of the circle) + * + * @since 29.0.0 + */ + public function getId(): string { + return $this->teamId; + } + + /** + * @since 29.0.0 + */ + public function getDisplayName(): string { + return $this->displayName; + } + + /** + * @since 29.0.0 + */ + public function getLink(): ?string { + return $this->link; + } + + /** + * @since 29.0.0 + */ + public function jsonSerialize(): array { + return [ + 'teamId' => $this->teamId, + 'displayName' => $this->displayName, + 'link' => $this->link, + ]; + } +} diff --git a/lib/public/Teams/TeamResource.php b/lib/public/Teams/TeamResource.php new file mode 100644 index 00000000000..569583bb393 --- /dev/null +++ b/lib/public/Teams/TeamResource.php @@ -0,0 +1,129 @@ +<?php +/** + * @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\Teams; + +/** + * @since 29.0.0 + */ +class TeamResource implements \JsonSerializable { + /** + * @since 29.0.0 + */ + public function __construct( + private ITeamResourceProvider $teamResourceProvider, + private string $resourceId, + private string $label, + private string $url, + private ?string $iconSvg = null, + private ?string $iconURL = null, + private ?string $iconEmoji = null, + ) { + } + + /** + * Returns the provider details for the current resource + * + * @since 29.0.0 + */ + public function getProvider(): ITeamResourceProvider { + return $this->teamResourceProvider; + } + + /** + * Unique id of the resource (e.g. primary key id) + * @since 29.0.0 + */ + public function getId(): string { + return $this->resourceId; + } + + /** + * User visible label when listing resources + * + * @since 29.0.0 + */ + public function getLabel(): string { + return $this->label; + } + + /** + * Absolute url to navigate the user to the resource + * + * @since 29.0.0 + */ + public function getUrl(): string { + return $this->url; + } + + /** + * Svg icon to show next to the name for the resource + * + * From all icons the first one returning not null will be picked in order: iconEmoji, iconSvg, iconUrl + * + * @since 29.0.0 + */ + public function getIconSvg(): ?string { + return $this->iconSvg; + } + + /** + * Image url of the icon to show next to the name for the resource + * + * From all icons the first one returning not null will be picked in order: iconEmoji, iconSvg, iconUrl + * + * @since 29.0.0 + */ + public function getIconURL(): ?string { + return $this->iconURL; + } + + /** + * Emoji show next to the name for the resource + * + * From all icons the first one returning not null will be picked in order: iconEmoji, iconSvg, iconUrl + * + * @since 29.0.0 + */ + public function getIconEmoji(): ?string { + return $this->iconEmoji; + } + + /** + * @since 29.0.0 + */ + public function jsonSerialize(): array { + return [ + 'id' => $this->resourceId, + 'label' => $this->label, + 'url' => $this->url, + 'iconSvg' => $this->iconSvg, + 'iconURL' => $this->iconURL, + 'iconEmoji' => $this->iconEmoji, + 'provider' => [ + 'id' => $this->teamResourceProvider->getId(), + 'name' => $this->teamResourceProvider->getName(), + 'icon' => $this->teamResourceProvider->getIconSvg(), + ] + ]; + } +} diff --git a/lib/public/TextProcessing/Exception/TaskFailureException.php b/lib/public/TextProcessing/Exception/TaskFailureException.php new file mode 100644 index 00000000000..300864711e7 --- /dev/null +++ b/lib/public/TextProcessing/Exception/TaskFailureException.php @@ -0,0 +1,10 @@ +<?php + +namespace OCP\TextProcessing\Exception; + +/** + * Exception thrown when a task failed + * @since 28.0.0 + */ +class TaskFailureException extends \RuntimeException { +} diff --git a/lib/public/TextProcessing/IManager.php b/lib/public/TextProcessing/IManager.php index dec0baba4bb..2f517a4ebe2 100644 --- a/lib/public/TextProcessing/IManager.php +++ b/lib/public/TextProcessing/IManager.php @@ -27,7 +27,9 @@ declare(strict_types=1); namespace OCP\TextProcessing; use OCP\Common\Exception\NotFoundException; +use OCP\DB\Exception; use OCP\PreConditionNotMetException; +use OCP\TextProcessing\Exception\TaskFailureException; use RuntimeException; /** @@ -48,7 +50,7 @@ interface IManager { public function getProviders(): array; /** - * @return class-string<ITaskType>[] + * @return string[] * @since 27.1.0 */ public function getAvailableTaskTypes(): array; @@ -56,7 +58,7 @@ interface IManager { /** * @param Task $task The task to run * @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called - * @throws RuntimeException If something else failed + * @throws TaskFailureException If running the task failed * @since 27.1.0 */ public function runTask(Task $task): string; @@ -68,11 +70,26 @@ interface IManager { * * @param Task $task The task to schedule * @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called + * @throws Exception storing the task in the database failed * @since 27.1.0 */ public function scheduleTask(Task $task) : void; /** + * If the designated provider for the passed task provides an expected average runtime, we check if the runtime fits into the + * max execution time of this php process and run it synchronously if it does, if it doesn't fit (or the provider doesn't provide that information) + * execution is deferred to a background job + * + * @param Task $task The task to schedule + * @returns bool A boolean indicating whether the task was run synchronously (`true`) or offloaded to a background job (`false`) + * @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called + * @throws TaskFailureException If running the task failed + * @throws Exception storing the task in the database failed + * @since 28.0.0 + */ + public function runOrScheduleTask(Task $task): bool; + + /** * Delete a task that has been scheduled before * * @param Task $task The task to delete diff --git a/lib/public/TextProcessing/IProvider.php b/lib/public/TextProcessing/IProvider.php index 6132e60b493..fc57add1835 100644 --- a/lib/public/TextProcessing/IProvider.php +++ b/lib/public/TextProcessing/IProvider.php @@ -31,7 +31,7 @@ use RuntimeException; /** * This is the interface that is implemented by apps that * implement a text processing provider - * @template T of ITaskType + * @psalm-template-covariant T of ITaskType * @since 27.1.0 */ interface IProvider { diff --git a/lib/public/TextProcessing/IProviderWithExpectedRuntime.php b/lib/public/TextProcessing/IProviderWithExpectedRuntime.php new file mode 100644 index 00000000000..17767fc02d4 --- /dev/null +++ b/lib/public/TextProcessing/IProviderWithExpectedRuntime.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +namespace OCP\TextProcessing; + +/** + * This interface allows the system to learn the provider's expected runtime + * @since 28.0.0 + * @template T of ITaskType + * @template-extends IProvider<T> + */ +interface IProviderWithExpectedRuntime extends IProvider { + /** + * @return int The expected average runtime of a task in seconds + * @since 28.0.0 + */ + public function getExpectedRuntime(): int; +} diff --git a/lib/public/TextProcessing/IProviderWithId.php b/lib/public/TextProcessing/IProviderWithId.php new file mode 100644 index 00000000000..1bd02278d1c --- /dev/null +++ b/lib/public/TextProcessing/IProviderWithId.php @@ -0,0 +1,39 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\TextProcessing; + +/** + * @since 28.0.0 + * @extends IProvider<T> + * @template T of ITaskType + */ +interface IProviderWithId extends IProvider { + /** + * The id of this provider + * @since 28.0.0 + */ + public function getId(): string; +} diff --git a/lib/public/TextProcessing/IProviderWithUserId.php b/lib/public/TextProcessing/IProviderWithUserId.php new file mode 100644 index 00000000000..0a01a4c56c4 --- /dev/null +++ b/lib/public/TextProcessing/IProviderWithUserId.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +namespace OCP\TextProcessing; + +/** + * This interface allows providers to access the user that initiated the task being run. + * @since 28.0.0 + * @template T of ITaskType + * @template-extends IProvider<T> + */ +interface IProviderWithUserId extends IProvider { + /** + * @param ?string $userId the current user's id + * @since 28.0.0 + */ + public function setUserId(?string $userId): void; +} diff --git a/lib/public/TextProcessing/Task.php b/lib/public/TextProcessing/Task.php index 446e414cb04..c62b7b2fff8 100644 --- a/lib/public/TextProcessing/Task.php +++ b/lib/public/TextProcessing/Task.php @@ -28,13 +28,12 @@ namespace OCP\TextProcessing; /** * This is a text processing task * @since 27.1.0 - * @psalm-template T of ITaskType - * @psalm-template S as class-string<T> - * @psalm-template P as IProvider<T> + * @psalm-template-covariant T of ITaskType */ final class Task implements \JsonSerializable { protected ?int $id = null; protected ?string $output = null; + private ?\DateTime $completionExpectedAt = null; /** * @since 27.1.0 @@ -73,7 +72,7 @@ final class Task implements \JsonSerializable { protected int $status = self::STATUS_UNKNOWN; /** - * @psalm-param S $type + * @psalm-param class-string<T> $type * @param string $type * @param string $input * @param string $appId @@ -91,13 +90,16 @@ final class Task implements \JsonSerializable { } /** - * @psalm-param P $provider + * @psalm-param IProvider<T> $provider * @param IProvider $provider * @return string * @since 27.1.0 */ public function visitProvider(IProvider $provider): string { if ($this->canUseProvider($provider)) { + if ($provider instanceof IProviderWithUserId) { + $provider->setUserId($this->getUserId()); + } return $provider->process($this->getInput()); } else { throw new \RuntimeException('Task of type ' . $this->getType() . ' cannot visit provider with task type ' . $provider->getTaskType()); @@ -105,7 +107,7 @@ final class Task implements \JsonSerializable { } /** - * @psalm-param P $provider + * @psalm-param IProvider<T> $provider * @param IProvider $provider * @return bool * @since 27.1.0 @@ -115,7 +117,7 @@ final class Task implements \JsonSerializable { } /** - * @psalm-return S + * @psalm-return class-string<T> * @since 27.1.0 */ final public function getType(): string { @@ -203,7 +205,7 @@ final class Task implements \JsonSerializable { } /** - * @psalm-return array{id: ?int, type: S, status: 0|1|2|3|4, userId: ?string, appId: string, input: string, output: ?string, identifier: string} + * @psalm-return array{id: ?int, type: class-string<T>, status: 0|1|2|3|4, userId: ?string, appId: string, input: string, output: ?string, identifier: string, completionExpectedAt: ?int} * @since 27.1.0 */ public function jsonSerialize(): array { @@ -216,6 +218,24 @@ final class Task implements \JsonSerializable { 'input' => $this->getInput(), 'output' => $this->getOutput(), 'identifier' => $this->getIdentifier(), + 'completionExpectedAt' => $this->getCompletionExpectedAt()?->getTimestamp(), ]; } + + /** + * @param null|\DateTime $completionExpectedAt + * @return void + * @since 28.0.0 + */ + final public function setCompletionExpectedAt(?\DateTime $completionExpectedAt): void { + $this->completionExpectedAt = $completionExpectedAt; + } + + /** + * @return \DateTime|null + * @since 28.0.0 + */ + final public function getCompletionExpectedAt(): ?\DateTime { + return $this->completionExpectedAt; + } } diff --git a/lib/public/TextToImage/Events/AbstractTextToImageEvent.php b/lib/public/TextToImage/Events/AbstractTextToImageEvent.php new file mode 100644 index 00000000000..56c68195602 --- /dev/null +++ b/lib/public/TextToImage/Events/AbstractTextToImageEvent.php @@ -0,0 +1,52 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\TextToImage\Events; + +use OCP\EventDispatcher\Event; +use OCP\TextToImage\Task; + +/** + * @since 28.0.0 + */ +abstract class AbstractTextToImageEvent extends Event { + /** + * @since 28.0.0 + */ + public function __construct( + private Task $task + ) { + parent::__construct(); + } + + /** + * @return Task + * @since 28.0.0 + */ + public function getTask(): Task { + return $this->task; + } +} diff --git a/lib/public/TextToImage/Events/TaskFailedEvent.php b/lib/public/TextToImage/Events/TaskFailedEvent.php new file mode 100644 index 00000000000..0d91b3a4f67 --- /dev/null +++ b/lib/public/TextToImage/Events/TaskFailedEvent.php @@ -0,0 +1,54 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\TextToImage\Events; + +use OCP\TextToImage\Task; + +/** + * @since 28.0.0 + */ +class TaskFailedEvent extends AbstractTextToImageEvent { + /** + * @param Task $task + * @param string $errorMessage + * @since 28.0.0 + */ + public function __construct( + Task $task, + private string $errorMessage, + ) { + parent::__construct($task); + } + + /** + * @return string + * @since 28.0.0 + */ + public function getErrorMessage(): string { + return $this->errorMessage; + } +} diff --git a/lib/public/TextToImage/Events/TaskSuccessfulEvent.php b/lib/public/TextToImage/Events/TaskSuccessfulEvent.php new file mode 100644 index 00000000000..15d263c0ff0 --- /dev/null +++ b/lib/public/TextToImage/Events/TaskSuccessfulEvent.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\TextToImage\Events; + +/** + * @since 28.0.0 + */ +class TaskSuccessfulEvent extends AbstractTextToImageEvent { +} diff --git a/lib/public/TextToImage/Exception/TaskFailureException.php b/lib/public/TextToImage/Exception/TaskFailureException.php new file mode 100644 index 00000000000..a640fdff2e8 --- /dev/null +++ b/lib/public/TextToImage/Exception/TaskFailureException.php @@ -0,0 +1,31 @@ +<?php + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\TextToImage\Exception; + +/** + * @since 28.0.0 + */ +class TaskFailureException extends TextToImageException { +} diff --git a/lib/public/TextToImage/Exception/TaskNotFoundException.php b/lib/public/TextToImage/Exception/TaskNotFoundException.php new file mode 100644 index 00000000000..bd713fe3905 --- /dev/null +++ b/lib/public/TextToImage/Exception/TaskNotFoundException.php @@ -0,0 +1,31 @@ +<?php + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\TextToImage\Exception; + +/** + * @since 28.0.0 + */ +class TaskNotFoundException extends TextToImageException { +} diff --git a/lib/public/TextToImage/Exception/TextToImageException.php b/lib/public/TextToImage/Exception/TextToImageException.php new file mode 100644 index 00000000000..3d4fd192c94 --- /dev/null +++ b/lib/public/TextToImage/Exception/TextToImageException.php @@ -0,0 +1,31 @@ +<?php + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\TextToImage\Exception; + +/** + * @since 28.0.0 + */ +class TextToImageException extends \Exception { +} diff --git a/lib/public/TextToImage/IManager.php b/lib/public/TextToImage/IManager.php new file mode 100644 index 00000000000..f2092476e78 --- /dev/null +++ b/lib/public/TextToImage/IManager.php @@ -0,0 +1,116 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +namespace OCP\TextToImage; + +use OCP\DB\Exception; +use OCP\PreConditionNotMetException; +use OCP\TextToImage\Exception\TaskFailureException; +use OCP\TextToImage\Exception\TaskNotFoundException; +use RuntimeException; + +/** + * API surface for apps interacting with and making use of TextToImage providers + * without knowing which providers are installed + * @since 28.0.0 + */ +interface IManager { + /** + * @since 28.0.0 + */ + public function hasProviders(): bool; + + /** + * @since 28.0.0 + * @return list<IProvider> + */ + public function getProviders(): array; + + /** + * @param Task $task The task to run + * @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called + * @throws TaskFailureException If something else failed. When this is thrown task status was already set to failure. + * @since 28.0.0 + */ + public function runTask(Task $task): void; + + /** + * Will schedule a TextToImage process in the background. The result will become available + * with the \OCP\TextToImage\TaskSuccessfulEvent + * If inference fails a \OCP\TextToImage\Events\TaskFailedEvent will be dispatched instead + * + * @param Task $task The task to schedule + * @throws PreConditionNotMetException If no provider was registered but this method was still called + * @throws Exception If there was a problem inserting the task into the database + * @since 28.0.0 + */ + public function scheduleTask(Task $task) : void; + + /** + * @throws Exception if there was a problem inserting the task into the database + * @throws PreConditionNotMetException if no provider is registered + * @throws TaskFailureException If the task run failed + * @since 28.0.0 + */ + public function runOrScheduleTask(Task $task) : void; + + /** + * Delete a task that has been scheduled before + * + * @param Task $task The task to delete + * @since 28.0.0 + */ + public function deleteTask(Task $task): void; + + /** + * @param int $id The id of the task + * @return Task + * @throws RuntimeException If the query failed + * @throws TaskNotFoundException If the task could not be found + * @since 28.0.0 + */ + public function getTask(int $id): Task; + + /** + * @param int $id The id of the task + * @param string|null $userId The user id that scheduled the task + * @return Task + * @throws RuntimeException If the query failed + * @throws TaskNotFoundException If the task could not be found + * @since 28.0.0 + */ + public function getUserTask(int $id, ?string $userId): Task; + + /** + * @param ?string $userId + * @param string $appId + * @param string|null $identifier + * @return Task[] + * @since 28.0.0 + * @throws RuntimeException If the query failed + */ + public function getUserTasksByApp(?string $userId, string $appId, ?string $identifier = null): array; +} diff --git a/lib/public/TextToImage/IProvider.php b/lib/public/TextToImage/IProvider.php new file mode 100644 index 00000000000..9f2ff51f599 --- /dev/null +++ b/lib/public/TextToImage/IProvider.php @@ -0,0 +1,64 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\TextToImage; + +use RuntimeException; + +/** + * This is the interface that is implemented by apps that + * implement a text to image provider + * @since 28.0.0 + */ +interface IProvider { + /** + * An arbitrary unique text string identifying this provider + * @since 28.0.0 + */ + public function getId(): string; + + /** + * The localized name of this provider + * @since 28.0.0 + */ + public function getName(): string; + + /** + * Processes a text + * + * @param string $prompt The input text + * @param resource[] $resources The file resources to write the images to + * @return void + * @since 28.0.0 + * @throws RuntimeException If the text could not be processed + */ + public function generate(string $prompt, array $resources): void; + + /** + * The expected runtime for one task with this provider in seconds + * @since 28.0.0 + */ + public function getExpectedRuntime(): int; +} diff --git a/lib/public/TextToImage/IProviderWithUserId.php b/lib/public/TextToImage/IProviderWithUserId.php new file mode 100644 index 00000000000..8afb0e56fbb --- /dev/null +++ b/lib/public/TextToImage/IProviderWithUserId.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OCP\TextToImage; + +/** + * @since 29.0.0 + */ +interface IProviderWithUserId extends IProvider { + /** + * @since 29.0.0 + */ + public function setUserId(?string $userId): void; +} diff --git a/lib/public/TextToImage/Task.php b/lib/public/TextToImage/Task.php new file mode 100644 index 00000000000..e610af6aa96 --- /dev/null +++ b/lib/public/TextToImage/Task.php @@ -0,0 +1,212 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\TextToImage; + +use DateTime; +use OCP\Files\AppData\IAppDataFactory; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; +use OCP\IImage; +use OCP\Image; + +/** + * This is a text to image task + * + * @since 28.0.0 + */ +final class Task implements \JsonSerializable { + protected ?int $id = null; + + protected ?DateTime $completionExpectedAt = null; + + /** + * @since 28.0.0 + */ + public const STATUS_FAILED = 4; + /** + * @since 28.0.0 + */ + public const STATUS_SUCCESSFUL = 3; + /** + * @since 28.0.0 + */ + public const STATUS_RUNNING = 2; + /** + * @since 28.0.0 + */ + public const STATUS_SCHEDULED = 1; + /** + * @since 28.0.0 + */ + public const STATUS_UNKNOWN = 0; + + /** + * @psalm-var self::STATUS_* + */ + protected int $status = self::STATUS_UNKNOWN; + + /** + * @param string $input + * @param string $appId + * @param int $numberOfImages + * @param string|null $userId + * @param null|string $identifier An arbitrary identifier for this task. max length: 255 chars + * @since 28.0.0 + */ + final public function __construct( + protected string $input, + protected string $appId, + protected int $numberOfImages, + protected ?string $userId, + protected ?string $identifier = '', + ) { + } + + /** + * @return IImage[]|null + * @since 28.0.0 + */ + final public function getOutputImages(): ?array { + $appData = \OCP\Server::get(IAppDataFactory::class)->get('core'); + try { + $folder = $appData->getFolder('text2image')->getFolder((string)$this->getId()); + $images = []; + for ($i = 0; $i < $this->getNumberOfImages(); $i++) { + $image = new Image(); + $image->loadFromFileHandle($folder->getFile((string) $i)->read()); + $images[] = $image; + } + return $images; + } catch (NotFoundException|NotPermittedException) { + return null; + } + } + + /** + * @return int + * @since 28.0.0 + */ + final public function getNumberOfImages(): int { + return $this->numberOfImages; + } + + /** + * @psalm-return self::STATUS_* + * @since 28.0.0 + */ + final public function getStatus(): int { + return $this->status; + } + + /** + * @psalm-param self::STATUS_* $status + * @since 28.0.0 + */ + final public function setStatus(int $status): void { + $this->status = $status; + } + + /** + * @param ?DateTime $at + * @since 28.0.0 + */ + final public function setCompletionExpectedAt(?DateTime $at): void { + $this->completionExpectedAt = $at; + } + + /** + * @return ?DateTime + * @since 28.0.0 + */ + final public function getCompletionExpectedAt(): ?DateTime { + return $this->completionExpectedAt; + } + + /** + * @return int|null + * @since 28.0.0 + */ + final public function getId(): ?int { + return $this->id; + } + + /** + * @param int|null $id + * @since 28.0.0 + */ + final public function setId(?int $id): void { + $this->id = $id; + } + + /** + * @return string + * @since 28.0.0 + */ + final public function getInput(): string { + return $this->input; + } + + /** + * @return string + * @since 28.0.0 + */ + final public function getAppId(): string { + return $this->appId; + } + + /** + * @return null|string + * @since 28.0.0 + */ + final public function getIdentifier(): ?string { + return $this->identifier; + } + + /** + * @return string|null + * @since 28.0.0 + */ + final public function getUserId(): ?string { + return $this->userId; + } + + /** + * @psalm-return array{id: ?int, status: self::STATUS_*, userId: ?string, appId: string, input: string, identifier: ?string, numberOfImages: int, completionExpectedAt: ?int} + * @since 28.0.0 + */ + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'status' => $this->getStatus(), + 'userId' => $this->getUserId(), + 'appId' => $this->getAppId(), + 'numberOfImages' => $this->getNumberOfImages(), + 'input' => $this->getInput(), + 'identifier' => $this->getIdentifier(), + 'completionExpectedAt' => $this->getCompletionExpectedAt()->getTimestamp(), + ]; + } +} diff --git a/lib/public/Translation/ITranslationProviderWithId.php b/lib/public/Translation/ITranslationProviderWithId.php new file mode 100644 index 00000000000..fa08ef7cb17 --- /dev/null +++ b/lib/public/Translation/ITranslationProviderWithId.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2024 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +namespace OCP\Translation; + +/** + * @since 29.0.0 + */ +interface ITranslationProviderWithId extends ITranslationProvider { + /** + * @since 29.0.0 + */ + public function getId(): string; +} diff --git a/lib/public/Translation/ITranslationProviderWithUserId.php b/lib/public/Translation/ITranslationProviderWithUserId.php new file mode 100644 index 00000000000..9a573a8150e --- /dev/null +++ b/lib/public/Translation/ITranslationProviderWithUserId.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2024 Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +namespace OCP\Translation; + +/** + * @since 29.0.0 + */ +interface ITranslationProviderWithUserId extends ITranslationProvider { + /** + * @param string|null $userId The userId of the user requesting the current task + * @since 29.0.0 + */ + public function setUserId(?string $userId); +} diff --git a/lib/public/User/Backend/IProvideEnabledStateBackend.php b/lib/public/User/Backend/IProvideEnabledStateBackend.php index d03beacd7b8..f12d99fd1a6 100644 --- a/lib/public/User/Backend/IProvideEnabledStateBackend.php +++ b/lib/public/User/Backend/IProvideEnabledStateBackend.php @@ -52,5 +52,5 @@ interface IProvideEnabledStateBackend { * * @return string[] */ - public function getDisabledUserList(int $offset = 0, ?int $limit = null): array; + public function getDisabledUserList(?int $limit = null, int $offset = 0): array; } diff --git a/lib/public/User/Events/BeforePasswordUpdatedEvent.php b/lib/public/User/Events/BeforePasswordUpdatedEvent.php index 11eb5ad9dd0..ee228ae01e7 100644 --- a/lib/public/User/Events/BeforePasswordUpdatedEvent.php +++ b/lib/public/User/Events/BeforePasswordUpdatedEvent.php @@ -51,8 +51,8 @@ class BeforePasswordUpdatedEvent extends Event { * @since 18.0.0 */ public function __construct(IUser $user, - string $password, - string $recoveryPassword = null) { + string $password, + string $recoveryPassword = null) { parent::__construct(); $this->user = $user; $this->password = $password; diff --git a/lib/public/User/Events/BeforeUserCreatedEvent.php b/lib/public/User/Events/BeforeUserCreatedEvent.php index 67e9177b34d..ee33239a12c 100644 --- a/lib/public/User/Events/BeforeUserCreatedEvent.php +++ b/lib/public/User/Events/BeforeUserCreatedEvent.php @@ -44,7 +44,7 @@ class BeforeUserCreatedEvent extends Event { * @since 18.0.0 */ public function __construct(string $uid, - string $password) { + string $password) { parent::__construct(); $this->uid = $uid; $this->password = $password; diff --git a/lib/public/User/Events/OutOfOfficeChangedEvent.php b/lib/public/User/Events/OutOfOfficeChangedEvent.php new file mode 100644 index 00000000000..5e5753b7202 --- /dev/null +++ b/lib/public/User/Events/OutOfOfficeChangedEvent.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +/* + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\User\Events; + +use OCP\EventDispatcher\Event; +use OCP\User\IOutOfOfficeData; + +/** + * Emitted when a user's out-of-office period has changed + * + * @since 28.0.0 + */ +class OutOfOfficeChangedEvent extends Event { + /** + * @since 28.0.0 + */ + public function __construct(private IOutOfOfficeData $data) { + parent::__construct(); + } + + /** + * @since 28.0.0 + */ + public function getData(): IOutOfOfficeData { + return $this->data; + } +} diff --git a/lib/public/User/Events/OutOfOfficeClearedEvent.php b/lib/public/User/Events/OutOfOfficeClearedEvent.php new file mode 100644 index 00000000000..48a77c77023 --- /dev/null +++ b/lib/public/User/Events/OutOfOfficeClearedEvent.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +/* + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\User\Events; + +use OCP\EventDispatcher\Event; +use OCP\User\IOutOfOfficeData; + +/** + * Emitted when a user's out-of-office period is cleared + * + * @since 28.0.0 + */ +class OutOfOfficeClearedEvent extends Event { + /** + * @since 28.0.0 + */ + public function __construct(private IOutOfOfficeData $data) { + parent::__construct(); + } + + /** + * @since 28.0.0 + */ + public function getData(): IOutOfOfficeData { + return $this->data; + } +} diff --git a/lib/public/User/Events/OutOfOfficeEndedEvent.php b/lib/public/User/Events/OutOfOfficeEndedEvent.php new file mode 100644 index 00000000000..43a6bf77e28 --- /dev/null +++ b/lib/public/User/Events/OutOfOfficeEndedEvent.php @@ -0,0 +1,51 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud> + * + * @author Richard Steinmetz <richard@steinmetz.cloud> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\User\Events; + +use OCP\EventDispatcher\Event; +use OCP\User\IOutOfOfficeData; + +/** + * Emitted when a user's out-of-office period ended + * + * @since 28.0.0 + */ +class OutOfOfficeEndedEvent extends Event { + /** + * @since 28.0.0 + */ + public function __construct(private IOutOfOfficeData $data) { + parent::__construct(); + } + + /** + * @since 28.0.0 + */ + public function getData(): IOutOfOfficeData { + return $this->data; + } +} diff --git a/lib/public/User/Events/OutOfOfficeScheduledEvent.php b/lib/public/User/Events/OutOfOfficeScheduledEvent.php new file mode 100644 index 00000000000..2bcbec63478 --- /dev/null +++ b/lib/public/User/Events/OutOfOfficeScheduledEvent.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +/* + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\User\Events; + +use OCP\EventDispatcher\Event; +use OCP\User\IOutOfOfficeData; + +/** + * Emitted when a user's out-of-office period is scheduled + * + * @since 28.0.0 + */ +class OutOfOfficeScheduledEvent extends Event { + /** + * @since 28.0.0 + */ + public function __construct(private IOutOfOfficeData $data) { + parent::__construct(); + } + + /** + * @since 28.0.0 + */ + public function getData(): IOutOfOfficeData { + return $this->data; + } +} diff --git a/lib/public/User/Events/OutOfOfficeStartedEvent.php b/lib/public/User/Events/OutOfOfficeStartedEvent.php new file mode 100644 index 00000000000..f7816c968dd --- /dev/null +++ b/lib/public/User/Events/OutOfOfficeStartedEvent.php @@ -0,0 +1,51 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud> + * + * @author Richard Steinmetz <richard@steinmetz.cloud> + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\User\Events; + +use OCP\EventDispatcher\Event; +use OCP\User\IOutOfOfficeData; + +/** + * Emitted when a user's out-of-office period started + * + * @since 28.0.0 + */ +class OutOfOfficeStartedEvent extends Event { + /** + * @since 28.0.0 + */ + public function __construct(private IOutOfOfficeData $data) { + parent::__construct(); + } + + /** + * @since 28.0.0 + */ + public function getData(): IOutOfOfficeData { + return $this->data; + } +} diff --git a/lib/public/User/Events/PasswordUpdatedEvent.php b/lib/public/User/Events/PasswordUpdatedEvent.php index 41d510553b5..782d6d270ea 100644 --- a/lib/public/User/Events/PasswordUpdatedEvent.php +++ b/lib/public/User/Events/PasswordUpdatedEvent.php @@ -51,8 +51,8 @@ class PasswordUpdatedEvent extends Event { * @since 18.0.0 */ public function __construct(IUser $user, - string $password, - string $recoveryPassword = null) { + string $password, + string $recoveryPassword = null) { parent::__construct(); $this->user = $user; $this->password = $password; diff --git a/lib/public/User/Events/UserChangedEvent.php b/lib/public/User/Events/UserChangedEvent.php index f48dd3914e6..870b0326920 100644 --- a/lib/public/User/Events/UserChangedEvent.php +++ b/lib/public/User/Events/UserChangedEvent.php @@ -43,9 +43,9 @@ class UserChangedEvent extends Event { * @since 18.0.0 */ public function __construct(IUser $user, - string $feature, - $value, - $oldValue = null) { + string $feature, + $value, + $oldValue = null) { parent::__construct(); $this->user = $user; $this->feature = $feature; diff --git a/lib/public/User/Events/UserCreatedEvent.php b/lib/public/User/Events/UserCreatedEvent.php index 7d343bfd5b8..b0a734be0cb 100644 --- a/lib/public/User/Events/UserCreatedEvent.php +++ b/lib/public/User/Events/UserCreatedEvent.php @@ -45,7 +45,7 @@ class UserCreatedEvent extends Event { * @since 18.0.0 */ public function __construct(IUser $user, - string $password) { + string $password) { parent::__construct(); $this->user = $user; $this->password = $password; diff --git a/lib/public/User/Events/UserLiveStatusEvent.php b/lib/public/User/Events/UserLiveStatusEvent.php index d04c3b61e24..8b6207d685d 100644 --- a/lib/public/User/Events/UserLiveStatusEvent.php +++ b/lib/public/User/Events/UserLiveStatusEvent.php @@ -60,8 +60,8 @@ class UserLiveStatusEvent extends Event { * @since 20.0.0 */ public function __construct(IUser $user, - string $status, - int $timestamp) { + string $status, + int $timestamp) { parent::__construct(); $this->user = $user; $this->status = $status; diff --git a/lib/public/User/IAvailabilityCoordinator.php b/lib/public/User/IAvailabilityCoordinator.php new file mode 100644 index 00000000000..3a79e39b7b7 --- /dev/null +++ b/lib/public/User/IAvailabilityCoordinator.php @@ -0,0 +1,67 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\User; + +use OCP\IUser; + +/** + * Coordinator for availability and out-of-office messages + * + * @since 28.0.0 + */ +interface IAvailabilityCoordinator { + /** + * Check if the feature is enabled on this instance + * + * @return bool + * + * @since 28.0.0 + */ + public function isEnabled(): bool; + + /** + * Get the user's out-of-office message, if any + * + * @since 28.0.0 + */ + public function getCurrentOutOfOfficeData(IUser $user): ?IOutOfOfficeData; + + /** + * Reset the absence cache to null + * + * @since 28.0.0 + */ + public function clearCache(string $userId): void; + + /** + * Is the absence in effect at this moment + * + * @param IOutOfOfficeData $data + * @return bool + * @since 28.0.0 + */ + public function isInEffect(IOutOfOfficeData $data): bool; +} diff --git a/lib/public/User/IOutOfOfficeData.php b/lib/public/User/IOutOfOfficeData.php new file mode 100644 index 00000000000..31281104382 --- /dev/null +++ b/lib/public/User/IOutOfOfficeData.php @@ -0,0 +1,94 @@ +<?php + +declare(strict_types=1); + +/* + * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\User; + +use JsonSerializable; +use OCP\IUser; + +/** + * DTO to hold out-of-office information of a user + * + * @psalm-type OutOfOfficeData = array{ + * id: string, + * userId: string, + * startDate: int, + * endDate: int, + * shortMessage: string, + * message: string, + * } + * + * @since 28.0.0 + */ +interface IOutOfOfficeData extends JsonSerializable { + /** + * Get the unique token assigned to the current out-of-office event + * + * @since 28.0.0 + */ + public function getId(): string; + + /** + * @since 28.0.0 + */ + public function getUser(): IUser; + + /** + * Get the accurate out-of-office start date + * + * This event is not guaranteed to be emitted exactly at start date + * + * @since 28.0.0 + */ + public function getStartDate(): int; + + /** + * Get the (preliminary) out-of-office end date + * + * @since 28.0.0 + */ + public function getEndDate(): int; + + /** + * Get the short summary text displayed in the user status and similar + * + * @since 28.0.0 + */ + public function getShortMessage(): string; + + /** + * Get the long out-of-office message for auto responders and similar + * + * @since 28.0.0 + */ + public function getMessage(): string; + + /** + * @return OutOfOfficeData + * + * @since 28.0.0 + */ + public function jsonSerialize(): array; +} diff --git a/lib/public/UserMigration/IImportSource.php b/lib/public/UserMigration/IImportSource.php index da2c87ba241..e9d49784f5d 100644 --- a/lib/public/UserMigration/IImportSource.php +++ b/lib/public/UserMigration/IImportSource.php @@ -32,6 +32,9 @@ use OCP\Files\Folder; * @since 24.0.0 */ interface IImportSource { + /** + * @since 24.0.0 + */ public const PATH_USER = 'user.json'; /** diff --git a/lib/public/UserStatus/IManager.php b/lib/public/UserStatus/IManager.php index 9cc8eaad8ee..a85c1894c65 100644 --- a/lib/public/UserStatus/IManager.php +++ b/lib/public/UserStatus/IManager.php @@ -52,9 +52,11 @@ interface IManager { * @param string $messageId The id of the predefined message. * @param string $status The status to assign * @param bool $createBackup If true, this will store the old status so that it is possible to revert it later (e.g. after a call). + * @param string|null $customMessage * @since 23.0.0 + * @since 28.0.0 Optional parameter $customMessage was added */ - public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup = false): void; + public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup = false, ?string $customMessage = null): void; /** * Revert an automatically set user status. For example after leaving a call, diff --git a/lib/public/UserStatus/IUserStatus.php b/lib/public/UserStatus/IUserStatus.php index 74c54cc9da2..f167f9a82ee 100644 --- a/lib/public/UserStatus/IUserStatus.php +++ b/lib/public/UserStatus/IUserStatus.php @@ -53,6 +53,12 @@ interface IUserStatus { /** * @var string + * @since 28.0.0 + */ + public const BUSY = 'busy'; + + /** + * @var string * @since 20.0.0 */ public const OFFLINE = 'offline'; @@ -76,6 +82,30 @@ interface IUserStatus { public const MESSAGE_AVAILABILITY = 'availability'; /** + * @var string + * @since 28.0.1 + */ + public const MESSAGE_OUT_OF_OFFICE = 'out-of-office'; + + /** + * @var string + * @since 28.0.0 + */ + public const MESSAGE_VACATION = 'vacationing'; + + /** + * @var string + * @since 28.0.0 + */ + public const MESSAGE_CALENDAR_BUSY = 'meeting'; + + /** + * @var string + * @since 28.0.0 + */ + public const MESSAGE_CALENDAR_BUSY_TENTATIVE = 'busy-tentative'; + + /** * Get the user this status is connected to * * @return string diff --git a/lib/public/Util.php b/lib/public/Util.php index 34ccc61074f..87b0700f12b 100644 --- a/lib/public/Util.php +++ b/lib/public/Util.php @@ -46,11 +46,13 @@ namespace OCP; +use bantu\IniGetWrapper\IniGetWrapper; use OC\AppScriptDependency; use OC\AppScriptSort; use OCP\Share\IManager as IShareManager; -use bantu\IniGetWrapper\IniGetWrapper; +use OCP\Share\IManager; use Psr\Container\ContainerExceptionInterface; +use Psr\Log\LoggerInterface; /** * This class provides different helper functions to make the life of a developer easier @@ -58,17 +60,11 @@ use Psr\Container\ContainerExceptionInterface; * @since 4.0.0 */ class Util { - /** @var \OCP\Share\IManager */ - private static $shareManager; - - /** @var array */ - private static $scripts = []; + private static ?IManager $shareManager = null; - /** @var array */ - private static $scriptDeps = []; - - /** @var array */ - private static $sortedScriptDeps = []; + private static array $scriptsInit = []; + private static array $scripts = []; + private static array $scriptDeps = []; /** * get the current installed version of Nextcloud @@ -111,19 +107,6 @@ class Util { } /** - * write a message in the log - * @param string $app - * @param string $message - * @param int $level - * @since 4.0.0 - * @deprecated 13.0.0 use log of \OCP\ILogger - */ - public static function writeLog($app, $message, $level) { - $context = ['app' => $app]; - \OC::$server->getLogger()->log($level, $message, $context); - } - - /** * check if sharing is disabled for the current user * * @return boolean @@ -145,13 +128,10 @@ class Util { /** * get l10n object - * @param string $application - * @param string|null $language - * @return \OCP\IL10N * @since 6.0.0 - parameter $language was added in 8.0.0 */ - public static function getL10N($application, $language = null) { - return \OC::$server->getL10N($application, $language); + public static function getL10N(string $application, ?string $language = null): IL10N { + return Server::get(\OCP\L10N\IFactory::class)->get($application, $language); } /** @@ -165,6 +145,31 @@ class Util { } /** + * Add a standalone init js file that is loaded for initialization + * + * Be careful loading scripts using this method as they are loaded early + * and block the initial page rendering. They should not have dependencies + * on any other scripts than core-common and core-main. + * + * @since 28.0.0 + */ + public static function addInitScript(string $application, string $file): void { + if (!empty($application)) { + $path = "$application/js/$file"; + } else { + $path = "js/$file"; + } + + // We need to handle the translation BEFORE the init script + // is loaded, as the init script might use translations + if ($application !== 'core' && !str_contains($file, 'l10n')) { + self::addTranslations($application, null, true); + } + + self::$scriptsInit[] = $path; + } + + /** * add a javascript file * * @param string $application @@ -215,7 +220,8 @@ class Util { $sortedScripts = $scriptSort->sort(self::$scripts, self::$scriptDeps); // Flatten array and remove duplicates - $sortedScripts = $sortedScripts ? array_merge(...array_values(($sortedScripts))) : []; + $sortedScripts = array_merge([self::$scriptsInit], $sortedScripts); + $sortedScripts = array_merge(...array_values($sortedScripts)); // Override core-common and core-main order if (in_array('core/js/main', $sortedScripts)) { @@ -232,9 +238,10 @@ class Util { * Add a translation JS file * @param string $application application id * @param string $languageCode language code, defaults to the current locale + * @param bool $init whether the translations should be loaded early or not * @since 8.0.0 */ - public static function addTranslations($application, $languageCode = null) { + public static function addTranslations($application, $languageCode = null, $init = false) { if (is_null($languageCode)) { $languageCode = \OC::$server->getL10NFactory()->findLanguage($application); } @@ -243,7 +250,12 @@ class Util { } else { $path = "l10n/$languageCode"; } - self::$scripts[$application][] = $path; + + if ($init) { + self::$scriptsInit[] = $path; + } else { + self::$scripts[$application][] = $path; + } } /** @@ -511,10 +523,31 @@ class Util { } /** + * Get a list of characters forbidden in file names + * @return string[] + * @since 29.0.0 + */ + public static function getForbiddenFileNameChars(): array { + // Get always forbidden characters + $invalidChars = str_split(\OCP\Constants::FILENAME_INVALID_CHARS); + if ($invalidChars === false) { + $invalidChars = []; + } + + // Get admin defined invalid characters + $additionalChars = \OCP\Server::get(IConfig::class)->getSystemValue('forbidden_chars', []); + if (!is_array($additionalChars)) { + \OCP\Server::get(LoggerInterface::class)->error('Invalid system config value for "forbidden_chars" is ignored.'); + $additionalChars = []; + } + return array_merge($invalidChars, $additionalChars); + } + + /** * Returns whether the given file name is valid * @param string $file file name to check * @return bool true if the file name is valid, false otherwise - * @deprecated 8.1.0 use \OC\Files\View::verifyPath() + * @deprecated 8.1.0 use OCP\Files\Storage\IStorage::verifyPath() * @since 7.0.0 * @suppress PhanDeprecatedFunction */ diff --git a/lib/public/WorkflowEngine/IManager.php b/lib/public/WorkflowEngine/IManager.php index abdcdfa107a..83e2b69dc65 100644 --- a/lib/public/WorkflowEngine/IManager.php +++ b/lib/public/WorkflowEngine/IManager.php @@ -31,7 +31,14 @@ namespace OCP\WorkflowEngine; * @since 9.1 */ interface IManager { + /** + * @since 18.0.0 + */ public const SCOPE_ADMIN = 0; + + /** + * @since 18.0.0 + */ public const SCOPE_USER = 1; /** diff --git a/lib/versioncheck.php b/lib/versioncheck.php index 8869fe95453..29c278370cd 100644 --- a/lib/versioncheck.php +++ b/lib/versioncheck.php @@ -33,10 +33,10 @@ if (PHP_VERSION_ID < 80000) { exit(1); } -// Show warning if >= PHP 8.3 is used as Nextcloud is not compatible with >= PHP 8.3 for now -if (PHP_VERSION_ID >= 80300) { +// Show warning if >= PHP 8.4 is used as Nextcloud is not compatible with >= PHP 8.4 for now +if (PHP_VERSION_ID >= 80400) { http_response_code(500); - echo 'This version of Nextcloud is not compatible with PHP>=8.3.<br/>'; + echo 'This version of Nextcloud is not compatible with PHP>=8.4.<br/>'; echo 'You are currently running ' . PHP_VERSION . '.'; exit(1); } |