aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/base.php39
-rw-r--r--lib/composer/composer/ClassLoader.php96
-rw-r--r--lib/composer/composer/LICENSE2
-rw-r--r--lib/composer/composer/autoload_classmap.php75
-rw-r--r--lib/composer/composer/autoload_static.php75
-rw-r--r--lib/l10n/ar.js128
-rw-r--r--lib/l10n/ar.json128
-rw-r--r--lib/l10n/ast.js1
-rw-r--r--lib/l10n/ast.json1
-rw-r--r--lib/l10n/az.js2
-rw-r--r--lib/l10n/az.json2
-rw-r--r--lib/l10n/bg.js6
-rw-r--r--lib/l10n/bg.json6
-rw-r--r--lib/l10n/ca.js15
-rw-r--r--lib/l10n/ca.json15
-rw-r--r--lib/l10n/cs.js15
-rw-r--r--lib/l10n/cs.json15
-rw-r--r--lib/l10n/da.js20
-rw-r--r--lib/l10n/da.json20
-rw-r--r--lib/l10n/de.js8
-rw-r--r--lib/l10n/de.json8
-rw-r--r--lib/l10n/de_DE.js17
-rw-r--r--lib/l10n/de_DE.json17
-rw-r--r--lib/l10n/el.js6
-rw-r--r--lib/l10n/el.json6
-rw-r--r--lib/l10n/en_GB.js15
-rw-r--r--lib/l10n/en_GB.json15
-rw-r--r--lib/l10n/es.js15
-rw-r--r--lib/l10n/es.json15
-rw-r--r--lib/l10n/es_EC.js101
-rw-r--r--lib/l10n/es_EC.json101
-rw-r--r--lib/l10n/et_EE.js4
-rw-r--r--lib/l10n/et_EE.json4
-rw-r--r--lib/l10n/eu.js16
-rw-r--r--lib/l10n/eu.json16
-rw-r--r--lib/l10n/fa.js56
-rw-r--r--lib/l10n/fa.json56
-rw-r--r--lib/l10n/fi.js8
-rw-r--r--lib/l10n/fi.json8
-rw-r--r--lib/l10n/fr.js6
-rw-r--r--lib/l10n/fr.json6
-rw-r--r--lib/l10n/gl.js59
-rw-r--r--lib/l10n/gl.json59
-rw-r--r--lib/l10n/hu.js6
-rw-r--r--lib/l10n/hu.json6
-rw-r--r--lib/l10n/it.js15
-rw-r--r--lib/l10n/it.json15
-rw-r--r--lib/l10n/ja.js16
-rw-r--r--lib/l10n/ja.json16
-rw-r--r--lib/l10n/ko.js4
-rw-r--r--lib/l10n/ko.json4
-rw-r--r--lib/l10n/mk.js6
-rw-r--r--lib/l10n/mk.json6
-rw-r--r--lib/l10n/mn.js2
-rw-r--r--lib/l10n/mn.json2
-rw-r--r--lib/l10n/nl.js7
-rw-r--r--lib/l10n/nl.json7
-rw-r--r--lib/l10n/pl.js6
-rw-r--r--lib/l10n/pl.json6
-rw-r--r--lib/l10n/pt_BR.js15
-rw-r--r--lib/l10n/pt_BR.json15
-rw-r--r--lib/l10n/pt_PT.js6
-rw-r--r--lib/l10n/pt_PT.json6
-rw-r--r--lib/l10n/ru.js15
-rw-r--r--lib/l10n/ru.json15
-rw-r--r--lib/l10n/sk.js6
-rw-r--r--lib/l10n/sk.json6
-rw-r--r--lib/l10n/sr.js15
-rw-r--r--lib/l10n/sr.json15
-rw-r--r--lib/l10n/sv.js13
-rw-r--r--lib/l10n/sv.json13
-rw-r--r--lib/l10n/tr.js15
-rw-r--r--lib/l10n/tr.json15
-rw-r--r--lib/l10n/uk.js24
-rw-r--r--lib/l10n/uk.json24
-rw-r--r--lib/l10n/vi.js1
-rw-r--r--lib/l10n/vi.json1
-rw-r--r--lib/l10n/zh_CN.js10
-rw-r--r--lib/l10n/zh_CN.json10
-rw-r--r--lib/l10n/zh_HK.js15
-rw-r--r--lib/l10n/zh_HK.json15
-rw-r--r--lib/l10n/zh_TW.js15
-rw-r--r--lib/l10n/zh_TW.json15
-rw-r--r--lib/private/Accounts/Account.php10
-rw-r--r--lib/private/Accounts/AccountManager.php117
-rw-r--r--lib/private/Accounts/AccountProperty.php62
-rw-r--r--lib/private/Accounts/AccountPropertyCollection.php10
-rw-r--r--lib/private/Accounts/Hooks.php12
-rw-r--r--lib/private/Activity/Manager.php6
-rw-r--r--lib/private/App/AppManager.php10
-rw-r--r--lib/private/App/InfoParser.php6
-rw-r--r--lib/private/AppConfig.php2
-rw-r--r--lib/private/AppFramework/Bootstrap/RegistrationContext.php21
-rw-r--r--lib/private/AppFramework/DependencyInjection/DIContainer.php7
-rw-r--r--lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php39
-rw-r--r--lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php6
-rw-r--r--lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php18
-rw-r--r--lib/private/AppFramework/Middleware/Security/CORSMiddleware.php12
-rw-r--r--lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php22
-rw-r--r--lib/private/AppFramework/OCS/BaseResponse.php10
-rw-r--r--lib/private/AppFramework/OCS/V1Response.php9
-rw-r--r--lib/private/AppFramework/OCS/V2Response.php9
-rw-r--r--lib/private/AppFramework/Utility/SimpleContainer.php1
-rw-r--r--lib/private/Authentication/Token/IProvider.php5
-rw-r--r--lib/private/Authentication/Token/Manager.php4
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenMapper.php9
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenProvider.php6
-rw-r--r--lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php6
-rw-r--r--lib/private/Authentication/TwoFactorAuth/Manager.php29
-rw-r--r--lib/private/Authentication/TwoFactorAuth/ProviderLoader.php4
-rw-r--r--lib/private/Authentication/TwoFactorAuth/Registry.php6
-rw-r--r--lib/private/BackgroundJob/JobList.php32
-rw-r--r--lib/private/Calendar/CalendarQuery.php31
-rw-r--r--lib/private/Calendar/Manager.php105
-rw-r--r--lib/private/Calendar/Resource/Manager.php31
-rw-r--r--lib/private/Calendar/Room/Manager.php26
-rw-r--r--lib/private/CapabilitiesManager.php2
-rw-r--r--lib/private/Collaboration/Resources/Listener.php62
-rw-r--r--lib/private/Comments/Manager.php16
-rw-r--r--lib/private/Console/Application.php33
-rw-r--r--lib/private/Contacts/ContactsMenu/ActionProviderStore.php15
-rw-r--r--lib/private/Contacts/ContactsMenu/Actions/LinkAction.php13
-rw-r--r--lib/private/Contacts/ContactsMenu/ContactsStore.php35
-rw-r--r--lib/private/Contacts/ContactsMenu/Entry.php8
-rw-r--r--lib/private/Contacts/ContactsMenu/Manager.php22
-rw-r--r--lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php15
-rw-r--r--lib/private/Contacts/ContactsMenu/Providers/LocalTimeProvider.php34
-rw-r--r--lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php26
-rw-r--r--lib/private/ContactsManager.php34
-rw-r--r--lib/private/DB/Adapter.php10
-rw-r--r--lib/private/DB/Connection.php16
-rw-r--r--lib/private/DB/ConnectionAdapter.php21
-rw-r--r--lib/private/DB/MigrationService.php115
-rw-r--r--lib/private/DB/OracleConnection.php2
-rw-r--r--lib/private/DB/PostgreSqlMigrator.php2
-rw-r--r--lib/private/Dashboard/Manager.php7
-rw-r--r--lib/private/Encryption/EncryptionWrapper.php12
-rw-r--r--lib/private/Encryption/Manager.php7
-rw-r--r--lib/private/Encryption/Util.php28
-rw-r--r--lib/private/EventDispatcher/EventDispatcher.php2
-rw-r--r--lib/private/EventDispatcher/GenericEventWrapper.php124
-rw-r--r--lib/private/EventDispatcher/SymfonyAdapter.php208
-rw-r--r--lib/private/Federation/CloudFederationProviderManager.php100
-rw-r--r--lib/private/Federation/CloudIdManager.php9
-rw-r--r--lib/private/Files/Cache/Cache.php20
-rw-r--r--lib/private/Files/Cache/CacheEntry.php8
-rw-r--r--lib/private/Files/Cache/QuerySearchHelper.php65
-rw-r--r--lib/private/Files/Cache/Scanner.php24
-rw-r--r--lib/private/Files/Cache/SearchBuilder.php17
-rw-r--r--lib/private/Files/Cache/Wrapper/CacheWrapper.php14
-rw-r--r--lib/private/Files/FileInfo.php38
-rw-r--r--lib/private/Files/Mount/MoveableMount.php4
-rw-r--r--lib/private/Files/Node/Folder.php7
-rw-r--r--lib/private/Files/Node/HookConnector.php38
-rw-r--r--lib/private/Files/Node/LazyFolder.php73
-rw-r--r--lib/private/Files/Node/LazyRoot.php15
-rw-r--r--lib/private/Files/Node/LazyUserFolder.php19
-rw-r--r--lib/private/Files/Node/Node.php43
-rw-r--r--lib/private/Files/Node/NonExistingFolder.php4
-rw-r--r--lib/private/Files/ObjectStore/HomeObjectStoreStorage.php3
-rw-r--r--lib/private/Files/ObjectStore/ObjectStoreScanner.php2
-rw-r--r--lib/private/Files/ObjectStore/ObjectStoreStorage.php2
-rw-r--r--lib/private/Files/ObjectStore/S3.php12
-rw-r--r--lib/private/Files/ObjectStore/S3ConnectionTrait.php2
-rw-r--r--lib/private/Files/ObjectStore/S3ObjectTrait.php16
-rw-r--r--lib/private/Files/SetupManager.php73
-rw-r--r--lib/private/Files/SetupManagerFactory.php45
-rw-r--r--lib/private/Files/Storage/Home.php3
-rw-r--r--lib/private/Files/Storage/Local.php26
-rw-r--r--lib/private/Files/Storage/Wrapper/Encryption.php82
-rw-r--r--lib/private/Files/Storage/Wrapper/Quota.php5
-rw-r--r--lib/private/Files/Stream/SeekableHttpStream.php4
-rw-r--r--lib/private/Files/Type/Loader.php36
-rw-r--r--lib/private/Files/Utils/Scanner.php8
-rw-r--r--lib/private/Files/View.php54
-rw-r--r--lib/private/Group/Database.php88
-rw-r--r--lib/private/Group/DisplayNameCache.php6
-rw-r--r--lib/private/Group/Group.php46
-rw-r--r--lib/private/Group/Manager.php89
-rw-r--r--lib/private/Http/Client/Client.php231
-rw-r--r--lib/private/Http/Client/ClientService.php9
-rw-r--r--lib/private/Http/Client/DnsPinMiddleware.php15
-rw-r--r--lib/private/Http/Client/GuzzlePromiseAdapter.php139
-rw-r--r--lib/private/Installer.php4
-rw-r--r--lib/private/Log.php26
-rw-r--r--lib/private/Log/ErrorHandler.php28
-rw-r--r--lib/private/Log/Errorlog.php13
-rw-r--r--lib/private/Log/ExceptionSerializer.php12
-rw-r--r--lib/private/Log/File.php28
-rw-r--r--lib/private/Log/LogDetails.php8
-rw-r--r--lib/private/Log/LogFactory.php58
-rw-r--r--lib/private/Log/PsrLoggerAdapter.php53
-rw-r--r--lib/private/Log/Rotate.php2
-rw-r--r--lib/private/Log/Syslog.php11
-rw-r--r--lib/private/Log/Systemdlog.php13
-rw-r--r--lib/private/Mail/Attachment.php20
-rw-r--r--lib/private/Mail/EMailTemplate.php135
-rw-r--r--lib/private/Mail/Mailer.php60
-rw-r--r--lib/private/Mail/Message.php46
-rw-r--r--lib/private/Memcache/APCu.php5
-rw-r--r--lib/private/Memcache/Factory.php16
-rw-r--r--lib/private/NavigationManager.php4
-rw-r--r--lib/private/OCM/Model/OCMProvider.php211
-rw-r--r--lib/private/OCM/Model/OCMResource.php125
-rw-r--r--lib/private/OCM/OCMDiscoveryService.php138
-rw-r--r--lib/private/OCS/CoreCapabilities.php2
-rw-r--r--lib/private/Preview/Generator.php20
-rw-r--r--lib/private/Preview/Imaginary.php24
-rw-r--r--lib/private/Preview/MP3.php17
-rw-r--r--lib/private/Preview/MimeIconProvider.php98
-rw-r--r--lib/private/Preview/WatcherConnector.php2
-rw-r--r--lib/private/PreviewManager.php5
-rw-r--r--lib/private/Profile/ProfileManager.php2
-rw-r--r--lib/private/RedisFactory.php28
-rw-r--r--lib/private/Repair.php8
-rw-r--r--lib/private/Repair/AddRemoveOldTasksBackgroundJob.php47
-rw-r--r--lib/private/Search/Provider/File.php4
-rw-r--r--lib/private/Security/Bruteforce/Backend/DatabaseBackend.php116
-rw-r--r--lib/private/Security/Bruteforce/Backend/IBackend.php82
-rw-r--r--lib/private/Security/Bruteforce/Backend/MemoryCacheBackend.php161
-rw-r--r--lib/private/Security/Bruteforce/Capabilities.php33
-rw-r--r--lib/private/Security/Bruteforce/Throttler.php211
-rw-r--r--lib/private/Security/CSP/ContentSecurityPolicy.php8
-rw-r--r--lib/private/Security/IdentityProof/Key.php16
-rw-r--r--lib/private/Security/IdentityProof/Manager.php28
-rw-r--r--lib/private/Security/IdentityProof/Signer.php31
-rw-r--r--lib/private/Security/RateLimiting/Backend/DatabaseBackend.php47
-rw-r--r--lib/private/Security/RateLimiting/Backend/IBackend.php15
-rw-r--r--lib/private/Security/RateLimiting/Backend/MemoryCacheBackend.php43
-rw-r--r--lib/private/Security/RateLimiting/Limiter.php50
-rw-r--r--lib/private/Security/VerificationToken/CleanUpJob.php17
-rw-r--r--lib/private/Security/VerificationToken/VerificationToken.php40
-rw-r--r--lib/private/Server.php122
-rw-r--r--lib/private/Session/Internal.php2
-rw-r--r--lib/private/Setup.php12
-rw-r--r--lib/private/Share20/DefaultShareProvider.php54
-rw-r--r--lib/private/Share20/LegacyHooks.php83
-rw-r--r--lib/private/Share20/Manager.php120
-rw-r--r--lib/private/Share20/ProviderFactory.php13
-rw-r--r--lib/private/Share20/ShareDisableChecker.php65
-rw-r--r--lib/private/SpeechToText/SpeechToTextManager.php15
-rw-r--r--lib/private/Streamer.php7
-rw-r--r--lib/private/SystemTag/ManagerFactory.php5
-rw-r--r--lib/private/SystemTag/SystemTagManager.php49
-rw-r--r--lib/private/SystemTag/SystemTagObjectMapper.php28
-rw-r--r--lib/private/TemplateLayout.php6
-rw-r--r--lib/private/TextProcessing/Db/Task.php112
-rw-r--r--lib/private/TextProcessing/Db/TaskMapper.php118
-rw-r--r--lib/private/TextProcessing/Manager.php256
-rw-r--r--lib/private/TextProcessing/RemoveOldTasksBackgroundJob.php59
-rw-r--r--lib/private/TextProcessing/TaskBackgroundJob.php63
-rw-r--r--lib/private/Translation/TranslationManager.php25
-rw-r--r--lib/private/Updater/ChangesCheck.php1
-rw-r--r--lib/private/Updater/VersionCheck.php49
-rw-r--r--lib/private/User/Database.php2
-rw-r--r--lib/private/User/DisplayNameCache.php6
-rw-r--r--lib/private/User/Manager.php8
-rw-r--r--lib/private/User/Session.php14
-rw-r--r--lib/private/User/User.php77
-rw-r--r--lib/private/legacy/OC_App.php14
-rw-r--r--lib/private/legacy/OC_Files.php6
-rw-r--r--lib/private/legacy/OC_Helper.php50
-rw-r--r--lib/private/legacy/OC_Image.php2
-rw-r--r--lib/private/legacy/OC_Template.php42
-rw-r--r--lib/private/legacy/OC_Util.php43
-rw-r--r--lib/private/legacy/template/functions.php5
-rw-r--r--lib/public/Accounts/UserUpdatedEvent.php58
-rw-r--r--lib/public/AppFramework/Bootstrap/IRegistrationContext.php11
-rw-r--r--lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php37
-rw-r--r--lib/public/AppFramework/Http/ContentSecurityPolicy.php2
-rw-r--r--lib/public/AppFramework/Http/DataDisplayResponse.php15
-rw-r--r--lib/public/AppFramework/Http/DataDownloadResponse.php15
-rw-r--r--lib/public/AppFramework/Http/DataResponse.php26
-rw-r--r--lib/public/AppFramework/Http/DownloadResponse.php15
-rw-r--r--lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php18
-rw-r--r--lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php52
-rw-r--r--lib/public/AppFramework/Http/FileDisplayResponse.php21
-rw-r--r--lib/public/AppFramework/Http/JSONResponse.php23
-rw-r--r--lib/public/AppFramework/Http/NotFoundResponse.php13
-rw-r--r--lib/public/AppFramework/Http/RedirectResponse.php11
-rw-r--r--lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php11
-rw-r--r--lib/public/AppFramework/Http/Response.php70
-rw-r--r--lib/public/AppFramework/Http/StandaloneTemplateResponse.php4
-rw-r--r--lib/public/AppFramework/Http/StreamResponse.php10
-rw-r--r--lib/public/AppFramework/Http/StrictContentSecurityPolicy.php2
-rw-r--r--lib/public/AppFramework/Http/Template/PublicTemplateResponse.php11
-rw-r--r--lib/public/AppFramework/Http/TemplateResponse.php23
-rw-r--r--lib/public/AppFramework/Http/TextPlainResponse.php12
-rw-r--r--lib/public/AppFramework/Http/TooManyRequestsResponse.php12
-rw-r--r--lib/public/AppFramework/Http/ZipResponse.php11
-rw-r--r--lib/public/AppFramework/OCS/OCSPreconditionFailedException.php44
-rw-r--r--lib/public/AppFramework/Utility/ITimeFactory.php2
-rw-r--r--lib/public/Authentication/TwoFactorAuth/IProvider.php11
-rw-r--r--lib/public/Authentication/TwoFactorAuth/RegistryEvent.php9
-rw-r--r--lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengeFailed.php58
-rw-r--r--lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengePassed.php58
-rw-r--r--lib/public/Authentication/TwoFactorAuth/TwoFactorProviderDisabled.php2
-rw-r--r--lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserDisabled.php2
-rw-r--r--lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserEnabled.php2
-rw-r--r--lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserRegistered.php58
-rw-r--r--lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserUnregistered.php58
-rw-r--r--lib/public/Authentication/TwoFactorAuth/TwoFactorProviderUserDeleted.php59
-rw-r--r--lib/public/BackgroundJob/Job.php5
-rw-r--r--lib/public/BackgroundJob/TimedJob.php9
-rw-r--r--lib/public/Capabilities/ICapability.php21
-rw-r--r--lib/public/Collaboration/Reference/IReference.php7
-rw-r--r--lib/public/Collaboration/Reference/Reference.php6
-rw-r--r--lib/public/Comments/CommentsEntityEvent.php10
-rw-r--r--lib/public/Common/Exception/NotFoundException.php41
-rw-r--r--lib/public/Contacts/IManager.php17
-rw-r--r--lib/public/DB/Events/AddMissingColumnsEvent.php60
-rw-r--r--lib/public/DB/Events/AddMissingIndicesEvent.php78
-rw-r--r--lib/public/DB/Events/AddMissingPrimaryKeyEvent.php60
-rw-r--r--lib/public/DB/QueryBuilder/IQueryBuilder.php11
-rw-r--r--lib/public/Dashboard/IAPIWidgetV2.php43
-rw-r--r--lib/public/Dashboard/IManager.php2
-rw-r--r--lib/public/Dashboard/IReloadableWidget.php41
-rw-r--r--lib/public/Dashboard/Model/WidgetItem.php27
-rw-r--r--lib/public/Dashboard/Model/WidgetItems.php100
-rw-r--r--lib/public/Federation/ICloudFederationProvider.php2
-rw-r--r--lib/public/Federation/ICloudIdManager.php10
-rw-r--r--lib/public/Files/ConnectionLostException.php33
-rw-r--r--lib/public/Files/DavUtil.php29
-rw-r--r--lib/public/Files/Events/NodeAddedToFavorite.php66
-rw-r--r--lib/public/Files/Events/NodeRemovedFromFavorite.php66
-rw-r--r--lib/public/Files/FileInfo.php9
-rw-r--r--lib/public/Files/Folder.php10
-rw-r--r--lib/public/Files/IHomeStorage.php8
-rw-r--r--lib/public/Files/IMimeTypeDetector.php6
-rw-r--r--lib/public/Files/Mount/IMovableMount.php48
-rw-r--r--lib/public/Files/Template/TemplateFileCreator.php4
-rw-r--r--lib/public/Group/Backend/ABackend.php28
-rw-r--r--lib/public/Group/Backend/IBatchMethodsBackend.php61
-rw-r--r--lib/public/Group/Backend/IGroupDetailsBackend.php8
-rw-r--r--lib/public/GroupInterface.php6
-rw-r--r--lib/public/Http/Client/IClient.php183
-rw-r--r--lib/public/Http/Client/IPromise.php100
-rw-r--r--lib/public/IAppConfig.php2
-rw-r--r--lib/public/IDBConnection.php42
-rw-r--r--lib/public/IPreview.php6
-rw-r--r--lib/public/IRequest.php24
-rw-r--r--lib/public/IServerContainer.php10
-rw-r--r--lib/public/OCM/Exceptions/OCMArgumentException.php34
-rw-r--r--lib/public/OCM/Exceptions/OCMProviderException.php34
-rw-r--r--lib/public/OCM/IOCMDiscoveryService.php48
-rw-r--r--lib/public/OCM/IOCMProvider.php143
-rw-r--r--lib/public/OCM/IOCMResource.php99
-rw-r--r--lib/public/Preview/BeforePreviewFetchedEvent.php45
-rw-r--r--lib/public/Preview/IMimeIconProvider.php37
-rw-r--r--lib/public/Security/Bruteforce/IThrottler.php29
-rw-r--r--lib/public/Share/Events/BeforeShareCreatedEvent.php66
-rw-r--r--lib/public/Share/Events/BeforeShareDeletedEvent.php50
-rw-r--r--lib/public/Share/Events/ShareAcceptedEvent.php50
-rw-r--r--lib/public/Share/Events/ShareDeletedFromSelfEvent.php50
-rw-r--r--lib/public/SpeechToText/ISpeechToTextManager.php6
-rw-r--r--lib/public/SystemTag/ISystemTagManager.php5
-rw-r--r--lib/public/SystemTag/SystemTagsEntityEvent.php12
-rw-r--r--lib/public/TextProcessing/Events/AbstractTextProcessingEvent.php51
-rw-r--r--lib/public/TextProcessing/Events/TaskFailedEvent.php30
-rw-r--r--lib/public/TextProcessing/Events/TaskSuccessfulEvent.php9
-rw-r--r--lib/public/TextProcessing/FreePromptTaskType.php66
-rw-r--r--lib/public/TextProcessing/HeadlineTaskType.php66
-rw-r--r--lib/public/TextProcessing/IManager.php110
-rw-r--r--lib/public/TextProcessing/IProvider.php62
-rw-r--r--lib/public/TextProcessing/ITaskType.php49
-rw-r--r--lib/public/TextProcessing/SummaryTaskType.php66
-rw-r--r--lib/public/TextProcessing/Task.php221
-rw-r--r--lib/public/TextProcessing/TopicsTaskType.php66
-rw-r--r--lib/public/Translation/ITranslationManager.php6
-rw-r--r--lib/public/Translation/LanguageTuple.php1
-rw-r--r--lib/public/User/Backend/IProvideEnabledStateBackend.php56
-rw-r--r--lib/public/User/Events/UserFirstTimeLoggedInEvent.php50
-rw-r--r--lib/public/Util.php58
-rw-r--r--lib/public/WorkflowEngine/IManager.php15
374 files changed, 9043 insertions, 3249 deletions
diff --git a/lib/base.php b/lib/base.php
index 09ec5be441b..26e88979a48 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -67,7 +67,6 @@ declare(strict_types=1);
*/
use OC\Encryption\HookManager;
-use OC\EventDispatcher\SymfonyAdapter;
use OC\Share20\Hooks;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Group\Events\UserRemovedEvent;
@@ -75,6 +74,7 @@ use OCP\ILogger;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserSession;
+use OCP\Security\Bruteforce\IThrottler;
use OCP\Server;
use OCP\Share;
use OCP\User\Events\UserChangedEvent;
@@ -114,8 +114,6 @@ class OC {
public static string $configDir;
- public static int $VERSION_MTIME = 0;
-
/**
* requested app
*/
@@ -588,6 +586,11 @@ class OC {
}
public static function init(): void {
+ // prevent any XML processing from loading external entities
+ libxml_set_external_entity_loader(static function () {
+ return null;
+ });
+
// calculate the root directories
OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4));
@@ -605,10 +608,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();
@@ -867,7 +869,7 @@ class OC {
// reset brute force delay for this IP address and username
$uid = $userSession->getUser()->getUID();
$request = Server::get(IRequest::class);
- $throttler = Server::get(\OC\Security\Bruteforce\Throttler::class);
+ $throttler = Server::get(IThrottler::class);
$throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]);
}
@@ -934,7 +936,7 @@ class OC {
}
private static function registerResourceCollectionHooks(): void {
- \OC\Collaboration\Resources\Listener::register(Server::get(SymfonyAdapter::class), Server::get(IEventDispatcher::class));
+ \OC\Collaboration\Resources\Listener::register(Server::get(IEventDispatcher::class));
}
private static function registerFileReferenceEventListener(): void {
@@ -1133,6 +1135,9 @@ class OC {
if (OC_User::handleApacheAuth()) {
return true;
}
+ if (self::tryAppAPILogin($request)) {
+ return true;
+ }
if ($userSession->tryTokenLogin($request)) {
return true;
}
@@ -1142,7 +1147,7 @@ class OC {
&& $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
return true;
}
- if ($userSession->tryBasicAuthLogin($request, Server::get(\OC\Security\Bruteforce\Throttler::class))) {
+ if ($userSession->tryBasicAuthLogin($request, Server::get(IThrottler::class))) {
return true;
}
return false;
@@ -1170,6 +1175,22 @@ class OC {
}
}
}
+
+ protected static function tryAppAPILogin(OCP\IRequest $request): bool {
+ $appManager = Server::get(OCP\App\IAppManager::class);
+ if (!$request->getHeader('AUTHORIZATION-APP-API')) {
+ return false;
+ }
+ if (!$appManager->isInstalled('app_api')) {
+ return false;
+ }
+ try {
+ $appAPIService = Server::get(OCA\AppAPI\Service\AppAPIService::class);
+ return $appAPIService->validateExAppRequestToNC($request);
+ } catch (\Psr\Container\NotFoundExceptionInterface|\Psr\Container\ContainerExceptionInterface $e) {
+ return false;
+ }
+ }
}
OC::init();
diff --git a/lib/composer/composer/ClassLoader.php b/lib/composer/composer/ClassLoader.php
index a72151c77c8..7824d8f7eaf 100644
--- a/lib/composer/composer/ClassLoader.php
+++ b/lib/composer/composer/ClassLoader.php
@@ -45,35 +45,34 @@ class ClassLoader
/** @var \Closure(string):void */
private static $includeFile;
- /** @var ?string */
+ /** @var string|null */
private $vendorDir;
// PSR-4
/**
- * @var array[]
- * @psalm-var array<string, array<string, int>>
+ * @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
- * @var array[]
- * @psalm-var array<string, array<int, string>>
+ * @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
- * @var array[]
- * @psalm-var array<string, string>
+ * @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
- * @var array[]
- * @psalm-var array<string, array<string, string[]>>
+ * List of PSR-0 prefixes
+ *
+ * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
+ *
+ * @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
- * @var array[]
- * @psalm-var array<string, string>
+ * @var list<string>
*/
private $fallbackDirsPsr0 = array();
@@ -81,8 +80,7 @@ class ClassLoader
private $useIncludePath = false;
/**
- * @var string[]
- * @psalm-var array<string, string>
+ * @var array<string, string>
*/
private $classMap = array();
@@ -90,21 +88,20 @@ class ClassLoader
private $classMapAuthoritative = false;
/**
- * @var bool[]
- * @psalm-var array<string, bool>
+ * @var array<string, bool>
*/
private $missingClasses = array();
- /** @var ?string */
+ /** @var string|null */
private $apcuPrefix;
/**
- * @var self[]
+ * @var array<string, self>
*/
private static $registeredLoaders = array();
/**
- * @param ?string $vendorDir
+ * @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
@@ -113,7 +110,7 @@ class ClassLoader
}
/**
- * @return string[]
+ * @return array<string, list<string>>
*/
public function getPrefixes()
{
@@ -125,8 +122,7 @@ class ClassLoader
}
/**
- * @return array[]
- * @psalm-return array<string, array<int, string>>
+ * @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
@@ -134,8 +130,7 @@ class ClassLoader
}
/**
- * @return array[]
- * @psalm-return array<string, string>
+ * @return list<string>
*/
public function getFallbackDirs()
{
@@ -143,8 +138,7 @@ class ClassLoader
}
/**
- * @return array[]
- * @psalm-return array<string, string>
+ * @return list<string>
*/
public function getFallbackDirsPsr4()
{
@@ -152,8 +146,7 @@ class ClassLoader
}
/**
- * @return string[] Array of classname => path
- * @psalm-return array<string, string>
+ * @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
@@ -161,8 +154,7 @@ class ClassLoader
}
/**
- * @param string[] $classMap Class to filename map
- * @psalm-param array<string, string> $classMap
+ * @param array<string, string> $classMap Class to filename map
*
* @return void
*/
@@ -179,24 +171,25 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
- * @param string $prefix The prefix
- * @param string[]|string $paths The PSR-0 root directories
- * @param bool $prepend Whether to prepend the directories
+ * @param string $prefix The prefix
+ * @param list<string>|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
+ $paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
- (array) $paths,
+ $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
- (array) $paths
+ $paths
);
}
@@ -205,19 +198,19 @@ class ClassLoader
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
- $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+ $this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
- (array) $paths,
+ $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
- (array) $paths
+ $paths
);
}
}
@@ -226,9 +219,9 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
- * @param string $prefix The prefix/namespace, with trailing '\\'
- * @param string[]|string $paths The PSR-4 base directories
- * @param bool $prepend Whether to prepend the directories
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param list<string>|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
@@ -236,17 +229,18 @@ class ClassLoader
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
+ $paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
- (array) $paths,
+ $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
- (array) $paths
+ $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -256,18 +250,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
- $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ $this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
- (array) $paths,
+ $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
- (array) $paths
+ $paths
);
}
}
@@ -276,8 +270,8 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
- * @param string $prefix The prefix
- * @param string[]|string $paths The PSR-0 base directories
+ * @param string $prefix The prefix
+ * @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
@@ -294,8 +288,8 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
- * @param string $prefix The prefix/namespace, with trailing '\\'
- * @param string[]|string $paths The PSR-4 base directories
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
@@ -481,9 +475,9 @@ class ClassLoader
}
/**
- * Returns the currently registered loaders indexed by their corresponding vendor directories.
+ * Returns the currently registered loaders keyed by their corresponding vendor directories.
*
- * @return self[]
+ * @return array<string, self>
*/
public static function getRegisteredLoaders()
{
diff --git a/lib/composer/composer/LICENSE b/lib/composer/composer/LICENSE
index 62ecfd8d004..f27399a042d 100644
--- a/lib/composer/composer/LICENSE
+++ b/lib/composer/composer/LICENSE
@@ -1,3 +1,4 @@
+
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -17,3 +18,4 @@ 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 0be1c83f83d..c2d9d153673 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -12,6 +12,7 @@ return array(
'OCP\\Accounts\\IAccountProperty' => $baseDir . '/lib/public/Accounts/IAccountProperty.php',
'OCP\\Accounts\\IAccountPropertyCollection' => $baseDir . '/lib/public/Accounts/IAccountPropertyCollection.php',
'OCP\\Accounts\\PropertyDoesNotExistException' => $baseDir . '/lib/public/Accounts/PropertyDoesNotExistException.php',
+ 'OCP\\Accounts\\UserUpdatedEvent' => $baseDir . '/lib/public/Accounts/UserUpdatedEvent.php',
'OCP\\Activity\\ActivitySettings' => $baseDir . '/lib/public/Activity/ActivitySettings.php',
'OCP\\Activity\\IConsumer' => $baseDir . '/lib/public/Activity/IConsumer.php',
'OCP\\Activity\\IEvent' => $baseDir . '/lib/public/Activity/IEvent.php',
@@ -40,6 +41,7 @@ return array(
'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\\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\\PasswordConfirmationRequired' => $baseDir . '/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php',
@@ -55,6 +57,7 @@ return array(
'OCP\\AppFramework\\Http\\DownloadResponse' => $baseDir . '/lib/public/AppFramework/Http/DownloadResponse.php',
'OCP\\AppFramework\\Http\\EmptyContentSecurityPolicy' => $baseDir . '/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php',
'OCP\\AppFramework\\Http\\EmptyFeaturePolicy' => $baseDir . '/lib/public/AppFramework/Http/EmptyFeaturePolicy.php',
+ 'OCP\\AppFramework\\Http\\Events\\BeforeLoginTemplateRenderedEvent' => $baseDir . '/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php',
'OCP\\AppFramework\\Http\\Events\\BeforeTemplateRenderedEvent' => $baseDir . '/lib/public/AppFramework/Http/Events/BeforeTemplateRenderedEvent.php',
'OCP\\AppFramework\\Http\\FeaturePolicy' => $baseDir . '/lib/public/AppFramework/Http/FeaturePolicy.php',
'OCP\\AppFramework\\Http\\FileDisplayResponse' => $baseDir . '/lib/public/AppFramework/Http/FileDisplayResponse.php',
@@ -86,6 +89,7 @@ return array(
'OCP\\AppFramework\\OCS\\OCSException' => $baseDir . '/lib/public/AppFramework/OCS/OCSException.php',
'OCP\\AppFramework\\OCS\\OCSForbiddenException' => $baseDir . '/lib/public/AppFramework/OCS/OCSForbiddenException.php',
'OCP\\AppFramework\\OCS\\OCSNotFoundException' => $baseDir . '/lib/public/AppFramework/OCS/OCSNotFoundException.php',
+ 'OCP\\AppFramework\\OCS\\OCSPreconditionFailedException' => $baseDir . '/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php',
'OCP\\AppFramework\\PublicShareController' => $baseDir . '/lib/public/AppFramework/PublicShareController.php',
'OCP\\AppFramework\\QueryException' => $baseDir . '/lib/public/AppFramework/QueryException.php',
'OCP\\AppFramework\\Services\\IAppConfig' => $baseDir . '/lib/public/AppFramework/Services/IAppConfig.php',
@@ -122,9 +126,14 @@ return array(
'OCP\\Authentication\\TwoFactorAuth\\IRegistry' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IRegistry.php',
'OCP\\Authentication\\TwoFactorAuth\\RegistryEvent' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorException' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorException.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderChallengeFailed' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengeFailed.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderChallengePassed' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengePassed.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderDisabled' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderDisabled.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderForUserDisabled' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserDisabled.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderForUserEnabled' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserEnabled.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderForUserRegistered' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserRegistered.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderForUserUnregistered' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserUnregistered.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderUserDeleted' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderUserDeleted.php',
'OCP\\AutoloadNotAllowedException' => $baseDir . '/lib/public/AutoloadNotAllowedException.php',
'OCP\\BackgroundJob\\IJob' => $baseDir . '/lib/public/BackgroundJob/IJob.php',
'OCP\\BackgroundJob\\IJobList' => $baseDir . '/lib/public/BackgroundJob/IJobList.php',
@@ -190,6 +199,7 @@ return array(
'OCP\\Comments\\IllegalIDChangeException' => $baseDir . '/lib/public/Comments/IllegalIDChangeException.php',
'OCP\\Comments\\MessageTooLongException' => $baseDir . '/lib/public/Comments/MessageTooLongException.php',
'OCP\\Comments\\NotFoundException' => $baseDir . '/lib/public/Comments/NotFoundException.php',
+ 'OCP\\Common\\Exception\\NotFoundException' => $baseDir . '/lib/public/Common/Exception/NotFoundException.php',
'OCP\\Config\\BeforePreferenceDeletedEvent' => $baseDir . '/lib/public/Config/BeforePreferenceDeletedEvent.php',
'OCP\\Config\\BeforePreferenceSetEvent' => $baseDir . '/lib/public/Config/BeforePreferenceSetEvent.php',
'OCP\\Console\\ConsoleEvent' => $baseDir . '/lib/public/Console/ConsoleEvent.php',
@@ -202,6 +212,9 @@ return array(
'OCP\\Contacts\\ContactsMenu\\IProvider' => $baseDir . '/lib/public/Contacts/ContactsMenu/IProvider.php',
'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => $baseDir . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php',
'OCP\\Contacts\\IManager' => $baseDir . '/lib/public/Contacts/IManager.php',
+ 'OCP\\DB\\Events\\AddMissingColumnsEvent' => $baseDir . '/lib/public/DB/Events/AddMissingColumnsEvent.php',
+ 'OCP\\DB\\Events\\AddMissingIndicesEvent' => $baseDir . '/lib/public/DB/Events/AddMissingIndicesEvent.php',
+ 'OCP\\DB\\Events\\AddMissingPrimaryKeyEvent' => $baseDir . '/lib/public/DB/Events/AddMissingPrimaryKeyEvent.php',
'OCP\\DB\\Exception' => $baseDir . '/lib/public/DB/Exception.php',
'OCP\\DB\\IPreparedStatement' => $baseDir . '/lib/public/DB/IPreparedStatement.php',
'OCP\\DB\\IResult' => $baseDir . '/lib/public/DB/IResult.php',
@@ -215,14 +228,17 @@ return array(
'OCP\\DB\\QueryBuilder\\IQueryFunction' => $baseDir . '/lib/public/DB/QueryBuilder/IQueryFunction.php',
'OCP\\DB\\Types' => $baseDir . '/lib/public/DB/Types.php',
'OCP\\Dashboard\\IAPIWidget' => $baseDir . '/lib/public/Dashboard/IAPIWidget.php',
+ 'OCP\\Dashboard\\IAPIWidgetV2' => $baseDir . '/lib/public/Dashboard/IAPIWidgetV2.php',
'OCP\\Dashboard\\IButtonWidget' => $baseDir . '/lib/public/Dashboard/IButtonWidget.php',
'OCP\\Dashboard\\IConditionalWidget' => $baseDir . '/lib/public/Dashboard/IConditionalWidget.php',
'OCP\\Dashboard\\IIconWidget' => $baseDir . '/lib/public/Dashboard/IIconWidget.php',
'OCP\\Dashboard\\IManager' => $baseDir . '/lib/public/Dashboard/IManager.php',
'OCP\\Dashboard\\IOptionWidget' => $baseDir . '/lib/public/Dashboard/IOptionWidget.php',
+ 'OCP\\Dashboard\\IReloadableWidget' => $baseDir . '/lib/public/Dashboard/IReloadableWidget.php',
'OCP\\Dashboard\\IWidget' => $baseDir . '/lib/public/Dashboard/IWidget.php',
'OCP\\Dashboard\\Model\\WidgetButton' => $baseDir . '/lib/public/Dashboard/Model/WidgetButton.php',
'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',
@@ -286,6 +302,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',
@@ -298,7 +315,9 @@ return array(
'OCP\\Files\\Events\\FolderScannedEvent' => $baseDir . '/lib/public/Files/Events/FolderScannedEvent.php',
'OCP\\Files\\Events\\InvalidateMountCacheEvent' => $baseDir . '/lib/public/Files/Events/InvalidateMountCacheEvent.php',
'OCP\\Files\\Events\\NodeAddedToCache' => $baseDir . '/lib/public/Files/Events/NodeAddedToCache.php',
+ 'OCP\\Files\\Events\\NodeAddedToFavorite' => $baseDir . '/lib/public/Files/Events/NodeAddedToFavorite.php',
'OCP\\Files\\Events\\NodeRemovedFromCache' => $baseDir . '/lib/public/Files/Events/NodeRemovedFromCache.php',
+ 'OCP\\Files\\Events\\NodeRemovedFromFavorite' => $baseDir . '/lib/public/Files/Events/NodeRemovedFromFavorite.php',
'OCP\\Files\\Events\\Node\\AbstractNodeEvent' => $baseDir . '/lib/public/Files/Events/Node/AbstractNodeEvent.php',
'OCP\\Files\\Events\\Node\\AbstractNodesEvent' => $baseDir . '/lib/public/Files/Events/Node/AbstractNodesEvent.php',
'OCP\\Files\\Events\\Node\\BeforeNodeCopiedEvent' => $baseDir . '/lib/public/Files/Events/Node/BeforeNodeCopiedEvent.php',
@@ -339,6 +358,7 @@ return array(
'OCP\\Files\\Lock\\OwnerLockedException' => $baseDir . '/lib/public/Files/Lock/OwnerLockedException.php',
'OCP\\Files\\Mount\\IMountManager' => $baseDir . '/lib/public/Files/Mount/IMountManager.php',
'OCP\\Files\\Mount\\IMountPoint' => $baseDir . '/lib/public/Files/Mount/IMountPoint.php',
+ 'OCP\\Files\\Mount\\IMovableMount' => $baseDir . '/lib/public/Files/Mount/IMovableMount.php',
'OCP\\Files\\Mount\\ISystemMountPoint' => $baseDir . '/lib/public/Files/Mount/ISystemMountPoint.php',
'OCP\\Files\\Node' => $baseDir . '/lib/public/Files/Node.php',
'OCP\\Files\\NotEnoughSpaceException' => $baseDir . '/lib/public/Files/NotEnoughSpaceException.php',
@@ -402,6 +422,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',
@@ -430,6 +451,7 @@ return array(
'OCP\\HintException' => $baseDir . '/lib/public/HintException.php',
'OCP\\Http\\Client\\IClient' => $baseDir . '/lib/public/Http/Client/IClient.php',
'OCP\\Http\\Client\\IClientService' => $baseDir . '/lib/public/Http/Client/IClientService.php',
+ 'OCP\\Http\\Client\\IPromise' => $baseDir . '/lib/public/Http/Client/IPromise.php',
'OCP\\Http\\Client\\IResponse' => $baseDir . '/lib/public/Http/Client/IResponse.php',
'OCP\\Http\\Client\\LocalServerException' => $baseDir . '/lib/public/Http/Client/LocalServerException.php',
'OCP\\Http\\WellKnown\\GenericResponse' => $baseDir . '/lib/public/Http/WellKnown/GenericResponse.php',
@@ -514,9 +536,15 @@ 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\\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',
+ 'OCP\\Preview\\IMimeIconProvider' => $baseDir . '/lib/public/Preview/IMimeIconProvider.php',
'OCP\\Preview\\IProvider' => $baseDir . '/lib/public/Preview/IProvider.php',
'OCP\\Preview\\IProviderV2' => $baseDir . '/lib/public/Preview/IProviderV2.php',
'OCP\\Preview\\IVersionedPreviewFile' => $baseDir . '/lib/public/Preview/IVersionedPreviewFile.php',
@@ -570,8 +598,12 @@ return array(
'OCP\\Settings\\ISettings' => $baseDir . '/lib/public/Settings/ISettings.php',
'OCP\\Settings\\ISubAdminSettings' => $baseDir . '/lib/public/Settings/ISubAdminSettings.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',
+ 'OCP\\Share\\Events\\ShareAcceptedEvent' => $baseDir . '/lib/public/Share/Events/ShareAcceptedEvent.php',
'OCP\\Share\\Events\\ShareCreatedEvent' => $baseDir . '/lib/public/Share/Events/ShareCreatedEvent.php',
'OCP\\Share\\Events\\ShareDeletedEvent' => $baseDir . '/lib/public/Share/Events/ShareDeletedEvent.php',
+ 'OCP\\Share\\Events\\ShareDeletedFromSelfEvent' => $baseDir . '/lib/public/Share/Events/ShareDeletedFromSelfEvent.php',
'OCP\\Share\\Events\\VerifyMountPointEvent' => $baseDir . '/lib/public/Share/Events/VerifyMountPointEvent.php',
'OCP\\Share\\Exceptions\\AlreadySharedException' => $baseDir . '/lib/public/Share/Exceptions/AlreadySharedException.php',
'OCP\\Share\\Exceptions\\GenericShareException' => $baseDir . '/lib/public/Share/Exceptions/GenericShareException.php',
@@ -617,6 +649,17 @@ return array(
'OCP\\Talk\\IConversationOptions' => $baseDir . '/lib/public/Talk/IConversationOptions.php',
'OCP\\Talk\\ITalkBackend' => $baseDir . '/lib/public/Talk/ITalkBackend.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\\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\\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\\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',
@@ -643,6 +686,7 @@ return array(
'OCP\\User\\Backend\\IGetRealUIDBackend' => $baseDir . '/lib/public/User/Backend/IGetRealUIDBackend.php',
'OCP\\User\\Backend\\IPasswordConfirmationBackend' => $baseDir . '/lib/public/User/Backend/IPasswordConfirmationBackend.php',
'OCP\\User\\Backend\\IProvideAvatarBackend' => $baseDir . '/lib/public/User/Backend/IProvideAvatarBackend.php',
+ 'OCP\\User\\Backend\\IProvideEnabledStateBackend' => $baseDir . '/lib/public/User/Backend/IProvideEnabledStateBackend.php',
'OCP\\User\\Backend\\ISearchKnownUsersBackend' => $baseDir . '/lib/public/User/Backend/ISearchKnownUsersBackend.php',
'OCP\\User\\Backend\\ISetDisplayNameBackend' => $baseDir . '/lib/public/User/Backend/ISetDisplayNameBackend.php',
'OCP\\User\\Backend\\ISetPasswordBackend' => $baseDir . '/lib/public/User/Backend/ISetPasswordBackend.php',
@@ -657,6 +701,7 @@ return array(
'OCP\\User\\Events\\UserChangedEvent' => $baseDir . '/lib/public/User/Events/UserChangedEvent.php',
'OCP\\User\\Events\\UserCreatedEvent' => $baseDir . '/lib/public/User/Events/UserCreatedEvent.php',
'OCP\\User\\Events\\UserDeletedEvent' => $baseDir . '/lib/public/User/Events/UserDeletedEvent.php',
+ 'OCP\\User\\Events\\UserFirstTimeLoggedInEvent' => $baseDir . '/lib/public/User/Events/UserFirstTimeLoggedInEvent.php',
'OCP\\User\\Events\\UserLiveStatusEvent' => $baseDir . '/lib/public/User/Events/UserLiveStatusEvent.php',
'OCP\\User\\Events\\UserLoggedInEvent' => $baseDir . '/lib/public/User/Events/UserLoggedInEvent.php',
'OCP\\User\\Events\\UserLoggedInWithCookieEvent' => $baseDir . '/lib/public/User/Events/UserLoggedInWithCookieEvent.php',
@@ -986,10 +1031,11 @@ return array(
'OC\\Core\\Command\\Preview\\Generate' => $baseDir . '/core/Command/Preview/Generate.php',
'OC\\Core\\Command\\Preview\\Repair' => $baseDir . '/core/Command/Preview/Repair.php',
'OC\\Core\\Command\\Preview\\ResetRenderedTexts' => $baseDir . '/core/Command/Preview/ResetRenderedTexts.php',
+ 'OC\\Core\\Command\\Security\\BruteforceAttempts' => $baseDir . '/core/Command/Security/BruteforceAttempts.php',
+ 'OC\\Core\\Command\\Security\\BruteforceResetAttempts' => $baseDir . '/core/Command/Security/BruteforceResetAttempts.php',
'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\\Security\\ResetBruteforceAttempts' => $baseDir . '/core/Command/Security/ResetBruteforceAttempts.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',
@@ -1003,7 +1049,9 @@ return array(
'OC\\Core\\Command\\TwoFactorAuth\\State' => $baseDir . '/core/Command/TwoFactorAuth/State.php',
'OC\\Core\\Command\\Upgrade' => $baseDir . '/core/Command/Upgrade.php',
'OC\\Core\\Command\\User\\Add' => $baseDir . '/core/Command/User/Add.php',
- 'OC\\Core\\Command\\User\\AddAppPassword' => $baseDir . '/core/Command/User/AddAppPassword.php',
+ 'OC\\Core\\Command\\User\\AuthTokens\\Add' => $baseDir . '/core/Command/User/AuthTokens/Add.php',
+ 'OC\\Core\\Command\\User\\AuthTokens\\Delete' => $baseDir . '/core/Command/User/AuthTokens/Delete.php',
+ 'OC\\Core\\Command\\User\\AuthTokens\\ListCommand' => $baseDir . '/core/Command/User/AuthTokens/ListCommand.php',
'OC\\Core\\Command\\User\\Delete' => $baseDir . '/core/Command/User/Delete.php',
'OC\\Core\\Command\\User\\Disable' => $baseDir . '/core/Command/User/Disable.php',
'OC\\Core\\Command\\User\\Enable' => $baseDir . '/core/Command/User/Enable.php',
@@ -1013,6 +1061,7 @@ return array(
'OC\\Core\\Command\\User\\Report' => $baseDir . '/core/Command/User/Report.php',
'OC\\Core\\Command\\User\\ResetPassword' => $baseDir . '/core/Command/User/ResetPassword.php',
'OC\\Core\\Command\\User\\Setting' => $baseDir . '/core/Command/User/Setting.php',
+ 'OC\\Core\\Command\\User\\SyncAccountDataCommand' => $baseDir . '/core/Command/User/SyncAccountDataCommand.php',
'OC\\Core\\Controller\\AppPasswordController' => $baseDir . '/core/Controller/AppPasswordController.php',
'OC\\Core\\Controller\\AutoCompleteController' => $baseDir . '/core/Controller/AutoCompleteController.php',
'OC\\Core\\Controller\\AvatarController' => $baseDir . '/core/Controller/AvatarController.php',
@@ -1030,6 +1079,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',
@@ -1039,6 +1089,7 @@ 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\\TextProcessingApiController' => $baseDir . '/core/Controller/TextProcessingApiController.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',
@@ -1117,6 +1168,9 @@ return array(
'OC\\Core\\Migrations\\Version27000Date20220613163520' => $baseDir . '/core/Migrations/Version27000Date20220613163520.php',
'OC\\Core\\Migrations\\Version27000Date20230309104325' => $baseDir . '/core/Migrations/Version27000Date20230309104325.php',
'OC\\Core\\Migrations\\Version27000Date20230309104802' => $baseDir . '/core/Migrations/Version27000Date20230309104802.php',
+ '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\\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',
@@ -1195,9 +1249,7 @@ return array(
'OC\\Encryption\\Update' => $baseDir . '/lib/private/Encryption/Update.php',
'OC\\Encryption\\Util' => $baseDir . '/lib/private/Encryption/Util.php',
'OC\\EventDispatcher\\EventDispatcher' => $baseDir . '/lib/private/EventDispatcher/EventDispatcher.php',
- 'OC\\EventDispatcher\\GenericEventWrapper' => $baseDir . '/lib/private/EventDispatcher/GenericEventWrapper.php',
'OC\\EventDispatcher\\ServiceEventListener' => $baseDir . '/lib/private/EventDispatcher/ServiceEventListener.php',
- 'OC\\EventDispatcher\\SymfonyAdapter' => $baseDir . '/lib/private/EventDispatcher/SymfonyAdapter.php',
'OC\\EventSourceFactory' => $baseDir . '/lib/private/EventSourceFactory.php',
'OC\\Federation\\CloudFederationFactory' => $baseDir . '/lib/private/Federation/CloudFederationFactory.php',
'OC\\Federation\\CloudFederationNotification' => $baseDir . '/lib/private/Federation/CloudFederationNotification.php',
@@ -1336,6 +1388,7 @@ return array(
'OC\\Http\\Client\\Client' => $baseDir . '/lib/private/Http/Client/Client.php',
'OC\\Http\\Client\\ClientService' => $baseDir . '/lib/private/Http/Client/ClientService.php',
'OC\\Http\\Client\\DnsPinMiddleware' => $baseDir . '/lib/private/Http/Client/DnsPinMiddleware.php',
+ 'OC\\Http\\Client\\GuzzlePromiseAdapter' => $baseDir . '/lib/private/Http/Client/GuzzlePromiseAdapter.php',
'OC\\Http\\Client\\NegativeDnsCache' => $baseDir . '/lib/private/Http/Client/NegativeDnsCache.php',
'OC\\Http\\Client\\Response' => $baseDir . '/lib/private/Http/Client/Response.php',
'OC\\Http\\CookieHelper' => $baseDir . '/lib/private/Http/CookieHelper.php',
@@ -1416,6 +1469,9 @@ 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',
@@ -1443,6 +1499,7 @@ return array(
'OC\\Preview\\MSOffice2007' => $baseDir . '/lib/private/Preview/MSOffice2007.php',
'OC\\Preview\\MSOfficeDoc' => $baseDir . '/lib/private/Preview/MSOfficeDoc.php',
'OC\\Preview\\MarkDown' => $baseDir . '/lib/private/Preview/MarkDown.php',
+ 'OC\\Preview\\MimeIconProvider' => $baseDir . '/lib/private/Preview/MimeIconProvider.php',
'OC\\Preview\\Movie' => $baseDir . '/lib/private/Preview/Movie.php',
'OC\\Preview\\Office' => $baseDir . '/lib/private/Preview/Office.php',
'OC\\Preview\\OpenDocument' => $baseDir . '/lib/private/Preview/OpenDocument.php',
@@ -1489,6 +1546,7 @@ return array(
'OC\\RepairException' => $baseDir . '/lib/private/RepairException.php',
'OC\\Repair\\AddBruteForceCleanupJob' => $baseDir . '/lib/private/Repair/AddBruteForceCleanupJob.php',
'OC\\Repair\\AddCleanupUpdaterBackupsJob' => $baseDir . '/lib/private/Repair/AddCleanupUpdaterBackupsJob.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',
'OC\\Repair\\ClearFrontendCaches' => $baseDir . '/lib/private/Repair/ClearFrontendCaches.php',
@@ -1544,6 +1602,9 @@ 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\\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',
'OC\\Security\\Bruteforce\\Capabilities' => $baseDir . '/lib/private/Security/Bruteforce/Capabilities.php',
'OC\\Security\\Bruteforce\\CleanupJob' => $baseDir . '/lib/private/Security/Bruteforce/CleanupJob.php',
'OC\\Security\\Bruteforce\\Throttler' => $baseDir . '/lib/private/Security/Bruteforce/Throttler.php',
@@ -1605,6 +1666,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',
@@ -1640,6 +1702,11 @@ return array(
'OC\\Template\\ResourceLocator' => $baseDir . '/lib/private/Template/ResourceLocator.php',
'OC\\Template\\ResourceNotFoundException' => $baseDir . '/lib/private/Template/ResourceNotFoundException.php',
'OC\\Template\\TemplateFileLocator' => $baseDir . '/lib/private/Template/TemplateFileLocator.php',
+ 'OC\\TextProcessing\\Db\\Task' => $baseDir . '/lib/private/TextProcessing/Db/Task.php',
+ 'OC\\TextProcessing\\Db\\TaskMapper' => $baseDir . '/lib/private/TextProcessing/Db/TaskMapper.php',
+ '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\\Translation\\TranslationManager' => $baseDir . '/lib/private/Translation/TranslationManager.php',
'OC\\URLGenerator' => $baseDir . '/lib/private/URLGenerator.php',
'OC\\Updater' => $baseDir . '/lib/private/Updater.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index aecbb51bb55..73a90620605 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -45,6 +45,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Accounts\\IAccountProperty' => __DIR__ . '/../../..' . '/lib/public/Accounts/IAccountProperty.php',
'OCP\\Accounts\\IAccountPropertyCollection' => __DIR__ . '/../../..' . '/lib/public/Accounts/IAccountPropertyCollection.php',
'OCP\\Accounts\\PropertyDoesNotExistException' => __DIR__ . '/../../..' . '/lib/public/Accounts/PropertyDoesNotExistException.php',
+ 'OCP\\Accounts\\UserUpdatedEvent' => __DIR__ . '/../../..' . '/lib/public/Accounts/UserUpdatedEvent.php',
'OCP\\Activity\\ActivitySettings' => __DIR__ . '/../../..' . '/lib/public/Activity/ActivitySettings.php',
'OCP\\Activity\\IConsumer' => __DIR__ . '/../../..' . '/lib/public/Activity/IConsumer.php',
'OCP\\Activity\\IEvent' => __DIR__ . '/../../..' . '/lib/public/Activity/IEvent.php',
@@ -73,6 +74,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'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\\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\\PasswordConfirmationRequired' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/PasswordConfirmationRequired.php',
@@ -88,6 +90,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\AppFramework\\Http\\DownloadResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/DownloadResponse.php',
'OCP\\AppFramework\\Http\\EmptyContentSecurityPolicy' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php',
'OCP\\AppFramework\\Http\\EmptyFeaturePolicy' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/EmptyFeaturePolicy.php',
+ 'OCP\\AppFramework\\Http\\Events\\BeforeLoginTemplateRenderedEvent' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php',
'OCP\\AppFramework\\Http\\Events\\BeforeTemplateRenderedEvent' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Events/BeforeTemplateRenderedEvent.php',
'OCP\\AppFramework\\Http\\FeaturePolicy' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/FeaturePolicy.php',
'OCP\\AppFramework\\Http\\FileDisplayResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/FileDisplayResponse.php',
@@ -119,6 +122,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\AppFramework\\OCS\\OCSException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/OCS/OCSException.php',
'OCP\\AppFramework\\OCS\\OCSForbiddenException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/OCS/OCSForbiddenException.php',
'OCP\\AppFramework\\OCS\\OCSNotFoundException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/OCS/OCSNotFoundException.php',
+ 'OCP\\AppFramework\\OCS\\OCSPreconditionFailedException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php',
'OCP\\AppFramework\\PublicShareController' => __DIR__ . '/../../..' . '/lib/public/AppFramework/PublicShareController.php',
'OCP\\AppFramework\\QueryException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/QueryException.php',
'OCP\\AppFramework\\Services\\IAppConfig' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Services/IAppConfig.php',
@@ -155,9 +159,14 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Authentication\\TwoFactorAuth\\IRegistry' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IRegistry.php',
'OCP\\Authentication\\TwoFactorAuth\\RegistryEvent' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorException' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorException.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderChallengeFailed' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengeFailed.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderChallengePassed' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengePassed.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderDisabled' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderDisabled.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderForUserDisabled' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserDisabled.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderForUserEnabled' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserEnabled.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderForUserRegistered' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserRegistered.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderForUserUnregistered' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserUnregistered.php',
+ 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderUserDeleted' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderUserDeleted.php',
'OCP\\AutoloadNotAllowedException' => __DIR__ . '/../../..' . '/lib/public/AutoloadNotAllowedException.php',
'OCP\\BackgroundJob\\IJob' => __DIR__ . '/../../..' . '/lib/public/BackgroundJob/IJob.php',
'OCP\\BackgroundJob\\IJobList' => __DIR__ . '/../../..' . '/lib/public/BackgroundJob/IJobList.php',
@@ -223,6 +232,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Comments\\IllegalIDChangeException' => __DIR__ . '/../../..' . '/lib/public/Comments/IllegalIDChangeException.php',
'OCP\\Comments\\MessageTooLongException' => __DIR__ . '/../../..' . '/lib/public/Comments/MessageTooLongException.php',
'OCP\\Comments\\NotFoundException' => __DIR__ . '/../../..' . '/lib/public/Comments/NotFoundException.php',
+ 'OCP\\Common\\Exception\\NotFoundException' => __DIR__ . '/../../..' . '/lib/public/Common/Exception/NotFoundException.php',
'OCP\\Config\\BeforePreferenceDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Config/BeforePreferenceDeletedEvent.php',
'OCP\\Config\\BeforePreferenceSetEvent' => __DIR__ . '/../../..' . '/lib/public/Config/BeforePreferenceSetEvent.php',
'OCP\\Console\\ConsoleEvent' => __DIR__ . '/../../..' . '/lib/public/Console/ConsoleEvent.php',
@@ -235,6 +245,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Contacts\\ContactsMenu\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IProvider.php',
'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => __DIR__ . '/../../..' . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php',
'OCP\\Contacts\\IManager' => __DIR__ . '/../../..' . '/lib/public/Contacts/IManager.php',
+ 'OCP\\DB\\Events\\AddMissingColumnsEvent' => __DIR__ . '/../../..' . '/lib/public/DB/Events/AddMissingColumnsEvent.php',
+ 'OCP\\DB\\Events\\AddMissingIndicesEvent' => __DIR__ . '/../../..' . '/lib/public/DB/Events/AddMissingIndicesEvent.php',
+ 'OCP\\DB\\Events\\AddMissingPrimaryKeyEvent' => __DIR__ . '/../../..' . '/lib/public/DB/Events/AddMissingPrimaryKeyEvent.php',
'OCP\\DB\\Exception' => __DIR__ . '/../../..' . '/lib/public/DB/Exception.php',
'OCP\\DB\\IPreparedStatement' => __DIR__ . '/../../..' . '/lib/public/DB/IPreparedStatement.php',
'OCP\\DB\\IResult' => __DIR__ . '/../../..' . '/lib/public/DB/IResult.php',
@@ -248,14 +261,17 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\DB\\QueryBuilder\\IQueryFunction' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/IQueryFunction.php',
'OCP\\DB\\Types' => __DIR__ . '/../../..' . '/lib/public/DB/Types.php',
'OCP\\Dashboard\\IAPIWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IAPIWidget.php',
+ 'OCP\\Dashboard\\IAPIWidgetV2' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IAPIWidgetV2.php',
'OCP\\Dashboard\\IButtonWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IButtonWidget.php',
'OCP\\Dashboard\\IConditionalWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IConditionalWidget.php',
'OCP\\Dashboard\\IIconWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IIconWidget.php',
'OCP\\Dashboard\\IManager' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IManager.php',
'OCP\\Dashboard\\IOptionWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IOptionWidget.php',
+ 'OCP\\Dashboard\\IReloadableWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IReloadableWidget.php',
'OCP\\Dashboard\\IWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IWidget.php',
'OCP\\Dashboard\\Model\\WidgetButton' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetButton.php',
'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',
@@ -319,6 +335,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',
@@ -331,7 +348,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Files\\Events\\FolderScannedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/FolderScannedEvent.php',
'OCP\\Files\\Events\\InvalidateMountCacheEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/InvalidateMountCacheEvent.php',
'OCP\\Files\\Events\\NodeAddedToCache' => __DIR__ . '/../../..' . '/lib/public/Files/Events/NodeAddedToCache.php',
+ 'OCP\\Files\\Events\\NodeAddedToFavorite' => __DIR__ . '/../../..' . '/lib/public/Files/Events/NodeAddedToFavorite.php',
'OCP\\Files\\Events\\NodeRemovedFromCache' => __DIR__ . '/../../..' . '/lib/public/Files/Events/NodeRemovedFromCache.php',
+ 'OCP\\Files\\Events\\NodeRemovedFromFavorite' => __DIR__ . '/../../..' . '/lib/public/Files/Events/NodeRemovedFromFavorite.php',
'OCP\\Files\\Events\\Node\\AbstractNodeEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/AbstractNodeEvent.php',
'OCP\\Files\\Events\\Node\\AbstractNodesEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/AbstractNodesEvent.php',
'OCP\\Files\\Events\\Node\\BeforeNodeCopiedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/BeforeNodeCopiedEvent.php',
@@ -372,6 +391,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Files\\Lock\\OwnerLockedException' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/OwnerLockedException.php',
'OCP\\Files\\Mount\\IMountManager' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMountManager.php',
'OCP\\Files\\Mount\\IMountPoint' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMountPoint.php',
+ 'OCP\\Files\\Mount\\IMovableMount' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMovableMount.php',
'OCP\\Files\\Mount\\ISystemMountPoint' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/ISystemMountPoint.php',
'OCP\\Files\\Node' => __DIR__ . '/../../..' . '/lib/public/Files/Node.php',
'OCP\\Files\\NotEnoughSpaceException' => __DIR__ . '/../../..' . '/lib/public/Files/NotEnoughSpaceException.php',
@@ -435,6 +455,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',
@@ -463,6 +484,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\HintException' => __DIR__ . '/../../..' . '/lib/public/HintException.php',
'OCP\\Http\\Client\\IClient' => __DIR__ . '/../../..' . '/lib/public/Http/Client/IClient.php',
'OCP\\Http\\Client\\IClientService' => __DIR__ . '/../../..' . '/lib/public/Http/Client/IClientService.php',
+ 'OCP\\Http\\Client\\IPromise' => __DIR__ . '/../../..' . '/lib/public/Http/Client/IPromise.php',
'OCP\\Http\\Client\\IResponse' => __DIR__ . '/../../..' . '/lib/public/Http/Client/IResponse.php',
'OCP\\Http\\Client\\LocalServerException' => __DIR__ . '/../../..' . '/lib/public/Http/Client/LocalServerException.php',
'OCP\\Http\\WellKnown\\GenericResponse' => __DIR__ . '/../../..' . '/lib/public/Http/WellKnown/GenericResponse.php',
@@ -547,9 +569,15 @@ 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\\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',
+ 'OCP\\Preview\\IMimeIconProvider' => __DIR__ . '/../../..' . '/lib/public/Preview/IMimeIconProvider.php',
'OCP\\Preview\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Preview/IProvider.php',
'OCP\\Preview\\IProviderV2' => __DIR__ . '/../../..' . '/lib/public/Preview/IProviderV2.php',
'OCP\\Preview\\IVersionedPreviewFile' => __DIR__ . '/../../..' . '/lib/public/Preview/IVersionedPreviewFile.php',
@@ -603,8 +631,12 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Settings\\ISettings' => __DIR__ . '/../../..' . '/lib/public/Settings/ISettings.php',
'OCP\\Settings\\ISubAdminSettings' => __DIR__ . '/../../..' . '/lib/public/Settings/ISubAdminSettings.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',
+ 'OCP\\Share\\Events\\ShareAcceptedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareAcceptedEvent.php',
'OCP\\Share\\Events\\ShareCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareCreatedEvent.php',
'OCP\\Share\\Events\\ShareDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareDeletedEvent.php',
+ 'OCP\\Share\\Events\\ShareDeletedFromSelfEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareDeletedFromSelfEvent.php',
'OCP\\Share\\Events\\VerifyMountPointEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/VerifyMountPointEvent.php',
'OCP\\Share\\Exceptions\\AlreadySharedException' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/AlreadySharedException.php',
'OCP\\Share\\Exceptions\\GenericShareException' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/GenericShareException.php',
@@ -650,6 +682,17 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Talk\\IConversationOptions' => __DIR__ . '/../../..' . '/lib/public/Talk/IConversationOptions.php',
'OCP\\Talk\\ITalkBackend' => __DIR__ . '/../../..' . '/lib/public/Talk/ITalkBackend.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\\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\\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\\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',
@@ -676,6 +719,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\User\\Backend\\IGetRealUIDBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IGetRealUIDBackend.php',
'OCP\\User\\Backend\\IPasswordConfirmationBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IPasswordConfirmationBackend.php',
'OCP\\User\\Backend\\IProvideAvatarBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IProvideAvatarBackend.php',
+ 'OCP\\User\\Backend\\IProvideEnabledStateBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IProvideEnabledStateBackend.php',
'OCP\\User\\Backend\\ISearchKnownUsersBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/ISearchKnownUsersBackend.php',
'OCP\\User\\Backend\\ISetDisplayNameBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/ISetDisplayNameBackend.php',
'OCP\\User\\Backend\\ISetPasswordBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/ISetPasswordBackend.php',
@@ -690,6 +734,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\User\\Events\\UserChangedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserChangedEvent.php',
'OCP\\User\\Events\\UserCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserCreatedEvent.php',
'OCP\\User\\Events\\UserDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserDeletedEvent.php',
+ 'OCP\\User\\Events\\UserFirstTimeLoggedInEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserFirstTimeLoggedInEvent.php',
'OCP\\User\\Events\\UserLiveStatusEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLiveStatusEvent.php',
'OCP\\User\\Events\\UserLoggedInEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLoggedInEvent.php',
'OCP\\User\\Events\\UserLoggedInWithCookieEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLoggedInWithCookieEvent.php',
@@ -1019,10 +1064,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Core\\Command\\Preview\\Generate' => __DIR__ . '/../../..' . '/core/Command/Preview/Generate.php',
'OC\\Core\\Command\\Preview\\Repair' => __DIR__ . '/../../..' . '/core/Command/Preview/Repair.php',
'OC\\Core\\Command\\Preview\\ResetRenderedTexts' => __DIR__ . '/../../..' . '/core/Command/Preview/ResetRenderedTexts.php',
+ 'OC\\Core\\Command\\Security\\BruteforceAttempts' => __DIR__ . '/../../..' . '/core/Command/Security/BruteforceAttempts.php',
+ 'OC\\Core\\Command\\Security\\BruteforceResetAttempts' => __DIR__ . '/../../..' . '/core/Command/Security/BruteforceResetAttempts.php',
'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\\Security\\ResetBruteforceAttempts' => __DIR__ . '/../../..' . '/core/Command/Security/ResetBruteforceAttempts.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',
@@ -1036,7 +1082,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Core\\Command\\TwoFactorAuth\\State' => __DIR__ . '/../../..' . '/core/Command/TwoFactorAuth/State.php',
'OC\\Core\\Command\\Upgrade' => __DIR__ . '/../../..' . '/core/Command/Upgrade.php',
'OC\\Core\\Command\\User\\Add' => __DIR__ . '/../../..' . '/core/Command/User/Add.php',
- 'OC\\Core\\Command\\User\\AddAppPassword' => __DIR__ . '/../../..' . '/core/Command/User/AddAppPassword.php',
+ 'OC\\Core\\Command\\User\\AuthTokens\\Add' => __DIR__ . '/../../..' . '/core/Command/User/AuthTokens/Add.php',
+ 'OC\\Core\\Command\\User\\AuthTokens\\Delete' => __DIR__ . '/../../..' . '/core/Command/User/AuthTokens/Delete.php',
+ 'OC\\Core\\Command\\User\\AuthTokens\\ListCommand' => __DIR__ . '/../../..' . '/core/Command/User/AuthTokens/ListCommand.php',
'OC\\Core\\Command\\User\\Delete' => __DIR__ . '/../../..' . '/core/Command/User/Delete.php',
'OC\\Core\\Command\\User\\Disable' => __DIR__ . '/../../..' . '/core/Command/User/Disable.php',
'OC\\Core\\Command\\User\\Enable' => __DIR__ . '/../../..' . '/core/Command/User/Enable.php',
@@ -1046,6 +1094,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Core\\Command\\User\\Report' => __DIR__ . '/../../..' . '/core/Command/User/Report.php',
'OC\\Core\\Command\\User\\ResetPassword' => __DIR__ . '/../../..' . '/core/Command/User/ResetPassword.php',
'OC\\Core\\Command\\User\\Setting' => __DIR__ . '/../../..' . '/core/Command/User/Setting.php',
+ 'OC\\Core\\Command\\User\\SyncAccountDataCommand' => __DIR__ . '/../../..' . '/core/Command/User/SyncAccountDataCommand.php',
'OC\\Core\\Controller\\AppPasswordController' => __DIR__ . '/../../..' . '/core/Controller/AppPasswordController.php',
'OC\\Core\\Controller\\AutoCompleteController' => __DIR__ . '/../../..' . '/core/Controller/AutoCompleteController.php',
'OC\\Core\\Controller\\AvatarController' => __DIR__ . '/../../..' . '/core/Controller/AvatarController.php',
@@ -1063,6 +1112,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',
@@ -1072,6 +1122,7 @@ 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\\TextProcessingApiController' => __DIR__ . '/../../..' . '/core/Controller/TextProcessingApiController.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',
@@ -1150,6 +1201,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Core\\Migrations\\Version27000Date20220613163520' => __DIR__ . '/../../..' . '/core/Migrations/Version27000Date20220613163520.php',
'OC\\Core\\Migrations\\Version27000Date20230309104325' => __DIR__ . '/../../..' . '/core/Migrations/Version27000Date20230309104325.php',
'OC\\Core\\Migrations\\Version27000Date20230309104802' => __DIR__ . '/../../..' . '/core/Migrations/Version27000Date20230309104802.php',
+ '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\\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',
@@ -1228,9 +1282,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Encryption\\Update' => __DIR__ . '/../../..' . '/lib/private/Encryption/Update.php',
'OC\\Encryption\\Util' => __DIR__ . '/../../..' . '/lib/private/Encryption/Util.php',
'OC\\EventDispatcher\\EventDispatcher' => __DIR__ . '/../../..' . '/lib/private/EventDispatcher/EventDispatcher.php',
- 'OC\\EventDispatcher\\GenericEventWrapper' => __DIR__ . '/../../..' . '/lib/private/EventDispatcher/GenericEventWrapper.php',
'OC\\EventDispatcher\\ServiceEventListener' => __DIR__ . '/../../..' . '/lib/private/EventDispatcher/ServiceEventListener.php',
- 'OC\\EventDispatcher\\SymfonyAdapter' => __DIR__ . '/../../..' . '/lib/private/EventDispatcher/SymfonyAdapter.php',
'OC\\EventSourceFactory' => __DIR__ . '/../../..' . '/lib/private/EventSourceFactory.php',
'OC\\Federation\\CloudFederationFactory' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudFederationFactory.php',
'OC\\Federation\\CloudFederationNotification' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudFederationNotification.php',
@@ -1369,6 +1421,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Http\\Client\\Client' => __DIR__ . '/../../..' . '/lib/private/Http/Client/Client.php',
'OC\\Http\\Client\\ClientService' => __DIR__ . '/../../..' . '/lib/private/Http/Client/ClientService.php',
'OC\\Http\\Client\\DnsPinMiddleware' => __DIR__ . '/../../..' . '/lib/private/Http/Client/DnsPinMiddleware.php',
+ 'OC\\Http\\Client\\GuzzlePromiseAdapter' => __DIR__ . '/../../..' . '/lib/private/Http/Client/GuzzlePromiseAdapter.php',
'OC\\Http\\Client\\NegativeDnsCache' => __DIR__ . '/../../..' . '/lib/private/Http/Client/NegativeDnsCache.php',
'OC\\Http\\Client\\Response' => __DIR__ . '/../../..' . '/lib/private/Http/Client/Response.php',
'OC\\Http\\CookieHelper' => __DIR__ . '/../../..' . '/lib/private/Http/CookieHelper.php',
@@ -1449,6 +1502,9 @@ 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',
@@ -1476,6 +1532,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Preview\\MSOffice2007' => __DIR__ . '/../../..' . '/lib/private/Preview/MSOffice2007.php',
'OC\\Preview\\MSOfficeDoc' => __DIR__ . '/../../..' . '/lib/private/Preview/MSOfficeDoc.php',
'OC\\Preview\\MarkDown' => __DIR__ . '/../../..' . '/lib/private/Preview/MarkDown.php',
+ 'OC\\Preview\\MimeIconProvider' => __DIR__ . '/../../..' . '/lib/private/Preview/MimeIconProvider.php',
'OC\\Preview\\Movie' => __DIR__ . '/../../..' . '/lib/private/Preview/Movie.php',
'OC\\Preview\\Office' => __DIR__ . '/../../..' . '/lib/private/Preview/Office.php',
'OC\\Preview\\OpenDocument' => __DIR__ . '/../../..' . '/lib/private/Preview/OpenDocument.php',
@@ -1522,6 +1579,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\RepairException' => __DIR__ . '/../../..' . '/lib/private/RepairException.php',
'OC\\Repair\\AddBruteForceCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Repair/AddBruteForceCleanupJob.php',
'OC\\Repair\\AddCleanupUpdaterBackupsJob' => __DIR__ . '/../../..' . '/lib/private/Repair/AddCleanupUpdaterBackupsJob.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',
'OC\\Repair\\ClearFrontendCaches' => __DIR__ . '/../../..' . '/lib/private/Repair/ClearFrontendCaches.php',
@@ -1577,6 +1635,9 @@ 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\\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',
'OC\\Security\\Bruteforce\\Capabilities' => __DIR__ . '/../../..' . '/lib/private/Security/Bruteforce/Capabilities.php',
'OC\\Security\\Bruteforce\\CleanupJob' => __DIR__ . '/../../..' . '/lib/private/Security/Bruteforce/CleanupJob.php',
'OC\\Security\\Bruteforce\\Throttler' => __DIR__ . '/../../..' . '/lib/private/Security/Bruteforce/Throttler.php',
@@ -1638,6 +1699,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',
@@ -1673,6 +1735,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Template\\ResourceLocator' => __DIR__ . '/../../..' . '/lib/private/Template/ResourceLocator.php',
'OC\\Template\\ResourceNotFoundException' => __DIR__ . '/../../..' . '/lib/private/Template/ResourceNotFoundException.php',
'OC\\Template\\TemplateFileLocator' => __DIR__ . '/../../..' . '/lib/private/Template/TemplateFileLocator.php',
+ 'OC\\TextProcessing\\Db\\Task' => __DIR__ . '/../../..' . '/lib/private/TextProcessing/Db/Task.php',
+ 'OC\\TextProcessing\\Db\\TaskMapper' => __DIR__ . '/../../..' . '/lib/private/TextProcessing/Db/TaskMapper.php',
+ '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\\Translation\\TranslationManager' => __DIR__ . '/../../..' . '/lib/private/Translation/TranslationManager.php',
'OC\\URLGenerator' => __DIR__ . '/../../..' . '/lib/private/URLGenerator.php',
'OC\\Updater' => __DIR__ . '/../../..' . '/lib/private/Updater.php',
diff --git a/lib/l10n/ar.js b/lib/l10n/ar.js
index b9e1b74bf4d..bc043479d2f 100644
--- a/lib/l10n/ar.js
+++ b/lib/l10n/ar.js
@@ -2,44 +2,87 @@ OC.L10N.register(
"lib",
{
"Cannot write into \"config\" directory!" : "الكتابة في مجلد \"config\" غير ممكنة!",
- "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." : "لم يُمكن إيجاد الصفحة على الخادوم",
+ "This can usually be fixed by giving the web server write access to the config directory." : "يمكن عادةً إصلاح ذلك من خلال منح خادم الويب حق الوصول للكتابة إلى دليل التكوين config directory.",
+ "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "ولكن، إذا كنت تُفضّل الاحتفاظ بملف config.php للقراءة فقط، فعيّن الخيار \"config_is_read_only\" إلى \"صح\" \"True\".",
+ "See %s" : "أنظر%s",
+ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "التطبيق %1$s غير موجود أو ليس له إصدار متطابق مع هذا الخادوم. رجاءً، راجع دليل التطبيقات apps directory.",
+ "Sample configuration detected" : "تمّ العثور على عيّنة إعدادات sample configuration.",
+ "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." : "إضغط الرابط التالي لتوكيد الإيميل",
+ "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",
"Education Edition" : "الإصدار التعليمي",
"Enterprise bundle" : "حزمة المؤسسة",
+ "Groupware bundle" : "حزمة أدوات العمل الجماعي Groupware",
+ "Hub bundle" : "حزمة الـ\"هَبْ\" Hub",
+ "Social sharing bundle" : "حزمة المشاركة الاجتماعية Social Sharing",
"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 بت أو أعلى مطلوبة.",
+ "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, 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.",
+ "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" : "يوم أمس",
+ "_in %n day_::_in %n days_" : ["في %nأيام","في %nيوم","في %nأيام","في %nأيام","في %n أيام","في %nأيام"],
"_%n day ago_::_%n days ago_" : ["قبل ساعات","قبل يوم","قبل يومين","قبل %n يوماً","قبل %n يوماً","قبل %n يوماً"],
"next month" : "الشهر القادم",
"last month" : "الشهر الماضي",
+ "_in %n month_::_in %n months_" : ["في %nشهور","في %nشهر","في %nشهور","في %nشهور","في %nشهور","في %nشهور"],
"_%n month ago_::_%n months ago_" : ["قبل عدة أيام","قبل شهر","قبل شهرين","قبل %n شهراً","قبل %n شهراً","قبل %n شهراً"],
"next year" : "العام القادم",
"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 ساعات"],
"_%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 منذ دقائق"],
"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." : "الوحدة module ذات الرقم 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" : "اسم الملف به ، على الأقل ، حرف غير صالح",
@@ -51,21 +94,38 @@ OC.L10N.register(
"__language_name__" : "اللغة العربية",
"This is an automatically sent email, please do not reply." : "هذه رسالة آلية، يرجى عدم الرد عليها.",
"Help" : "المساعدة",
+ "Appearance and accessibility" : "المظهر appearance، و سهولة الوصول accessibility",
"Apps" : "التطبيقات",
+ "Personal settings" : "إعدادات شخصيّة",
+ "Administration settings" : "إعدادات الإدارة",
"Settings" : "الإعدادات",
"Log out" : "الخروج",
"Users" : "المستخدمين",
"Email" : "البريد الإلكتروني",
+ "Mail %s" : "بريد %s",
+ "Fediverse" : "الشبكة اللامركزية للتواصل الاجتماعي \"فيديفيرس\" Fediverse",
+ "View %s on the fediverse" : "عرض %s على الفيديفيرس Fediverse",
"Phone" : "الهاتف",
+ "Call %s" : "إتصل بـ%s",
"Twitter" : "تويتر",
+ "View %s on Twitter" : "عرض %s على تويتر Twitter",
"Website" : "موقع الويب",
+ "Visit %s" : "زيارة %s",
"Address" : "العنوان",
"Profile picture" : "صورة الملف الشخصي",
"About" : "عن",
"Display name" : "الاسم المعروض",
+ "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" : "لا يمكنك استخدام النقاط dots في اسم قاعدة البيانات %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 غير صحيحة",
@@ -75,13 +135,29 @@ OC.L10N.register(
"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",
"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 غير موجود",
+ "%1$s shared »%2$s« with you and wants to add:" : "%1$s شارك »%2$s« معك و يرغب في إضافة:",
+ "%1$s shared »%2$s« with you and wants to add" : "%1$s شارك »%2$s« معك و يرغب في إضافة",
+ "»%s« added a note to a file shared with you" : "»%s« أضاف ملاحظة لملفٍ سلفت مشاركته معك",
"Open »%s«" : "فتح »%s«",
+ "%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" : "تاريخ انتهاء الصلاحية غير صالح. التاريخ المحدد في الماضي!",
+ "_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",
+ "%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" : "الإثنين",
@@ -131,34 +207,76 @@ OC.L10N.register(
"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" : "تم إلغاء الدخول مِن طرف التطبيق",
+ "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\". أنظر: %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 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 لا يمكن الكتابة فيه.",
+ "Setting locale to %s failed." : "تعذّر تعيين إعدادت اللغة و المَحلّيّات locale إلى %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 سوف يُمكّن نيكست كلاود من العمل مجدداً",
+ "<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." : "لإصلاح هذا الخطأ، قم بتعيين<code>mbstring.func_overload</code> إلى <code>0</code> في php.ini.",
"PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "يبدو أنه تم إعداد PHP لتجريد كتل المستندات المضمنة. سيؤدي ذلك إلى جعل العديد من التطبيقات الأساسية غير قابلة للوصول.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "ربما يكون السبب في ذلك هو ذاكرة التخزين المؤقت/المسرع مثل Zend OPcache أو eAccelerator.",
"PHP modules have been installed, but they are still listed as missing?" : "تم تثبيت وحدات PHP ، لكنها لا تزال مدرجة على أنها وحدات مفقودة؟",
"Please ask your server administrator to restart the web server." : "يرجى مطالبة مسؤول الخادم بإعادة تشغيل خادم الويب.",
+ "The required %s config variable is not configured in the config.php file." : "مُتغيّر التهيئة %s المطلوب لم تتم تهيئته في الملف config.php.",
+ "Please ask your server administrator to check the Nextcloud configuration." : "رجاءً، أطلب من مشرف نظامك مراجعة تهيئة نكست كلاود Nextcloud 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 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 غير صحيح.",
+ "Ensure there is a file called \".ocdata\" in the root of the data directory." : "تأكد من وجود ملفٍ باسم \".ocdata\" في جذر دليل البيانات data directory.",
+ "Action \"%s\" not supported or implemented." : "الإجراء \"%s\" غيرُ مدعومٍ أو غيرً مُطبّقٍ.",
+ "Authentication failed, wrong token or provider ID given" : "فشلت المصادقة بسبب خطأ في الرمز token أو في رقم المُزوّد provider ID المُعطى.",
+ "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "بارامترات لازمة لإكمال الطلب مفقودةٌ. و البارامترات هي: \"%s\"",
+ "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : " المُعّرف \"%1$s\" مٌستخدمٌ سلفاُ من مُزوّد اتحاد سحابي cloud fereration provider \"%2$s\"",
+ "Cloud Federation Provider with ID: \"%s\" does not exist." : "لا يوجد مُزوّد اتحاد سحابي Cloud Federation Provider بهذا الاسم: \"%s\" .",
"Could not obtain lock type %d on \"%s\"." : "تعذر الحصول على نوع القفل%d على \"%s\".",
"Storage unauthorized. %s" : "التخزين غير مصرح به.%s",
"Storage incomplete configuration. %s" : "تكوين التخزين غير مكتمل. %s",
"Storage connection error. %s" : "خطأ في اتصال التخزين. %s ",
"Storage is temporarily not available" : "وحدة التخزين غير متوفرة",
"Storage connection timeout. %s" : "انتهت مهلة الاتصال بالتخزين. %s",
+ "Free prompt" : "مَحَثْ prompt مجاني",
+ "Runs an arbitrary prompt through the language model." : "يقوم بتشغيل مَحَث عشوائي arbitrary prompt من خلال نموذج اللغة 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 لم يتم استبدالها مؤخّراً. تأكد من تطابق إصدارها مع الخادوم.",
"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\" و \"_. @ - '\"",
"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 الخاص بك وأعد تشغيل خادم الويب."
+ "To fix this issue update your libxml2 version and restart your web server." : "لإصلاح هذه المشكلة، قم بتحديث إصدار libxml2 الخاص بك وأعد تشغيل خادم الويب.",
+ "PostgreSQL >= 9 required." : "PostgreSQL >= 9 مطلوبة.",
+ "Please upgrade your database version." : "رجاءً، قم بترقية إصدار قاعدة بياناتك."
},
"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 7f5a5f61242..5ac53142dee 100644
--- a/lib/l10n/ar.json
+++ b/lib/l10n/ar.json
@@ -1,43 +1,86 @@
{ "translations": {
"Cannot write into \"config\" directory!" : "الكتابة في مجلد \"config\" غير ممكنة!",
- "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." : "لم يُمكن إيجاد الصفحة على الخادوم",
+ "This can usually be fixed by giving the web server write access to the config directory." : "يمكن عادةً إصلاح ذلك من خلال منح خادم الويب حق الوصول للكتابة إلى دليل التكوين config directory.",
+ "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "ولكن، إذا كنت تُفضّل الاحتفاظ بملف config.php للقراءة فقط، فعيّن الخيار \"config_is_read_only\" إلى \"صح\" \"True\".",
+ "See %s" : "أنظر%s",
+ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "التطبيق %1$s غير موجود أو ليس له إصدار متطابق مع هذا الخادوم. رجاءً، راجع دليل التطبيقات apps directory.",
+ "Sample configuration detected" : "تمّ العثور على عيّنة إعدادات sample configuration.",
+ "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." : "إضغط الرابط التالي لتوكيد الإيميل",
+ "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",
"Education Edition" : "الإصدار التعليمي",
"Enterprise bundle" : "حزمة المؤسسة",
+ "Groupware bundle" : "حزمة أدوات العمل الجماعي Groupware",
+ "Hub bundle" : "حزمة الـ\"هَبْ\" Hub",
+ "Social sharing bundle" : "حزمة المشاركة الاجتماعية Social Sharing",
"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 بت أو أعلى مطلوبة.",
+ "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, 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.",
+ "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" : "يوم أمس",
+ "_in %n day_::_in %n days_" : ["في %nأيام","في %nيوم","في %nأيام","في %nأيام","في %n أيام","في %nأيام"],
"_%n day ago_::_%n days ago_" : ["قبل ساعات","قبل يوم","قبل يومين","قبل %n يوماً","قبل %n يوماً","قبل %n يوماً"],
"next month" : "الشهر القادم",
"last month" : "الشهر الماضي",
+ "_in %n month_::_in %n months_" : ["في %nشهور","في %nشهر","في %nشهور","في %nشهور","في %nشهور","في %nشهور"],
"_%n month ago_::_%n months ago_" : ["قبل عدة أيام","قبل شهر","قبل شهرين","قبل %n شهراً","قبل %n شهراً","قبل %n شهراً"],
"next year" : "العام القادم",
"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 ساعات"],
"_%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 منذ دقائق"],
"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." : "الوحدة module ذات الرقم 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" : "اسم الملف به ، على الأقل ، حرف غير صالح",
@@ -49,21 +92,38 @@
"__language_name__" : "اللغة العربية",
"This is an automatically sent email, please do not reply." : "هذه رسالة آلية، يرجى عدم الرد عليها.",
"Help" : "المساعدة",
+ "Appearance and accessibility" : "المظهر appearance، و سهولة الوصول accessibility",
"Apps" : "التطبيقات",
+ "Personal settings" : "إعدادات شخصيّة",
+ "Administration settings" : "إعدادات الإدارة",
"Settings" : "الإعدادات",
"Log out" : "الخروج",
"Users" : "المستخدمين",
"Email" : "البريد الإلكتروني",
+ "Mail %s" : "بريد %s",
+ "Fediverse" : "الشبكة اللامركزية للتواصل الاجتماعي \"فيديفيرس\" Fediverse",
+ "View %s on the fediverse" : "عرض %s على الفيديفيرس Fediverse",
"Phone" : "الهاتف",
+ "Call %s" : "إتصل بـ%s",
"Twitter" : "تويتر",
+ "View %s on Twitter" : "عرض %s على تويتر Twitter",
"Website" : "موقع الويب",
+ "Visit %s" : "زيارة %s",
"Address" : "العنوان",
"Profile picture" : "صورة الملف الشخصي",
"About" : "عن",
"Display name" : "الاسم المعروض",
+ "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" : "لا يمكنك استخدام النقاط dots في اسم قاعدة البيانات %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 غير صحيحة",
@@ -73,13 +133,29 @@
"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",
"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 غير موجود",
+ "%1$s shared »%2$s« with you and wants to add:" : "%1$s شارك »%2$s« معك و يرغب في إضافة:",
+ "%1$s shared »%2$s« with you and wants to add" : "%1$s شارك »%2$s« معك و يرغب في إضافة",
+ "»%s« added a note to a file shared with you" : "»%s« أضاف ملاحظة لملفٍ سلفت مشاركته معك",
"Open »%s«" : "فتح »%s«",
+ "%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" : "تاريخ انتهاء الصلاحية غير صالح. التاريخ المحدد في الماضي!",
+ "_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",
+ "%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" : "الإثنين",
@@ -129,34 +205,76 @@
"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" : "تم إلغاء الدخول مِن طرف التطبيق",
+ "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\". أنظر: %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 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 لا يمكن الكتابة فيه.",
+ "Setting locale to %s failed." : "تعذّر تعيين إعدادت اللغة و المَحلّيّات locale إلى %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 سوف يُمكّن نيكست كلاود من العمل مجدداً",
+ "<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." : "لإصلاح هذا الخطأ، قم بتعيين<code>mbstring.func_overload</code> إلى <code>0</code> في php.ini.",
"PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "يبدو أنه تم إعداد PHP لتجريد كتل المستندات المضمنة. سيؤدي ذلك إلى جعل العديد من التطبيقات الأساسية غير قابلة للوصول.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "ربما يكون السبب في ذلك هو ذاكرة التخزين المؤقت/المسرع مثل Zend OPcache أو eAccelerator.",
"PHP modules have been installed, but they are still listed as missing?" : "تم تثبيت وحدات PHP ، لكنها لا تزال مدرجة على أنها وحدات مفقودة؟",
"Please ask your server administrator to restart the web server." : "يرجى مطالبة مسؤول الخادم بإعادة تشغيل خادم الويب.",
+ "The required %s config variable is not configured in the config.php file." : "مُتغيّر التهيئة %s المطلوب لم تتم تهيئته في الملف config.php.",
+ "Please ask your server administrator to check the Nextcloud configuration." : "رجاءً، أطلب من مشرف نظامك مراجعة تهيئة نكست كلاود Nextcloud 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 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 غير صحيح.",
+ "Ensure there is a file called \".ocdata\" in the root of the data directory." : "تأكد من وجود ملفٍ باسم \".ocdata\" في جذر دليل البيانات data directory.",
+ "Action \"%s\" not supported or implemented." : "الإجراء \"%s\" غيرُ مدعومٍ أو غيرً مُطبّقٍ.",
+ "Authentication failed, wrong token or provider ID given" : "فشلت المصادقة بسبب خطأ في الرمز token أو في رقم المُزوّد provider ID المُعطى.",
+ "Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "بارامترات لازمة لإكمال الطلب مفقودةٌ. و البارامترات هي: \"%s\"",
+ "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : " المُعّرف \"%1$s\" مٌستخدمٌ سلفاُ من مُزوّد اتحاد سحابي cloud fereration provider \"%2$s\"",
+ "Cloud Federation Provider with ID: \"%s\" does not exist." : "لا يوجد مُزوّد اتحاد سحابي Cloud Federation Provider بهذا الاسم: \"%s\" .",
"Could not obtain lock type %d on \"%s\"." : "تعذر الحصول على نوع القفل%d على \"%s\".",
"Storage unauthorized. %s" : "التخزين غير مصرح به.%s",
"Storage incomplete configuration. %s" : "تكوين التخزين غير مكتمل. %s",
"Storage connection error. %s" : "خطأ في اتصال التخزين. %s ",
"Storage is temporarily not available" : "وحدة التخزين غير متوفرة",
"Storage connection timeout. %s" : "انتهت مهلة الاتصال بالتخزين. %s",
+ "Free prompt" : "مَحَثْ prompt مجاني",
+ "Runs an arbitrary prompt through the language model." : "يقوم بتشغيل مَحَث عشوائي arbitrary prompt من خلال نموذج اللغة 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 لم يتم استبدالها مؤخّراً. تأكد من تطابق إصدارها مع الخادوم.",
"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\" و \"_. @ - '\"",
"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 الخاص بك وأعد تشغيل خادم الويب."
+ "To fix this issue update your libxml2 version and restart your web server." : "لإصلاح هذه المشكلة، قم بتحديث إصدار libxml2 الخاص بك وأعد تشغيل خادم الويب.",
+ "PostgreSQL >= 9 required." : "PostgreSQL >= 9 مطلوبة.",
+ "Please upgrade your database version." : "رجاءً، قم بترقية إصدار قاعدة بياناتك."
},"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 4c570bbbfd7..330901f03c3 100644
--- a/lib/l10n/ast.js
+++ b/lib/l10n/ast.js
@@ -66,6 +66,7 @@ OC.L10N.register(
"Oct." : "Och.",
"Nov." : "Pay.",
"Dec." : "Avi.",
+ "a safe home for all your data" : "un llugar seguru pa los datos personales",
"Application is not enabled" : "L'aplicación nun ta activada",
"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"
diff --git a/lib/l10n/ast.json b/lib/l10n/ast.json
index 7f4c8383db1..5780dd94141 100644
--- a/lib/l10n/ast.json
+++ b/lib/l10n/ast.json
@@ -64,6 +64,7 @@
"Oct." : "Och.",
"Nov." : "Pay.",
"Dec." : "Avi.",
+ "a safe home for all your data" : "un llugar seguru pa los datos personales",
"Application is not enabled" : "L'aplicación nun ta activada",
"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"
diff --git a/lib/l10n/az.js b/lib/l10n/az.js
index 63ea076c54b..20d1ce300a1 100644
--- a/lib/l10n/az.js
+++ b/lib/l10n/az.js
@@ -11,6 +11,7 @@ OC.L10N.register(
"seconds ago" : "saniyələr öncə",
"__language_name__" : "Azərbaycan dili",
"Help" : "Kömək",
+ "Apps" : "Tətbiqlər",
"Settings" : "Quraşdırmalar",
"Users" : "İstifadəçilər",
"Email" : "Email",
@@ -18,6 +19,7 @@ OC.L10N.register(
"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.",
diff --git a/lib/l10n/az.json b/lib/l10n/az.json
index 59446bcb412..b88fbb1337d 100644
--- a/lib/l10n/az.json
+++ b/lib/l10n/az.json
@@ -9,6 +9,7 @@
"seconds ago" : "saniyələr öncə",
"__language_name__" : "Azərbaycan dili",
"Help" : "Kömək",
+ "Apps" : "Tətbiqlər",
"Settings" : "Quraşdırmalar",
"Users" : "İstifadəçilər",
"Email" : "Email",
@@ -16,6 +17,7 @@
"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.",
diff --git a/lib/l10n/bg.js b/lib/l10n/bg.js
index 7f46345d73c..a6532e5be26 100644
--- a/lib/l10n/bg.js
+++ b/lib/l10n/bg.js
@@ -243,8 +243,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.",
- "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, за да не може директорията да бъде видяна от други потребители.",
"Your data directory must be an absolute path." : "Вашата директория с данни трябва да е абсолютен път.",
@@ -267,6 +265,8 @@ OC.L10N.register(
"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\" и \"_.@-'\"",
"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." : "Моля, надстройте версията на вашата база данни."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/bg.json b/lib/l10n/bg.json
index 275dfc543ad..6bc6ae317c6 100644
--- a/lib/l10n/bg.json
+++ b/lib/l10n/bg.json
@@ -241,8 +241,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.",
- "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, за да не може директорията да бъде видяна от други потребители.",
"Your data directory must be an absolute path." : "Вашата директория с данни трябва да е абсолютен път.",
@@ -265,6 +263,8 @@
"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\" и \"_.@-'\"",
"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." : "Моля, надстройте версията на вашата база данни."
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/ca.js b/lib/l10n/ca.js
index fa67dd41eda..421f7e69652 100644
--- a/lib/l10n/ca.js
+++ b/lib/l10n/ca.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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.",
"The requested share does not exist anymore" : "L'element compartit sol·licitat ja no existeix",
+ "The requested share comes from a disabled user" : "L'element compartit sol·licitat prové d'un usuari inhabilitat",
"The user was not created because the user limit has been reached. Check your notifications to learn more." : "No s'ha creat l'usuari perquè s'ha assolit el límit d'usuaris. Consulteu les notificacions per a obtenir més informació.",
"Could not find category \"%s\"" : "No s'ha trobat la categoria «%s»",
"Sunday" : "Diumenge",
@@ -244,8 +245,6 @@ 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.",
- "PostgreSQL >= 9 required." : "Cal el PostgreSQL >= 9.",
- "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.",
"Your data directory must be an absolute path." : "La carpeta de dades ha de ser un camí absolut.",
@@ -263,11 +262,21 @@ OC.L10N.register(
"Storage connection error. %s" : "S'ha produït un error de connexió amb l'emmagatzematge. %s",
"Storage is temporarily not available" : "L'emmagatzematge no està disponible temporalment",
"Storage connection timeout. %s" : "S'ha superat el temps d'espera de la connexió d'emmagatzematge. %s",
+ "Free prompt" : "Sol·licitud lliure",
+ "Runs an arbitrary prompt through the language model." : "Executa una sol·licitud arbitrària mitjançant el model de llengua.",
+ "Generate headline" : "Genera un titular",
+ "Generates a possible headline for a text." : "Genera un titular possible per a un text.",
+ "Summarize" : "Resumeix",
+ "Summarizes text by reducing its length without losing key information." : "Resumeix el text reduint-ne la longitud sense perdre la informació clau.",
+ "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.",
"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 «_.@-'»",
"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."
+ "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."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/ca.json b/lib/l10n/ca.json
index aa0f9d5e8e4..e18f5be8c9d 100644
--- a/lib/l10n/ca.json
+++ b/lib/l10n/ca.json
@@ -154,6 +154,7 @@
"%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.",
"The requested share does not exist anymore" : "L'element compartit sol·licitat ja no existeix",
+ "The requested share comes from a disabled user" : "L'element compartit sol·licitat prové d'un usuari inhabilitat",
"The user was not created because the user limit has been reached. Check your notifications to learn more." : "No s'ha creat l'usuari perquè s'ha assolit el límit d'usuaris. Consulteu les notificacions per a obtenir més informació.",
"Could not find category \"%s\"" : "No s'ha trobat la categoria «%s»",
"Sunday" : "Diumenge",
@@ -242,8 +243,6 @@
"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.",
- "PostgreSQL >= 9 required." : "Cal el PostgreSQL >= 9.",
- "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.",
"Your data directory must be an absolute path." : "La carpeta de dades ha de ser un camí absolut.",
@@ -261,11 +260,21 @@
"Storage connection error. %s" : "S'ha produït un error de connexió amb l'emmagatzematge. %s",
"Storage is temporarily not available" : "L'emmagatzematge no està disponible temporalment",
"Storage connection timeout. %s" : "S'ha superat el temps d'espera de la connexió d'emmagatzematge. %s",
+ "Free prompt" : "Sol·licitud lliure",
+ "Runs an arbitrary prompt through the language model." : "Executa una sol·licitud arbitrària mitjançant el model de llengua.",
+ "Generate headline" : "Genera un titular",
+ "Generates a possible headline for a text." : "Genera un titular possible per a un text.",
+ "Summarize" : "Resumeix",
+ "Summarizes text by reducing its length without losing key information." : "Resumeix el text reduint-ne la longitud sense perdre la informació clau.",
+ "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.",
"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 «_.@-'»",
"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."
+ "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."
},"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 ddab3de0439..deeb3f3b996 100644
--- a/lib/l10n/cs.js
+++ b/lib/l10n/cs.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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",
@@ -244,8 +245,6 @@ OC.L10N.register(
"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.",
- "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.",
"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í.",
@@ -263,11 +262,21 @@ OC.L10N.register(
"Storage connection error. %s" : "Chyba připojení úložiště. %s",
"Storage is temporarily not available" : "Úložiště je dočasně nedostupné",
"Storage connection timeout. %s" : "Překročen časový limit připojování k úložišti. %s",
+ "Free prompt" : "Prompt zdarma",
+ "Runs an arbitrary prompt through the language model." : "Spouští libovolnou výzvu skrze jazykový model.",
+ "Generate headline" : "Vytvořit nadpis",
+ "Generates a possible headline for a text." : "Vytvoří možný nadpis pro text.",
+ "Summarize" : "Stručný souhrn",
+ "Summarizes text by reducing its length without losing key information." : "Vytvoří stručný souhrn textu tím, že zkrátí jeho délku aniž by byly ztraceny klíčové informace",
+ "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.",
"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 „_.@-'“",
"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."
+ "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."
},
"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 416a3d9b8af..0fa73b1568e 100644
--- a/lib/l10n/cs.json
+++ b/lib/l10n/cs.json
@@ -154,6 +154,7 @@
"%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",
@@ -242,8 +243,6 @@
"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.",
- "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.",
"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í.",
@@ -261,11 +260,21 @@
"Storage connection error. %s" : "Chyba připojení úložiště. %s",
"Storage is temporarily not available" : "Úložiště je dočasně nedostupné",
"Storage connection timeout. %s" : "Překročen časový limit připojování k úložišti. %s",
+ "Free prompt" : "Prompt zdarma",
+ "Runs an arbitrary prompt through the language model." : "Spouští libovolnou výzvu skrze jazykový model.",
+ "Generate headline" : "Vytvořit nadpis",
+ "Generates a possible headline for a text." : "Vytvoří možný nadpis pro text.",
+ "Summarize" : "Stručný souhrn",
+ "Summarizes text by reducing its length without losing key information." : "Vytvoří stručný souhrn textu tím, že zkrátí jeho délku aniž by byly ztraceny klíčové informace",
+ "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.",
"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 „_.@-'“",
"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."
+ "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."
},"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;"
} \ No newline at end of file
diff --git a/lib/l10n/da.js b/lib/l10n/da.js
index ed73275fed9..c549f68b3f3 100644
--- a/lib/l10n/da.js
+++ b/lib/l10n/da.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"This can usually be fixed by giving the web server write access to the config directory." : "Dette kan normalt rettes ved at give webserveren skriveadgang til config folderen.",
"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 foretrækker at bibeholde config.php skrivebeskyttet, så sæt parameter \"config_is_read_only\" til true i filen. ",
"See %s" : "Se %s",
+ "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",
@@ -57,6 +58,7 @@ OC.L10N.register(
"Avatar image is not square" : "Avatar billedet er ikke kvadratisk",
"Files" : "Filer",
"View profile" : "Vis profil",
+ "Local time: %s" : "Lokal tid: %s",
"today" : "i dag",
"tomorrow" : "i morgen",
"yesterday" : "i går",
@@ -101,6 +103,8 @@ OC.L10N.register(
"Users" : "Brugere",
"Email" : "E-mail",
"Mail %s" : "Mail %s",
+ "Fediverse" : "Fediverse",
+ "View %s on the fediverse" : "Vis %s på fediverset",
"Phone" : "Telefon",
"Call %s" : "Ring op %s",
"Twitter" : "Twitter",
@@ -152,6 +156,7 @@ OC.L10N.register(
"%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.",
"The requested share does not exist anymore" : "Det delte emne eksisterer ikke længere",
+ "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Brugeren blev ikke oprettet, fordi brugergrænsen er nået. Tjek dine notifikationer for at få flere oplysninger.",
"Could not find category \"%s\"" : "Kunne ikke finde kategorien \"%s\"",
"Sunday" : "Søndag",
"Monday" : "Mandag",
@@ -201,6 +206,7 @@ OC.L10N.register(
"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",
@@ -238,8 +244,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 kræves.",
- "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.",
"Your data directory must be an absolute path." : "Datamappen skal have en absolut sti.",
@@ -257,11 +261,21 @@ OC.L10N.register(
"Storage connection error. %s" : "Forbindelses fejl til lageret. %s",
"Storage is temporarily not available" : "Lagerplads er midlertidigt ikke tilgængeligt",
"Storage connection timeout. %s" : "Lageret svarer ikke. %s",
+ "Free prompt" : "Gratis prompt",
+ "Runs an arbitrary prompt through the language model." : "Kører en arbitrær prompt gennem sprogmodellen.",
+ "Generate headline" : "Generer overskrift",
+ "Generates a possible headline for a text." : "Genererer en mulig overskrift til en tekst.",
+ "Summarize" : "Opsummer",
+ "Summarizes text by reducing its length without losing key information." : "Opsummerer tekst ved at reducere dens længde uden at miste nøgleinformation.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/da.json b/lib/l10n/da.json
index d30cf76d846..24b42a7ac5e 100644
--- a/lib/l10n/da.json
+++ b/lib/l10n/da.json
@@ -3,6 +3,7 @@
"This can usually be fixed by giving the web server write access to the config directory." : "Dette kan normalt rettes ved at give webserveren skriveadgang til config folderen.",
"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 foretrækker at bibeholde config.php skrivebeskyttet, så sæt parameter \"config_is_read_only\" til true i filen. ",
"See %s" : "Se %s",
+ "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",
@@ -55,6 +56,7 @@
"Avatar image is not square" : "Avatar billedet er ikke kvadratisk",
"Files" : "Filer",
"View profile" : "Vis profil",
+ "Local time: %s" : "Lokal tid: %s",
"today" : "i dag",
"tomorrow" : "i morgen",
"yesterday" : "i går",
@@ -99,6 +101,8 @@
"Users" : "Brugere",
"Email" : "E-mail",
"Mail %s" : "Mail %s",
+ "Fediverse" : "Fediverse",
+ "View %s on the fediverse" : "Vis %s på fediverset",
"Phone" : "Telefon",
"Call %s" : "Ring op %s",
"Twitter" : "Twitter",
@@ -150,6 +154,7 @@
"%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.",
"The requested share does not exist anymore" : "Det delte emne eksisterer ikke længere",
+ "The user was not created because the user limit has been reached. Check your notifications to learn more." : "Brugeren blev ikke oprettet, fordi brugergrænsen er nået. Tjek dine notifikationer for at få flere oplysninger.",
"Could not find category \"%s\"" : "Kunne ikke finde kategorien \"%s\"",
"Sunday" : "Søndag",
"Monday" : "Mandag",
@@ -199,6 +204,7 @@
"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",
@@ -236,8 +242,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 kræves.",
- "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.",
"Your data directory must be an absolute path." : "Datamappen skal have en absolut sti.",
@@ -255,11 +259,21 @@
"Storage connection error. %s" : "Forbindelses fejl til lageret. %s",
"Storage is temporarily not available" : "Lagerplads er midlertidigt ikke tilgængeligt",
"Storage connection timeout. %s" : "Lageret svarer ikke. %s",
+ "Free prompt" : "Gratis prompt",
+ "Runs an arbitrary prompt through the language model." : "Kører en arbitrær prompt gennem sprogmodellen.",
+ "Generate headline" : "Generer overskrift",
+ "Generates a possible headline for a text." : "Genererer en mulig overskrift til en tekst.",
+ "Summarize" : "Opsummer",
+ "Summarizes text by reducing its length without losing key information." : "Opsummerer tekst ved at reducere dens længde uden at miste nøgleinformation.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},"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 dc1dae73211..4adbe25257c 100644
--- a/lib/l10n/de.js
+++ b/lib/l10n/de.js
@@ -91,7 +91,7 @@ OC.L10N.register(
"App \"%s\" cannot be installed because appinfo file cannot be read." : "Die Anwendung \"%s\" kann nicht installiert werden, weil die Anwendungsinfodatei nicht gelesen werden kann.",
"App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Die App \"%s\" kann nicht installiert werden, da sie mit dieser Serverversion nicht kompatibel ist.",
"__language_name__" : "Deutsch (Persönlich: Du)",
- "This is an automatically sent email, please do not reply." : "Dies ist eine automatisch versandte E-Mail, bitte nicht antworten.",
+ "This is an automatically sent email, please do not reply." : "Dies ist eine automatisch gesendete E-Mail. Bitte antworte nicht auf diese E-Mail.",
"Help" : "Hilfe",
"Appearance and accessibility" : "Erscheinungsbild und Barrierefreiheit",
"Apps" : "Apps",
@@ -243,8 +243,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 benötigt",
- "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.",
"Your data directory must be an absolute path." : "Dein Datenverzeichnis muss einen eindeutigen Pfad haben",
@@ -267,6 +265,8 @@ OC.L10N.register(
"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 „_.@-'“",
"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."
+ "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"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/de.json b/lib/l10n/de.json
index a297b2fd5c4..1356295ad32 100644
--- a/lib/l10n/de.json
+++ b/lib/l10n/de.json
@@ -89,7 +89,7 @@
"App \"%s\" cannot be installed because appinfo file cannot be read." : "Die Anwendung \"%s\" kann nicht installiert werden, weil die Anwendungsinfodatei nicht gelesen werden kann.",
"App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Die App \"%s\" kann nicht installiert werden, da sie mit dieser Serverversion nicht kompatibel ist.",
"__language_name__" : "Deutsch (Persönlich: Du)",
- "This is an automatically sent email, please do not reply." : "Dies ist eine automatisch versandte E-Mail, bitte nicht antworten.",
+ "This is an automatically sent email, please do not reply." : "Dies ist eine automatisch gesendete E-Mail. Bitte antworte nicht auf diese E-Mail.",
"Help" : "Hilfe",
"Appearance and accessibility" : "Erscheinungsbild und Barrierefreiheit",
"Apps" : "Apps",
@@ -241,8 +241,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 benötigt",
- "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.",
"Your data directory must be an absolute path." : "Dein Datenverzeichnis muss einen eindeutigen Pfad haben",
@@ -265,6 +263,8 @@
"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 „_.@-'“",
"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."
+ "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"
},"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 5bac22838c6..4b1a4c4c274 100644
--- a/lib/l10n/de_DE.js
+++ b/lib/l10n/de_DE.js
@@ -55,7 +55,7 @@ OC.L10N.register(
"Authentication" : "Authentifizierung",
"Unknown filetype" : "Unbekannter Dateityp",
"Invalid image" : "Ungültiges Bild",
- "Avatar image is not square" : "Benutzerbild ist nicht quadratisch",
+ "Avatar image is not square" : "Avatar-Bild ist nicht quadratisch",
"Files" : "Dateien",
"View profile" : "Profil ansehen",
"Local time: %s" : "Ortszeit: %s",
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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.",
"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üfen Sie Ihre Benachrichtigungen, um mehr zu erfahren.",
"Could not find category \"%s\"" : "Die Kategorie \"%s“ konnte nicht gefunden werden",
"Sunday" : "Sonntag",
@@ -244,8 +245,6 @@ 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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 benötigt.",
- "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.",
"Your data directory must be an absolute path." : "Ihr Datenverzeichnis muss einen absoluten Pfad haben.",
@@ -263,11 +262,21 @@ 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" : "Kopfzeile 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$s wurden nicht korrekt ersetzt. Stellen Sie sicher, dass es sich um eine mit dem Server kompatible Version handelt.",
"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 „_.@-'“",
"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."
+ "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."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/de_DE.json b/lib/l10n/de_DE.json
index 112cbb4627f..98681f76384 100644
--- a/lib/l10n/de_DE.json
+++ b/lib/l10n/de_DE.json
@@ -53,7 +53,7 @@
"Authentication" : "Authentifizierung",
"Unknown filetype" : "Unbekannter Dateityp",
"Invalid image" : "Ungültiges Bild",
- "Avatar image is not square" : "Benutzerbild ist nicht quadratisch",
+ "Avatar image is not square" : "Avatar-Bild ist nicht quadratisch",
"Files" : "Dateien",
"View profile" : "Profil ansehen",
"Local time: %s" : "Ortszeit: %s",
@@ -154,6 +154,7 @@
"%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.",
"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üfen Sie Ihre Benachrichtigungen, um mehr zu erfahren.",
"Could not find category \"%s\"" : "Die Kategorie \"%s“ konnte nicht gefunden werden",
"Sunday" : "Sonntag",
@@ -242,8 +243,6 @@
"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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 benötigt.",
- "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.",
"Your data directory must be an absolute path." : "Ihr Datenverzeichnis muss einen absoluten Pfad haben.",
@@ -261,11 +260,21 @@
"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" : "Kopfzeile 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$s wurden nicht korrekt ersetzt. Stellen Sie sicher, dass es sich um eine mit dem Server kompatible Version handelt.",
"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 „_.@-'“",
"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."
+ "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."
},"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 df8fd0a0bdf..fe2cea83496 100644
--- a/lib/l10n/el.js
+++ b/lib/l10n/el.js
@@ -232,8 +232,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.",
- "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 έτσι ώστε ο κατάλογος να μην μπορεί να προβάλλεται από άλλους χρήστες.",
"Your data directory must be an absolute path." : "Ο κατάλογος δεδομένων σας πρέπει να είναι μια απόλυτη διαδρομή.",
@@ -255,6 +253,8 @@ OC.L10N.register(
"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 \"_.@-'\"",
"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." : "Παρακαλούμε αναβαθμίστε την έκδοση της βάσης δεδομένων σας."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/el.json b/lib/l10n/el.json
index 72fc0826cc9..5d8e3e87a85 100644
--- a/lib/l10n/el.json
+++ b/lib/l10n/el.json
@@ -230,8 +230,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.",
- "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 έτσι ώστε ο κατάλογος να μην μπορεί να προβάλλεται από άλλους χρήστες.",
"Your data directory must be an absolute path." : "Ο κατάλογος δεδομένων σας πρέπει να είναι μια απόλυτη διαδρομή.",
@@ -253,6 +251,8 @@
"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 \"_.@-'\"",
"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." : "Παρακαλούμε αναβαθμίστε την έκδοση της βάσης δεδομένων σας."
},"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 45120d9c82e..ed51e1fd5fc 100644
--- a/lib/l10n/en_GB.js
+++ b/lib/l10n/en_GB.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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 any more",
+ "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",
@@ -244,8 +245,6 @@ 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.",
- "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.",
"Your data directory must be an absolute path." : "Your data directory must be an absolute path.",
@@ -263,11 +262,21 @@ OC.L10N.register(
"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" : "Summarise",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/en_GB.json b/lib/l10n/en_GB.json
index 9dee7e3443e..40563e1980e 100644
--- a/lib/l10n/en_GB.json
+++ b/lib/l10n/en_GB.json
@@ -154,6 +154,7 @@
"%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 any more",
+ "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",
@@ -242,8 +243,6 @@
"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.",
- "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.",
"Your data directory must be an absolute path." : "Your data directory must be an absolute path.",
@@ -261,11 +260,21 @@
"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" : "Summarise",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},"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 08d752960a3..b80753e6e10 100644
--- a/lib/l10n/es.js
+++ b/lib/l10n/es.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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.",
"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." : "El usuario no fue creado ya que el límite de usuarios fue alcanzado. Compruebe sus notificaciones para aprender más.",
"Could not find category \"%s\"" : "No puede encontrar la categoría \"%s\"",
"Sunday" : "Domingo",
@@ -244,8 +245,6 @@ OC.L10N.register(
"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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 requerido.",
- "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.",
"Your data directory must be an absolute path." : "Tu carpeta de datos debe ser una ruta absoluta.",
@@ -263,11 +262,21 @@ OC.L10N.register(
"Storage connection error. %s" : "Error de conexión de almacenamiento. %s",
"Storage is temporarily not available" : "El almacenamiento no esta disponible temporalmente",
"Storage connection timeout. %s" : "Tiempo de conexión de almacenamiento agotado. %s",
+ "Free prompt" : "Prompt libre",
+ "Runs an arbitrary prompt through the language model." : "Ejecuta un prompt arbitrario mediante el modelo de lenguaje integrado.",
+ "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 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.",
"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 \"_.@-'\"",
"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 error, actualiza la versión de tu libxml2 y reinicia 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."
},
"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 1def3530daf..a4870ed898d 100644
--- a/lib/l10n/es.json
+++ b/lib/l10n/es.json
@@ -154,6 +154,7 @@
"%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.",
"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." : "El usuario no fue creado ya que el límite de usuarios fue alcanzado. Compruebe sus notificaciones para aprender más.",
"Could not find category \"%s\"" : "No puede encontrar la categoría \"%s\"",
"Sunday" : "Domingo",
@@ -242,8 +243,6 @@
"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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 requerido.",
- "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.",
"Your data directory must be an absolute path." : "Tu carpeta de datos debe ser una ruta absoluta.",
@@ -261,11 +260,21 @@
"Storage connection error. %s" : "Error de conexión de almacenamiento. %s",
"Storage is temporarily not available" : "El almacenamiento no esta disponible temporalmente",
"Storage connection timeout. %s" : "Tiempo de conexión de almacenamiento agotado. %s",
+ "Free prompt" : "Prompt libre",
+ "Runs an arbitrary prompt through the language model." : "Ejecuta un prompt arbitrario mediante el modelo de lenguaje integrado.",
+ "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 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.",
"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 \"_.@-'\"",
"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 error, actualiza la versión de tu libxml2 y reinicia 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."
},"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 af256923d22..dd170b3d912 100644
--- a/lib/l10n/es_EC.js
+++ b/lib/l10n/es_EC.js
@@ -2,9 +2,20 @@ 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." : "Esto generalmente se puede solucionar otorgando permisos de escritura al servidor web en el 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 prefieres mantener el archivo config.php como de solo lectura, establece la opción \"config_is_read_only\" en true.",
"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, 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",
+ "Click the following button to confirm your email." : "Haz clic en el siguiente botón para confirmar tu correo electrónico.",
+ "Click the following link to confirm your email." : "Haz clic en el siguiente enlace para confirmar tu correo electrónico.",
+ "Confirm your email" : "Confirma tu 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 +23,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 son compatibles: %s",
+ "The following databases are supported: %s" : "Las siguientes bases de datos son compatibles: %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 biblioteca %1$s con una versión superior a %2$s; la versión disponible es %3$s.",
+ "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Se requiere la biblioteca %1$s con una versión inferior a %2$s; la versión disponible es %3$s.",
+ "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",
+ "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 borrado remoto. Recibirás otro correo electrónico una vez que el proceso haya finalizado.",
+ "Wiping of device %s has finished" : "El borrado del dispositivo %s ha finalizado",
+ "Wiping of device »%s« has finished" : "El borrado del dispositivo »%s« ha finalizado",
+ "»%s« finished remote wipe" : "»%s« ha finalizado el borrado remoto",
+ "Device or application »%s« has finished the remote wipe process." : "El dispositivo o la aplicación »%s« ha finalizado el proceso de borrado remoto.",
+ "Remote wipe started" : "Borrado remoto iniciado",
+ "A remote wipe was started on device %s" : "Se ha iniciado un borrado remoto en el dispositivo %s",
+ "Remote wipe finished" : "Borrado remoto finalizado",
+ "The remote wipe on %s has finished" : "El borrado remoto 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 +78,12 @@ 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 no válida",
+ "Failed to create file from template" : "Error al crear el archivo a partir de 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",
"File name is too long" : "El nombre del archivo es demasiado largo",
@@ -57,19 +94,37 @@ OC.L10N.register(
"__language_name__" : "Español (Ecuador)",
"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" : "Fediverse",
+ "View %s on the fediverse" : "Ver %s en Fediverse",
"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",
+ "Display name" : "Nombre para mostrar",
+ "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",
@@ -80,16 +135,28 @@ OC.L10N.register(
"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",
"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 a través de %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",
+ "_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. ",
"The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe",
+ "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",
@@ -139,36 +206,68 @@ OC.L10N.register(
"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",
"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" : "Generalmente, esto se puede solucionar otorgando permisos de escritura al servidor web en el directorio de configuración. Consulta %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, si prefieres mantener el archivo config.php como de solo lectura, establece la opción \"config_is_read_only\" en true. Consulta %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." : "Generalmente, esto se puede solucionar otorgando permisos de escritura al servidor web en el directorio de aplicaciones o deshabilitando la tienda de aplicaciones en el 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" : "Generalmente, esto se puede solucionar otorgando permisos de escritura al servidor web en el directorio raíz. Consulta %s",
+ "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Los permisos generalmente se pueden solucionar otorgando permisos de escritura al servidor web en el directorio raíz. Consulta %s.",
+ "Your data directory is not writable." : "El directorio de datos no es escribible.",
+ "Setting locale to %s failed." : "Error al establecer la configuración regional en %s.",
+ "Please install one of these locales on your system and restart your web server." : "Instala una de estas configuraciones regionales en tu sistema y reinicia tu 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 solucionar este problema, establece <code>mbstring.func_overload</code> como <code>0</code> en tu archivo 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. ",
+ "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.",
"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 autenticación, se proporcionó un token o un ID 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 ID \"%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." : "No existe un Proveedor de Federación de la Nube con el ID: \"%s\".",
"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",
+ "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.",
"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 \"_.@-'\"",
"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." : "Actualiza la versión de tu base de datos."
},
"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 609c62bdf2d..55b7dcd4d84 100644
--- a/lib/l10n/es_EC.json
+++ b/lib/l10n/es_EC.json
@@ -1,8 +1,19 @@
{ "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." : "Esto generalmente se puede solucionar otorgando permisos de escritura al servidor web en el 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 prefieres mantener el archivo config.php como de solo lectura, establece la opción \"config_is_read_only\" en true.",
"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, 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",
+ "Click the following button to confirm your email." : "Haz clic en el siguiente botón para confirmar tu correo electrónico.",
+ "Click the following link to confirm your email." : "Haz clic en el siguiente enlace para confirmar tu correo electrónico.",
+ "Confirm your email" : "Confirma tu 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 +21,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 son compatibles: %s",
+ "The following databases are supported: %s" : "Las siguientes bases de datos son compatibles: %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 biblioteca %1$s con una versión superior a %2$s; la versión disponible es %3$s.",
+ "Library %1$s with a version lower than %2$s is required - available version %3$s." : "Se requiere la biblioteca %1$s con una versión inferior a %2$s; la versión disponible es %3$s.",
+ "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",
+ "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 borrado remoto. Recibirás otro correo electrónico una vez que el proceso haya finalizado.",
+ "Wiping of device %s has finished" : "El borrado del dispositivo %s ha finalizado",
+ "Wiping of device »%s« has finished" : "El borrado del dispositivo »%s« ha finalizado",
+ "»%s« finished remote wipe" : "»%s« ha finalizado el borrado remoto",
+ "Device or application »%s« has finished the remote wipe process." : "El dispositivo o la aplicación »%s« ha finalizado el proceso de borrado remoto.",
+ "Remote wipe started" : "Borrado remoto iniciado",
+ "A remote wipe was started on device %s" : "Se ha iniciado un borrado remoto en el dispositivo %s",
+ "Remote wipe finished" : "Borrado remoto finalizado",
+ "The remote wipe on %s has finished" : "El borrado remoto 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 +76,12 @@
"_%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 no válida",
+ "Failed to create file from template" : "Error al crear el archivo a partir de 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",
"File name is too long" : "El nombre del archivo es demasiado largo",
@@ -55,19 +92,37 @@
"__language_name__" : "Español (Ecuador)",
"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" : "Fediverse",
+ "View %s on the fediverse" : "Ver %s en Fediverse",
"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",
+ "Display name" : "Nombre para mostrar",
+ "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",
@@ -78,16 +133,28 @@
"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",
"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 a través de %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",
+ "_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. ",
"The requested share does not exist anymore" : "El recurso compartido solicitado ya no existe",
+ "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",
@@ -137,36 +204,68 @@
"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",
"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" : "Generalmente, esto se puede solucionar otorgando permisos de escritura al servidor web en el directorio de configuración. Consulta %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, si prefieres mantener el archivo config.php como de solo lectura, establece la opción \"config_is_read_only\" en true. Consulta %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." : "Generalmente, esto se puede solucionar otorgando permisos de escritura al servidor web en el directorio de aplicaciones o deshabilitando la tienda de aplicaciones en el 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" : "Generalmente, esto se puede solucionar otorgando permisos de escritura al servidor web en el directorio raíz. Consulta %s",
+ "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Los permisos generalmente se pueden solucionar otorgando permisos de escritura al servidor web en el directorio raíz. Consulta %s.",
+ "Your data directory is not writable." : "El directorio de datos no es escribible.",
+ "Setting locale to %s failed." : "Error al establecer la configuración regional en %s.",
+ "Please install one of these locales on your system and restart your web server." : "Instala una de estas configuraciones regionales en tu sistema y reinicia tu 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 solucionar este problema, establece <code>mbstring.func_overload</code> como <code>0</code> en tu archivo 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. ",
+ "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.",
"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 autenticación, se proporcionó un token o un ID 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 ID \"%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." : "No existe un Proveedor de Federación de la Nube con el ID: \"%s\".",
"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",
+ "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.",
"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 \"_.@-'\"",
"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." : "Actualiza la versión de tu base de datos."
},"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 ceeb0415aac..ab62f94437e 100644
--- a/lib/l10n/et_EE.js
+++ b/lib/l10n/et_EE.js
@@ -147,13 +147,13 @@ 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 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",
"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 \"_.@-'\"",
- "libxml2 2.7.0 is at least required. Currently %s is installed." : "Vaja on vähemalt libxml2 2.7.0. Hetkel on installitud %s."
+ "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"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/et_EE.json b/lib/l10n/et_EE.json
index ecbc3bd178a..27abedc8f33 100644
--- a/lib/l10n/et_EE.json
+++ b/lib/l10n/et_EE.json
@@ -145,13 +145,13 @@
"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 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",
"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 \"_.@-'\"",
- "libxml2 2.7.0 is at least required. Currently %s is installed." : "Vaja on vähemalt libxml2 2.7.0. Hetkel on installitud %s."
+ "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"
},"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 a7757978cc8..5b80a7c1a09 100644
--- a/lib/l10n/eu.js
+++ b/lib/l10n/eu.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"This can usually be fixed by giving the web server write access to the config directory." : "Hau normalean konpon daiteke web zerbitzariari konfigurazio direktoriorako idazteko sarbidea emanez.",
"But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Bestela, config.php fitxategia irakurtzeko soilik mantendu nahi baduzu, ezarri bertan \"config_is_read_only\" aukerari 'egia' balioa.",
"See %s" : "Ikusi %s",
+ "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",
@@ -155,6 +156,7 @@ OC.L10N.register(
"%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",
@@ -243,8 +245,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 behar da",
- "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.",
"Your data directory must be an absolute path." : "Zure datuen karpeta bide-izen absolutua izan behar da.",
@@ -262,11 +262,21 @@ OC.L10N.register(
"Storage connection error. %s" : "Biltegiratze-konexioaren errorea. %s",
"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",
+ "Summarizes text by reducing its length without losing key information." : "Testua laburtzen du bere luzera murrizten informazio baliotsua galdu gabe.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/eu.json b/lib/l10n/eu.json
index 4f7f384f727..1f63ae8b053 100644
--- a/lib/l10n/eu.json
+++ b/lib/l10n/eu.json
@@ -3,6 +3,7 @@
"This can usually be fixed by giving the web server write access to the config directory." : "Hau normalean konpon daiteke web zerbitzariari konfigurazio direktoriorako idazteko sarbidea emanez.",
"But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "Bestela, config.php fitxategia irakurtzeko soilik mantendu nahi baduzu, ezarri bertan \"config_is_read_only\" aukerari 'egia' balioa.",
"See %s" : "Ikusi %s",
+ "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",
@@ -153,6 +154,7 @@
"%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",
@@ -241,8 +243,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 behar da",
- "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.",
"Your data directory must be an absolute path." : "Zure datuen karpeta bide-izen absolutua izan behar da.",
@@ -260,11 +260,21 @@
"Storage connection error. %s" : "Biltegiratze-konexioaren errorea. %s",
"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",
+ "Summarizes text by reducing its length without losing key information." : "Testua laburtzen du bere luzera murrizten informazio baliotsua galdu gabe.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},"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 26c2ff4460e..6c69b85d691 100644
--- a/lib/l10n/fa.js
+++ b/lib/l10n/fa.js
@@ -2,10 +2,20 @@ OC.L10N.register(
"lib",
{
"Cannot write into \"config\" directory!" : "نمیتوانید داخل دایرکتوری \"config\" تغییراتی ایجاد کنید",
+ "This can usually be fixed by giving the web server write access to the config directory." : "This can usually be fixed by giving the web server write access to the config directory.",
+ "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it.",
"See %s" : "مشاهده %s",
+ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory.",
"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",
+ "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و%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",
@@ -27,6 +37,7 @@ 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 شروع شده است",
@@ -47,6 +58,7 @@ OC.L10N.register(
"Avatar image is not square" : "تصویر آواتار مربع نیست",
"Files" : "پوشه‌ها",
"View profile" : "مشاهده پروفایل",
+ "Local time: %s" : "Local time: %s",
"today" : "امروز",
"tomorrow" : "فردا",
"yesterday" : "دیروز",
@@ -91,6 +103,8 @@ OC.L10N.register(
"Users" : "کاربران",
"Email" : "رایانامه",
"Mail %s" : "نامه به %s",
+ "Fediverse" : "Fediverse",
+ "View %s on the fediverse" : "View %s on the fediverse",
"Phone" : "تلفن",
"Call %s" : "تماس با %s",
"Twitter" : "توییتر",
@@ -100,6 +114,7 @@ OC.L10N.register(
"Address" : "نشانی",
"Profile picture" : "تصویر نمایه",
"About" : "درباره",
+ "Display name" : "Display name",
"Headline" : "عنوان",
"Organisation" : "سازمان",
"Role" : "نقش",
@@ -120,6 +135,7 @@ OC.L10N.register(
"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را پیاده سازی کند",
"Sharing backend %s not found" : "به اشتراک گذاشتن باطن%s یافت نشد",
"Sharing backend for %s not found" : "به اشتراک گذاشتن باطن برای%s یافت نشد",
@@ -129,11 +145,18 @@ OC.L10N.register(
"Open »%s«" : "باز کن »%s«",
"%1$s via %2$s" : "%1$s از طریق %2$s",
"You are not allowed to share %s" : "شما مجاز به اشتراک گذاری نیستید%s",
+ "Cannot increase permissions of %s" : "Cannot increase permissions of %s",
+ "Files cannot be shared with delete permissions" : "Files cannot be shared with delete permissions",
+ "Files cannot be shared with create permissions" : "Files cannot be shared with create permissions",
"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." : "برای باز کردن آن روی دکمه زیر کلیک کنید.",
"The requested share does not exist anymore" : "سهم درخواست شده دیگر وجود ندارد",
+ "The user was not created because the user limit has been reached. Check your notifications to learn more." : "The user was not created because the user limit has been reached. Check your notifications to learn more.",
"Could not find category \"%s\"" : "دسته بندی %s یافت نشد",
"Sunday" : "یک‌شنبه",
"Monday" : "دوشنبه",
@@ -183,9 +206,11 @@ OC.L10N.register(
"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",
@@ -196,16 +221,34 @@ OC.L10N.register(
"Authentication error" : "خطا در اعتبار سنجی",
"Token expired. Please reload page." : "Token منقضی شده است. لطفا دوباره صفحه را بارگذاری نمایید.",
"No database drivers (sqlite, mysql, or postgresql) installed." : "هیچ درایور پایگاه داده (sqlite ، mysql یا postgresql) نصب نشده است.",
+ "Cannot write into \"config\" directory." : "Cannot write into \"config\" directory.",
+ "This can usually be fixed by giving the web server write access to the config directory. See %s" : "This can usually be fixed by giving the web server write access to the config directory. See %s",
"Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "یا اگر ترجیح می دهید پرونده config.php را فقط بخوانید ، گزینه \"config_is_read_only\" را در آن تنظیم کنید. دیدن%s",
+ "Cannot write into \"apps\" directory." : "Cannot write into \"apps\" directory.",
+ "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file." : "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file.",
+ "Cannot create \"data\" directory." : "Cannot create \"data\" directory.",
+ "This can usually be fixed by giving the web server write access to the root directory. See %s" : "This can usually be fixed by giving the web server write access to the root directory. See %s",
+ "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Permissions can usually be fixed by giving the web server write access to the root directory. See %s.",
+ "Your data directory is not writable." : "Your data directory is not writable.",
+ "Setting locale to %s failed." : "Setting locale to %s failed.",
+ "Please install one of these locales on your system and restart your web server." : "Please install one of these locales on your system and restart your web server.",
"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> is set to <code>%s</code> instead of the expected value <code>0</code>.",
+ "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.",
"PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP ظاهراً برای خنثی کردن بلوک های اسناد درون خطی تنظیم شده است. این کار چندین برنامه اصلی را غیرقابل دسترسی خواهد کرد.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "این احتمالاً توسط حافظه پنهان / کش مانند Zend OPcache یا eAccelerator ایجاد شده است.",
"PHP modules have been installed, but they are still listed as missing?" : "ماژول های پی اچ پی نصب شده اند ، اما هنوز هم به عنوان مفقود شده ذکر شده اند؟",
"Please ask your server administrator to restart the web server." : "لطفاً از سرور سرور خود بخواهید که وب سرور را مجدداً راه اندازی کند.",
+ "The required %s config variable is not configured in the config.php file." : "The required %s config variable is not configured in the config.php file.",
+ "Please ask your server administrator to check the Nextcloud configuration." : "Please ask your server administrator to check the Nextcloud configuration.",
+ "Your data directory 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.",
"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" : "تأیید اعتبار انجام نشد ، نشانه اشتباه یا شناسه ارائه دهنده داده شد",
@@ -218,10 +261,21 @@ 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." : "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." : "فایل های برنامه %1$sبه درستی تعویض نشد. اطمینان حاصل کنید که این یک نسخه سازگار با سرور است.",
"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\" و \"_. @ - '\"",
"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 required.",
+ "Please upgrade your database version." : "Please upgrade your database version."
},
"nplurals=2; plural=(n > 1);");
diff --git a/lib/l10n/fa.json b/lib/l10n/fa.json
index 4bfc1b04842..a5024351f34 100644
--- a/lib/l10n/fa.json
+++ b/lib/l10n/fa.json
@@ -1,9 +1,19 @@
{ "translations": {
"Cannot write into \"config\" directory!" : "نمیتوانید داخل دایرکتوری \"config\" تغییراتی ایجاد کنید",
+ "This can usually be fixed by giving the web server write access to the config directory." : "This can usually be fixed by giving the web server write access to the config directory.",
+ "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it." : "But, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it.",
"See %s" : "مشاهده %s",
+ "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory." : "Application %1$s is not present or has a non-compatible version with this server. Please check the apps directory.",
"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",
+ "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و%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",
@@ -25,6 +35,7 @@
"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 شروع شده است",
@@ -45,6 +56,7 @@
"Avatar image is not square" : "تصویر آواتار مربع نیست",
"Files" : "پوشه‌ها",
"View profile" : "مشاهده پروفایل",
+ "Local time: %s" : "Local time: %s",
"today" : "امروز",
"tomorrow" : "فردا",
"yesterday" : "دیروز",
@@ -89,6 +101,8 @@
"Users" : "کاربران",
"Email" : "رایانامه",
"Mail %s" : "نامه به %s",
+ "Fediverse" : "Fediverse",
+ "View %s on the fediverse" : "View %s on the fediverse",
"Phone" : "تلفن",
"Call %s" : "تماس با %s",
"Twitter" : "توییتر",
@@ -98,6 +112,7 @@
"Address" : "نشانی",
"Profile picture" : "تصویر نمایه",
"About" : "درباره",
+ "Display name" : "Display name",
"Headline" : "عنوان",
"Organisation" : "سازمان",
"Role" : "نقش",
@@ -118,6 +133,7 @@
"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را پیاده سازی کند",
"Sharing backend %s not found" : "به اشتراک گذاشتن باطن%s یافت نشد",
"Sharing backend for %s not found" : "به اشتراک گذاشتن باطن برای%s یافت نشد",
@@ -127,11 +143,18 @@
"Open »%s«" : "باز کن »%s«",
"%1$s via %2$s" : "%1$s از طریق %2$s",
"You are not allowed to share %s" : "شما مجاز به اشتراک گذاری نیستید%s",
+ "Cannot increase permissions of %s" : "Cannot increase permissions of %s",
+ "Files cannot be shared with delete permissions" : "Files cannot be shared with delete permissions",
+ "Files cannot be shared with create permissions" : "Files cannot be shared with create permissions",
"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." : "برای باز کردن آن روی دکمه زیر کلیک کنید.",
"The requested share does not exist anymore" : "سهم درخواست شده دیگر وجود ندارد",
+ "The user was not created because the user limit has been reached. Check your notifications to learn more." : "The user was not created because the user limit has been reached. Check your notifications to learn more.",
"Could not find category \"%s\"" : "دسته بندی %s یافت نشد",
"Sunday" : "یک‌شنبه",
"Monday" : "دوشنبه",
@@ -181,9 +204,11 @@
"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",
@@ -194,16 +219,34 @@
"Authentication error" : "خطا در اعتبار سنجی",
"Token expired. Please reload page." : "Token منقضی شده است. لطفا دوباره صفحه را بارگذاری نمایید.",
"No database drivers (sqlite, mysql, or postgresql) installed." : "هیچ درایور پایگاه داده (sqlite ، mysql یا postgresql) نصب نشده است.",
+ "Cannot write into \"config\" directory." : "Cannot write into \"config\" directory.",
+ "This can usually be fixed by giving the web server write access to the config directory. See %s" : "This can usually be fixed by giving the web server write access to the config directory. See %s",
"Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "یا اگر ترجیح می دهید پرونده config.php را فقط بخوانید ، گزینه \"config_is_read_only\" را در آن تنظیم کنید. دیدن%s",
+ "Cannot write into \"apps\" directory." : "Cannot write into \"apps\" directory.",
+ "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file." : "This can usually be fixed by giving the web server write access to the apps directory or disabling the App Store in the config file.",
+ "Cannot create \"data\" directory." : "Cannot create \"data\" directory.",
+ "This can usually be fixed by giving the web server write access to the root directory. See %s" : "This can usually be fixed by giving the web server write access to the root directory. See %s",
+ "Permissions can usually be fixed by giving the web server write access to the root directory. See %s." : "Permissions can usually be fixed by giving the web server write access to the root directory. See %s.",
+ "Your data directory is not writable." : "Your data directory is not writable.",
+ "Setting locale to %s failed." : "Setting locale to %s failed.",
+ "Please install one of these locales on your system and restart your web server." : "Please install one of these locales on your system and restart your web server.",
"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> is set to <code>%s</code> instead of the expected value <code>0</code>.",
+ "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.",
"PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP ظاهراً برای خنثی کردن بلوک های اسناد درون خطی تنظیم شده است. این کار چندین برنامه اصلی را غیرقابل دسترسی خواهد کرد.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "این احتمالاً توسط حافظه پنهان / کش مانند Zend OPcache یا eAccelerator ایجاد شده است.",
"PHP modules have been installed, but they are still listed as missing?" : "ماژول های پی اچ پی نصب شده اند ، اما هنوز هم به عنوان مفقود شده ذکر شده اند؟",
"Please ask your server administrator to restart the web server." : "لطفاً از سرور سرور خود بخواهید که وب سرور را مجدداً راه اندازی کند.",
+ "The required %s config variable is not configured in the config.php file." : "The required %s config variable is not configured in the config.php file.",
+ "Please ask your server administrator to check the Nextcloud configuration." : "Please ask your server administrator to check the Nextcloud configuration.",
+ "Your data directory 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.",
"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" : "تأیید اعتبار انجام نشد ، نشانه اشتباه یا شناسه ارائه دهنده داده شد",
@@ -216,10 +259,21 @@
"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." : "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." : "فایل های برنامه %1$sبه درستی تعویض نشد. اطمینان حاصل کنید که این یک نسخه سازگار با سرور است.",
"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\" و \"_. @ - '\"",
"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 required.",
+ "Please upgrade your database version." : "Please upgrade your database version."
},"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 836831e3ba9..7eb441edd14 100644
--- a/lib/l10n/fi.js
+++ b/lib/l10n/fi.js
@@ -205,6 +205,7 @@ OC.L10N.register(
"Cannot create \"data\" directory." : "Ei voi luoda \"data\"-hakemistoa",
"Your data directory is not writable." : "Datahakemistosi ei ole kirjoitettavissa.",
"Setting locale to %s failed." : "Maa-asetuston %s asettaminen epäonnistui.",
+ "Please install one of these locales on your system and restart your web server." : "Asenna ainakin yksi näistä maa-asetuksista järjestelmään ja käynnistä http-palvelin uudelleen.",
"PHP module %s not installed." : "PHP-moduulia %s ei ole asennettu.",
"Please ask your server administrator to install the module." : "Pyydä palvelimen ylläpitäjää asentamaan moduulin.",
"PHP setting \"%s\" is not set to \"%s\"." : "PHP-asetusta \"%s\" ei ole asetettu arvoon \"%s\".",
@@ -214,8 +215,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 vaaditaan.",
- "Please upgrade your database version." : "Päivitä tietokannan versio.",
"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\".",
@@ -228,8 +227,11 @@ OC.L10N.register(
"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.",
"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 \"_.@-'\"",
"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."
+ "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."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/fi.json b/lib/l10n/fi.json
index d7687e4c792..3ec59a0eff9 100644
--- a/lib/l10n/fi.json
+++ b/lib/l10n/fi.json
@@ -203,6 +203,7 @@
"Cannot create \"data\" directory." : "Ei voi luoda \"data\"-hakemistoa",
"Your data directory is not writable." : "Datahakemistosi ei ole kirjoitettavissa.",
"Setting locale to %s failed." : "Maa-asetuston %s asettaminen epäonnistui.",
+ "Please install one of these locales on your system and restart your web server." : "Asenna ainakin yksi näistä maa-asetuksista järjestelmään ja käynnistä http-palvelin uudelleen.",
"PHP module %s not installed." : "PHP-moduulia %s ei ole asennettu.",
"Please ask your server administrator to install the module." : "Pyydä palvelimen ylläpitäjää asentamaan moduulin.",
"PHP setting \"%s\" is not set to \"%s\"." : "PHP-asetusta \"%s\" ei ole asetettu arvoon \"%s\".",
@@ -212,8 +213,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 vaaditaan.",
- "Please upgrade your database version." : "Päivitä tietokannan versio.",
"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\".",
@@ -226,8 +225,11 @@
"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.",
"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 \"_.@-'\"",
"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."
+ "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."
},"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 428c98e243f..412c4c86c53 100644
--- a/lib/l10n/fr.js
+++ b/lib/l10n/fr.js
@@ -244,8 +244,6 @@ 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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 requis.",
- "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.",
"Your data directory must be an absolute path." : "Le chemin de votre répertoire doit être un chemin absolu.",
@@ -268,6 +266,8 @@ OC.L10N.register(
"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)",
"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."
+ "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."
},
"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 98a93778416..6d75989d48e 100644
--- a/lib/l10n/fr.json
+++ b/lib/l10n/fr.json
@@ -242,8 +242,6 @@
"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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 requis.",
- "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.",
"Your data directory must be an absolute path." : "Le chemin de votre répertoire doit être un chemin absolu.",
@@ -266,6 +264,8 @@
"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)",
"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."
+ "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."
},"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 69f7e837fa0..46440e27bcc 100644
--- a/lib/l10n/gl.js
+++ b/lib/l10n/gl.js
@@ -14,7 +14,7 @@ OC.L10N.register(
"Email verification" : "Verificación do correo-e",
"Click the following button to confirm your email." : "Prema no seguinte botón para confirmar o seu correo-e.",
"Click the following link to confirm your email." : "Prema na seguinte ligazón para confirmar o seu correo-e.",
- "Confirm your email" : "Confirme o seu correo-e",
+ "Confirm your email" : "Confirmar o seu correo-e",
"Other activities" : "Outras actividades",
"%1$s and %2$s" : "%1$s e %2$s",
"%1$s, %2$s and %3$s" : "%1$s, %2$s e %3$s",
@@ -25,18 +25,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." : "É necesario PHP %s ou superior.",
- "PHP with a version lower than %s is required." : "É necesario PHP cunha versión inferior a %s.",
- "%sbit or higher PHP required." : "É necesario PHP para %sbits ou superior.",
+ "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.",
"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." : "É necesaria 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." : "É necesaria 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." : "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.",
"The following platforms are supported: %s" : "Admítense as seguintes plataformas: %s",
- "Server version %s or higher is required." : "É necesaria a versión %s ou superior do servidor.",
- "Server version %s or lower is required." : "É necesaria a versión %s ou inferior do servidor.",
+ "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",
@@ -79,7 +79,7 @@ OC.L10N.register(
"in a few seconds" : "en poucos segundos",
"seconds ago" : "segundos atrás",
"Empty file" : "Ficheiro baleiro",
- "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Non existe o módulo co ID: %s. Actíveo nos axustes das aplicacións ou contacte co administrador.",
+ "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Non existe o módulo co ID: %s. Actíveo nos axustes das aplicacións ou contacte coa administración desta instancia.",
"File already exists" : "O ficheiro xa existe",
"Invalid path" : "Ruta incorrecta.",
"Failed to create file from template" : "Produciuse un fallo ao crear un ficheiro a partir do modelo",
@@ -139,9 +139,9 @@ OC.L10N.register(
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "A infraestrutura de compartición %s ten que implementar a interface OCP\\Share_Backend",
"Sharing backend %s not found" : "Non se atopou a infraestrutura de compartición %s",
"Sharing backend for %s not found" : "Non se atopou a infraestrutura de compartición para %s",
- "%1$s shared »%2$s« with you and wants to add:" : "%1$s compartiu «%2$s» con vostede e quere engadir:",
- "%1$s shared »%2$s« with you and wants to add" : "%1$s compartiu «%2$s» con vostede e quere engadir",
- "»%s« added a note to a file shared with you" : "«%s» engadiu unha nota a un ficheiro compartido con vostede",
+ "%1$s shared »%2$s« with you and wants to add:" : "%1$s compartiu «%2$s» con Vde. e quere engadir:",
+ "%1$s shared »%2$s« with you and wants to add" : "%1$s compartiu «%2$s» con Vde. e quere engadir",
+ "»%s« added a note to a file shared with you" : "«%s» engadiu unha nota a un ficheiro compartido con Vde.",
"Open »%s«" : "Abrir «%s»",
"%1$s via %2$s" : "%1$s mediante %2$s",
"You are not allowed to share %s" : "Non ten permiso para compartir %s",
@@ -152,10 +152,11 @@ OC.L10N.register(
"_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 vostede",
- "%1$s shared »%2$s« with you." : "%1$s compartiu «%2$s» con vostede.",
+ "%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.",
- "The requested share does not exist anymore" : "O recurso compartido solicitado xa non existe",
+ "The requested share does not exist anymore" : "A compartición solicitada xa non existe",
+ "The requested share comes from a disabled user" : "A compartición solicitada procede dun usuario desactivado",
"The user was not created because the user limit has been reached. Check your notifications to learn more." : "Non se creou o usuario porque acadouse o límite de usuarios. Consulte as súas notificacións para obter máis información.",
"Could not find category \"%s\"" : "Non foi posíbel atopar a categoría «%s»",
"Sunday" : "domingo",
@@ -233,19 +234,17 @@ OC.L10N.register(
"Setting locale to %s failed." : "Produciuse un fallo ao axustar a configuración rexional en %s.",
"Please install one of these locales on your system and restart your web server." : "Instale un destes locais no seu sistema e reinicie o seu servidor web.",
"PHP module %s not installed." : "O módulo PHP %s non está instalado.",
- "Please ask your server administrator to install the module." : "Pregúntelle ao administrador do servidor pola instalación do módulo.",
+ "Please ask your server administrator to install the module." : "Pídalle á administración do seu servidor que instale o módulo.",
"PHP setting \"%s\" is not set to \"%s\"." : "O axuste de PHP «%s» non está estabelecido a «%s».",
"Adjusting this setting in php.ini will make Nextcloud run again" : "Cambiar este axuste no ficheiro php.ini fará que Nextcloud funcione de novo",
- "<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á definido en <code>%s</code> no canto do valor agardado <code>0</code>.",
+ "<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á estabelecido en <code>%s</code> no canto do valor agardado <code>0</code>.",
"To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para solucionar este problema, estabeleza <code>mbstring.func_overload</code> en <code>0</code> no seu php.ini.",
- "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Semella que PHP foi configurado para quitar bloques de documentos en liña. Isto fará que varias aplicacións sexan inaccesíbeis.",
+ "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Semella que PHP foi configurado para quitar bloques de documentos en liña. Isto fará que varios aplicativos sexan inaccesíbeis. ",
"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." : "Pregúntelle ao administrador do servidor polo reinicio do servidor web..",
- "The required %s config variable is not configured in the config.php file." : "A variábel de configuración %s necesaria non está configurada no ficheiro config.php.",
- "Please ask your server administrator to check the Nextcloud configuration." : "Pídalle ao administrador do seu servidor que verifique a configuración de Nextcloud.",
- "PostgreSQL >= 9 required." : "É necesario PostgreSQL >= 9.",
- "Please upgrade your database version." : "Anove a versión da súa base de datos",
+ "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.",
+ "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.",
@@ -263,11 +262,21 @@ OC.L10N.register(
"Storage connection error. %s" : "Produciuse un erro na conexión ao almacenamento. %s",
"Storage is temporarily not available" : "O almacenamento non está dispoñíbel temporalmente",
"Storage connection timeout. %s" : "Esgotouse o tempo de conexión co almacenamento. %s",
+ "Free prompt" : "Indicación libre",
+ "Runs an arbitrary prompt through the language model." : "Procesa unha indicación arbitraria a través do modelo de linguaxe.",
+ "Generate headline" : "Xerar título",
+ "Generates a possible headline for a text." : "Xera un posíbel título para un texto.",
+ "Summarize" : "Resumir",
+ "Summarizes text by reducing its length without losing key information." : "Resume o texto reducindo a súa lonxitude sen perder a información clave.",
+ "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.",
"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." : "É necesario, cando menos, 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. "
+ "libxml2 2.7.0 is at least required. Currently %s is installed." : "Precisase, cando menos, 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"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/gl.json b/lib/l10n/gl.json
index 0503e77db93..982199d4f7c 100644
--- a/lib/l10n/gl.json
+++ b/lib/l10n/gl.json
@@ -12,7 +12,7 @@
"Email verification" : "Verificación do correo-e",
"Click the following button to confirm your email." : "Prema no seguinte botón para confirmar o seu correo-e.",
"Click the following link to confirm your email." : "Prema na seguinte ligazón para confirmar o seu correo-e.",
- "Confirm your email" : "Confirme o seu correo-e",
+ "Confirm your email" : "Confirmar o seu correo-e",
"Other activities" : "Outras actividades",
"%1$s and %2$s" : "%1$s e %2$s",
"%1$s, %2$s and %3$s" : "%1$s, %2$s e %3$s",
@@ -23,18 +23,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." : "É necesario PHP %s ou superior.",
- "PHP with a version lower than %s is required." : "É necesario PHP cunha versión inferior a %s.",
- "%sbit or higher PHP required." : "É necesario PHP para %sbits ou superior.",
+ "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.",
"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." : "É necesaria 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." : "É necesaria 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." : "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.",
"The following platforms are supported: %s" : "Admítense as seguintes plataformas: %s",
- "Server version %s or higher is required." : "É necesaria a versión %s ou superior do servidor.",
- "Server version %s or lower is required." : "É necesaria a versión %s ou inferior do servidor.",
+ "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",
@@ -77,7 +77,7 @@
"in a few seconds" : "en poucos segundos",
"seconds ago" : "segundos atrás",
"Empty file" : "Ficheiro baleiro",
- "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Non existe o módulo co ID: %s. Actíveo nos axustes das aplicacións ou contacte co administrador.",
+ "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Non existe o módulo co ID: %s. Actíveo nos axustes das aplicacións ou contacte coa administración desta instancia.",
"File already exists" : "O ficheiro xa existe",
"Invalid path" : "Ruta incorrecta.",
"Failed to create file from template" : "Produciuse un fallo ao crear un ficheiro a partir do modelo",
@@ -137,9 +137,9 @@
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "A infraestrutura de compartición %s ten que implementar a interface OCP\\Share_Backend",
"Sharing backend %s not found" : "Non se atopou a infraestrutura de compartición %s",
"Sharing backend for %s not found" : "Non se atopou a infraestrutura de compartición para %s",
- "%1$s shared »%2$s« with you and wants to add:" : "%1$s compartiu «%2$s» con vostede e quere engadir:",
- "%1$s shared »%2$s« with you and wants to add" : "%1$s compartiu «%2$s» con vostede e quere engadir",
- "»%s« added a note to a file shared with you" : "«%s» engadiu unha nota a un ficheiro compartido con vostede",
+ "%1$s shared »%2$s« with you and wants to add:" : "%1$s compartiu «%2$s» con Vde. e quere engadir:",
+ "%1$s shared »%2$s« with you and wants to add" : "%1$s compartiu «%2$s» con Vde. e quere engadir",
+ "»%s« added a note to a file shared with you" : "«%s» engadiu unha nota a un ficheiro compartido con Vde.",
"Open »%s«" : "Abrir «%s»",
"%1$s via %2$s" : "%1$s mediante %2$s",
"You are not allowed to share %s" : "Non ten permiso para compartir %s",
@@ -150,10 +150,11 @@
"_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 vostede",
- "%1$s shared »%2$s« with you." : "%1$s compartiu «%2$s» con vostede.",
+ "%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.",
- "The requested share does not exist anymore" : "O recurso compartido solicitado xa non existe",
+ "The requested share does not exist anymore" : "A compartición solicitada xa non existe",
+ "The requested share comes from a disabled user" : "A compartición solicitada procede dun usuario desactivado",
"The user was not created because the user limit has been reached. Check your notifications to learn more." : "Non se creou o usuario porque acadouse o límite de usuarios. Consulte as súas notificacións para obter máis información.",
"Could not find category \"%s\"" : "Non foi posíbel atopar a categoría «%s»",
"Sunday" : "domingo",
@@ -231,19 +232,17 @@
"Setting locale to %s failed." : "Produciuse un fallo ao axustar a configuración rexional en %s.",
"Please install one of these locales on your system and restart your web server." : "Instale un destes locais no seu sistema e reinicie o seu servidor web.",
"PHP module %s not installed." : "O módulo PHP %s non está instalado.",
- "Please ask your server administrator to install the module." : "Pregúntelle ao administrador do servidor pola instalación do módulo.",
+ "Please ask your server administrator to install the module." : "Pídalle á administración do seu servidor que instale o módulo.",
"PHP setting \"%s\" is not set to \"%s\"." : "O axuste de PHP «%s» non está estabelecido a «%s».",
"Adjusting this setting in php.ini will make Nextcloud run again" : "Cambiar este axuste no ficheiro php.ini fará que Nextcloud funcione de novo",
- "<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á definido en <code>%s</code> no canto do valor agardado <code>0</code>.",
+ "<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á estabelecido en <code>%s</code> no canto do valor agardado <code>0</code>.",
"To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini." : "Para solucionar este problema, estabeleza <code>mbstring.func_overload</code> en <code>0</code> no seu php.ini.",
- "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Semella que PHP foi configurado para quitar bloques de documentos en liña. Isto fará que varias aplicacións sexan inaccesíbeis.",
+ "PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "Semella que PHP foi configurado para quitar bloques de documentos en liña. Isto fará que varios aplicativos sexan inaccesíbeis. ",
"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." : "Pregúntelle ao administrador do servidor polo reinicio do servidor web..",
- "The required %s config variable is not configured in the config.php file." : "A variábel de configuración %s necesaria non está configurada no ficheiro config.php.",
- "Please ask your server administrator to check the Nextcloud configuration." : "Pídalle ao administrador do seu servidor que verifique a configuración de Nextcloud.",
- "PostgreSQL >= 9 required." : "É necesario PostgreSQL >= 9.",
- "Please upgrade your database version." : "Anove a versión da súa base de datos",
+ "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.",
+ "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.",
@@ -261,11 +260,21 @@
"Storage connection error. %s" : "Produciuse un erro na conexión ao almacenamento. %s",
"Storage is temporarily not available" : "O almacenamento non está dispoñíbel temporalmente",
"Storage connection timeout. %s" : "Esgotouse o tempo de conexión co almacenamento. %s",
+ "Free prompt" : "Indicación libre",
+ "Runs an arbitrary prompt through the language model." : "Procesa unha indicación arbitraria a través do modelo de linguaxe.",
+ "Generate headline" : "Xerar título",
+ "Generates a possible headline for a text." : "Xera un posíbel título para un texto.",
+ "Summarize" : "Resumir",
+ "Summarizes text by reducing its length without losing key information." : "Resume o texto reducindo a súa lonxitude sen perder a información clave.",
+ "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.",
"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." : "É necesario, cando menos, 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. "
+ "libxml2 2.7.0 is at least required. Currently %s is installed." : "Precisase, cando menos, 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"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/hu.js b/lib/l10n/hu.js
index ca91da7d2a9..54aa8d7f36a 100644
--- a/lib/l10n/hu.js
+++ b/lib/l10n/hu.js
@@ -244,8 +244,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 szükséges.",
- "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.",
"Your data directory must be an absolute path." : "Az adatkönyvtárnak abszolút útvonalnak kell lennie",
@@ -268,6 +266,8 @@ OC.L10N.register(
"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 „_.@-'”",
"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."
+ "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."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/hu.json b/lib/l10n/hu.json
index 7d59052dba8..1f4c8021868 100644
--- a/lib/l10n/hu.json
+++ b/lib/l10n/hu.json
@@ -242,8 +242,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 szükséges.",
- "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.",
"Your data directory must be an absolute path." : "Az adatkönyvtárnak abszolút útvonalnak kell lennie",
@@ -266,6 +264,8 @@
"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 „_.@-'”",
"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."
+ "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."
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/it.js b/lib/l10n/it.js
index 98d3e1c1bb0..52cf1721362 100644
--- a/lib/l10n/it.js
+++ b/lib/l10n/it.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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.",
"The requested share does not exist anymore" : "La condivisione richiesta non esiste più",
+ "The requested share comes from a disabled user" : "La condivisione richiesta proviene da un utente disabilitato",
"The user was not created because the user limit has been reached. Check your notifications to learn more." : "L'utente non è stato creato perché il limite è stato raggiunto. Controlla le notifiche per maggiori informazioni.",
"Could not find category \"%s\"" : "Impossibile trovare la categoria \"%s\"",
"Sunday" : "Domenica",
@@ -244,8 +245,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.",
- "PostgreSQL >= 9 required." : "Richiesto PostgreSQL >= 9.",
- "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.",
"Your data directory must be an absolute path." : "La cartella dei dati deve essere un percorso assoluto.",
@@ -263,11 +262,21 @@ OC.L10N.register(
"Storage connection error. %s" : "Errore di connessione all'archiviazione. %s",
"Storage is temporarily not available" : "L'archiviazione è temporaneamente non disponibile",
"Storage connection timeout. %s" : "Timeout di connessione all'archiviazione. %s",
+ "Free prompt" : "Prompt libero",
+ "Runs an arbitrary prompt through the language model." : "Esegue un prompt arbitrario attraverso il modello di lingua.",
+ "Generate headline" : "Genera titolo",
+ "Generates a possible headline for a text." : "Genera un possibile titolo per un testo.",
+ "Summarize" : "Riassumi",
+ "Summarizes text by reducing its length without losing key information." : "Riassume il testo riducendone la lunghezza senza perdere le informazioni chiave.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},
"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 74880c56998..8fb450a83fd 100644
--- a/lib/l10n/it.json
+++ b/lib/l10n/it.json
@@ -154,6 +154,7 @@
"%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.",
"The requested share does not exist anymore" : "La condivisione richiesta non esiste più",
+ "The requested share comes from a disabled user" : "La condivisione richiesta proviene da un utente disabilitato",
"The user was not created because the user limit has been reached. Check your notifications to learn more." : "L'utente non è stato creato perché il limite è stato raggiunto. Controlla le notifiche per maggiori informazioni.",
"Could not find category \"%s\"" : "Impossibile trovare la categoria \"%s\"",
"Sunday" : "Domenica",
@@ -242,8 +243,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.",
- "PostgreSQL >= 9 required." : "Richiesto PostgreSQL >= 9.",
- "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.",
"Your data directory must be an absolute path." : "La cartella dei dati deve essere un percorso assoluto.",
@@ -261,11 +260,21 @@
"Storage connection error. %s" : "Errore di connessione all'archiviazione. %s",
"Storage is temporarily not available" : "L'archiviazione è temporaneamente non disponibile",
"Storage connection timeout. %s" : "Timeout di connessione all'archiviazione. %s",
+ "Free prompt" : "Prompt libero",
+ "Runs an arbitrary prompt through the language model." : "Esegue un prompt arbitrario attraverso il modello di lingua.",
+ "Generate headline" : "Genera titolo",
+ "Generates a possible headline for a text." : "Genera un possibile titolo per un testo.",
+ "Summarize" : "Riassumi",
+ "Summarizes text by reducing its length without losing key information." : "Riassume il testo riducendone la lunghezza senza perdere le informazioni chiave.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},"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 ffc8b3383d3..a58519f02ca 100644
--- a/lib/l10n/ja.js
+++ b/lib/l10n/ja.js
@@ -5,6 +5,7 @@ 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が存在しないか、このサーバと互換性のないバージョンがあります。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",
@@ -113,6 +114,7 @@ OC.L10N.register(
"Address" : "アドレス",
"Profile picture" : "プロフィールの写真",
"About" : "詳細",
+ "Display name" : "表示名",
"Headline" : "見出し",
"Organisation" : "組織",
"Role" : "ロール",
@@ -242,8 +244,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構成を確認するように依頼してください。",
- "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 に変更してください。",
"Your data directory must be an absolute path." : "データディレクトリは、絶対パスにする必要があります",
@@ -261,11 +261,21 @@ 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 のファイルが正しく置き換えられませんでした。サーバーと互換性のあるバージョンであることを確認してください。",
"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\", \"_.@-\"",
"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サーバーを再起動してください。"
+ "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." : "新しいバージョンのデータベースにアップグレードしてください。"
},
"nplurals=1; plural=0;");
diff --git a/lib/l10n/ja.json b/lib/l10n/ja.json
index 4f270b34f02..f45d9b5e93f 100644
--- a/lib/l10n/ja.json
+++ b/lib/l10n/ja.json
@@ -3,6 +3,7 @@
"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が存在しないか、このサーバと互換性のないバージョンがあります。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",
@@ -111,6 +112,7 @@
"Address" : "アドレス",
"Profile picture" : "プロフィールの写真",
"About" : "詳細",
+ "Display name" : "表示名",
"Headline" : "見出し",
"Organisation" : "組織",
"Role" : "ロール",
@@ -240,8 +242,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構成を確認するように依頼してください。",
- "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 に変更してください。",
"Your data directory must be an absolute path." : "データディレクトリは、絶対パスにする必要があります",
@@ -259,11 +259,21 @@
"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 のファイルが正しく置き換えられませんでした。サーバーと互換性のあるバージョンであることを確認してください。",
"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\", \"_.@-\"",
"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サーバーを再起動してください。"
+ "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." : "新しいバージョンのデータベースにアップグレードしてください。"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/lib/l10n/ko.js b/lib/l10n/ko.js
index 62675562c72..00377f3d7e3 100644
--- a/lib/l10n/ko.js
+++ b/lib/l10n/ko.js
@@ -105,7 +105,7 @@ OC.L10N.register(
"Open »%s«" : "%s 열기",
"%1$s via %2$s" : "%1$s(%2$s 경유)",
"You are not allowed to share %s" : "%s을(를) 공유할 수 있는 권한이 없습니다",
- "Cannot increase permissions of %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." : "아래 단추를 눌러서 열 수 있습니다.",
@@ -182,7 +182,7 @@ OC.L10N.register(
"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\"을(를) 지원하지 않거나 사용할 수 없습니다. ",
+ "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\"",
"Cloud Federation Provider with ID: \"%s\" does not exist." : "ID가 \"%s\"인 클라우드 연합 제공자가 없습니다.",
diff --git a/lib/l10n/ko.json b/lib/l10n/ko.json
index f7b6d02bf29..0fb317916e3 100644
--- a/lib/l10n/ko.json
+++ b/lib/l10n/ko.json
@@ -103,7 +103,7 @@
"Open »%s«" : "%s 열기",
"%1$s via %2$s" : "%1$s(%2$s 경유)",
"You are not allowed to share %s" : "%s을(를) 공유할 수 있는 권한이 없습니다",
- "Cannot increase permissions of %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." : "아래 단추를 눌러서 열 수 있습니다.",
@@ -180,7 +180,7 @@
"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\"을(를) 지원하지 않거나 사용할 수 없습니다. ",
+ "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\"",
"Cloud Federation Provider with ID: \"%s\" does not exist." : "ID가 \"%s\"인 클라우드 연합 제공자가 없습니다.",
diff --git a/lib/l10n/mk.js b/lib/l10n/mk.js
index a35cd5885d7..bda43400d66 100644
--- a/lib/l10n/mk.js
+++ b/lib/l10n/mk.js
@@ -243,8 +243,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." : "Замолете го сервер администраторот да ја провери конфигурацијата.",
- "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, за да неможе да се чита од други корисници.",
"Your data directory must be an absolute path." : "Вашата папка со податоци мора да биде апсолутна патека.",
@@ -267,6 +265,8 @@ OC.L10N.register(
"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\", и \"_.@-'\"",
"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." : "Ве молиме надградете ја верзијата на базата со податоци"
},
"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;");
diff --git a/lib/l10n/mk.json b/lib/l10n/mk.json
index e72ba751d46..3177350622d 100644
--- a/lib/l10n/mk.json
+++ b/lib/l10n/mk.json
@@ -241,8 +241,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." : "Замолете го сервер администраторот да ја провери конфигурацијата.",
- "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, за да неможе да се чита од други корисници.",
"Your data directory must be an absolute path." : "Вашата папка со податоци мора да биде апсолутна патека.",
@@ -265,6 +263,8 @@
"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\", и \"_.@-'\"",
"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." : "Ве молиме надградете ја верзијата на базата со податоци"
},"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 a5dd5e23fb7..a705374d0ac 100644
--- a/lib/l10n/mn.js
+++ b/lib/l10n/mn.js
@@ -28,7 +28,7 @@ OC.L10N.register(
"Address" : "хаяг",
"Profile picture" : "Профайл зураг",
"About" : "Тухай",
- "Unknown user" : " хэрэглэгч",
+ "Unknown user" : "Тодорхойгүй хэрэглэгч",
"Open »%s«" : "»%s« нээх",
"Sunday" : "ням гариг",
"Monday" : "даваа",
diff --git a/lib/l10n/mn.json b/lib/l10n/mn.json
index d9c15daa144..a684de4999f 100644
--- a/lib/l10n/mn.json
+++ b/lib/l10n/mn.json
@@ -26,7 +26,7 @@
"Address" : "хаяг",
"Profile picture" : "Профайл зураг",
"About" : "Тухай",
- "Unknown user" : " хэрэглэгч",
+ "Unknown user" : "Тодорхойгүй хэрэглэгч",
"Open »%s«" : "»%s« нээх",
"Sunday" : "ням гариг",
"Monday" : "даваа",
diff --git a/lib/l10n/nl.js b/lib/l10n/nl.js
index 86a5eeedc34..5aa59620e0c 100644
--- a/lib/l10n/nl.js
+++ b/lib/l10n/nl.js
@@ -94,6 +94,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",
@@ -228,8 +229,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 is vereist.",
- "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.",
"Your data directory must be an absolute path." : "Je datamap moet een absolute bestandslocatie hebben.",
@@ -251,6 +250,8 @@ OC.L10N.register(
"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 \"_.@-\"",
"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."
+ "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."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/nl.json b/lib/l10n/nl.json
index aae3495d0e9..c4ab53ebcd1 100644
--- a/lib/l10n/nl.json
+++ b/lib/l10n/nl.json
@@ -92,6 +92,7 @@
"Appearance and accessibility" : "Weergave en toegankelijkheid",
"Apps" : "Apps",
"Personal settings" : "Persoonlijke instellingen",
+ "Administration settings" : "Beheerder instellingen",
"Settings" : "Instellingen",
"Log out" : "Uitloggen",
"Users" : "Gebruikers",
@@ -226,8 +227,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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 is vereist.",
- "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.",
"Your data directory must be an absolute path." : "Je datamap moet een absolute bestandslocatie hebben.",
@@ -249,6 +248,8 @@
"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 \"_.@-\"",
"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."
+ "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."
},"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 3fd4c3f6b01..68de01a6171 100644
--- a/lib/l10n/pl.js
+++ b/lib/l10n/pl.js
@@ -242,8 +242,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.",
- "PostgreSQL >= 9 required." : "Wymagany PostgreSQL >= 9",
- "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.",
"Your data directory must be an absolute path." : "Katalog danych musi mieć ścieżkę absolutną.",
@@ -266,6 +264,8 @@ OC.L10N.register(
"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 \"_.@-'\"",
"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."
+ "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."
},
"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 72204b53517..ea9d21d3b76 100644
--- a/lib/l10n/pl.json
+++ b/lib/l10n/pl.json
@@ -240,8 +240,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.",
- "PostgreSQL >= 9 required." : "Wymagany PostgreSQL >= 9",
- "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.",
"Your data directory must be an absolute path." : "Katalog danych musi mieć ścieżkę absolutną.",
@@ -264,6 +262,8 @@
"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 \"_.@-'\"",
"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."
+ "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."
},"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 ce9efca34a4..265de0ee0a8 100644
--- a/lib/l10n/pt_BR.js
+++ b/lib/l10n/pt_BR.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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",
@@ -244,8 +245,6 @@ 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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 é necessário.",
- "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.",
"Your data directory must be an absolute path." : "Seu diretório de dados deve ser um caminho absoluto.",
@@ -263,11 +262,21 @@ OC.L10N.register(
"Storage connection error. %s" : "Erro na conexão de armazenamento. %s",
"Storage is temporarily not available" : "Armazenamento temporariamente indisponível",
"Storage connection timeout. %s" : "Atingido o tempo limite de conexão ao armazenamento. %s",
+ "Free prompt" : "Solicitação gratuita",
+ "Runs an arbitrary prompt through the language model." : "Executa um prompt arbitrário por meio do modelo de idioma.",
+ "Generate headline" : "Gerar título",
+ "Generates a possible headline for a text." : "Gera um título possível para um texto.",
+ "Summarize" : "Resumir",
+ "Summarizes text by reducing its length without losing key information." : "Resume o texto reduzindo seu comprimento sem perder informações importantes.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},
"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 3b19728a501..2609d133dd4 100644
--- a/lib/l10n/pt_BR.json
+++ b/lib/l10n/pt_BR.json
@@ -154,6 +154,7 @@
"%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",
@@ -242,8 +243,6 @@
"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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 é necessário.",
- "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.",
"Your data directory must be an absolute path." : "Seu diretório de dados deve ser um caminho absoluto.",
@@ -261,11 +260,21 @@
"Storage connection error. %s" : "Erro na conexão de armazenamento. %s",
"Storage is temporarily not available" : "Armazenamento temporariamente indisponível",
"Storage connection timeout. %s" : "Atingido o tempo limite de conexão ao armazenamento. %s",
+ "Free prompt" : "Solicitação gratuita",
+ "Runs an arbitrary prompt through the language model." : "Executa um prompt arbitrário por meio do modelo de idioma.",
+ "Generate headline" : "Gerar título",
+ "Generates a possible headline for a text." : "Gera um título possível para um texto.",
+ "Summarize" : "Resumir",
+ "Summarizes text by reducing its length without losing key information." : "Resume o texto reduzindo seu comprimento sem perder informações importantes.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},"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 841f65b3d17..c30c214db40 100644
--- a/lib/l10n/pt_PT.js
+++ b/lib/l10n/pt_PT.js
@@ -189,8 +189,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.",
- "PostgreSQL >= 9 required." : "Necessário PostgreSQL >= 9",
- "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.",
"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",
@@ -204,6 +202,8 @@ OC.L10N.register(
"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 \"_.@-'\"",
"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."
+ "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"
},
"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 cbca785c3cf..a2df26d40e8 100644
--- a/lib/l10n/pt_PT.json
+++ b/lib/l10n/pt_PT.json
@@ -187,8 +187,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.",
- "PostgreSQL >= 9 required." : "Necessário PostgreSQL >= 9",
- "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.",
"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",
@@ -202,6 +200,8 @@
"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 \"_.@-'\"",
"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."
+ "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"
},"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/ru.js b/lib/l10n/ru.js
index 5fa9e82edd2..a2dad125c09 100644
--- a/lib/l10n/ru.js
+++ b/lib/l10n/ru.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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" : "Воскресенье",
@@ -244,8 +245,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.",
- "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, чтобы другие пользователи не могли получить список файлов этого каталога.",
"Your data directory must be an absolute path." : "Каталог данных должен быть указан в виде абсолютного пути.",
@@ -263,11 +262,21 @@ 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 не были заменены корректно. Удостоверьтесь, что устанавливаемая версия этого приложения совместима с версией сервера.",
"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» и «_.@-'»",
"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." : "Обновите базу данных."
},
"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 df8dbcfaaaf..3c15ec3a58d 100644
--- a/lib/l10n/ru.json
+++ b/lib/l10n/ru.json
@@ -154,6 +154,7 @@
"%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" : "Воскресенье",
@@ -242,8 +243,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.",
- "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, чтобы другие пользователи не могли получить список файлов этого каталога.",
"Your data directory must be an absolute path." : "Каталог данных должен быть указан в виде абсолютного пути.",
@@ -261,11 +260,21 @@
"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 не были заменены корректно. Удостоверьтесь, что устанавливаемая версия этого приложения совместима с версией сервера.",
"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» и «_.@-'»",
"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." : "Обновите базу данных."
},"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/sk.js b/lib/l10n/sk.js
index c6ade2e9028..4c2843a76aa 100644
--- a/lib/l10n/sk.js
+++ b/lib/l10n/sk.js
@@ -240,8 +240,6 @@ 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.",
- "PostgreSQL >= 9 required." : "Vyžadované PostgreSQL >= 9.",
- "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ť.",
"Your data directory must be an absolute path." : "Priečinok s dátami musí byť zadaný ako absolútna cesta.",
@@ -264,6 +262,8 @@ OC.L10N.register(
"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 \"_.@-'\"",
"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."
+ "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."
},
"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 6c99f7a56a7..23c783f5e3e 100644
--- a/lib/l10n/sk.json
+++ b/lib/l10n/sk.json
@@ -238,8 +238,6 @@
"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.",
- "PostgreSQL >= 9 required." : "Vyžadované PostgreSQL >= 9.",
- "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ť.",
"Your data directory must be an absolute path." : "Priečinok s dátami musí byť zadaný ako absolútna cesta.",
@@ -262,6 +260,8 @@
"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 \"_.@-'\"",
"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."
+ "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."
},"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/sr.js b/lib/l10n/sr.js
index dfa86c59d14..047cd8d4083 100644
--- a/lib/l10n/sr.js
+++ b/lib/l10n/sr.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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" : "Недеља",
@@ -244,8 +245,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." : "У config.php фајлу није подешена потребна config променљива %s.",
"Please ask your server administrator to check the Nextcloud configuration." : "Молимо вас да замолите свог систем администратора да провери Некстклауд конфигурацију.",
- "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 како директоријуми не би могли бити излистани од стране других корисника.",
"Your data directory must be an absolute path." : "Ваш директоријум са подацима мора бити апсолутна путања.",
@@ -263,11 +262,21 @@ 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“ нису правилно замењени. Проверите да ли је верзија компатибилна са сервером.",
"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 \"_.@-'\"",
"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." : "Молимо вас да ажурирате верзију базе података."
},
"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 9775a9ea4b6..f4da5fe632e 100644
--- a/lib/l10n/sr.json
+++ b/lib/l10n/sr.json
@@ -154,6 +154,7 @@
"%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" : "Недеља",
@@ -242,8 +243,6 @@
"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." : "Молимо вас да замолите свог систем администратора да провери Некстклауд конфигурацију.",
- "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 како директоријуми не би могли бити излистани од стране других корисника.",
"Your data directory must be an absolute path." : "Ваш директоријум са подацима мора бити апсолутна путања.",
@@ -261,11 +260,21 @@
"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“ нису правилно замењени. Проверите да ли је верзија компатибилна са сервером.",
"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 \"_.@-'\"",
"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." : "Молимо вас да ажурирате верзију базе података."
},"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 c6181858b7c..de470185b61 100644
--- a/lib/l10n/sv.js
+++ b/lib/l10n/sv.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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",
@@ -244,8 +245,6 @@ 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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 krävs.",
- "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.",
"Your data directory must be an absolute path." : "Din datakatalog måste vara en absolut sökväg.",
@@ -263,11 +262,19 @@ OC.L10N.register(
"Storage connection error. %s" : "Lagringsutrymme lyckas inte ansluta. %s",
"Storage is temporarily not available" : "Lagringsutrymme är för tillfället inte tillgängligt",
"Storage connection timeout. %s" : "Lagringsutrymme lyckas inte ansluta \"timeout\". %s",
+ "Generate headline" : "Skapa rubrik",
+ "Generates a possible headline for a text." : "Genererar en möjlig rubrik för en text.",
+ "Summarize" : "Sammanfatta",
+ "Summarizes text by reducing its length without losing key information." : "Sammanfattar text genom att minska dess längd utan att förlora viktig information.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/sv.json b/lib/l10n/sv.json
index e69fdf211d2..aea308ffdc2 100644
--- a/lib/l10n/sv.json
+++ b/lib/l10n/sv.json
@@ -154,6 +154,7 @@
"%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",
@@ -242,8 +243,6 @@
"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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 krävs.",
- "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.",
"Your data directory must be an absolute path." : "Din datakatalog måste vara en absolut sökväg.",
@@ -261,11 +260,19 @@
"Storage connection error. %s" : "Lagringsutrymme lyckas inte ansluta. %s",
"Storage is temporarily not available" : "Lagringsutrymme är för tillfället inte tillgängligt",
"Storage connection timeout. %s" : "Lagringsutrymme lyckas inte ansluta \"timeout\". %s",
+ "Generate headline" : "Skapa rubrik",
+ "Generates a possible headline for a text." : "Genererar en möjlig rubrik för en text.",
+ "Summarize" : "Sammanfatta",
+ "Summarizes text by reducing its length without losing key information." : "Sammanfattar text genom att minska dess längd utan att förlora viktig information.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/l10n/tr.js b/lib/l10n/tr.js
index 9b8b850edc0..df403564ca0 100644
--- a/lib/l10n/tr.js
+++ b/lib/l10n/tr.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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 etkisizleştirilmiş 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",
@@ -244,8 +245,6 @@ 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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 gerekli.",
- "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.",
"Your data directory must be an absolute path." : "Veri klasörünüz mutlak bir yol olmalıdır.",
@@ -263,11 +262,21 @@ OC.L10N.register(
"Storage connection error. %s" : "Depolama bağlantısı sorunu. %s",
"Storage is temporarily not available" : "Depolama geçici olarak kullanılamıyor",
"Storage connection timeout. %s" : "Depolama bağlantısı zaman aşımı. %s",
+ "Free prompt" : "Ücretsiz bilgi istemi",
+ "Runs an arbitrary prompt through the language model." : "Dil modeli ile isteğe bağlı bir bilgi istemi çalıştırır.",
+ "Generate headline" : "Başlık oluşturulsun",
+ "Generates a possible headline for a text." : "Bir metin için olası bir başlık oluşturur.",
+ "Summarize" : "Özetlensin",
+ "Summarizes text by reducing its length without losing key information." : "Temel içeriği kaybetmeden uzunluğunu kısaltarak metni özetler.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},
"nplurals=2; plural=(n > 1);");
diff --git a/lib/l10n/tr.json b/lib/l10n/tr.json
index b98b2deefc9..5db37fb770c 100644
--- a/lib/l10n/tr.json
+++ b/lib/l10n/tr.json
@@ -154,6 +154,7 @@
"%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 etkisizleştirilmiş 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",
@@ -242,8 +243,6 @@
"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.",
- "PostgreSQL >= 9 required." : "PostgreSQL >= 9 gerekli.",
- "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.",
"Your data directory must be an absolute path." : "Veri klasörünüz mutlak bir yol olmalıdır.",
@@ -261,11 +260,21 @@
"Storage connection error. %s" : "Depolama bağlantısı sorunu. %s",
"Storage is temporarily not available" : "Depolama geçici olarak kullanılamıyor",
"Storage connection timeout. %s" : "Depolama bağlantısı zaman aşımı. %s",
+ "Free prompt" : "Ücretsiz bilgi istemi",
+ "Runs an arbitrary prompt through the language model." : "Dil modeli ile isteğe bağlı bir bilgi istemi çalıştırır.",
+ "Generate headline" : "Başlık oluşturulsun",
+ "Generates a possible headline for a text." : "Bir metin için olası bir başlık oluşturur.",
+ "Summarize" : "Özetlensin",
+ "Summarizes text by reducing its length without losing key information." : "Temel içeriği kaybetmeden uzunluğunu kısaltarak metni özetler.",
+ "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.",
"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 \"_.@-'\"",
"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."
+ "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."
},"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 c1b8c82b72f..66cdea90e01 100644
--- a/lib/l10n/uk.js
+++ b/lib/l10n/uk.js
@@ -139,10 +139,10 @@ OC.L10N.register(
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "Бекенд спільного доступу %s повинен реалізовувати інтерфейс OCP\\Share_Backend",
"Sharing backend %s not found" : "Бекенд спільного доступу %s не знайдено",
"Sharing backend for %s not found" : "Бекенд спільного доступу для %s не знайдено",
- "%1$s shared »%2$s« with you and wants to add:" : "%1$s надано доступ до \"%2$s\" та хоче додати:",
- "%1$s shared »%2$s« with you and wants to add" : "%1$s надано доступ до \"%2$s\" та хоче додати",
+ "%1$s shared »%2$s« with you and wants to add:" : "%1$s надав(-ла) доступ до \"%2$s\" та хоче додати:",
+ "%1$s shared »%2$s« with you and wants to add" : "%1$s надав(-ла) доступ до \"%2$s\" та хоче додати",
"»%s« added a note to a file shared with you" : "\"%s\" додано примітку до файлу у спільному доступі",
- "Open »%s«" : "Відкрити 1%s",
+ "Open »%s«" : "Відкрити %s",
"%1$s via %2$s" : "%1$s через %2$s",
"You are not allowed to share %s" : "Вам заборонено поширювати %s",
"Cannot increase permissions of %s" : "Не вдалося підвищити дозволи для %s",
@@ -152,8 +152,8 @@ OC.L10N.register(
"_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\".",
+ "%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 user was not created because the user limit has been reached. Check your notifications to learn more." : "Користувача не створено, оскільки досягнуто обмеження на кількість користувачів. Перевірте сповіщення для докладної інформації.",
@@ -244,8 +244,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.",
- "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, щоб інші користувачі не могли отримати список файлів цього каталогу.",
"Your data directory must be an absolute path." : "Ваш каталог даних має бути абсолютним шляхом.",
@@ -263,11 +261,21 @@ 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 замінено неправильно. Переконайтеся, що це версія, сумісна з сервером.",
"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\", і \"_.@-'\"",
"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." : "Оновіть версію бази даних."
},
"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 551b039c869..9c102a738e0 100644
--- a/lib/l10n/uk.json
+++ b/lib/l10n/uk.json
@@ -137,10 +137,10 @@
"Sharing backend %s must implement the interface OCP\\Share_Backend" : "Бекенд спільного доступу %s повинен реалізовувати інтерфейс OCP\\Share_Backend",
"Sharing backend %s not found" : "Бекенд спільного доступу %s не знайдено",
"Sharing backend for %s not found" : "Бекенд спільного доступу для %s не знайдено",
- "%1$s shared »%2$s« with you and wants to add:" : "%1$s надано доступ до \"%2$s\" та хоче додати:",
- "%1$s shared »%2$s« with you and wants to add" : "%1$s надано доступ до \"%2$s\" та хоче додати",
+ "%1$s shared »%2$s« with you and wants to add:" : "%1$s надав(-ла) доступ до \"%2$s\" та хоче додати:",
+ "%1$s shared »%2$s« with you and wants to add" : "%1$s надав(-ла) доступ до \"%2$s\" та хоче додати",
"»%s« added a note to a file shared with you" : "\"%s\" додано примітку до файлу у спільному доступі",
- "Open »%s«" : "Відкрити 1%s",
+ "Open »%s«" : "Відкрити %s",
"%1$s via %2$s" : "%1$s через %2$s",
"You are not allowed to share %s" : "Вам заборонено поширювати %s",
"Cannot increase permissions of %s" : "Не вдалося підвищити дозволи для %s",
@@ -150,8 +150,8 @@
"_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\".",
+ "%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 user was not created because the user limit has been reached. Check your notifications to learn more." : "Користувача не створено, оскільки досягнуто обмеження на кількість користувачів. Перевірте сповіщення для докладної інформації.",
@@ -242,8 +242,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.",
- "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, щоб інші користувачі не могли отримати список файлів цього каталогу.",
"Your data directory must be an absolute path." : "Ваш каталог даних має бути абсолютним шляхом.",
@@ -261,11 +259,21 @@
"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 замінено неправильно. Переконайтеся, що це версія, сумісна з сервером.",
"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\", і \"_.@-'\"",
"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." : "Оновіть версію бази даних."
},"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/vi.js b/lib/l10n/vi.js
index a4c189cbf31..7ea1f68dca5 100644
--- a/lib/l10n/vi.js
+++ b/lib/l10n/vi.js
@@ -3,6 +3,7 @@ OC.L10N.register(
{
"Cannot write into \"config\" directory!" : "Không thể ghi vào thư mục \"config\"!",
"See %s" : "Xem %s",
+ "The page could not be found on the server." : "Không thể tìm thấy trang trên máy chủ.",
"Email verification" : "Xác thực email",
"Click the following button to confirm your email." : "Nhấn nút sau để xác nhận email của bạn.",
"Click the following link to confirm your email." : "Nhấn liên kết sau để xác nhận email của bạn.",
diff --git a/lib/l10n/vi.json b/lib/l10n/vi.json
index 3bc1a78d1db..31603bf9c63 100644
--- a/lib/l10n/vi.json
+++ b/lib/l10n/vi.json
@@ -1,6 +1,7 @@
{ "translations": {
"Cannot write into \"config\" directory!" : "Không thể ghi vào thư mục \"config\"!",
"See %s" : "Xem %s",
+ "The page could not be found on the server." : "Không thể tìm thấy trang trên máy chủ.",
"Email verification" : "Xác thực email",
"Click the following button to confirm your email." : "Nhấn nút sau để xác nhận email của bạn.",
"Click the following link to confirm your email." : "Nhấn liên kết sau để xác nhận email của bạn.",
diff --git a/lib/l10n/zh_CN.js b/lib/l10n/zh_CN.js
index 106c13c86cf..834a20822c3 100644
--- a/lib/l10n/zh_CN.js
+++ b/lib/l10n/zh_CN.js
@@ -106,8 +106,8 @@ OC.L10N.register(
"View %s on the fediverse" : "在联邦宇宙上浏览%s",
"Phone" : "电话",
"Call %s" : "呼叫 %s",
- "Twitter" : "推特",
- "View %s on Twitter" : "在推特上查看 %s",
+ "Twitter" : "Twitter",
+ "View %s on Twitter" : "在Twitter上查看 %s",
"Website" : "网站",
"Visit %s" : "访问 %s",
"Address" : "地址",
@@ -241,8 +241,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 设置。",
- "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 以避免其他用户查看目录。",
"Your data directory must be an absolute path." : "您的数据目录必须是绝对路径。",
@@ -265,6 +263,8 @@ OC.L10N.register(
"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” 和 \"_.@-'\"",
"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服务器以解决该问题。"
+ "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." : "请升级您的数据库版本。"
},
"nplurals=1; plural=0;");
diff --git a/lib/l10n/zh_CN.json b/lib/l10n/zh_CN.json
index 6aa9035fdd5..87a73aec9b4 100644
--- a/lib/l10n/zh_CN.json
+++ b/lib/l10n/zh_CN.json
@@ -104,8 +104,8 @@
"View %s on the fediverse" : "在联邦宇宙上浏览%s",
"Phone" : "电话",
"Call %s" : "呼叫 %s",
- "Twitter" : "推特",
- "View %s on Twitter" : "在推特上查看 %s",
+ "Twitter" : "Twitter",
+ "View %s on Twitter" : "在Twitter上查看 %s",
"Website" : "网站",
"Visit %s" : "访问 %s",
"Address" : "地址",
@@ -239,8 +239,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 设置。",
- "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 以避免其他用户查看目录。",
"Your data directory must be an absolute path." : "您的数据目录必须是绝对路径。",
@@ -263,6 +261,8 @@
"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” 和 \"_.@-'\"",
"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服务器以解决该问题。"
+ "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." : "请升级您的数据库版本。"
},"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 6100021b056..345cf40a584 100644
--- a/lib/l10n/zh_HK.js
+++ b/lib/l10n/zh_HK.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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" : "星期日",
@@ -244,8 +245,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 配置。",
- "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 ,以免其他用戶讀取目錄列表",
"Your data directory must be an absolute path." : "您的資料目錄必須為絕對路徑。",
@@ -263,11 +262,21 @@ 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 的檔案。請確保它們的版本與伺服器的版本兼容。",
"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\", 和 \"_.@-'\"",
"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 以上版本,再重啟網頁伺服器。"
+ "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." : "請升級您數據庫的版本。"
},
"nplurals=1; plural=0;");
diff --git a/lib/l10n/zh_HK.json b/lib/l10n/zh_HK.json
index c9d79f09311..08e823d5723 100644
--- a/lib/l10n/zh_HK.json
+++ b/lib/l10n/zh_HK.json
@@ -154,6 +154,7 @@
"%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" : "星期日",
@@ -242,8 +243,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 配置。",
- "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 ,以免其他用戶讀取目錄列表",
"Your data directory must be an absolute path." : "您的資料目錄必須為絕對路徑。",
@@ -261,11 +260,21 @@
"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 的檔案。請確保它們的版本與伺服器的版本兼容。",
"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\", 和 \"_.@-'\"",
"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 以上版本,再重啟網頁伺服器。"
+ "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." : "請升級您數據庫的版本。"
},"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 6432ea9e418..c950bc7636d 100644
--- a/lib/l10n/zh_TW.js
+++ b/lib/l10n/zh_TW.js
@@ -156,6 +156,7 @@ OC.L10N.register(
"%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" : "週日",
@@ -244,8 +245,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 設定。",
- "PostgreSQL >= 9 required." : "需要 PostgreSQL 版本 >= 9。",
- "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 ,以免其他使用者讀取目錄列表",
"Your data directory must be an absolute path." : "您的 data 目錄必須是絕對路徑。",
@@ -263,11 +262,21 @@ 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 中的檔案沒有被正確取代,請確認它的版本與伺服器相容。",
"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\", 和 \"_.@-'\"",
"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 以上版本,再重啟網頁伺服器。"
+ "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." : "請升級您的資料庫版本。"
},
"nplurals=1; plural=0;");
diff --git a/lib/l10n/zh_TW.json b/lib/l10n/zh_TW.json
index 3e5deb88365..f767cb5a8b3 100644
--- a/lib/l10n/zh_TW.json
+++ b/lib/l10n/zh_TW.json
@@ -154,6 +154,7 @@
"%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" : "週日",
@@ -242,8 +243,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 設定。",
- "PostgreSQL >= 9 required." : "需要 PostgreSQL 版本 >= 9。",
- "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 ,以免其他使用者讀取目錄列表",
"Your data directory must be an absolute path." : "您的 data 目錄必須是絕對路徑。",
@@ -261,11 +260,21 @@
"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 中的檔案沒有被正確取代,請確認它的版本與伺服器相容。",
"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\", 和 \"_.@-'\"",
"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 以上版本,再重啟網頁伺服器。"
+ "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." : "請升級您的資料庫版本。"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/lib/private/Accounts/Account.php b/lib/private/Accounts/Account.php
index d3287b219d0..22bbe3d11a0 100644
--- a/lib/private/Accounts/Account.php
+++ b/lib/private/Accounts/Account.php
@@ -39,13 +39,11 @@ class Account implements IAccount {
use TAccountsHelper;
/** @var IAccountPropertyCollection[]|IAccountProperty[] */
- private $properties = [];
+ private array $properties = [];
- /** @var IUser */
- private $user;
-
- public function __construct(IUser $user) {
- $this->user = $user;
+ public function __construct(
+ private IUser $user,
+ ) {
}
public function setProperty(string $property, string $value, string $scope, string $verified, string $verificationData = ''): IAccount {
diff --git a/lib/private/Accounts/AccountManager.php b/lib/private/Accounts/AccountManager.php
index e3068a7ff25..9865438161b 100644
--- a/lib/private/Accounts/AccountManager.php
+++ b/lib/private/Accounts/AccountManager.php
@@ -41,6 +41,7 @@ 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;
@@ -51,6 +52,7 @@ use OCP\Accounts\PropertyDoesNotExistException;
use OCP\BackgroundJob\IJobList;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Defaults;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IL10N;
@@ -60,10 +62,9 @@ use OCP\L10N\IFactory;
use OCP\Mail\IMailer;
use OCP\Security\ICrypto;
use OCP\Security\VerificationToken\IVerificationToken;
+use OCP\User\Backend\IGetDisplayNameBackend;
use OCP\Util;
use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
use function array_flip;
use function iterator_to_array;
use function json_decode;
@@ -83,40 +84,9 @@ class AccountManager implements IAccountManager {
use TProfileHelper;
- /** @var IDBConnection database connection */
- private $connection;
-
- /** @var IConfig */
- private $config;
-
- /** @var string table name */
- private $table = 'accounts';
-
- /** @var string table name */
- private $dataTable = 'accounts_data';
-
- /** @var EventDispatcherInterface */
- private $eventDispatcher;
-
- /** @var IJobList */
- private $jobList;
-
- /** @var LoggerInterface */
- private $logger;
- /** @var IVerificationToken */
- private $verificationToken;
- /** @var IMailer */
- private $mailer;
- /** @var Defaults */
- private $defaults;
- /** @var IL10N */
- private $l10n;
- /** @var IURLGenerator */
- private $urlGenerator;
- /** @var ICrypto */
- private $crypto;
- /** @var IFactory */
- private $l10nfactory;
+ private string $table = 'accounts';
+ private string $dataTable = 'accounts_data';
+ private ?IL10N $l10n = null;
private CappedMemoryCache $internalCache;
/**
@@ -138,35 +108,22 @@ class AccountManager implements IAccountManager {
];
public function __construct(
- IDBConnection $connection,
- IConfig $config,
- EventDispatcherInterface $eventDispatcher,
- IJobList $jobList,
- LoggerInterface $logger,
- IVerificationToken $verificationToken,
- IMailer $mailer,
- Defaults $defaults,
- IFactory $factory,
- IURLGenerator $urlGenerator,
- ICrypto $crypto
+ private IDBConnection $connection,
+ private IConfig $config,
+ private IEventDispatcher $dispatcher,
+ private IJobList $jobList,
+ private LoggerInterface $logger,
+ private IVerificationToken $verificationToken,
+ private IMailer $mailer,
+ private Defaults $defaults,
+ private IFactory $l10nFactory,
+ private IURLGenerator $urlGenerator,
+ private ICrypto $crypto,
) {
- $this->connection = $connection;
- $this->config = $config;
- $this->eventDispatcher = $eventDispatcher;
- $this->jobList = $jobList;
- $this->logger = $logger;
- $this->verificationToken = $verificationToken;
- $this->mailer = $mailer;
- $this->defaults = $defaults;
- $this->urlGenerator = $urlGenerator;
- $this->crypto = $crypto;
- // DIing IL10N results in a dependency loop
- $this->l10nfactory = $factory;
$this->internalCache = new CappedMemoryCache();
}
/**
- * @param string $input
* @return string Provided phone number in E.164 format when it was a valid number
* @throws InvalidArgumentException When the phone number was invalid or no default region is set and the number doesn't start with a country code
*/
@@ -195,9 +152,6 @@ class AccountManager implements IAccountManager {
}
/**
- *
- * @param string $input
- * @return string
* @throws InvalidArgumentException When the website did not have http(s) as protocol or the host name was empty
*/
protected function parseWebsite(string $input): string {
@@ -251,7 +205,7 @@ class AccountManager implements IAccountManager {
}
}
- protected function sanitizePhoneNumberValue(IAccountProperty $property, bool $throwOnData = false) {
+ protected function sanitizePhoneNumberValue(IAccountProperty $property, bool $throwOnData = false): void {
if ($property->getName() !== self::PROPERTY_PHONE) {
if ($throwOnData) {
throw new InvalidArgumentException(sprintf('sanitizePhoneNumberValue can only sanitize phone numbers, %s given', $property->getName()));
@@ -271,7 +225,7 @@ class AccountManager implements IAccountManager {
}
}
- protected function sanitizeWebsite(IAccountProperty $property, bool $throwOnData = false) {
+ protected function sanitizeWebsite(IAccountProperty $property, bool $throwOnData = false): void {
if ($property->getName() !== self::PROPERTY_WEBSITE) {
if ($throwOnData) {
throw new InvalidArgumentException(sprintf('sanitizeWebsite can only sanitize web domains, %s given', $property->getName()));
@@ -302,10 +256,10 @@ class AccountManager implements IAccountManager {
}
if ($updated) {
- $this->eventDispatcher->dispatch(
- 'OC\AccountManager::userUpdated',
- new GenericEvent($user, $data)
- );
+ $this->dispatcher->dispatchTyped(new UserUpdatedEvent(
+ $user,
+ $data,
+ ));
}
return $data;
@@ -313,10 +267,8 @@ class AccountManager implements IAccountManager {
/**
* delete user from accounts table
- *
- * @param IUser $user
*/
- public function deleteUser(IUser $user) {
+ public function deleteUser(IUser $user): void {
$uid = $user->getUID();
$query = $this->connection->getQueryBuilder();
$query->delete($this->table)
@@ -328,8 +280,6 @@ class AccountManager implements IAccountManager {
/**
* delete user from accounts table
- *
- * @param IUser $user
*/
public function deleteUserData(IUser $user): void {
$uid = $user->getUID();
@@ -398,12 +348,10 @@ class AccountManager implements IAccountManager {
}
protected function searchUsersForRelatedCollection(string $property, array $values): array {
- switch ($property) {
- case IAccountManager::PROPERTY_EMAIL:
- return array_flip($this->searchUsers(IAccountManager::COLLECTION_EMAIL, $values));
- default:
- return [];
- }
+ return match ($property) {
+ IAccountManager::PROPERTY_EMAIL => array_flip($this->searchUsers(IAccountManager::COLLECTION_EMAIL, $values)),
+ default => [],
+ };
}
/**
@@ -467,7 +415,7 @@ class AccountManager implements IAccountManager {
]);
if (!$this->l10n) {
- $this->l10n = $this->l10nfactory->get('core');
+ $this->l10n = $this->l10nFactory->get('core');
}
$emailTemplate->setSubject($this->l10n->t('%s email verification', [$this->defaults->getName()]));
@@ -552,9 +500,6 @@ class AccountManager implements IAccountManager {
/**
* add new user to accounts table
- *
- * @param IUser $user
- * @param array $data
*/
protected function insertNewUser(IUser $user, array $data): void {
$uid = $user->getUID();
@@ -800,6 +745,10 @@ class AccountManager implements IAccountManager {
return $cached;
}
$account = $this->parseAccountData($user, $this->getUser($user));
+ if ($user->getBackend() instanceof IGetDisplayNameBackend) {
+ $property = $account->getProperty(self::PROPERTY_DISPLAYNAME);
+ $account->setProperty(self::PROPERTY_DISPLAYNAME, $user->getDisplayName(), $property->getScope(), $property->getVerified());
+ }
$this->internalCache->set($user->getUID(), $account);
return $account;
}
diff --git a/lib/private/Accounts/AccountProperty.php b/lib/private/Accounts/AccountProperty.php
index 2023d185a4b..207dc1d139d 100644
--- a/lib/private/Accounts/AccountProperty.php
+++ b/lib/private/Accounts/AccountProperty.php
@@ -32,25 +32,17 @@ use OCP\Accounts\IAccountManager;
use OCP\Accounts\IAccountProperty;
class AccountProperty implements IAccountProperty {
- /** @var string */
- private $name;
- /** @var string */
- private $value;
- /** @var string */
- private $scope;
- /** @var string */
- private $verified;
- /** @var string */
- private $verificationData;
- /** @var string */
- private $locallyVerified = IAccountManager::NOT_VERIFIED;
-
- public function __construct(string $name, string $value, string $scope, string $verified, string $verificationData) {
- $this->name = $name;
- $this->value = $value;
+ private string $scope;
+ private string $locallyVerified = IAccountManager::NOT_VERIFIED;
+
+ public function __construct(
+ private string $name,
+ private string $value,
+ string $scope,
+ private string $verified,
+ private string $verificationData,
+ ) {
$this->setScope($scope);
- $this->verified = $verified;
- $this->verificationData = $verificationData;
}
public function jsonSerialize(): array {
@@ -67,9 +59,6 @@ class AccountProperty implements IAccountProperty {
* Set the value of a property
*
* @since 15.0.0
- *
- * @param string $value
- * @return IAccountProperty
*/
public function setValue(string $value): IAccountProperty {
$this->value = $value;
@@ -80,9 +69,6 @@ class AccountProperty implements IAccountProperty {
* Set the scope of a property
*
* @since 15.0.0
- *
- * @param string $scope
- * @return IAccountProperty
*/
public function setScope(string $scope): IAccountProperty {
$newScope = $this->mapScopeToV2($scope);
@@ -102,9 +88,6 @@ class AccountProperty implements IAccountProperty {
* Set the verification status of a property
*
* @since 15.0.0
- *
- * @param string $verified
- * @return IAccountProperty
*/
public function setVerified(string $verified): IAccountProperty {
$this->verified = $verified;
@@ -115,8 +98,6 @@ class AccountProperty implements IAccountProperty {
* Get the name of a property
*
* @since 15.0.0
- *
- * @return string
*/
public function getName(): string {
return $this->name;
@@ -126,8 +107,6 @@ class AccountProperty implements IAccountProperty {
* Get the value of a property
*
* @since 15.0.0
- *
- * @return string
*/
public function getValue(): string {
return $this->value;
@@ -137,8 +116,6 @@ class AccountProperty implements IAccountProperty {
* Get the scope of a property
*
* @since 15.0.0
- *
- * @return string
*/
public function getScope(): string {
return $this->scope;
@@ -149,25 +126,18 @@ class AccountProperty implements IAccountProperty {
return $scope;
}
- switch ($scope) {
- case IAccountManager::VISIBILITY_PRIVATE:
- case '':
- return IAccountManager::SCOPE_LOCAL;
- case IAccountManager::VISIBILITY_CONTACTS_ONLY:
- return IAccountManager::SCOPE_FEDERATED;
- case IAccountManager::VISIBILITY_PUBLIC:
- return IAccountManager::SCOPE_PUBLISHED;
- default:
- return $scope;
- }
+ return match ($scope) {
+ IAccountManager::VISIBILITY_PRIVATE, '' => IAccountManager::SCOPE_LOCAL,
+ IAccountManager::VISIBILITY_CONTACTS_ONLY => IAccountManager::SCOPE_FEDERATED,
+ IAccountManager::VISIBILITY_PUBLIC => IAccountManager::SCOPE_PUBLISHED,
+ default => $scope,
+ };
}
/**
* Get the verification status of a property
*
* @since 15.0.0
- *
- * @return string
*/
public function getVerified(): string {
return $this->verified;
diff --git a/lib/private/Accounts/AccountPropertyCollection.php b/lib/private/Accounts/AccountPropertyCollection.php
index 1e5d8a5112a..660a245714d 100644
--- a/lib/private/Accounts/AccountPropertyCollection.php
+++ b/lib/private/Accounts/AccountPropertyCollection.php
@@ -32,14 +32,12 @@ use OCP\Accounts\IAccountProperty;
use OCP\Accounts\IAccountPropertyCollection;
class AccountPropertyCollection implements IAccountPropertyCollection {
- /** @var string */
- protected $collectionName = '';
-
/** @var IAccountProperty[] */
- protected $properties = [];
+ protected array $properties = [];
- public function __construct(string $collectionName) {
- $this->collectionName = $collectionName;
+ public function __construct(
+ protected string $collectionName,
+ ) {
}
public function setProperties(array $properties): IAccountPropertyCollection {
diff --git a/lib/private/Accounts/Hooks.php b/lib/private/Accounts/Hooks.php
index a6c52275d2d..b449c41c1da 100644
--- a/lib/private/Accounts/Hooks.php
+++ b/lib/private/Accounts/Hooks.php
@@ -36,14 +36,10 @@ use Psr\Log\LoggerInterface;
* @template-implements IEventListener<UserChangedEvent>
*/
class Hooks implements IEventListener {
- /** @var IAccountManager */
- private $accountManager;
- /** @var LoggerInterface */
- private $logger;
-
- public function __construct(LoggerInterface $logger, IAccountManager $accountManager) {
- $this->logger = $logger;
- $this->accountManager = $accountManager;
+ public function __construct(
+ private LoggerInterface $logger,
+ private IAccountManager $accountManager,
+ ) {
}
/**
diff --git a/lib/private/Activity/Manager.php b/lib/private/Activity/Manager.php
index 00b2ba434a8..a7d24510d53 100644
--- a/lib/private/Activity/Manager.php
+++ b/lib/private/Activity/Manager.php
@@ -192,7 +192,7 @@ class Manager implements IManager {
public function getFilters(): array {
foreach ($this->filterClasses as $class => $false) {
/** @var IFilter $filter */
- $filter = \OC::$server->query($class);
+ $filter = \OCP\Server::get($class);
if (!$filter instanceof IFilter) {
throw new \InvalidArgumentException('Invalid activity filter registered');
@@ -242,7 +242,7 @@ class Manager implements IManager {
public function getProviders(): array {
foreach ($this->providerClasses as $class => $false) {
/** @var IProvider $provider */
- $provider = \OC::$server->query($class);
+ $provider = \OCP\Server::get($class);
if (!$provider instanceof IProvider) {
throw new \InvalidArgumentException('Invalid activity provider registered');
@@ -276,7 +276,7 @@ class Manager implements IManager {
public function getSettings(): array {
foreach ($this->settingsClasses as $class => $false) {
/** @var ISetting $setting */
- $setting = \OC::$server->query($class);
+ $setting = \OCP\Server::get($class);
if ($setting instanceof ISetting) {
if (!$setting instanceof ActivitySettings) {
diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php
index b881d37440e..88044fbf7b6 100644
--- a/lib/private/App/AppManager.php
+++ b/lib/private/App/AppManager.php
@@ -59,7 +59,6 @@ use OCP\IUser;
use OCP\IUserSession;
use OCP\Settings\IManager as ISettingsManager;
use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class AppManager implements IAppManager {
/**
@@ -79,7 +78,6 @@ class AppManager implements IAppManager {
private AppConfig $appConfig;
private IGroupManager $groupManager;
private ICacheFactory $memCacheFactory;
- private EventDispatcherInterface $legacyDispatcher;
private IEventDispatcher $dispatcher;
private LoggerInterface $logger;
@@ -110,7 +108,6 @@ class AppManager implements IAppManager {
AppConfig $appConfig,
IGroupManager $groupManager,
ICacheFactory $memCacheFactory,
- EventDispatcherInterface $legacyDispatcher,
IEventDispatcher $dispatcher,
LoggerInterface $logger) {
$this->userSession = $userSession;
@@ -118,7 +115,6 @@ class AppManager implements IAppManager {
$this->appConfig = $appConfig;
$this->groupManager = $groupManager;
$this->memCacheFactory = $memCacheFactory;
- $this->legacyDispatcher = $legacyDispatcher;
$this->dispatcher = $dispatcher;
$this->logger = $logger;
}
@@ -543,7 +539,7 @@ class AppManager implements IAppManager {
$this->installedAppsCache[$appId] = 'yes';
$this->appConfig->setValue($appId, 'enabled', 'yes');
$this->dispatcher->dispatchTyped(new AppEnableEvent($appId));
- $this->legacyDispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent(
+ $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent(
ManagerEvent::EVENT_APP_ENABLE, $appId
));
$this->clearAppsCache();
@@ -597,7 +593,7 @@ class AppManager implements IAppManager {
$this->installedAppsCache[$appId] = json_encode($groupIds);
$this->appConfig->setValue($appId, 'enabled', json_encode($groupIds));
$this->dispatcher->dispatchTyped(new AppEnableEvent($appId, $groupIds));
- $this->legacyDispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, new ManagerEvent(
+ $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, new ManagerEvent(
ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, $appId, $groups
));
$this->clearAppsCache();
@@ -633,7 +629,7 @@ class AppManager implements IAppManager {
}
$this->dispatcher->dispatchTyped(new AppDisableEvent($appId));
- $this->legacyDispatcher->dispatch(ManagerEvent::EVENT_APP_DISABLE, new ManagerEvent(
+ $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_DISABLE, new ManagerEvent(
ManagerEvent::EVENT_APP_DISABLE, $appId
));
$this->clearAppsCache();
diff --git a/lib/private/App/InfoParser.php b/lib/private/App/InfoParser.php
index c0f69e615bd..79d051fd2a1 100644
--- a/lib/private/App/InfoParser.php
+++ b/lib/private/App/InfoParser.php
@@ -31,7 +31,7 @@ namespace OC\App;
use OCP\ICache;
use function libxml_disable_entity_loader;
-use function simplexml_load_file;
+use function simplexml_load_string;
class InfoParser {
/** @var \OCP\ICache|null */
@@ -63,10 +63,10 @@ class InfoParser {
libxml_use_internal_errors(true);
if ((PHP_VERSION_ID < 80000)) {
$loadEntities = libxml_disable_entity_loader(false);
- $xml = simplexml_load_file($file);
+ $xml = simplexml_load_string(file_get_contents($file));
libxml_disable_entity_loader($loadEntities);
} else {
- $xml = simplexml_load_file($file);
+ $xml = simplexml_load_string(file_get_contents($file));
}
if ($xml === false) {
diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php
index 96fa6bf7467..84f0d5b9e5a 100644
--- a/lib/private/AppConfig.php
+++ b/lib/private/AppConfig.php
@@ -175,7 +175,7 @@ class AppConfig implements IAppConfig {
/**
* Get all apps using the config
*
- * @return array an array of app ids
+ * @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.
diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
index 8fcafab2d87..5aea2a7a744 100644
--- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php
+++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
@@ -33,6 +33,7 @@ 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;
@@ -115,6 +116,9 @@ class RegistrationContext {
/** @var ServiceRegistration<ISpeechToTextProvider>[] */
private $speechToTextProviders = [];
+ /** @var ServiceRegistration<ITextProcessingProvider>[] */
+ private $textProcessingProviders = [];
+
/** @var ServiceRegistration<ICustomTemplateProvider>[] */
private $templateProviders = [];
@@ -262,6 +266,12 @@ class RegistrationContext {
$providerClass
);
}
+ public function registerTextProcessingProvider(string $providerClass): void {
+ $this->context->registerTextProcessingProvider(
+ $this->appId,
+ $providerClass
+ );
+ }
public function registerTemplateProvider(string $providerClass): void {
$this->context->registerTemplateProvider(
@@ -429,6 +439,10 @@ class RegistrationContext {
$this->speechToTextProviders[] = new ServiceRegistration($appId, $class);
}
+ public function registerTextProcessingProvider(string $appId, string $class): void {
+ $this->textProcessingProviders[] = new ServiceRegistration($appId, $class);
+ }
+
public function registerTemplateProvider(string $appId, string $class): void {
$this->templateProviders[] = new ServiceRegistration($appId, $class);
}
@@ -708,6 +722,13 @@ class RegistrationContext {
}
/**
+ * @return ServiceRegistration<ITextProcessingProvider>[]
+ */
+ public function getTextProcessingProviders(): array {
+ return $this->textProcessingProviders;
+ }
+
+ /**
* @return ServiceRegistration<ICustomTemplateProvider>[]
*/
public function getTemplateProviders(): array {
diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php
index 9a9740b7bcc..a012d1e8ea6 100644
--- a/lib/private/AppFramework/DependencyInjection/DIContainer.php
+++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php
@@ -72,6 +72,7 @@ use OCP\IServerContainer;
use OCP\ISession;
use OCP\IURLGenerator;
use OCP\IUserSession;
+use OCP\Security\Bruteforce\IThrottler;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
@@ -233,7 +234,7 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$c->get(IRequest::class),
$c->get(IControllerMethodReflector::class),
$c->get(IUserSession::class),
- $c->get(OC\Security\Bruteforce\Throttler::class)
+ $c->get(IThrottler::class)
)
);
$dispatcher->registerMiddleware(
@@ -291,7 +292,7 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$dispatcher->registerMiddleware(
new OC\AppFramework\Middleware\Security\BruteForceMiddleware(
$c->get(IControllerMethodReflector::class),
- $c->get(OC\Security\Bruteforce\Throttler::class),
+ $c->get(IThrottler::class),
$c->get(IRequest::class),
$c->get(LoggerInterface::class)
)
@@ -309,7 +310,7 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$c->get(IRequest::class),
$c->get(ISession::class),
$c->get(\OCP\IConfig::class),
- $c->get(OC\Security\Bruteforce\Throttler::class)
+ $c->get(IThrottler::class)
)
);
$dispatcher->registerMiddleware(
diff --git a/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php b/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php
index ec52dde0ecd..64b1c7d2fcd 100644
--- a/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php
+++ b/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php
@@ -27,50 +27,31 @@ declare(strict_types=1);
*/
namespace OC\AppFramework\Middleware;
+use OC\Core\Controller\LoginController;
+use OCP\AppFramework\Http\Events\BeforeLoginTemplateRenderedEvent;
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\StandaloneTemplateResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Middleware;
-use OCP\AppFramework\PublicShareController;
-use OCP\EventDispatcher\GenericEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IUserSession;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class AdditionalScriptsMiddleware extends Middleware {
- /** @var EventDispatcherInterface */
- private $legacyDispatcher;
- /** @var IUserSession */
- private $userSession;
- /** @var IEventDispatcher */
- private $dispatcher;
-
- public function __construct(EventDispatcherInterface $legacyDispatcher, IUserSession $userSession, IEventDispatcher $dispatcher) {
- $this->legacyDispatcher = $legacyDispatcher;
- $this->userSession = $userSession;
- $this->dispatcher = $dispatcher;
+ public function __construct(
+ private IUserSession $userSession,
+ private IEventDispatcher $dispatcher,
+ ) {
}
public function afterController($controller, $methodName, Response $response): Response {
if ($response instanceof TemplateResponse) {
- if (!$controller instanceof PublicShareController) {
- /*
- * The old event was not dispatched on the public share controller as there was
- * OCA\Files_Sharing::loadAdditionalScripts for that. This is kept for compatibility reasons
- * only for the old event as this is now also included in BeforeTemplateRenderedEvent
- */
- $this->legacyDispatcher->dispatch(TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS, new GenericEvent());
- }
-
- if (!($response instanceof StandaloneTemplateResponse) && $this->userSession->isLoggedIn()) {
- $this->legacyDispatcher->dispatch(TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN, new GenericEvent());
- $isLoggedIn = true;
+ if ($controller instanceof LoginController) {
+ $this->dispatcher->dispatchTyped(new BeforeLoginTemplateRenderedEvent($response));
} else {
- $isLoggedIn = false;
+ $isLoggedIn = !($response instanceof StandaloneTemplateResponse) && $this->userSession->isLoggedIn();
+ $this->dispatcher->dispatchTyped(new BeforeTemplateRenderedEvent($isLoggedIn, $response));
}
-
- $this->dispatcher->dispatchTyped(new BeforeTemplateRenderedEvent($isLoggedIn, $response));
}
return $response;
diff --git a/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php b/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php
index f20bd333452..7acb579938b 100644
--- a/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php
+++ b/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php
@@ -24,7 +24,6 @@
namespace OC\AppFramework\Middleware\PublicShare;
use OC\AppFramework\Middleware\PublicShare\Exceptions\NeedAuthenticationException;
-use OC\Security\Bruteforce\Throttler;
use OCP\AppFramework\AuthPublicShareController;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\Middleware;
@@ -33,6 +32,7 @@ use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\IRequest;
use OCP\ISession;
+use OCP\Security\Bruteforce\IThrottler;
class PublicShareMiddleware extends Middleware {
/** @var IRequest */
@@ -44,10 +44,10 @@ class PublicShareMiddleware extends Middleware {
/** @var IConfig */
private $config;
- /** @var Throttler */
+ /** @var IThrottler */
private $throttler;
- public function __construct(IRequest $request, ISession $session, IConfig $config, Throttler $throttler) {
+ public function __construct(IRequest $request, ISession $session, IConfig $config, IThrottler $throttler) {
$this->request = $request;
$this->session = $session;
$this->config = $config;
diff --git a/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php b/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php
index 2ecd26a68e1..574e86a9ca2 100644
--- a/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php
@@ -29,7 +29,6 @@ declare(strict_types=1);
namespace OC\AppFramework\Middleware\Security;
use OC\AppFramework\Utility\ControllerMethodReflector;
-use OC\Security\Bruteforce\Throttler;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\BruteForceProtection;
@@ -39,6 +38,7 @@ use OCP\AppFramework\Middleware;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCSController;
use OCP\IRequest;
+use OCP\Security\Bruteforce\IThrottler;
use OCP\Security\Bruteforce\MaxDelayReached;
use Psr\Log\LoggerInterface;
use ReflectionMethod;
@@ -51,9 +51,11 @@ use ReflectionMethod;
* @package OC\AppFramework\Middleware\Security
*/
class BruteForceMiddleware extends Middleware {
+ private int $delaySlept = 0;
+
public function __construct(
protected ControllerMethodReflector $reflector,
- protected Throttler $throttler,
+ protected IThrottler $throttler,
protected IRequest $request,
protected LoggerInterface $logger,
) {
@@ -67,7 +69,7 @@ class BruteForceMiddleware extends Middleware {
if ($this->reflector->hasAnnotation('BruteForceProtection')) {
$action = $this->reflector->getAnnotationParameter('BruteForceProtection', 'action');
- $this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), $action);
+ $this->delaySlept += $this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), $action);
} else {
$reflectionMethod = new ReflectionMethod($controller, $methodName);
$attributes = $reflectionMethod->getAttributes(BruteForceProtection::class);
@@ -79,7 +81,7 @@ class BruteForceMiddleware extends Middleware {
/** @var BruteForceProtection $protection */
$protection = $attribute->newInstance();
$action = $protection->getAction();
- $this->throttler->sleepDelayOrThrowOnMax($remoteAddress, $action);
+ $this->delaySlept += $this->throttler->sleepDelayOrThrowOnMax($remoteAddress, $action);
}
}
}
@@ -95,7 +97,7 @@ class BruteForceMiddleware extends Middleware {
$action = $this->reflector->getAnnotationParameter('BruteForceProtection', 'action');
$ip = $this->request->getRemoteAddress();
$this->throttler->registerAttempt($action, $ip, $response->getThrottleMetadata());
- $this->throttler->sleepDelayOrThrowOnMax($ip, $action);
+ $this->delaySlept += $this->throttler->sleepDelayOrThrowOnMax($ip, $action);
} else {
$reflectionMethod = new ReflectionMethod($controller, $methodName);
$attributes = $reflectionMethod->getAttributes(BruteForceProtection::class);
@@ -111,7 +113,7 @@ class BruteForceMiddleware extends Middleware {
if (!isset($metaData['action']) || $metaData['action'] === $action) {
$this->throttler->registerAttempt($action, $ip, $metaData);
- $this->throttler->sleepDelayOrThrowOnMax($ip, $action);
+ $this->delaySlept += $this->throttler->sleepDelayOrThrowOnMax($ip, $action);
}
}
} else {
@@ -127,6 +129,10 @@ class BruteForceMiddleware extends Middleware {
}
}
+ if ($this->delaySlept) {
+ $response->addHeader('X-Nextcloud-Bruteforce-Throttled', $this->delaySlept . 'ms');
+ }
+
return parent::afterController($controller, $methodName, $response);
}
diff --git a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php
index e177a612d96..8bdacf550b6 100644
--- a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php
@@ -29,7 +29,6 @@ namespace OC\AppFramework\Middleware\Security;
use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OC\Authentication\Exceptions\PasswordLoginForbiddenException;
-use OC\Security\Bruteforce\Throttler;
use OC\User\Session;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
@@ -39,6 +38,7 @@ use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
use OCP\IRequest;
+use OCP\Security\Bruteforce\IThrottler;
use ReflectionMethod;
/**
@@ -54,19 +54,13 @@ class CORSMiddleware extends Middleware {
private $reflector;
/** @var Session */
private $session;
- /** @var Throttler */
+ /** @var IThrottler */
private $throttler;
- /**
- * @param IRequest $request
- * @param ControllerMethodReflector $reflector
- * @param Session $session
- * @param Throttler $throttler
- */
public function __construct(IRequest $request,
ControllerMethodReflector $reflector,
Session $session,
- Throttler $throttler) {
+ IThrottler $throttler) {
$this->request = $request;
$this->reflector = $reflector;
$this->session = $session;
diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
index 04f79361bc8..db6c7a02c77 100644
--- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
@@ -206,7 +206,7 @@ class SecurityMiddleware extends Middleware {
}
// CSRF check - also registers the CSRF token since the session may be closed later
Util::callRegister();
- if (!$this->hasAnnotationOrAttribute($reflectionMethod, 'NoCSRFRequired', NoCSRFRequired::class)) {
+ if ($this->isInvalidCSRFRequired($reflectionMethod)) {
/*
* Only allow the CSRF check to fail on OCS Requests. This kind of
* hacks around that we have no full token auth in place yet and we
@@ -215,12 +215,7 @@ class SecurityMiddleware extends Middleware {
* Additionally we allow Bearer authenticated requests to pass on OCS routes.
* This allows oauth apps (e.g. moodle) to use the OCS endpoints
*/
- if (!$this->request->passesCSRFCheck() && !(
- $controller instanceof OCSController && (
- $this->request->getHeader('OCS-APIREQUEST') === 'true' ||
- str_starts_with($this->request->getHeader('Authorization'), 'Bearer ')
- )
- )) {
+ if (!$controller instanceof OCSController || !$this->isValidOCSRequest()) {
throw new CrossSiteRequestForgeryException();
}
}
@@ -242,6 +237,19 @@ class SecurityMiddleware extends Middleware {
}
}
+ private function isInvalidCSRFRequired(ReflectionMethod $reflectionMethod): bool {
+ if ($this->hasAnnotationOrAttribute($reflectionMethod, 'NoCSRFRequired', NoCSRFRequired::class)) {
+ return false;
+ }
+
+ return !$this->request->passesCSRFCheck();
+ }
+
+ private function isValidOCSRequest(): bool {
+ return $this->request->getHeader('OCS-APIREQUEST') === 'true'
+ || str_starts_with($this->request->getHeader('Authorization'), 'Bearer ');
+ }
+
/**
* @template T
*
diff --git a/lib/private/AppFramework/OCS/BaseResponse.php b/lib/private/AppFramework/OCS/BaseResponse.php
index 533cff74a30..123b73d302c 100644
--- a/lib/private/AppFramework/OCS/BaseResponse.php
+++ b/lib/private/AppFramework/OCS/BaseResponse.php
@@ -7,6 +7,7 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -30,6 +31,13 @@ use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\Response;
+/**
+ * @psalm-import-type DataResponseType from DataResponse
+ * @template S of int
+ * @template-covariant T of DataResponseType
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
+ */
abstract class BaseResponse extends Response {
/** @var array */
protected $data;
@@ -49,7 +57,7 @@ abstract class BaseResponse extends Response {
/**
* BaseResponse constructor.
*
- * @param DataResponse $dataResponse
+ * @param DataResponse<S, T, H> $dataResponse
* @param string $format
* @param string|null $statusMessage
* @param int|null $itemsCount
diff --git a/lib/private/AppFramework/OCS/V1Response.php b/lib/private/AppFramework/OCS/V1Response.php
index cca3c267ec4..e6b01652789 100644
--- a/lib/private/AppFramework/OCS/V1Response.php
+++ b/lib/private/AppFramework/OCS/V1Response.php
@@ -5,6 +5,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -25,8 +26,16 @@
namespace OC\AppFramework\OCS;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
+/**
+ * @psalm-import-type DataResponseType from DataResponse
+ * @template S of int
+ * @template-covariant T of DataResponseType
+ * @template H of array<string, mixed>
+ * @template-extends BaseResponse<int, DataResponseType, array<string, mixed>>
+ */
class V1Response extends BaseResponse {
/**
* The V1 endpoint has very limited http status codes basically everything
diff --git a/lib/private/AppFramework/OCS/V2Response.php b/lib/private/AppFramework/OCS/V2Response.php
index 8bf4c37a578..1e81a3c7d93 100644
--- a/lib/private/AppFramework/OCS/V2Response.php
+++ b/lib/private/AppFramework/OCS/V2Response.php
@@ -4,6 +4,7 @@
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -24,8 +25,16 @@
namespace OC\AppFramework\OCS;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
+/**
+ * @psalm-import-type DataResponseType from DataResponse
+ * @template S of int
+ * @template-covariant T of DataResponseType
+ * @template H of array<string, mixed>
+ * @template-extends BaseResponse<int, DataResponseType, array<string, mixed>>
+ */
class V2Response extends BaseResponse {
/**
* The V2 endpoint just passes on status codes.
diff --git a/lib/private/AppFramework/Utility/SimpleContainer.php b/lib/private/AppFramework/Utility/SimpleContainer.php
index 89e4204c85e..7aa5cb83926 100644
--- a/lib/private/AppFramework/Utility/SimpleContainer.php
+++ b/lib/private/AppFramework/Utility/SimpleContainer.php
@@ -59,7 +59,6 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
* @psalm-template S as class-string<T>|string
* @psalm-param S $id
* @psalm-return (S is class-string<T> ? T : mixed)
- * @throws QueryException
*/
public function get(string $id) {
return $this->query($id);
diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php
index b5af3f3a5ee..a12d3ba34d9 100644
--- a/lib/private/Authentication/Token/IProvider.php
+++ b/lib/private/Authentication/Token/IProvider.php
@@ -110,6 +110,11 @@ interface IProvider {
public function invalidateOldTokens();
/**
+ * Invalidate (delete) tokens last used before a given date
+ */
+ public function invalidateLastUsedBefore(string $uid, int $before): void;
+
+ /**
* Save the updated token
*
* @param IToken $token
diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php
index 761e799d298..6a1c7d4c1e7 100644
--- a/lib/private/Authentication/Token/Manager.php
+++ b/lib/private/Authentication/Token/Manager.php
@@ -204,6 +204,10 @@ class Manager implements IProvider, OCPIProvider {
$this->publicKeyTokenProvider->invalidateOldTokens();
}
+ public function invalidateLastUsedBefore(string $uid, int $before): void {
+ $this->publicKeyTokenProvider->invalidateLastUsedBefore($uid, $before);
+ }
+
/**
* @param IToken $token
* @param string $oldTokenId
diff --git a/lib/private/Authentication/Token/PublicKeyTokenMapper.php b/lib/private/Authentication/Token/PublicKeyTokenMapper.php
index 8feb275b3b7..855639dd907 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenMapper.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenMapper.php
@@ -69,6 +69,15 @@ class PublicKeyTokenMapper extends QBMapper {
->execute();
}
+ public function invalidateLastUsedBefore(string $uid, int $before): int {
+ $qb = $this->db->getQueryBuilder();
+ $qb->delete($this->tableName)
+ ->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
+ ->andWhere($qb->expr()->lt('last_activity', $qb->createNamedParameter($before, IQueryBuilder::PARAM_INT)))
+ ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)));
+ return $qb->executeStatement();
+ }
+
/**
* Get the user UID for the given token
*
diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
index f5fcd4dcef2..3fb11611076 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
@@ -273,6 +273,12 @@ class PublicKeyTokenProvider implements IProvider {
$this->mapper->invalidateOld($rememberThreshold, IToken::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();
diff --git a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php
index 19d80218562..4817c6b8de0 100644
--- a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php
+++ b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php
@@ -69,7 +69,7 @@ class ProviderUserAssignmentDao {
/**
* Persist a new/updated (provider_id, uid, enabled) tuple
*/
- public function persist(string $providerId, string $uid, int $enabled) {
+ public function persist(string $providerId, string $uid, int $enabled): void {
$qb = $this->conn->getQueryBuilder();
try {
@@ -96,7 +96,7 @@ class ProviderUserAssignmentDao {
*
* @param string $uid
*
- * @return int[]
+ * @return list<array{provider_id: string, uid: string, enabled: bool}>
*/
public function deleteByUser(string $uid): array {
$qb1 = $this->conn->getQueryBuilder();
@@ -122,7 +122,7 @@ class ProviderUserAssignmentDao {
}, $rows);
}
- public function deleteAll(string $providerId) {
+ public function deleteAll(string $providerId): void {
$qb = $this->conn->getQueryBuilder();
$deleteQuery = $qb->delete(self::TABLE_NAME)
diff --git a/lib/private/Authentication/TwoFactorAuth/Manager.php b/lib/private/Authentication/TwoFactorAuth/Manager.php
index 7e115cf9b42..ff0c33445a2 100644
--- a/lib/private/Authentication/TwoFactorAuth/Manager.php
+++ b/lib/private/Authentication/TwoFactorAuth/Manager.php
@@ -36,6 +36,8 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Authentication\TwoFactorAuth\IActivatableAtLogin;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IRegistry;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengeFailed;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengePassed;
use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserDisabled;
use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserEnabled;
use OCP\EventDispatcher\IEventDispatcher;
@@ -44,8 +46,6 @@ use OCP\ISession;
use OCP\IUser;
use OCP\Session\Exceptions\SessionNotAvailableException;
use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
use function array_diff;
use function array_filter;
@@ -85,9 +85,6 @@ class Manager {
/** @var IEventDispatcher */
private $dispatcher;
- /** @var EventDispatcherInterface */
- private $legacyDispatcher;
-
/** @psalm-var array<string, bool> */
private $userIsTwoFactorAuthenticated = [];
@@ -100,8 +97,7 @@ class Manager {
LoggerInterface $logger,
TokenProvider $tokenProvider,
ITimeFactory $timeFactory,
- IEventDispatcher $eventDispatcher,
- EventDispatcherInterface $legacyDispatcher) {
+ IEventDispatcher $eventDispatcher) {
$this->providerLoader = $providerLoader;
$this->providerRegistry = $providerRegistry;
$this->mandatoryTwoFactor = $mandatoryTwoFactor;
@@ -112,14 +108,10 @@ class Manager {
$this->tokenProvider = $tokenProvider;
$this->timeFactory = $timeFactory;
$this->dispatcher = $eventDispatcher;
- $this->legacyDispatcher = $legacyDispatcher;
}
/**
* Determine whether the user must provide a second factor challenge
- *
- * @param IUser $user
- * @return boolean
*/
public function isTwoFactorAuthenticated(IUser $user): bool {
if (isset($this->userIsTwoFactorAuthenticated[$user->getUID()])) {
@@ -143,18 +135,13 @@ class Manager {
/**
* Get a 2FA provider by its ID
- *
- * @param IUser $user
- * @param string $challengeProviderId
- * @return IProvider|null
*/
- public function getProvider(IUser $user, string $challengeProviderId) {
+ public function getProvider(IUser $user, string $challengeProviderId): ?IProvider {
$providers = $this->getProviderSet($user)->getProviders();
return $providers[$challengeProviderId] ?? null;
}
/**
- * @param IUser $user
* @return IActivatableAtLogin[]
* @throws Exception
*/
@@ -282,19 +269,15 @@ class Manager {
$tokenId = $token->getId();
$this->config->deleteUserValue($user->getUID(), 'login_token_2fa', (string)$tokenId);
- $dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
- $this->legacyDispatcher->dispatch(IProvider::EVENT_SUCCESS, $dispatchEvent);
-
$this->dispatcher->dispatchTyped(new TwoFactorProviderForUserEnabled($user, $provider));
+ $this->dispatcher->dispatchTyped(new TwoFactorProviderChallengePassed($user, $provider));
$this->publishEvent($user, 'twofactor_success', [
'provider' => $provider->getDisplayName(),
]);
} else {
- $dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
- $this->legacyDispatcher->dispatch(IProvider::EVENT_FAILED, $dispatchEvent);
-
$this->dispatcher->dispatchTyped(new TwoFactorProviderForUserDisabled($user, $provider));
+ $this->dispatcher->dispatchTyped(new TwoFactorProviderChallengeFailed($user, $provider));
$this->publishEvent($user, 'twofactor_failed', [
'provider' => $provider->getDisplayName(),
diff --git a/lib/private/Authentication/TwoFactorAuth/ProviderLoader.php b/lib/private/Authentication/TwoFactorAuth/ProviderLoader.php
index 25cdc387f61..efd92f8ba30 100644
--- a/lib/private/Authentication/TwoFactorAuth/ProviderLoader.php
+++ b/lib/private/Authentication/TwoFactorAuth/ProviderLoader.php
@@ -66,7 +66,7 @@ class ProviderLoader {
foreach ($providerClasses as $class) {
try {
$this->loadTwoFactorApp($appId);
- $provider = OC::$server->query($class);
+ $provider = \OCP\Server::get($class);
$providers[$provider->getId()] = $provider;
} catch (QueryException $exc) {
// Provider class can not be resolved
@@ -80,7 +80,7 @@ class ProviderLoader {
foreach ($registeredProviders as $provider) {
try {
$this->loadTwoFactorApp($provider->getAppId());
- $provider = OC::$server->query($provider->getService());
+ $provider = \OCP\Server::get($provider->getService());
$providers[$provider->getId()] = $provider;
} catch (QueryException $exc) {
// Provider class can not be resolved
diff --git a/lib/private/Authentication/TwoFactorAuth/Registry.php b/lib/private/Authentication/TwoFactorAuth/Registry.php
index 6c82572578c..482c025e144 100644
--- a/lib/private/Authentication/TwoFactorAuth/Registry.php
+++ b/lib/private/Authentication/TwoFactorAuth/Registry.php
@@ -31,6 +31,9 @@ use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IRegistry;
use OCP\Authentication\TwoFactorAuth\RegistryEvent;
use OCP\Authentication\TwoFactorAuth\TwoFactorProviderDisabled;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserRegistered;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserUnregistered;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderUserDeleted;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IUser;
@@ -56,6 +59,7 @@ class Registry implements IRegistry {
$event = new RegistryEvent($provider, $user);
$this->dispatcher->dispatch(self::EVENT_PROVIDER_ENABLED, $event);
+ $this->dispatcher->dispatchTyped(new TwoFactorProviderForUserRegistered($user, $provider));
}
public function disableProviderFor(IProvider $provider, IUser $user) {
@@ -63,12 +67,14 @@ class Registry implements IRegistry {
$event = new RegistryEvent($provider, $user);
$this->dispatcher->dispatch(self::EVENT_PROVIDER_DISABLED, $event);
+ $this->dispatcher->dispatchTyped(new TwoFactorProviderForUserUnregistered($user, $provider));
}
public function deleteUserData(IUser $user): void {
foreach ($this->assignmentDao->deleteByUser($user->getUID()) as $provider) {
$event = new TwoFactorProviderDisabled($provider['provider_id']);
$this->dispatcher->dispatchTyped($event);
+ $this->dispatcher->dispatchTyped(new TwoFactorProviderUserDeleted($user, $provider['provider_id']));
}
}
diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php
index 3cdfee51138..36cccbd4eab 100644
--- a/lib/private/BackgroundJob/JobList.php
+++ b/lib/private/BackgroundJob/JobList.php
@@ -35,6 +35,7 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\AutoloadNotAllowedException;
use OCP\BackgroundJob\IJob;
use OCP\BackgroundJob\IJobList;
+use OCP\BackgroundJob\IParallelAwareJob;
use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
@@ -218,19 +219,33 @@ class JobList implements IJobList {
$query->andWhere($query->expr()->eq('time_sensitive', $query->createNamedParameter(IJob::TIME_SENSITIVE, IQueryBuilder::PARAM_INT)));
}
- $update = $this->connection->getQueryBuilder();
- $update->update('jobs')
- ->set('reserved_at', $update->createNamedParameter($this->timeFactory->getTime()))
- ->set('last_checked', $update->createNamedParameter($this->timeFactory->getTime()))
- ->where($update->expr()->eq('id', $update->createParameter('jobid')))
- ->andWhere($update->expr()->eq('reserved_at', $update->createParameter('reserved_at')))
- ->andWhere($update->expr()->eq('last_checked', $update->createParameter('last_checked')));
-
$result = $query->executeQuery();
$row = $result->fetch();
$result->closeCursor();
if ($row) {
+ $job = $this->buildJob($row);
+
+ if ($job instanceof IParallelAwareJob && !$job->getAllowParallelRuns() && $this->hasReservedJob(get_class($job))) {
+ $this->logger->debug('Skipping ' . get_class($job) . ' job with ID ' . $job->getId() . ' because another job with the same class is already running', ['app' => 'cron']);
+
+ $update = $this->connection->getQueryBuilder();
+ $update->update('jobs')
+ ->set('last_checked', $update->createNamedParameter($this->timeFactory->getTime() + 1))
+ ->where($update->expr()->eq('id', $update->createParameter('jobid')));
+ $update->setParameter('jobid', $row['id']);
+ $update->executeStatement();
+
+ return $this->getNext($onlyTimeSensitive);
+ }
+
+ $update = $this->connection->getQueryBuilder();
+ $update->update('jobs')
+ ->set('reserved_at', $update->createNamedParameter($this->timeFactory->getTime()))
+ ->set('last_checked', $update->createNamedParameter($this->timeFactory->getTime()))
+ ->where($update->expr()->eq('id', $update->createParameter('jobid')))
+ ->andWhere($update->expr()->eq('reserved_at', $update->createParameter('reserved_at')))
+ ->andWhere($update->expr()->eq('last_checked', $update->createParameter('last_checked')));
$update->setParameter('jobid', $row['id']);
$update->setParameter('reserved_at', $row['reserved_at']);
$update->setParameter('last_checked', $row['last_checked']);
@@ -240,7 +255,6 @@ class JobList implements IJobList {
// Background job already executed elsewhere, try again.
return $this->getNext($onlyTimeSensitive);
}
- $job = $this->buildJob($row);
if ($job === null) {
// set the last_checked to 12h in the future to not check failing jobs all over again
diff --git a/lib/private/Calendar/CalendarQuery.php b/lib/private/Calendar/CalendarQuery.php
index 64f74c2728b..3d37d9dc467 100644
--- a/lib/private/Calendar/CalendarQuery.php
+++ b/lib/private/Calendar/CalendarQuery.php
@@ -28,33 +28,24 @@ namespace OC\Calendar;
use OCP\Calendar\ICalendarQuery;
class CalendarQuery implements ICalendarQuery {
- /** @var string */
- private $principalUri;
+ public array $searchProperties = [];
- /** @var array */
- public $searchProperties;
+ private ?string $searchPattern = null;
- /** @var string|null */
- private $searchPattern;
+ private array $options = [
+ 'types' => [],
+ ];
- /** @var array */
- private $options;
+ private ?int $offset = null;
- /** @var int|null */
- private $offset;
-
- /** @var int|null */
- private $limit;
+ private ?int $limit = null;
/** @var string[] */
- private $calendarUris = [];
+ private array $calendarUris = [];
- public function __construct(string $principalUri) {
- $this->principalUri = $principalUri;
- $this->searchProperties = [];
- $this->options = [
- 'types' => [],
- ];
+ public function __construct(
+ private string $principalUri,
+ ) {
}
public function getPrincipalUri(): string {
diff --git a/lib/private/Calendar/Manager.php b/lib/private/Calendar/Manager.php
index 7ef9dc585ae..dc4801c69ce 100644
--- a/lib/private/Calendar/Manager.php
+++ b/lib/private/Calendar/Manager.php
@@ -50,33 +50,19 @@ class Manager implements IManager {
/**
* @var ICalendar[] holds all registered calendars
*/
- private $calendars = [];
+ private array $calendars = [];
/**
* @var \Closure[] to call to load/register calendar providers
*/
- private $calendarLoaders = [];
-
- /** @var Coordinator */
- private $coordinator;
-
- /** @var ContainerInterface */
- private $container;
-
- /** @var LoggerInterface */
- private $logger;
-
- private ITimeFactory $timeFactory;
-
-
- public function __construct(Coordinator $coordinator,
- ContainerInterface $container,
- LoggerInterface $logger,
- ITimeFactory $timeFactory) {
- $this->coordinator = $coordinator;
- $this->container = $container;
- $this->logger = $logger;
- $this->timeFactory = $timeFactory;
+ private array $calendarLoaders = [];
+
+ public function __construct(
+ private Coordinator $coordinator,
+ private ContainerInterface $container,
+ private LoggerInterface $logger,
+ private ITimeFactory $timeFactory,
+ ) {
}
/**
@@ -92,7 +78,13 @@ class Manager implements IManager {
* @return array an array of events/journals/todos which are arrays of arrays of key-value-pairs
* @since 13.0.0
*/
- public function search($pattern, array $searchProperties = [], array $options = [], $limit = null, $offset = null) {
+ public function search(
+ $pattern,
+ array $searchProperties = [],
+ array $options = [],
+ $limit = null,
+ $offset = null,
+ ): array {
$this->loadCalendars();
$result = [];
foreach ($this->calendars as $calendar) {
@@ -112,29 +104,25 @@ class Manager implements IManager {
* @return bool true if enabled, false if not
* @since 13.0.0
*/
- public function isEnabled() {
+ public function isEnabled(): bool {
return !empty($this->calendars) || !empty($this->calendarLoaders);
}
/**
* Registers a calendar
*
- * @param ICalendar $calendar
- * @return void
* @since 13.0.0
*/
- public function registerCalendar(ICalendar $calendar) {
+ public function registerCalendar(ICalendar $calendar): void {
$this->calendars[$calendar->getKey()] = $calendar;
}
/**
* Unregisters a calendar
*
- * @param ICalendar $calendar
- * @return void
* @since 13.0.0
*/
- public function unregisterCalendar(ICalendar $calendar) {
+ public function unregisterCalendar(ICalendar $calendar): void {
unset($this->calendars[$calendar->getKey()]);
}
@@ -142,19 +130,18 @@ class Manager implements IManager {
* In order to improve lazy loading a closure can be registered which will be called in case
* calendars are actually requested
*
- * @param \Closure $callable
- * @return void
* @since 13.0.0
*/
- public function register(\Closure $callable) {
+ public function register(\Closure $callable): void {
$this->calendarLoaders[] = $callable;
}
/**
* @return ICalendar[]
+ *
* @since 13.0.0
*/
- public function getCalendars() {
+ public function getCalendars(): array {
$this->loadCalendars();
return array_values($this->calendars);
@@ -162,10 +149,10 @@ class Manager implements IManager {
/**
* removes all registered calendar instances
- * @return void
+ *
* @since 13.0.0
*/
- public function clear() {
+ public function clear(): void {
$this->calendars = [];
$this->calendarLoaders = [];
}
@@ -173,7 +160,7 @@ class Manager implements IManager {
/**
* loads all calendars
*/
- private function loadCalendars() {
+ private function loadCalendars(): void {
foreach ($this->calendarLoaders as $callable) {
$callable($this);
}
@@ -181,8 +168,6 @@ class Manager implements IManager {
}
/**
- * @param string $principalUri
- * @param array $calendarUris
* @return ICreateFromString[]
*/
public function getCalendarsForPrincipal(string $principalUri, array $calendarUris = []): array {
@@ -240,12 +225,26 @@ class Manager implements IManager {
/**
* @throws \OCP\DB\Exception
*/
- public function handleIMipReply(string $principalUri, string $sender, string $recipient, string $calendarData): bool {
- /** @var VCalendar $vObject */
+ public function handleIMipReply(
+ string $principalUri,
+ string $sender,
+ string $recipient,
+ string $calendarData,
+ ): bool {
+ /** @var VCalendar $vObject|null */
$vObject = Reader::read($calendarData);
- /** @var VEvent $vEvent */
+
+ if ($vObject === null) {
+ return false;
+ }
+
+ /** @var VEvent|null $vEvent */
$vEvent = $vObject->{'VEVENT'};
+ if ($vEvent === null) {
+ return false;
+ }
+
// First, we check if the correct method is passed to us
if (strcasecmp('REPLY', $vObject->{'METHOD'}->getValue()) !== 0) {
$this->logger->warning('Wrong method provided for processing');
@@ -309,11 +308,27 @@ class Manager implements IManager {
* @since 25.0.0
* @throws \OCP\DB\Exception
*/
- public function handleIMipCancel(string $principalUri, string $sender, ?string $replyTo, string $recipient, string $calendarData): bool {
+ public function handleIMipCancel(
+ string $principalUri,
+ string $sender,
+ ?string $replyTo,
+ string $recipient,
+ string $calendarData,
+ ): bool {
+ /** @var VCalendar $vObject|null */
$vObject = Reader::read($calendarData);
- /** @var VEvent $vEvent */
+
+ if ($vObject === null) {
+ return false;
+ }
+
+ /** @var VEvent|null $vEvent */
$vEvent = $vObject->{'VEVENT'};
+ if ($vEvent === null) {
+ return false;
+ }
+
// First, we check if the correct method is passed to us
if (strcasecmp('CANCEL', $vObject->{'METHOD'}->getValue()) !== 0) {
$this->logger->warning('Wrong method provided for processing');
diff --git a/lib/private/Calendar/Resource/Manager.php b/lib/private/Calendar/Resource/Manager.php
index ebde4ac5eb5..88e733f3f24 100644
--- a/lib/private/Calendar/Resource/Manager.php
+++ b/lib/private/Calendar/Resource/Manager.php
@@ -33,46 +33,38 @@ use OCP\Calendar\Resource\IManager;
use OCP\IServerContainer;
class Manager implements IManager {
- private Coordinator $bootstrapCoordinator;
-
- private IServerContainer $server;
-
private bool $bootstrapBackendsLoaded = false;
/**
* @var string[] holds all registered resource backends
* @psalm-var class-string<IBackend>[]
*/
- private $backends = [];
+ private array $backends = [];
/** @var IBackend[] holds all backends that have been initialized already */
- private $initializedBackends = [];
+ private array $initializedBackends = [];
- public function __construct(Coordinator $bootstrapCoordinator,
- IServerContainer $server) {
- $this->bootstrapCoordinator = $bootstrapCoordinator;
- $this->server = $server;
+ public function __construct(
+ private Coordinator $bootstrapCoordinator,
+ private IServerContainer $server,
+ ) {
}
/**
* Registers a resource backend
*
- * @param string $backendClass
- * @return void
* @since 14.0.0
*/
- public function registerBackend(string $backendClass) {
+ public function registerBackend(string $backendClass): void {
$this->backends[$backendClass] = $backendClass;
}
/**
* Unregisters a resource backend
*
- * @param string $backendClass
- * @return void
* @since 14.0.0
*/
- public function unregisterBackend(string $backendClass) {
+ public function unregisterBackend(string $backendClass): void {
unset($this->backends[$backendClass], $this->initializedBackends[$backendClass]);
}
@@ -114,9 +106,8 @@ class Manager implements IManager {
/**
* @param string $backendId
* @throws \OCP\AppFramework\QueryException
- * @return IBackend|null
*/
- public function getBackend($backendId) {
+ public function getBackend($backendId): ?IBackend {
$backends = $this->getBackends();
foreach ($backends as $backend) {
if ($backend->getBackendIdentifier() === $backendId) {
@@ -129,10 +120,10 @@ class Manager implements IManager {
/**
* removes all registered backend instances
- * @return void
+ *
* @since 14.0.0
*/
- public function clear() {
+ public function clear(): void {
$this->backends = [];
$this->initializedBackends = [];
}
diff --git a/lib/private/Calendar/Room/Manager.php b/lib/private/Calendar/Room/Manager.php
index 7e6af2823a3..d7ecdfd8b36 100644
--- a/lib/private/Calendar/Room/Manager.php
+++ b/lib/private/Calendar/Room/Manager.php
@@ -33,10 +33,6 @@ use OCP\Calendar\Room\IManager;
use OCP\IServerContainer;
class Manager implements IManager {
- private Coordinator $bootstrapCoordinator;
-
- private IServerContainer $server;
-
private bool $bootstrapBackendsLoaded = false;
/**
@@ -48,20 +44,18 @@ class Manager implements IManager {
/** @var IBackend[] holds all backends that have been initialized already */
private array $initializedBackends = [];
- public function __construct(Coordinator $bootstrapCoordinator,
- IServerContainer $server) {
- $this->bootstrapCoordinator = $bootstrapCoordinator;
- $this->server = $server;
+ public function __construct(
+ private Coordinator $bootstrapCoordinator,
+ private IServerContainer $server,
+ ) {
}
/**
* Registers a resource backend
*
- * @param string $backendClass
- * @return void
* @since 14.0.0
*/
- public function registerBackend(string $backendClass) {
+ public function registerBackend(string $backendClass): void {
$this->backends[$backendClass] = $backendClass;
}
@@ -69,10 +63,9 @@ class Manager implements IManager {
* Unregisters a resource backend
*
* @param string $backendClass
- * @return void
* @since 14.0.0
*/
- public function unregisterBackend(string $backendClass) {
+ public function unregisterBackend(string $backendClass): void {
unset($this->backends[$backendClass], $this->initializedBackends[$backendClass]);
}
@@ -120,9 +113,8 @@ class Manager implements IManager {
/**
* @param string $backendId
* @throws \OCP\AppFramework\QueryException
- * @return IBackend|null
*/
- public function getBackend($backendId) {
+ public function getBackend($backendId): ?IBackend {
$backends = $this->getBackends();
foreach ($backends as $backend) {
if ($backend->getBackendIdentifier() === $backendId) {
@@ -135,10 +127,10 @@ class Manager implements IManager {
/**
* removes all registered backend instances
- * @return void
+ *
* @since 14.0.0
*/
- public function clear() {
+ public function clear(): void {
$this->backends = [];
$this->initializedBackends = [];
}
diff --git a/lib/private/CapabilitiesManager.php b/lib/private/CapabilitiesManager.php
index 9e63798475b..7885a98869d 100644
--- a/lib/private/CapabilitiesManager.php
+++ b/lib/private/CapabilitiesManager.php
@@ -50,7 +50,7 @@ class CapabilitiesManager {
*
* @param bool $public get public capabilities only
* @throws \InvalidArgumentException
- * @return array
+ * @return array<string, mixed>
*/
public function getCapabilities(bool $public = false, bool $initialState = false) : array {
$capabilities = [];
diff --git a/lib/private/Collaboration/Resources/Listener.php b/lib/private/Collaboration/Resources/Listener.php
index b9f1e72cbfa..4330f3570bc 100644
--- a/lib/private/Collaboration/Resources/Listener.php
+++ b/lib/private/Collaboration/Resources/Listener.php
@@ -26,64 +26,46 @@ declare(strict_types=1);
*/
namespace OC\Collaboration\Resources;
-use OC\EventDispatcher\SymfonyAdapter;
use OCP\Collaboration\Resources\IManager;
-use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent;
use OCP\EventDispatcher\IEventDispatcher;
-use OCP\IGroup;
-use OCP\IUser;
-use Symfony\Component\EventDispatcher\GenericEvent;
+use OCP\Group\Events\BeforeGroupDeletedEvent;
+use OCP\Group\Events\UserAddedEvent;
+use OCP\Group\Events\UserRemovedEvent;
+use OCP\User\Events\UserDeletedEvent;
class Listener {
- public static function register(SymfonyAdapter $symfonyDispatcher, IEventDispatcher $eventDispatcher): void {
- $listener = function (GenericEvent $event) {
- /** @var IUser $user */
- $user = $event->getArgument('user');
+ public static function register(IEventDispatcher $eventDispatcher): void {
+ $eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
+ $user = $event->getUser();
/** @var IManager $resourceManager */
- $resourceManager = \OC::$server->query(IManager::class);
+ $resourceManager = \OCP\Server::get(IManager::class);
$resourceManager->invalidateAccessCacheForUser($user);
- };
- $symfonyDispatcher->addListener(IGroup::class . '::postAddUser', $listener);
- $symfonyDispatcher->addListener(IGroup::class . '::postRemoveUser', $listener);
+ });
+ $eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
+ $user = $event->getUser();
+ /** @var IManager $resourceManager */
+ $resourceManager = \OCP\Server::get(IManager::class);
+
+ $resourceManager->invalidateAccessCacheForUser($user);
+ });
- $symfonyDispatcher->addListener(IUser::class . '::postDelete', function (GenericEvent $event) {
- /** @var IUser $user */
- $user = $event->getSubject();
+ $eventDispatcher->addListener(UserDeletedEvent::class, function (UserDeletedEvent $event) {
+ $user = $event->getUser();
/** @var IManager $resourceManager */
- $resourceManager = \OC::$server->query(IManager::class);
+ $resourceManager = \OCP\Server::get(IManager::class);
$resourceManager->invalidateAccessCacheForUser($user);
});
- $symfonyDispatcher->addListener(IGroup::class . '::preDelete', function (GenericEvent $event) {
- /** @var IGroup $group */
- $group = $event->getSubject();
+ $eventDispatcher->addListener(BeforeGroupDeletedEvent::class, function (BeforeGroupDeletedEvent $event) {
+ $group = $event->getGroup();
/** @var IManager $resourceManager */
- $resourceManager = \OC::$server->query(IManager::class);
+ $resourceManager = \OCP\Server::get(IManager::class);
foreach ($group->getUsers() as $user) {
$resourceManager->invalidateAccessCacheForUser($user);
}
});
-
- // Stay backward compatible with the legacy event for now
- $fallbackEventRunning = false;
- $symfonyDispatcher->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', function () use ($eventDispatcher, &$fallbackEventRunning) {
- if ($fallbackEventRunning) {
- return;
- }
- $fallbackEventRunning = true;
- $eventDispatcher->dispatchTyped(new LoadAdditionalScriptsEvent());
- $fallbackEventRunning = false;
- });
- $eventDispatcher->addListener(LoadAdditionalScriptsEvent::class, static function () use ($symfonyDispatcher, &$fallbackEventRunning) {
- if ($fallbackEventRunning) {
- return;
- }
- $fallbackEventRunning = true;
- $symfonyDispatcher->dispatch('\OCP\Collaboration\Resources::loadAdditionalScripts');
- $fallbackEventRunning = false;
- });
}
}
diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php
index af4fda277d6..725febef85d 100644
--- a/lib/private/Comments/Manager.php
+++ b/lib/private/Comments/Manager.php
@@ -501,6 +501,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();
diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php
index 94956364390..a0306c9798c 100644
--- a/lib/private/Console/Application.php
+++ b/lib/private/Console/Application.php
@@ -33,34 +33,29 @@ namespace OC\Console;
use OC\MemoryInfo;
use OC\NeedsUpdateException;
use OC_App;
-use OCP\AppFramework\QueryException;
use OCP\App\IAppManager;
use OCP\Console\ConsoleEvent;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IRequest;
+use Psr\Container\ContainerExceptionInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Application as SymfonyApplication;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class Application {
- /** @var IConfig */
- private $config;
+ private IConfig $config;
private SymfonyApplication $application;
- /** @var EventDispatcherInterface */
- 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,
- EventDispatcherInterface $dispatcher,
+ IEventDispatcher $dispatcher,
IRequest $request,
LoggerInterface $logger,
MemoryInfo $memoryInfo) {
@@ -74,8 +69,6 @@ class Application {
}
/**
- * @param InputInterface $input
- * @param ConsoleOutputInterface $output
* @throws \Exception
*/
public function loadCommands(
@@ -204,18 +197,20 @@ class Application {
* @throws \Exception
*/
public function run(InputInterface $input = null, OutputInterface $output = null) {
- $this->dispatcher->dispatch(ConsoleEvent::EVENT_RUN, new ConsoleEvent(
+ $event = new ConsoleEvent(
ConsoleEvent::EVENT_RUN,
$this->request->server['argv']
- ));
+ );
+ $this->dispatcher->dispatchTyped($event);
+ $this->dispatcher->dispatch(ConsoleEvent::EVENT_RUN, $event);
return $this->application->run($input, $output);
}
private function loadCommandsFromInfoXml($commands) {
foreach ($commands as $command) {
try {
- $c = \OC::$server->query($command);
- } catch (QueryException $e) {
+ $c = \OCP\Server::get($command);
+ } catch (ContainerExceptionInterface $e) {
if (class_exists($command)) {
try {
$c = new $command();
diff --git a/lib/private/Contacts/ContactsMenu/ActionProviderStore.php b/lib/private/Contacts/ContactsMenu/ActionProviderStore.php
index 485895de646..7ba5db4bb33 100644
--- a/lib/private/Contacts/ContactsMenu/ActionProviderStore.php
+++ b/lib/private/Contacts/ContactsMenu/ActionProviderStore.php
@@ -39,18 +39,14 @@ use OCP\IUser;
use Psr\Log\LoggerInterface;
class ActionProviderStore {
- private IServerContainer $serverContainer;
- private AppManager $appManager;
- private LoggerInterface $logger;
-
- public function __construct(IServerContainer $serverContainer, AppManager $appManager, LoggerInterface $logger) {
- $this->serverContainer = $serverContainer;
- $this->appManager = $appManager;
- $this->logger = $logger;
+ public function __construct(
+ private IServerContainer $serverContainer,
+ private AppManager $appManager,
+ private LoggerInterface $logger,
+ ) {
}
/**
- * @param IUser $user
* @return IProvider[]
* @throws Exception
*/
@@ -90,7 +86,6 @@ class ActionProviderStore {
}
/**
- * @param IUser $user
* @return string[]
*/
private function getAppProviderClasses(IUser $user): array {
diff --git a/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php b/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php
index a3054c9ee52..e0d3515f421 100644
--- a/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php
+++ b/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php
@@ -34,11 +34,11 @@ class LinkAction implements ILinkAction {
/**
* @param string $icon absolute URI to an icon
*/
- public function setIcon(string $icon) {
+ public function setIcon(string $icon): void {
$this->icon = $icon;
}
- public function setName(string $name) {
+ public function setName(string $name): void {
$this->name = $name;
}
@@ -46,7 +46,7 @@ class LinkAction implements ILinkAction {
return $this->name;
}
- public function setPriority(int $priority) {
+ public function setPriority(int $priority): void {
$this->priority = $priority;
}
@@ -54,7 +54,7 @@ class LinkAction implements ILinkAction {
return $this->priority;
}
- public function setHref(string $href) {
+ public function setHref(string $href): void {
$this->href = $href;
}
@@ -65,7 +65,7 @@ class LinkAction implements ILinkAction {
/**
* @since 23.0.0
*/
- public function setAppId(string $appId) {
+ public function setAppId(string $appId): void {
$this->appId = $appId;
}
@@ -76,6 +76,9 @@ class LinkAction implements ILinkAction {
return $this->appId;
}
+ /**
+ * @return array{title: string, icon: string, hyperlink: string, appId: string}
+ */
public function jsonSerialize(): array {
return [
'title' => $this->name,
diff --git a/lib/private/Contacts/ContactsMenu/ContactsStore.php b/lib/private/Contacts/ContactsMenu/ContactsStore.php
index e4dd80645ea..c692b486ae4 100644
--- a/lib/private/Contacts/ContactsMenu/ContactsStore.php
+++ b/lib/private/Contacts/ContactsMenu/ContactsStore.php
@@ -44,33 +44,16 @@ use OCP\IUserManager;
use OCP\L10N\IFactory as IL10NFactory;
class ContactsStore implements IContactsStore {
- private IManager $contactsManager;
- private IConfig $config;
- private ProfileManager $profileManager;
- private IUserManager $userManager;
- private IURLGenerator $urlGenerator;
- private IGroupManager $groupManager;
- private KnownUserService $knownUserService;
- private IL10NFactory $l10nFactory;
-
public function __construct(
- IManager $contactsManager,
- IConfig $config,
- ProfileManager $profileManager,
- IUserManager $userManager,
- IURLGenerator $urlGenerator,
- IGroupManager $groupManager,
- KnownUserService $knownUserService,
- IL10NFactory $l10nFactory
+ private IManager $contactsManager,
+ private IConfig $config,
+ private ProfileManager $profileManager,
+ private IUserManager $userManager,
+ private IURLGenerator $urlGenerator,
+ private IGroupManager $groupManager,
+ private KnownUserService $knownUserService,
+ private IL10NFactory $l10nFactory,
) {
- $this->contactsManager = $contactsManager;
- $this->config = $config;
- $this->profileManager = $profileManager;
- $this->userManager = $userManager;
- $this->urlGenerator = $urlGenerator;
- $this->groupManager = $groupManager;
- $this->knownUserService = $knownUserService;
- $this->l10nFactory = $l10nFactory;
}
/**
@@ -126,9 +109,7 @@ class ContactsStore implements IContactsStore {
* enabled it will filter all users which doesn't have a common group
* with the current user.
*
- * @param IUser $self
* @param Entry[] $entries
- * @param string|null $filter
* @return Entry[] the filtered contacts
*/
private function filterContacts(
diff --git a/lib/private/Contacts/ContactsMenu/Entry.php b/lib/private/Contacts/ContactsMenu/Entry.php
index 51fde760407..f1cb4f9c52f 100644
--- a/lib/private/Contacts/ContactsMenu/Entry.php
+++ b/lib/private/Contacts/ContactsMenu/Entry.php
@@ -134,11 +134,7 @@ class Entry implements IEntry {
$this->properties = $contact;
}
- /**
- * @param string $key
- * @return mixed
- */
- public function getProperty(string $key) {
+ public function getProperty(string $key): mixed {
if (!isset($this->properties[$key])) {
return null;
}
@@ -146,7 +142,7 @@ class Entry implements IEntry {
}
/**
- * @return array
+ * @return array{id: int|string|null, fullName: string, avatar: string|null, topAction: mixed, actions: array, lastMessage: '', emailAddresses: string[], profileTitle: string|null, profileUrl: string|null}
*/
public function jsonSerialize(): array {
$topAction = !empty($this->actions) ? $this->actions[0]->jsonSerialize() : null;
diff --git a/lib/private/Contacts/ContactsMenu/Manager.php b/lib/private/Contacts/ContactsMenu/Manager.php
index 5c3367a3d09..490cf602283 100644
--- a/lib/private/Contacts/ContactsMenu/Manager.php
+++ b/lib/private/Contacts/ContactsMenu/Manager.php
@@ -33,22 +33,15 @@ use OCP\IConfig;
use OCP\IUser;
class Manager {
- private ContactsStore $store;
- private ActionProviderStore $actionProviderStore;
- private IAppManager $appManager;
- private IConfig $config;
-
- public function __construct(ContactsStore $store, ActionProviderStore $actionProviderStore, IAppManager $appManager, IConfig $config) {
- $this->store = $store;
- $this->actionProviderStore = $actionProviderStore;
- $this->appManager = $appManager;
- $this->config = $config;
+ public function __construct(
+ private ContactsStore $store,
+ private ActionProviderStore $actionProviderStore,
+ private IAppManager $appManager,
+ private IConfig $config,
+ ) {
}
/**
- * @param IUser $user
- * @param string|null $filter
- * @return array
* @throws Exception
*/
public function getEntries(IUser $user, ?string $filter): array {
@@ -95,10 +88,9 @@ class Manager {
/**
* @param IEntry[] $entries
- * @param IUser $user
* @throws Exception
*/
- private function processEntries(array $entries, IUser $user) {
+ private function processEntries(array $entries, IUser $user): void {
$providers = $this->actionProviderStore->getProviders($user);
foreach ($entries as $entry) {
foreach ($providers as $provider) {
diff --git a/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php b/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php
index b79052e1f5d..145c30a2ce7 100644
--- a/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php
+++ b/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php
@@ -28,18 +28,13 @@ use OCP\Contacts\ContactsMenu\IProvider;
use OCP\IURLGenerator;
class EMailProvider implements IProvider {
- private IActionFactory $actionFactory;
- private IURLGenerator $urlGenerator;
-
- public function __construct(IActionFactory $actionFactory, IURLGenerator $urlGenerator) {
- $this->actionFactory = $actionFactory;
- $this->urlGenerator = $urlGenerator;
+ public function __construct(
+ private IActionFactory $actionFactory,
+ private IURLGenerator $urlGenerator,
+ ) {
}
- /**
- * @param IEntry $entry
- */
- public function process(IEntry $entry) {
+ public function process(IEntry $entry): void {
$iconUrl = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/mail.svg'));
foreach ($entry->getEMailAddresses() as $address) {
if (empty($address)) {
diff --git a/lib/private/Contacts/ContactsMenu/Providers/LocalTimeProvider.php b/lib/private/Contacts/ContactsMenu/Providers/LocalTimeProvider.php
index 17e30e89c37..32e1280ff0f 100644
--- a/lib/private/Contacts/ContactsMenu/Providers/LocalTimeProvider.php
+++ b/lib/private/Contacts/ContactsMenu/Providers/LocalTimeProvider.php
@@ -37,36 +37,18 @@ use OCP\IUserManager;
use OCP\L10N\IFactory as IL10NFactory;
class LocalTimeProvider implements IProvider {
- private IActionFactory $actionFactory;
- private IL10NFactory $l10nFactory;
- private IURLGenerator $urlGenerator;
- private IUserManager $userManager;
- private ITimeFactory $timeFactory;
- private IDateTimeFormatter $dateTimeFormatter;
- private IConfig $config;
-
public function __construct(
- IActionFactory $actionFactory,
- IL10NFactory $l10nFactory,
- IURLGenerator $urlGenerator,
- IUserManager $userManager,
- ITimeFactory $timeFactory,
- IDateTimeFormatter $dateTimeFormatter,
- IConfig $config
+ private IActionFactory $actionFactory,
+ private IL10NFactory $l10nFactory,
+ private IURLGenerator $urlGenerator,
+ private IUserManager $userManager,
+ private ITimeFactory $timeFactory,
+ private IDateTimeFormatter $dateTimeFormatter,
+ private IConfig $config,
) {
- $this->actionFactory = $actionFactory;
- $this->l10nFactory = $l10nFactory;
- $this->urlGenerator = $urlGenerator;
- $this->userManager = $userManager;
- $this->timeFactory = $timeFactory;
- $this->dateTimeFormatter = $dateTimeFormatter;
- $this->config = $config;
}
- /**
- * @param IEntry $entry
- */
- public function process(IEntry $entry) {
+ public function process(IEntry $entry): void {
$targetUserId = $entry->getProperty('UID');
$targetUser = $this->userManager->get($targetUserId);
if (!empty($targetUser)) {
diff --git a/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php b/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php
index af941fd7fd1..6b36b9fff0e 100644
--- a/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php
+++ b/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php
@@ -33,30 +33,16 @@ use OCP\IUserManager;
use OCP\L10N\IFactory as IL10NFactory;
class ProfileProvider implements IProvider {
- private IActionFactory $actionFactory;
- private ProfileManager $profileManager;
- private IL10NFactory $l10nFactory;
- private IURLGenerator $urlGenerator;
- private IUserManager $userManager;
-
public function __construct(
- IActionFactory $actionFactory,
- ProfileManager $profileManager,
- IL10NFactory $l10nFactory,
- IURLGenerator $urlGenerator,
- IUserManager $userManager
+ private IActionFactory $actionFactory,
+ private ProfileManager $profileManager,
+ private IL10NFactory $l10nFactory,
+ private IURLGenerator $urlGenerator,
+ private IUserManager $userManager,
) {
- $this->actionFactory = $actionFactory;
- $this->profileManager = $profileManager;
- $this->l10nFactory = $l10nFactory;
- $this->urlGenerator = $urlGenerator;
- $this->userManager = $userManager;
}
- /**
- * @param IEntry $entry
- */
- public function process(IEntry $entry) {
+ public function process(IEntry $entry): void {
$targetUserId = $entry->getProperty('UID');
$targetUser = $this->userManager->get($targetUserId);
if (!empty($targetUser)) {
diff --git a/lib/private/ContactsManager.php b/lib/private/ContactsManager.php
index 5a02968ad9b..cfbd4305cd8 100644
--- a/lib/private/ContactsManager.php
+++ b/lib/private/ContactsManager.php
@@ -58,15 +58,18 @@ class ContactsManager implements IManager {
$strictSearch = array_key_exists('strict_search', $options) && $options['strict_search'] === true;
if ($addressBook->isSystemAddressBook()) {
+ $enumeration = !\array_key_exists('enumeration', $options) || $options['enumeration'] !== false;
$fullMatch = !\array_key_exists('fullmatch', $options) || $options['fullmatch'] !== false;
- if (!$fullMatch) {
- // Neither full match is allowed, so skip the system address book
+
+ if (!$enumeration && !$fullMatch) {
+ // No access to system address book AND no full match allowed
continue;
}
+
if ($strictSearch) {
$searchOptions['wildcard'] = false;
} else {
- $searchOptions['wildcard'] = !\array_key_exists('enumeration', $options) || $options['enumeration'] !== false;
+ $searchOptions['wildcard'] = $enumeration;
}
} else {
$searchOptions['wildcard'] = !$strictSearch;
@@ -88,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;
}
/**
@@ -109,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;
}
@@ -130,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);
}
@@ -189,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..2bd1d4c824a 100644
--- a/lib/private/DB/Connection.php
+++ b/lib/private/DB/Connection.php
@@ -220,7 +220,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 +231,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);
@@ -321,14 +321,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);
}
/**
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/MigrationService.php b/lib/private/DB/MigrationService.php
index 7993730b230..29df1c1f78d 100644
--- a/lib/private/DB/MigrationService.php
+++ b/lib/private/DB/MigrationService.php
@@ -58,7 +58,7 @@ 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) {
$this->appName = $appName;
$this->connection = $connection;
if ($output === null) {
@@ -100,18 +100,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 +185,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 +194,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 +321,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 +340,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 +365,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,21 +379,16 @@ 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->migrateSchemaOnly($to);
return;
@@ -425,11 +409,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);
@@ -448,6 +430,7 @@ class MigrationService {
if ($toSchema instanceof SchemaWrapper) {
$targetSchema = $toSchema->getWrappedSchema();
+ $this->ensureUniqueNamesConstraints($targetSchema);
if ($this->checkOracle) {
$beforeSchema = $this->connection->createSchema();
$this->ensureOracleConstraints($beforeSchema, $targetSchema, strlen($this->connection->getPrefix()));
@@ -487,7 +470,7 @@ class MigrationService {
protected function createInstance($version) {
$class = $this->getClass($version);
try {
- $s = \OC::$server->query($class);
+ $s = \OCP\Server::get($class);
if (!$s instanceof IMigrationStep) {
throw new \InvalidArgumentException('Not a valid migration');
@@ -525,6 +508,7 @@ class MigrationService {
if ($toSchema instanceof SchemaWrapper) {
$targetSchema = $toSchema->getWrappedSchema();
+ $this->ensureUniqueNamesConstraints($targetSchema);
if ($this->checkOracle) {
$sourceSchema = $this->connection->createSchema();
$this->ensureOracleConstraints($sourceSchema, $targetSchema, strlen($this->connection->getPrefix()));
@@ -659,6 +643,59 @@ class MigrationService {
}
}
+ /**
+ * Naming constraints:
+ * - Index, sequence and primary key names must be unique within a Postgres Schema
+ *
+ * @param Schema $targetSchema
+ */
+ public function ensureUniqueNamesConstraints(Schema $targetSchema): void {
+ $constraintNames = [];
+
+ $sequences = $targetSchema->getSequences();
+
+ foreach ($targetSchema->getTables() as $table) {
+ foreach ($table->getIndexes() as $thing) {
+ $indexName = strtolower($thing->getName());
+ if ($indexName === 'primary' || $thing->isPrimary()) {
+ continue;
+ }
+
+ 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()] . '".');
+ }
+ $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()] . '".');
+ }
+ $constraintNames[$thing->getName()] = $table->getName();
+ }
+
+ $primaryKey = $table->getPrimaryKey();
+ if ($primaryKey instanceof Index) {
+ $indexName = strtolower($primaryKey->getName());
+ if ($indexName === 'primary') {
+ continue;
+ }
+
+ if (isset($constraintNames[$indexName])) {
+ throw new \InvalidArgumentException('Primary index name "' . $indexName . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".');
+ }
+ $constraintNames[$indexName] = $table->getName();
+ }
+ }
+
+ 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()] . '".');
+ }
+ $constraintNames[$sequence->getName()] = 'sequence';
+ }
+ }
+
private function ensureMigrationsAreLoaded() {
if (empty($this->migrations)) {
$this->migrations = $this->findMigrations();
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/PostgreSqlMigrator.php b/lib/private/DB/PostgreSqlMigrator.php
index 73e295705da..92a0842e1a7 100644
--- a/lib/private/DB/PostgreSqlMigrator.php
+++ b/lib/private/DB/PostgreSqlMigrator.php
@@ -42,7 +42,7 @@ class PostgreSqlMigrator extends Migrator {
}
$fromDefault = $column->fromColumn->getDefault();
$toDefault = $column->column->getDefault();
- $fromDefault = trim($fromDefault, "()");
+ $fromDefault = trim((string) $fromDefault, '()');
// by intention usage of !=
return $fromDefault != $toDefault;
diff --git a/lib/private/Dashboard/Manager.php b/lib/private/Dashboard/Manager.php
index 18a66499167..afe28872e69 100644
--- a/lib/private/Dashboard/Manager.php
+++ b/lib/private/Dashboard/Manager.php
@@ -40,8 +40,8 @@ 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;
@@ -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/Encryption/EncryptionWrapper.php b/lib/private/Encryption/EncryptionWrapper.php
index 37264e81823..e58b3656593 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;
/**
@@ -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/Manager.php b/lib/private/Encryption/Manager.php
index f751bd94b28..28bee7dacb7 100644
--- a/lib/private/Encryption/Manager.php
+++ b/lib/private/Encryption/Manager.php
@@ -32,6 +32,8 @@ 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;
@@ -234,6 +236,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/Util.php b/lib/private/Encryption/Util.php
index a468908ffc8..a828483265b 100644
--- a/lib/private/Encryption/Util.php
+++ b/lib/private/Encryption/Util.php
@@ -357,4 +357,32 @@ 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;
+ }
}
diff --git a/lib/private/EventDispatcher/EventDispatcher.php b/lib/private/EventDispatcher/EventDispatcher.php
index d64ad88be7e..88c6b2cf32c 100644
--- a/lib/private/EventDispatcher/EventDispatcher.php
+++ b/lib/private/EventDispatcher/EventDispatcher.php
@@ -58,7 +58,7 @@ class EventDispatcher implements IEventDispatcher {
// 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 or $this->logger instanceof Log\PsrLoggerAdapter) {
+ if ($this->logger instanceof Log || $this->logger instanceof Log\PsrLoggerAdapter) {
$this->logger->setEventDispatcher($this);
}
}
diff --git a/lib/private/EventDispatcher/GenericEventWrapper.php b/lib/private/EventDispatcher/GenericEventWrapper.php
deleted file mode 100644
index f0807b57a8b..00000000000
--- a/lib/private/EventDispatcher/GenericEventWrapper.php
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @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 OC\EventDispatcher;
-
-use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
-
-class GenericEventWrapper extends GenericEvent {
- private LoggerInterface $logger;
-
- /** @var GenericEvent */
- private $event;
-
- /** @var string */
- private $eventName;
-
- /** @var bool */
- private $deprecationNoticeLogged = false;
-
- public function __construct(LoggerInterface $logger, string $eventName, ?GenericEvent $event) {
- parent::__construct($eventName);
- $this->logger = $logger;
- $this->event = $event;
- $this->eventName = $eventName;
- }
-
- private function log() {
- if ($this->deprecationNoticeLogged) {
- return;
- }
-
- $class = ($this->event !== null && is_object($this->event)) ? get_class($this->event) : 'null';
- $this->logger->debug(
- 'Deprecated event type for {name}: {class} is used',
- [ 'name' => $this->eventName, 'class' => $class]
- );
- $this->deprecationNoticeLogged = true;
- }
-
- public function isPropagationStopped(): bool {
- $this->log();
- return $this->event->isPropagationStopped();
- }
-
- public function stopPropagation(): void {
- $this->log();
- $this->event->stopPropagation();
- }
-
- public function getSubject() {
- $this->log();
- return $this->event->getSubject();
- }
-
- public function getArgument($key) {
- $this->log();
- return $this->event->getArgument($key);
- }
-
- public function setArgument($key, $value) {
- $this->log();
- return $this->event->setArgument($key, $value);
- }
-
- public function getArguments() {
- return $this->event->getArguments();
- }
-
- public function setArguments(array $args = []) {
- return $this->event->setArguments($args);
- }
-
- public function hasArgument($key) {
- return $this->event->hasArgument($key);
- }
-
- /**
- * @return mixed
- */
- #[\ReturnTypeWillChange]
- public function offsetGet($key) {
- return $this->event->offsetGet($key);
- }
-
- public function offsetSet($key, $value): void {
- $this->event->offsetSet($key, $value);
- }
-
- public function offsetUnset($key): void {
- $this->event->offsetUnset($key);
- }
-
- public function offsetExists($key): bool {
- return $this->event->offsetExists($key);
- }
-
- public function getIterator() {
- return$this->event->getIterator();
- }
-}
diff --git a/lib/private/EventDispatcher/SymfonyAdapter.php b/lib/private/EventDispatcher/SymfonyAdapter.php
deleted file mode 100644
index 139f444ce44..00000000000
--- a/lib/private/EventDispatcher/SymfonyAdapter.php
+++ /dev/null
@@ -1,208 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @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 OC\EventDispatcher;
-
-use OCP\EventDispatcher\Event;
-use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
-use function is_callable;
-use function is_object;
-use function is_string;
-
-/**
- * @deprecated 20.0.0 use \OCP\EventDispatcher\IEventDispatcher
- */
-class SymfonyAdapter implements EventDispatcherInterface {
- /** @var EventDispatcher */
- private $eventDispatcher;
- private LoggerInterface $logger;
-
- /**
- * @deprecated 20.0.0
- */
- public function __construct(EventDispatcher $eventDispatcher, LoggerInterface $logger) {
- $this->eventDispatcher = $eventDispatcher;
- $this->logger = $logger;
- }
-
- private static function detectEventAndName($a, $b) {
- if (is_object($a) && (is_string($b) || $b === null)) {
- // a is the event, the other one is the optional name
- return [$a, $b];
- }
- if (is_object($b) && (is_string($a) || $a === null)) {
- // b is the event, the other one is the optional name
- return [$b, $a];
- }
- if (is_string($a) && $b === null) {
- // a is a payload-less event
- return [null, $a];
- }
- if (is_string($b) && $a === null) {
- // b is a payload-less event
- return [null, $b];
- }
-
- // Anything else we can't detect
- return [$a, $b];
- }
-
- /**
- * Dispatches an event to all registered listeners.
- *
- * @param string $eventName The name of the event to dispatch. The name of
- * the event is the name of the method that is
- * invoked on listeners.
- * @param Event|null $event The event to pass to the event handlers/listeners
- * If not supplied, an empty Event instance is created
- *
- * @return object the emitted event
- * @deprecated 20.0.0
- */
- public function dispatch($eventName, $event = null): object {
- [$event, $eventName] = self::detectEventAndName($event, $eventName);
-
- // type hinting is not possible, due to usage of GenericEvent
- if ($event instanceof Event && $eventName === null) {
- $this->eventDispatcher->dispatchTyped($event);
- return $event;
- }
- if ($event instanceof Event) {
- $this->eventDispatcher->dispatch($eventName, $event);
- return $event;
- }
-
- if ($event instanceof GenericEvent && get_class($event) === GenericEvent::class) {
- $newEvent = new GenericEventWrapper($this->logger, $eventName, $event);
- } else {
- $newEvent = $event;
-
- // Legacy event
- $this->logger->debug(
- 'Deprecated event type for {name}: {class}',
- ['name' => $eventName, 'class' => is_object($event) ? get_class($event) : 'null']
- );
- }
-
- // Event with no payload (object) need special handling
- if ($newEvent === null) {
- $newEvent = new Event();
- }
-
- // Flip the argument order for Symfony to prevent a trigger_error
- return $this->eventDispatcher->getSymfonyDispatcher()->dispatch($newEvent, $eventName);
- }
-
- /**
- * Adds an event listener that listens on the specified events.
- *
- * @param string $eventName The event to listen on
- * @param callable $listener The listener
- * @param int $priority The higher this value, the earlier an event
- * listener will be triggered in the chain (defaults to 0)
- * @deprecated 20.0.0
- */
- public function addListener($eventName, $listener, $priority = 0) {
- if (is_callable($listener)) {
- $this->eventDispatcher->addListener($eventName, $listener, $priority);
- } else {
- // Legacy listener
- $this->eventDispatcher->getSymfonyDispatcher()->addListener($eventName, $listener, $priority);
- }
- }
-
- /**
- * Adds an event subscriber.
- *
- * The subscriber is asked for all the events it is
- * interested in and added as a listener for these events.
- * @deprecated 20.0.0
- */
- public function addSubscriber(EventSubscriberInterface $subscriber) {
- $this->eventDispatcher->getSymfonyDispatcher()->addSubscriber($subscriber);
- }
-
- /**
- * Removes an event listener from the specified events.
- *
- * @param string $eventName The event to remove a listener from
- * @param callable $listener The listener to remove
- * @deprecated 20.0.0
- */
- public function removeListener($eventName, $listener) {
- $this->eventDispatcher->getSymfonyDispatcher()->removeListener($eventName, $listener);
- }
-
- /**
- * @deprecated 20.0.0
- */
- public function removeSubscriber(EventSubscriberInterface $subscriber) {
- $this->eventDispatcher->getSymfonyDispatcher()->removeSubscriber($subscriber);
- }
-
- /**
- * Gets the listeners of a specific event or all listeners sorted by descending priority.
- *
- * @param string|null $eventName The name of the event
- *
- * @return array The event listeners for the specified event, or all event listeners by event name
- * @deprecated 20.0.0
- */
- public function getListeners($eventName = null) {
- return $this->eventDispatcher->getSymfonyDispatcher()->getListeners($eventName);
- }
-
- /**
- * Gets the listener priority for a specific event.
- *
- * Returns null if the event or the listener does not exist.
- *
- * @param string $eventName The name of the event
- * @param callable $listener The listener
- *
- * @return int|null The event listener priority
- * @deprecated 20.0.0
- */
- public function getListenerPriority($eventName, $listener) {
- return $this->eventDispatcher->getSymfonyDispatcher()->getListenerPriority($eventName, $listener);
- }
-
- /**
- * Checks whether an event has any registered listeners.
- *
- * @param string|null $eventName The name of the event
- *
- * @return bool true if the specified event has any listeners, false otherwise
- * @deprecated 20.0.0
- */
- public function hasListeners($eventName = null) {
- return $this->eventDispatcher->getSymfonyDispatcher()->hasListeners($eventName);
- }
-}
diff --git a/lib/private/Federation/CloudFederationProviderManager.php b/lib/private/Federation/CloudFederationProviderManager.php
index b11c4060ab4..ea2f0dd7575 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,9 @@ use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\ICloudFederationShare;
use OCP\Federation\ICloudIdManager;
use OCP\Http\Client\IClientService;
+use OCP\IConfig;
+use OCP\OCM\Exceptions\OCMProviderException;
+use OCP\OCM\IOCMDiscoveryService;
use Psr\Log\LoggerInterface;
/**
@@ -43,40 +50,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
+ ) {
}
@@ -130,16 +113,18 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
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,
]);
@@ -168,17 +153,18 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
* @return array|false
*/
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,
]);
@@ -202,36 +188,4 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
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
- */
- protected function getOCMEndPoint($url) {
- if (isset($this->ocmEndPoints[$url])) {
- return $this->ocmEndPoints[$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'];
- }
-
- $this->ocmEndPoints[$url] = '';
- return '';
- }
}
diff --git a/lib/private/Federation/CloudIdManager.php b/lib/private/Federation/CloudIdManager.php
index 01e00c01181..22b06af386f 100644
--- a/lib/private/Federation/CloudIdManager.php
+++ b/lib/private/Federation/CloudIdManager.php
@@ -209,11 +209,12 @@ class CloudIdManager implements ICloudIdManager {
* @param string $url
* @return string
*/
- private function removeProtocolFromUrl($url) {
+ public function removeProtocolFromUrl(string $url): string {
if (str_starts_with($url, 'https://')) {
- return substr($url, strlen('https://'));
- } elseif (str_starts_with($url, 'http://')) {
- return substr($url, strlen('http://'));
+ return substr($url, 8);
+ }
+ if (str_starts_with($url, 'http://')) {
+ return substr($url, 7);
}
return $url;
diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php
index 5aa05683631..67d01bb6999 100644
--- a/lib/private/Files/Cache/Cache.php
+++ b/lib/private/Files/Cache/Cache.php
@@ -125,7 +125,7 @@ class Cache implements ICache {
$this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
$this->connection = \OC::$server->getDatabaseConnection();
$this->eventDispatcher = \OC::$server->get(IEventDispatcher::class);
- $this->querySearchHelper = \OC::$server->query(QuerySearchHelper::class);
+ $this->querySearchHelper = \OCP\Server::get(QuerySearchHelper::class);
}
protected function getQueryBuilder() {
@@ -149,7 +149,7 @@ class Cache implements ICache {
* get the stored metadata of a file or folder
*
* @param string | int $file either the path of a file or folder or the file id for a file or folder
- * @return ICacheEntry|false the cache entry as array of false if the file is not found in the cache
+ * @return ICacheEntry|false the cache entry as array or false if the file is not found in the cache
*/
public function get($file) {
$query = $this->getQueryBuilder();
@@ -668,7 +668,7 @@ class Cache implements ICache {
$targetPath = $this->normalize($targetPath);
$sourceData = $sourceCache->get($sourcePath);
- if ($sourceData === false) {
+ if (!$sourceData) {
throw new \Exception('Invalid source storage path: ' . $sourcePath);
}
@@ -1012,8 +1012,12 @@ class Cache implements ICache {
* @return string|false the path of the folder or false when no folder matched
*/
public function getIncomplete() {
+ // we select the fileid here first instead of directly selecting the path since this helps mariadb/mysql
+ // to use the correct index.
+ // The overhead of this should be minimal since the cost of selecting the path by id should be much lower
+ // than the cost of finding an item with size < 0
$query = $this->getQueryBuilder();
- $query->select('path')
+ $query->select('fileid')
->from('filecache')
->whereStorageId($this->getNumericStorageId())
->andWhere($query->expr()->lt('size', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
@@ -1021,15 +1025,15 @@ class Cache implements ICache {
->setMaxResults(1);
$result = $query->execute();
- $path = $result->fetchOne();
+ $id = $result->fetchOne();
$result->closeCursor();
- if ($path === false) {
+ if ($id === false) {
return false;
}
- // Make sure Oracle does not continue with null for empty strings
- return (string)$path;
+ $path = $this->getPathById($id);
+ return $path ?? false;
}
/**
diff --git a/lib/private/Files/Cache/CacheEntry.php b/lib/private/Files/Cache/CacheEntry.php
index 3c93296ff62..d1a64552fd1 100644
--- a/lib/private/Files/Cache/CacheEntry.php
+++ b/lib/private/Files/Cache/CacheEntry.php
@@ -114,15 +114,15 @@ class CacheEntry implements ICacheEntry {
}
public function getMetadataEtag(): ?string {
- return $this->data['metadata_etag'];
+ return $this->data['metadata_etag'] ?? null;
}
public function getCreationTime(): ?int {
- return $this->data['creation_time'];
+ return $this->data['creation_time'] ?? null;
}
public function getUploadTime(): ?int {
- return $this->data['upload_time'];
+ return $this->data['upload_time'] ?? null;
}
public function getData() {
@@ -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/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php
index 75e203d5fd9..15c089a0f11 100644
--- a/lib/private/Files/Cache/QuerySearchHelper.php
+++ b/lib/private/Files/Cache/QuerySearchHelper.php
@@ -38,6 +38,8 @@ use OCP\Files\Mount\IMountPoint;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchQuery;
use OCP\IDBConnection;
+use OCP\IGroupManager;
+use OCP\IUser;
use Psr\Log\LoggerInterface;
class QuerySearchHelper {
@@ -52,6 +54,7 @@ class QuerySearchHelper {
private $searchBuilder;
/** @var QueryOptimizer */
private $queryOptimizer;
+ private IGroupManager $groupManager;
public function __construct(
IMimeTypeLoader $mimetypeLoader,
@@ -59,7 +62,8 @@ class QuerySearchHelper {
SystemConfig $systemConfig,
LoggerInterface $logger,
SearchBuilder $searchBuilder,
- QueryOptimizer $queryOptimizer
+ QueryOptimizer $queryOptimizer,
+ IGroupManager $groupManager,
) {
$this->mimetypeLoader = $mimetypeLoader;
$this->connection = $connection;
@@ -67,6 +71,7 @@ class QuerySearchHelper {
$this->logger = $logger;
$this->searchBuilder = $searchBuilder;
$this->queryOptimizer = $queryOptimizer;
+ $this->groupManager = $groupManager;
}
protected function getQueryBuilder() {
@@ -116,6 +121,29 @@ class QuerySearchHelper {
return $tags;
}
+ protected function equipQueryForSystemTags(CacheQueryBuilder $query, IUser $user): void {
+ $query->leftJoin('file', 'systemtag_object_mapping', 'systemtagmap', $query->expr()->andX(
+ $query->expr()->eq('file.fileid', $query->expr()->castColumn('systemtagmap.objectid', IQueryBuilder::PARAM_INT)),
+ $query->expr()->eq('systemtagmap.objecttype', $query->createNamedParameter('files'))
+ ));
+ $on = $query->expr()->andX($query->expr()->eq('systemtag.id', 'systemtagmap.systemtagid'));
+ if (!$this->groupManager->isAdmin($user->getUID())) {
+ $on->add($query->expr()->eq('systemtag.visibility', $query->createNamedParameter(true)));
+ }
+ $query->leftJoin('systemtagmap', 'systemtag', 'systemtag', $on);
+ }
+
+ protected function equipQueryForDavTags(CacheQueryBuilder $query, IUser $user): void {
+ $query
+ ->leftJoin('file', 'vcategory_to_object', 'tagmap', $query->expr()->eq('file.fileid', 'tagmap.objid'))
+ ->leftJoin('tagmap', 'vcategory', 'tag', $query->expr()->andX(
+ $query->expr()->eq('tagmap.type', 'tag.type'),
+ $query->expr()->eq('tagmap.categoryid', 'tag.id'),
+ $query->expr()->eq('tag.type', $query->createNamedParameter('files')),
+ $query->expr()->eq('tag.uid', $query->createNamedParameter($user->getUID()))
+ ));
+ }
+
/**
* Perform a file system search in multiple caches
*
@@ -146,27 +174,12 @@ class QuerySearchHelper {
$query = $builder->selectFileCache('file', false);
- if ($this->searchBuilder->shouldJoinTags($searchQuery->getSearchOperation())) {
- $user = $searchQuery->getUser();
- if ($user === null) {
- throw new \InvalidArgumentException("Searching by tag requires the user to be set in the query");
- }
- $query
- ->leftJoin('file', 'vcategory_to_object', 'tagmap', $builder->expr()->eq('file.fileid', 'tagmap.objid'))
- ->leftJoin('tagmap', 'vcategory', 'tag', $builder->expr()->andX(
- $builder->expr()->eq('tagmap.type', 'tag.type'),
- $builder->expr()->eq('tagmap.categoryid', 'tag.id'),
- $builder->expr()->eq('tag.type', $builder->createNamedParameter('files')),
- $builder->expr()->eq('tag.uid', $builder->createNamedParameter($user->getUID()))
- ))
- ->leftJoin('file', 'systemtag_object_mapping', 'systemtagmap', $builder->expr()->andX(
- $builder->expr()->eq('file.fileid', $builder->expr()->castColumn('systemtagmap.objectid', IQueryBuilder::PARAM_INT)),
- $builder->expr()->eq('systemtagmap.objecttype', $builder->createNamedParameter('files'))
- ))
- ->leftJoin('systemtagmap', 'systemtag', 'systemtag', $builder->expr()->andX(
- $builder->expr()->eq('systemtag.id', 'systemtagmap.systemtagid'),
- $builder->expr()->eq('systemtag.visibility', $builder->createNamedParameter(true))
- ));
+ $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));
}
$this->applySearchConstraints($query, $searchQuery, $caches);
@@ -194,6 +207,14 @@ class QuerySearchHelper {
return $results;
}
+ protected function requireUser(ISearchQuery $searchQuery): IUser {
+ $user = $searchQuery->getUser();
+ if ($user === null) {
+ throw new \InvalidArgumentException("This search operation requires the user to be set in the query");
+ }
+ return $user;
+ }
+
/**
* @return list{0?: array<array-key, ICache>, 1?: array<array-key, IMountPoint>}
*/
diff --git a/lib/private/Files/Cache/Scanner.php b/lib/private/Files/Cache/Scanner.php
index edf9b5697e7..52268032409 100644
--- a/lib/private/Files/Cache/Scanner.php
+++ b/lib/private/Files/Cache/Scanner.php
@@ -291,7 +291,7 @@ class Scanner extends BasicEmitter implements IScanner {
$data['permissions'] = $data['scan_permissions'];
}
\OC_Hook::emit('Scanner', 'addToCache', ['file' => $path, 'data' => $data]);
- $this->emit('\OC\Files\Cache\Scanner', 'addToCache', [$path, $this->storageId, $data]);
+ $this->emit('\OC\Files\Cache\Scanner', 'addToCache', [$path, $this->storageId, $data, $fileId]);
if ($this->cacheActive) {
if ($fileId !== -1) {
$this->cache->update($fileId, $data);
@@ -344,7 +344,7 @@ class Scanner extends BasicEmitter implements IScanner {
try {
$data = $this->scanFile($path, $reuse, -1, null, $lock);
if ($data && $data['mimetype'] === 'httpd/unix-directory') {
- $size = $this->scanChildren($path, $recursive, $reuse, $data['fileid'], $lock, $data);
+ $size = $this->scanChildren($path, $recursive, $reuse, $data['fileid'], $lock, $data['size']);
$data['size'] = $size;
}
} catch (NotFoundException $e) {
@@ -381,33 +381,29 @@ class Scanner extends BasicEmitter implements IScanner {
* scan all the files and folders in a folder
*
* @param string $path
- * @param bool $recursive
- * @param int $reuse
+ * @param bool|IScanner::SCAN_RECURSIVE_INCOMPLETE $recursive
+ * @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 array $data the data of the folder before (re)scanning the children
+ * @param int $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($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true, array $data = []) {
+ protected function scanChildren(string $path, $recursive, int $reuse, int $folderId, bool $lock, int $oldSize) {
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;
- if (!is_null($folderId)) {
- $folderId = $this->cache->getId($path);
- }
$childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size);
- foreach ($childQueue as $child => $childId) {
- $childSize = $this->scanChildren($child, $recursive, $reuse, $childId, $lock);
+ foreach ($childQueue as $child => [$childId, $childSize]) {
+ $childSize = $this->scanChildren($child, $recursive, $reuse, $childId, $lock, $childSize);
if ($childSize === -1) {
$size = -1;
} elseif ($size !== -1) {
$size += $childSize;
}
}
- $oldSize = $data['size'] ?? null;
// for encrypted storages, we trigger a regular folder size calculation instead of using the calculated size
// to make sure we also updated the unencrypted-size where applicable
@@ -461,10 +457,10 @@ class Scanner extends BasicEmitter implements IScanner {
$data = $this->scanFile($child, $reuse, $folderId, $existingData, $lock, $fileMeta);
if ($data) {
if ($data['mimetype'] === 'httpd/unix-directory' && $recursive === self::SCAN_RECURSIVE) {
- $childQueue[$child] = $data['fileid'];
+ $childQueue[$child] = [$data['fileid'], $data['size']];
} elseif ($data['mimetype'] === 'httpd/unix-directory' && $recursive === self::SCAN_RECURSIVE_INCOMPLETE && $data['size'] === -1) {
// only recurse into folders which aren't fully scanned
- $childQueue[$child] = $data['fileid'];
+ $childQueue[$child] = [$data['fileid'], $data['size']];
} elseif ($data['size'] === -1) {
$size = -1;
} elseif ($size !== -1) {
diff --git a/lib/private/Files/Cache/SearchBuilder.php b/lib/private/Files/Cache/SearchBuilder.php
index c9f35ccd095..b9a70bbd39b 100644
--- a/lib/private/Files/Cache/SearchBuilder.php
+++ b/lib/private/Files/Cache/SearchBuilder.php
@@ -69,20 +69,17 @@ class SearchBuilder {
}
/**
- * Whether or not the tag tables should be joined to complete the search
- *
- * @param ISearchOperator $operator
- * @return boolean
+ * @return string[]
*/
- public function shouldJoinTags(ISearchOperator $operator) {
+ public function extractRequestedFields(ISearchOperator $operator): array {
if ($operator instanceof ISearchBinaryOperator) {
- return array_reduce($operator->getArguments(), function ($shouldJoin, ISearchOperator $operator) {
- return $shouldJoin || $this->shouldJoinTags($operator);
- }, false);
+ return array_reduce($operator->getArguments(), function (array $fields, ISearchOperator $operator) {
+ return array_unique(array_merge($fields, $this->extractRequestedFields($operator)));
+ }, []);
} elseif ($operator instanceof ISearchComparison) {
- return $operator->getField() === 'tagname' || $operator->getField() === 'favorite' || $operator->getField() === 'systemtag';
+ return [$operator->getField()];
}
- return false;
+ return [];
}
/**
diff --git a/lib/private/Files/Cache/Wrapper/CacheWrapper.php b/lib/private/Files/Cache/Wrapper/CacheWrapper.php
index 6479ea793b0..39a78f31343 100644
--- a/lib/private/Files/Cache/Wrapper/CacheWrapper.php
+++ b/lib/private/Files/Cache/Wrapper/CacheWrapper.php
@@ -33,8 +33,10 @@ use OC\Files\Cache\Cache;
use OC\Files\Cache\QuerySearchHelper;
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;
class CacheWrapper extends Cache {
/**
@@ -47,9 +49,15 @@ class CacheWrapper extends Cache {
*/
public function __construct($cache) {
$this->cache = $cache;
- $this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
- $this->connection = \OC::$server->getDatabaseConnection();
- $this->querySearchHelper = \OC::$server->get(QuerySearchHelper::class);
+ if ($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);
+ }
}
protected function getCache() {
diff --git a/lib/private/Files/FileInfo.php b/lib/private/Files/FileInfo.php
index 2b6b83a2546..7800074460b 100644
--- a/lib/private/Files/FileInfo.php
+++ b/lib/private/Files/FileInfo.php
@@ -32,7 +32,9 @@
*/
namespace OC\Files;
+use OCA\Files_Sharing\ISharedStorage;
use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\IHomeStorage;
use OCP\Files\Mount\IMountPoint;
use OCP\IUser;
@@ -205,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;
@@ -227,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;
@@ -241,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'];
}
/**
@@ -313,27 +311,13 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
* @return bool
*/
public function isShared() {
- $sid = $this->getStorage()->getId();
- if (!is_null($sid)) {
- $sid = explode(':', $sid);
- return ($sid[0] === 'shared');
- }
-
- return false;
+ $storage = $this->getStorage();
+ return $storage->instanceOfStorage(ISharedStorage::class);
}
public function isMounted() {
$storage = $this->getStorage();
- if ($storage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
- return false;
- }
- $sid = $storage->getId();
- if (!is_null($sid)) {
- $sid = explode(':', $sid);
- return ($sid[0] !== 'home' and $sid[0] !== 'shared');
- }
-
- return false;
+ return !($storage->instanceOfStorage(IHomeStorage::class) || $storage->instanceOfStorage(ISharedStorage::class));
}
/**
@@ -428,4 +412,8 @@ 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;
+ }
}
diff --git a/lib/private/Files/Mount/MoveableMount.php b/lib/private/Files/Mount/MoveableMount.php
index a7372153d75..7dbed24504e 100644
--- a/lib/private/Files/Mount/MoveableMount.php
+++ b/lib/private/Files/Mount/MoveableMount.php
@@ -22,10 +22,12 @@
*/
namespace OC\Files\Mount;
+use OCP\Files\Mount\IMovableMount;
+
/**
* Defines the mount point to be (re)moved by the user
*/
-interface MoveableMount {
+interface MoveableMount extends IMovableMount {
/**
* Move the mount point to $target
*
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index 6a009bded96..ccd10da9d0c 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -204,7 +204,7 @@ class Folder extends Node implements \OCP\Files\Folder {
$user = null;
} else {
/** @var IUserManager $userManager */
- $userManager = \OC::$server->query(IUserManager::class);
+ $userManager = \OCP\Server::get(IUserManager::class);
$user = $userManager->get($uid);
}
return new SearchQuery($operator, $limit, $offset, [], $user);
@@ -300,6 +300,11 @@ class Folder extends Node implements \OCP\Files\Folder {
return $this->search($query);
}
+ public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0): array {
+ $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'systemtag', $tagName), $userId, $limit, $offset);
+ return $this->search($query);
+ }
+
/**
* @param int $id
* @return \OC\Files\Node\Node[]
diff --git a/lib/private/Files/Node/HookConnector.php b/lib/private/Files/Node/HookConnector.php
index c61e098c227..a8e76d95c22 100644
--- a/lib/private/Files/Node/HookConnector.php
+++ b/lib/private/Files/Node/HookConnector.php
@@ -46,7 +46,6 @@ use OCP\Files\Events\Node\NodeWrittenEvent;
use OCP\Files\FileInfo;
use OCP\Files\IRootFolder;
use OCP\Util;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class HookConnector {
/** @var IRootFolder */
@@ -58,26 +57,15 @@ class HookConnector {
/** @var FileInfo[] */
private $deleteMetaCache = [];
- /** @var EventDispatcherInterface */
- private $legacyDispatcher;
-
/** @var IEventDispatcher */
private $dispatcher;
- /**
- * HookConnector constructor.
- *
- * @param Root $root
- * @param View $view
- */
public function __construct(
IRootFolder $root,
View $view,
- EventDispatcherInterface $legacyDispatcher,
IEventDispatcher $dispatcher) {
$this->root = $root;
$this->view = $view;
- $this->legacyDispatcher = $legacyDispatcher;
$this->dispatcher = $dispatcher;
}
@@ -106,7 +94,7 @@ class HookConnector {
public function write($arguments) {
$node = $this->getNodeForPath($arguments['path']);
$this->root->emit('\OC\Files', 'preWrite', [$node]);
- $this->legacyDispatcher->dispatch('\OCP\Files::preWrite', new GenericEvent($node));
+ $this->dispatcher->dispatch('\OCP\Files::preWrite', new GenericEvent($node));
$event = new BeforeNodeWrittenEvent($node);
$this->dispatcher->dispatchTyped($event);
@@ -115,7 +103,7 @@ class HookConnector {
public function postWrite($arguments) {
$node = $this->getNodeForPath($arguments['path']);
$this->root->emit('\OC\Files', 'postWrite', [$node]);
- $this->legacyDispatcher->dispatch('\OCP\Files::postWrite', new GenericEvent($node));
+ $this->dispatcher->dispatch('\OCP\Files::postWrite', new GenericEvent($node));
$event = new NodeWrittenEvent($node);
$this->dispatcher->dispatchTyped($event);
@@ -124,7 +112,7 @@ class HookConnector {
public function create($arguments) {
$node = $this->getNodeForPath($arguments['path']);
$this->root->emit('\OC\Files', 'preCreate', [$node]);
- $this->legacyDispatcher->dispatch('\OCP\Files::preCreate', new GenericEvent($node));
+ $this->dispatcher->dispatch('\OCP\Files::preCreate', new GenericEvent($node));
$event = new BeforeNodeCreatedEvent($node);
$this->dispatcher->dispatchTyped($event);
@@ -133,7 +121,7 @@ class HookConnector {
public function postCreate($arguments) {
$node = $this->getNodeForPath($arguments['path']);
$this->root->emit('\OC\Files', 'postCreate', [$node]);
- $this->legacyDispatcher->dispatch('\OCP\Files::postCreate', new GenericEvent($node));
+ $this->dispatcher->dispatch('\OCP\Files::postCreate', new GenericEvent($node));
$event = new NodeCreatedEvent($node);
$this->dispatcher->dispatchTyped($event);
@@ -143,7 +131,7 @@ class HookConnector {
$node = $this->getNodeForPath($arguments['path']);
$this->deleteMetaCache[$node->getPath()] = $node->getFileInfo();
$this->root->emit('\OC\Files', 'preDelete', [$node]);
- $this->legacyDispatcher->dispatch('\OCP\Files::preDelete', new GenericEvent($node));
+ $this->dispatcher->dispatch('\OCP\Files::preDelete', new GenericEvent($node));
$event = new BeforeNodeDeletedEvent($node);
$this->dispatcher->dispatchTyped($event);
@@ -153,7 +141,7 @@ class HookConnector {
$node = $this->getNodeForPath($arguments['path']);
unset($this->deleteMetaCache[$node->getPath()]);
$this->root->emit('\OC\Files', 'postDelete', [$node]);
- $this->legacyDispatcher->dispatch('\OCP\Files::postDelete', new GenericEvent($node));
+ $this->dispatcher->dispatch('\OCP\Files::postDelete', new GenericEvent($node));
$event = new NodeDeletedEvent($node);
$this->dispatcher->dispatchTyped($event);
@@ -162,7 +150,7 @@ class HookConnector {
public function touch($arguments) {
$node = $this->getNodeForPath($arguments['path']);
$this->root->emit('\OC\Files', 'preTouch', [$node]);
- $this->legacyDispatcher->dispatch('\OCP\Files::preTouch', new GenericEvent($node));
+ $this->dispatcher->dispatch('\OCP\Files::preTouch', new GenericEvent($node));
$event = new BeforeNodeTouchedEvent($node);
$this->dispatcher->dispatchTyped($event);
@@ -171,7 +159,7 @@ class HookConnector {
public function postTouch($arguments) {
$node = $this->getNodeForPath($arguments['path']);
$this->root->emit('\OC\Files', 'postTouch', [$node]);
- $this->legacyDispatcher->dispatch('\OCP\Files::postTouch', new GenericEvent($node));
+ $this->dispatcher->dispatch('\OCP\Files::postTouch', new GenericEvent($node));
$event = new NodeTouchedEvent($node);
$this->dispatcher->dispatchTyped($event);
@@ -181,7 +169,7 @@ class HookConnector {
$source = $this->getNodeForPath($arguments['oldpath']);
$target = $this->getNodeForPath($arguments['newpath']);
$this->root->emit('\OC\Files', 'preRename', [$source, $target]);
- $this->legacyDispatcher->dispatch('\OCP\Files::preRename', new GenericEvent([$source, $target]));
+ $this->dispatcher->dispatch('\OCP\Files::preRename', new GenericEvent([$source, $target]));
$event = new BeforeNodeRenamedEvent($source, $target);
$this->dispatcher->dispatchTyped($event);
@@ -191,7 +179,7 @@ class HookConnector {
$source = $this->getNodeForPath($arguments['oldpath']);
$target = $this->getNodeForPath($arguments['newpath']);
$this->root->emit('\OC\Files', 'postRename', [$source, $target]);
- $this->legacyDispatcher->dispatch('\OCP\Files::postRename', new GenericEvent([$source, $target]));
+ $this->dispatcher->dispatch('\OCP\Files::postRename', new GenericEvent([$source, $target]));
$event = new NodeRenamedEvent($source, $target);
$this->dispatcher->dispatchTyped($event);
@@ -201,7 +189,7 @@ class HookConnector {
$source = $this->getNodeForPath($arguments['oldpath']);
$target = $this->getNodeForPath($arguments['newpath']);
$this->root->emit('\OC\Files', 'preCopy', [$source, $target]);
- $this->legacyDispatcher->dispatch('\OCP\Files::preCopy', new GenericEvent([$source, $target]));
+ $this->dispatcher->dispatch('\OCP\Files::preCopy', new GenericEvent([$source, $target]));
$event = new BeforeNodeCopiedEvent($source, $target);
$this->dispatcher->dispatchTyped($event);
@@ -211,7 +199,7 @@ class HookConnector {
$source = $this->getNodeForPath($arguments['oldpath']);
$target = $this->getNodeForPath($arguments['newpath']);
$this->root->emit('\OC\Files', 'postCopy', [$source, $target]);
- $this->legacyDispatcher->dispatch('\OCP\Files::postCopy', new GenericEvent([$source, $target]));
+ $this->dispatcher->dispatch('\OCP\Files::postCopy', new GenericEvent([$source, $target]));
$event = new NodeCopiedEvent($source, $target);
$this->dispatcher->dispatchTyped($event);
@@ -220,7 +208,7 @@ class HookConnector {
public function read($arguments) {
$node = $this->getNodeForPath($arguments['path']);
$this->root->emit('\OC\Files', 'read', [$node]);
- $this->legacyDispatcher->dispatch('\OCP\Files::read', new GenericEvent([$node]));
+ $this->dispatcher->dispatch('\OCP\Files::read', new GenericEvent([$node]));
$event = new BeforeNodeReadEvent($node);
$this->dispatcher->dispatchTyped($event);
diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php
index 9f9528f69bd..f13cdc0c4f9 100644
--- a/lib/private/Files/Node/LazyFolder.php
+++ b/lib/private/Files/Node/LazyFolder.php
@@ -26,10 +26,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\IRootFolder;
use OCP\Files\Mount\IMountPoint;
+use OCP\Files\NotPermittedException;
/**
* Class LazyFolder
@@ -41,23 +44,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 +80,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 +157,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 +216,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 +233,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 +243,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 +253,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 +320,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 +417,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());
}
@@ -449,6 +483,10 @@ class LazyFolder implements Folder {
return $this->__call(__FUNCTION__, func_get_args());
}
+ public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0) {
+ return $this->__call(__FUNCTION__, func_get_args());
+ }
+
/**
* @inheritDoc
*/
@@ -529,4 +567,11 @@ 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());
+ }
}
diff --git a/lib/private/Files/Node/LazyRoot.php b/lib/private/Files/Node/LazyRoot.php
index c01b9fdbb83..ce140124f55 100644
--- a/lib/private/Files/Node/LazyRoot.php
+++ b/lib/private/Files/Node/LazyRoot.php
@@ -33,9 +33,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());
}
diff --git a/lib/private/Files/Node/LazyUserFolder.php b/lib/private/Files/Node/LazyUserFolder.php
index 8fbdec4b49d..503b0af8921 100644
--- a/lib/private/Files/Node/LazyUserFolder.php
+++ b/lib/private/Files/Node/LazyUserFolder.php
@@ -34,19 +34,17 @@ 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,21 +54,22 @@ 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, '/'));
+ return $this->getRootFolder()->get('/' . $this->user->getUID() . '/files/' . ltrim($path, '/'));
}
/**
@@ -78,7 +77,7 @@ class LazyUserFolder extends LazyFolder {
* @return \OCP\Files\Node[]
*/
public function getById($id) {
- return $this->root->getByIdInPath((int)$id, $this->getPath());
+ return $this->getRootFolder()->getByIdInPath((int)$id, $this->getPath());
}
public function getMountPoint() {
diff --git a/lib/private/Files/Node/Node.php b/lib/private/Files/Node/Node.php
index 4ba2c472c67..9729f79aae3 100644
--- a/lib/private/Files/Node/Node.php
+++ b/lib/private/Files/Node/Node.php
@@ -32,6 +32,8 @@ namespace OC\Files\Node;
use OC\Files\Filesystem;
use OC\Files\Mount\MoveableMount;
use OC\Files\Utils\PathHelper;
+use OCP\EventDispatcher\GenericEvent;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\FileInfo;
use OCP\Files\InvalidPathException;
use OCP\Files\IRootFolder;
@@ -40,7 +42,6 @@ use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\Lock\LockedException;
use OCP\PreConditionNotMetException;
-use Symfony\Component\EventDispatcher\GenericEvent;
// FIXME: this class really should be abstract
class Node implements INode {
@@ -58,10 +59,7 @@ class Node implements INode {
protected ?FileInfo $fileInfo;
- /**
- * @var Node|null
- */
- protected $parent;
+ protected ?INode $parent;
private bool $infoHasSubMountsIncluded;
@@ -127,7 +125,8 @@ class Node implements INode {
*/
protected function sendHooks($hooks, array $args = null) {
$args = !empty($args) ? $args : [$this];
- $dispatcher = \OC::$server->getEventDispatcher();
+ /** @var IEventDispatcher $dispatcher */
+ $dispatcher = \OC::$server->get(IEventDispatcher::class);
foreach ($hooks as $hook) {
if (method_exists($this->root, 'emit')) {
$this->root->emit('\OC\Files', $hook, $args);
@@ -298,7 +297,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;
@@ -326,13 +343,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() {
@@ -475,4 +486,8 @@ class Node implements INode {
public function getUploadTime(): int {
return $this->getFileInfo()->getUploadTime();
}
+
+ public function getParentId(): int {
+ return $this->fileInfo->getParentId();
+ }
}
diff --git a/lib/private/Files/Node/NonExistingFolder.php b/lib/private/Files/Node/NonExistingFolder.php
index 0d573df7727..34621b18f19 100644
--- a/lib/private/Files/Node/NonExistingFolder.php
+++ b/lib/private/Files/Node/NonExistingFolder.php
@@ -154,6 +154,10 @@ class NonExistingFolder extends Folder {
throw new NotFoundException();
}
+ public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0): array {
+ throw new NotFoundException();
+ }
+
public function getById($id) {
throw new NotFoundException();
}
diff --git a/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php b/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php
index 824adcc1d0e..b361249ff47 100644
--- a/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php
+++ b/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php
@@ -26,6 +26,7 @@
namespace OC\Files\ObjectStore;
use OC\User\User;
+use OCP\IUser;
class HomeObjectStoreStorage extends ObjectStoreStorage implements \OCP\Files\IHomeStorage {
/**
@@ -61,7 +62,7 @@ class HomeObjectStoreStorage extends ObjectStoreStorage implements \OCP\Files\IH
* @param string $path, optional
* @return \OC\User\User
*/
- public function getUser($path = null) {
+ public function getUser($path = null): IUser {
return $this->user;
}
}
diff --git a/lib/private/Files/ObjectStore/ObjectStoreScanner.php b/lib/private/Files/ObjectStore/ObjectStoreScanner.php
index e589ca51aae..f001f90fdaa 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($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true, array $data = []) {
+ protected function scanChildren(string $path, $recursive, int $reuse, int $folderId, bool $lock, int $oldSize) {
return 0;
}
diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
index d918bd98729..4dceee9a58b 100644
--- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php
+++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
@@ -559,6 +559,8 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
}
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)) {
diff --git a/lib/private/Files/ObjectStore/S3.php b/lib/private/Files/ObjectStore/S3.php
index 76eee2bc962..b1cd89388ae 100644
--- a/lib/private/Files/ObjectStore/S3.php
+++ b/lib/private/Files/ObjectStore/S3.php
@@ -49,7 +49,7 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload {
$upload = $this->getConnection()->createMultipartUpload([
'Bucket' => $this->bucket,
'Key' => $urn,
- ]);
+ ] + $this->getSSECParameters());
$uploadId = $upload->get('UploadId');
if ($uploadId === null) {
throw new Exception('No upload id returned');
@@ -65,7 +65,7 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload {
'ContentLength' => $size,
'PartNumber' => $partId,
'UploadId' => $uploadId,
- ]);
+ ] + $this->getSSECParameters());
}
public function getMultipartUploads(string $urn, string $uploadId): array {
@@ -80,12 +80,12 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload {
'UploadId' => $uploadId,
'MaxParts' => 1000,
'PartNumberMarker' => $partNumberMarker
- ]);
+ ] + $this->getSSECParameters());
$parts = array_merge($parts, $result->get('Parts') ?? []);
$isTruncated = $result->get('IsTruncated');
$partNumberMarker = $result->get('NextPartNumberMarker');
}
-
+
return $parts;
}
@@ -95,11 +95,11 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload {
'Key' => $urn,
'UploadId' => $uploadId,
'MultipartUpload' => ['Parts' => $result],
- ]);
+ ] + $this->getSSECParameters());
$stat = $this->getConnection()->headObject([
'Bucket' => $this->bucket,
'Key' => $urn,
- ]);
+ ] + $this->getSSECParameters());
return (int)$stat->get('ContentLength');
}
diff --git a/lib/private/Files/ObjectStore/S3ConnectionTrait.php b/lib/private/Files/ObjectStore/S3ConnectionTrait.php
index deb03571c76..49942b385bc 100644
--- a/lib/private/Files/ObjectStore/S3ConnectionTrait.php
+++ b/lib/private/Files/ObjectStore/S3ConnectionTrait.php
@@ -92,7 +92,7 @@ trait S3ConnectionTrait {
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;
}
diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php
index e0d0f2ce9c7..e9c52f11936 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,16 @@ 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 = []) {
+ $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)
+ ], $options));
+ $copy->copy();
}
}
diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php
index 2198c8c60b7..cae0fd2f232 100644
--- a/lib/private/Files/SetupManager.php
+++ b/lib/private/Files/SetupManager.php
@@ -34,9 +34,12 @@ 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_Sharing\ISharedStorage;
use OCP\Constants;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
@@ -64,52 +67,33 @@ 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;
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->setupListeners();
}
@@ -139,15 +123,23 @@ class SetupManager {
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 = $storage->instanceOfStorage(ISharedStorage::class);
+ 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) {
@@ -164,7 +156,8 @@ class SetupManager {
return $storage;
});
- Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
+ $quotaIncludeExternal = $this->config->getSystemValue('quota_include_external_storage', false);
+ Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) use ($quotaIncludeExternal) {
// set up quota for home storages, even for other users
// which can happen when using sharing
@@ -176,7 +169,7 @@ class SetupManager {
$user = $storage->getUser();
return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
return OC_Util::getUserQuota($user);
- }, 'root' => 'files']);
+ }, 'root' => 'files', 'include_external_storage' => $quotaIncludeExternal]);
}
}
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/Storage/Home.php b/lib/private/Files/Storage/Home.php
index 5427bc425c2..5100b15215b 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
@@ -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 c0ce0e7021a..fdc30b49259 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;
@@ -95,6 +96,12 @@ class Local extends \OC\Files\Storage\Common {
// 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() {
@@ -335,7 +342,7 @@ class Local extends \OC\Files\Storage\Common {
}
}
- public function rename($source, $target) {
+ public function rename($source, $target): bool {
$srcParent = dirname($source);
$dstParent = dirname($target);
@@ -361,21 +368,14 @@ class Local extends \OC\Files\Storage\Common {
}
if ($this->is_dir($source)) {
- // we can't move folders across devices, use copy instead
- $stat1 = stat(dirname($this->getSourcePath($source)));
- $stat2 = stat(dirname($this->getSourcePath($target)));
- if ($stat1['dev'] !== $stat2['dev']) {
- $result = $this->copy($source, $target);
- if ($result) {
- $result &= $this->rmdir($source);
- }
- return $result;
- }
-
$this->checkTreeForForbiddenItems($this->getSourcePath($source));
}
- return rename($this->getSourcePath($source), $this->getSourcePath($target));
+ if (@rename($this->getSourcePath($source), $this->getSourcePath($target))) {
+ return true;
+ }
+
+ return $this->copy($source, $target) && $this->unlink($source);
}
public function copy($source, $target) {
diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php
index ab3873a7ec0..7ce4338256f 100644
--- a/lib/private/Files/Storage/Wrapper/Encryption.php
+++ b/lib/private/Files/Storage/Wrapper/Encryption.php
@@ -17,6 +17,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
* @author Vincent Petry <vincent@nextcloud.com>
+ * @author Richard Steinmetz <richard@steinmetz.cloud>
*
* @license AGPL-3.0
*
@@ -99,6 +100,8 @@ class Encryption extends Wrapper {
/** @var CappedMemoryCache<bool> */
private CappedMemoryCache $encryptedPaths;
+ private $enabled = true;
+
/**
* @param array $parameters
*/
@@ -143,21 +146,28 @@ class Encryption extends Wrapper {
}
if (isset($this->unencryptedSize[$fullPath])) {
$size = $this->unencryptedSize[$fullPath];
- // update file cache
- if ($info instanceof ICacheEntry) {
- $info['encrypted'] = $info['encryptedVersion'];
- } else {
- if (!is_array($info)) {
- $info = [];
+
+ // Update file cache (only if file is already cached).
+ // Certain files are not cached (e.g. *.part).
+ if (isset($info['fileid'])) {
+ if ($info instanceof ICacheEntry) {
+ $info['encrypted'] = $info['encryptedVersion'];
+ } else {
+ /**
+ * @psalm-suppress RedundantCondition
+ */
+ if (!is_array($info)) {
+ $info = [];
+ }
+ $info['encrypted'] = true;
+ $info = new CacheEntry($info);
}
- $info['encrypted'] = true;
- $info = new CacheEntry($info);
- }
- if ($size !== $info->getUnencryptedSize()) {
- $this->getCache()->update($info->getId(), [
- 'unencrypted_size' => $size
- ]);
+ if ($size !== $info->getUnencryptedSize()) {
+ $this->getCache()->update($info->getId(), [
+ 'unencrypted_size' => $size
+ ]);
+ }
}
return $size;
@@ -384,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;
@@ -930,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
@@ -980,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
@@ -1085,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]);
}
@@ -1095,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/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php
index 5786dba5114..35dbc9fcd26 100644
--- a/lib/private/Files/Storage/Wrapper/Quota.php
+++ b/lib/private/Files/Storage/Wrapper/Quota.php
@@ -45,6 +45,7 @@ class Quota extends Wrapper {
protected int|float|null $quota;
protected string $sizeRoot;
private SystemConfig $config;
+ private bool $quotaIncludeExternalStorage;
/**
* @param array $parameters
@@ -54,7 +55,7 @@ class Quota extends Wrapper {
$this->quota = $parameters['quota'] ?? null;
$this->quotaCallback = $parameters['quotaCallback'] ?? null;
$this->sizeRoot = $parameters['root'] ?? '';
- $this->config = \OC::$server->get(SystemConfig::class);
+ $this->quotaIncludeExternalStorage = $parameters['include_external_storage'] ?? false;
}
/**
@@ -82,7 +83,7 @@ class Quota extends Wrapper {
* @return int|float
*/
protected function getSize($path, $storage = null) {
- if ($this->config->getValue('quota_include_external_storage', false)) {
+ if ($this->quotaIncludeExternalStorage) {
$rootInfo = Filesystem::getFileInfo('', 'ext');
if ($rootInfo) {
return $rootInfo->getSize(true);
diff --git a/lib/private/Files/Stream/SeekableHttpStream.php b/lib/private/Files/Stream/SeekableHttpStream.php
index 51ccaeba998..66f94768e62 100644
--- a/lib/private/Files/Stream/SeekableHttpStream.php
+++ b/lib/private/Files/Stream/SeekableHttpStream.php
@@ -219,7 +219,9 @@ class SeekableHttpStream implements File {
public function stream_stat() {
if ($this->getCurrent()) {
$stat = fstat($this->getCurrent());
- $stat['size'] = $this->totalSize;
+ if ($stat) {
+ $stat['size'] = $this->totalSize;
+ }
return $stat;
} else {
return false;
diff --git a/lib/private/Files/Type/Loader.php b/lib/private/Files/Type/Loader.php
index 20c298f21b3..7032e619385 100644
--- a/lib/private/Files/Type/Loader.php
+++ b/lib/private/Files/Type/Loader.php
@@ -116,8 +116,8 @@ class Loader implements IMimeTypeLoader {
* @return int inserted ID
*/
protected function store($mimetype) {
- $mimetypeId = $this->atomic(function () use ($mimetype) {
- try {
+ try {
+ $mimetypeId = $this->atomic(function () use ($mimetype) {
$insert = $this->dbConnection->getQueryBuilder();
$insert->insert('mimetypes')
->values([
@@ -125,26 +125,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;
diff --git a/lib/private/Files/Utils/Scanner.php b/lib/private/Files/Utils/Scanner.php
index 277ce38175f..b7f6972ee10 100644
--- a/lib/private/Files/Utils/Scanner.php
+++ b/lib/private/Files/Utils/Scanner.php
@@ -251,9 +251,13 @@ class Scanner extends PublicEmitter {
$this->postProcessEntry($storage, $path);
$this->dispatcher->dispatchTyped(new FileCacheUpdated($storage, $path));
});
- $scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', function ($path) use ($storage) {
+ $scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', function ($path, $storageId, $data, $fileId) use ($storage) {
$this->postProcessEntry($storage, $path);
- $this->dispatcher->dispatchTyped(new NodeAddedToCache($storage, $path));
+ if ($fileId) {
+ $this->dispatcher->dispatchTyped(new FileCacheUpdated($storage, $path));
+ } else {
+ $this->dispatcher->dispatchTyped(new NodeAddedToCache($storage, $path));
+ }
});
if (!$storage->file_exists($relativePath)) {
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index d256003537d..86651ab3e1a 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -56,6 +56,7 @@ use OC\User\Manager as UserManager;
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;
@@ -397,10 +398,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 +425,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 +455,7 @@ class View {
}
echo fread($handle, $len);
flush();
+ $this->checkConnectionStatus();
}
return ftell($handle) - $from;
}
@@ -462,6 +465,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
@@ -744,14 +754,18 @@ class View {
// if it was a rename from a part file to a regular file it was a write and not a rename operation
$this->emit_file_hooks_pre($exists, $target, $run);
} elseif ($this->shouldEmitHooks($source)) {
- \OC_Hook::emit(
- Filesystem::CLASSNAME, Filesystem::signal_rename,
- [
- Filesystem::signal_param_oldpath => $this->getHookPath($source),
- Filesystem::signal_param_newpath => $this->getHookPath($target),
- Filesystem::signal_param_run => &$run
- ]
- );
+ $sourcePath = $this->getHookPath($source);
+ $targetPath = $this->getHookPath($target);
+ if ($sourcePath !== null && $targetPath !== null) {
+ \OC_Hook::emit(
+ Filesystem::CLASSNAME, Filesystem::signal_rename,
+ [
+ Filesystem::signal_param_oldpath => $sourcePath,
+ Filesystem::signal_param_newpath => $targetPath,
+ Filesystem::signal_param_run => &$run
+ ]
+ );
+ }
}
if ($run) {
$this->verifyPath(dirname($target), basename($target));
@@ -817,14 +831,18 @@ class View {
}
} elseif ($result) {
if ($this->shouldEmitHooks($source) && $this->shouldEmitHooks($target)) {
- \OC_Hook::emit(
- Filesystem::CLASSNAME,
- Filesystem::signal_post_rename,
- [
- Filesystem::signal_param_oldpath => $this->getHookPath($source),
- Filesystem::signal_param_newpath => $this->getHookPath($target)
- ]
- );
+ $sourcePath = $this->getHookPath($source);
+ $targetPath = $this->getHookPath($target);
+ if ($sourcePath !== null && $targetPath !== null) {
+ \OC_Hook::emit(
+ Filesystem::CLASSNAME,
+ Filesystem::signal_post_rename,
+ [
+ Filesystem::signal_param_oldpath => $sourcePath,
+ Filesystem::signal_param_newpath => $targetPath,
+ ]
+ );
+ }
}
}
}
diff --git a/lib/private/Group/Database.php b/lib/private/Group/Database.php
index ef5641d8137..55792ce1dff 100644
--- a/lib/private/Group/Database.php
+++ b/lib/private/Group/Database.php
@@ -33,6 +33,7 @@ use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
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;
@@ -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 d724b6caf0e..4eb8211be6e 100644
--- a/lib/private/Group/DisplayNameCache.php
+++ b/lib/private/Group/DisplayNameCache.php
@@ -29,6 +29,7 @@ use OCP\Cache\CappedMemoryCache;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Group\Events\GroupChangedEvent;
+use OCP\Group\Events\GroupDeletedEvent;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\IGroupManager;
@@ -83,5 +84,10 @@ class DisplayNameCache implements IEventListener {
$this->cache[$groupId] = $newDisplayName;
$this->memCache->set($groupId, $newDisplayName, 60 * 10); // 10 minutes
}
+ if ($event instanceof GroupDeletedEvent) {
+ $groupId = $event->getGroup()->getGID();
+ unset($this->cache[$groupId]);
+ $this->memCache->remove($groupId);
+ }
}
}
diff --git a/lib/private/Group/Group.php b/lib/private/Group/Group.php
index efc21ad7c0d..441ee64604d 100644
--- a/lib/private/Group/Group.php
+++ b/lib/private/Group/Group.php
@@ -34,6 +34,13 @@ 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;
@@ -46,8 +53,6 @@ use OCP\Group\Events\GroupChangedEvent;
use OCP\IGroup;
use OCP\IUser;
use OCP\IUserManager;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
class Group implements IGroup {
/** @var null|string */
@@ -64,23 +69,14 @@ class Group implements IGroup {
/** @var Backend[] */
private $backends;
- /** @var EventDispatcherInterface */
+ /** @var IEventDispatcher */
private $dispatcher;
/** @var \OC\User\Manager|IUserManager */
private $userManager;
/** @var PublicEmitter */
private $emitter;
-
- /**
- * @param string $gid
- * @param Backend[] $backends
- * @param EventDispatcherInterface $dispatcher
- * @param IUserManager $userManager
- * @param PublicEmitter $emitter
- * @param string $displayName
- */
- public function __construct(string $gid, array $backends, EventDispatcherInterface $dispatcher, IUserManager $userManager, PublicEmitter $emitter = null, ?string $displayName = null) {
+ public function __construct(string $gid, array $backends, IEventDispatcher $dispatcher, IUserManager $userManager, PublicEmitter $emitter = null, ?string $displayName = null) {
$this->gid = $gid;
$this->backends = $backends;
$this->dispatcher = $dispatcher;
@@ -112,12 +108,12 @@ class Group implements IGroup {
public function setDisplayName(string $displayName): bool {
$displayName = trim($displayName);
if ($displayName !== '') {
- $this->dispatcher->dispatch(new BeforeGroupChangedEvent($this, 'displayName', $displayName, $this->displayName));
+ $this->dispatcher->dispatchTyped(new BeforeGroupChangedEvent($this, 'displayName', $displayName, $this->displayName));
foreach ($this->backends as $backend) {
if (($backend instanceof ISetDisplayNameBackend)
&& $backend->setDisplayName($this->gid, $displayName)) {
$this->displayName = $displayName;
- $this->dispatcher->dispatch(new GroupChangedEvent($this, 'displayName', $displayName, ''));
+ $this->dispatcher->dispatchTyped(new GroupChangedEvent($this, 'displayName', $displayName, ''));
return true;
}
}
@@ -180,9 +176,7 @@ class Group implements IGroup {
return;
}
- $this->dispatcher->dispatch(IGroup::class . '::preAddUser', new GenericEvent($this, [
- 'user' => $user,
- ]));
+ $this->dispatcher->dispatchTyped(new BeforeUserAddedEvent($this, $user));
if ($this->emitter) {
$this->emitter->emit('\OC\Group', 'preAddUser', [$this, $user]);
@@ -194,9 +188,7 @@ class Group implements IGroup {
$this->users[$user->getUID()] = $user;
}
- $this->dispatcher->dispatch(IGroup::class . '::postAddUser', new GenericEvent($this, [
- 'user' => $user,
- ]));
+ $this->dispatcher->dispatchTyped(new UserAddedEvent($this, $user));
if ($this->emitter) {
$this->emitter->emit('\OC\Group', 'postAddUser', [$this, $user]);
@@ -213,9 +205,7 @@ class Group implements IGroup {
*/
public function removeUser($user) {
$result = false;
- $this->dispatcher->dispatch(IGroup::class . '::preRemoveUser', new GenericEvent($this, [
- 'user' => $user,
- ]));
+ $this->dispatcher->dispatchTyped(new BeforeUserRemovedEvent($this, $user));
if ($this->emitter) {
$this->emitter->emit('\OC\Group', 'preRemoveUser', [$this, $user]);
}
@@ -226,9 +216,7 @@ class Group implements IGroup {
}
}
if ($result) {
- $this->dispatcher->dispatch(IGroup::class . '::postRemoveUser', new GenericEvent($this, [
- 'user' => $user,
- ]));
+ $this->dispatcher->dispatchTyped(new UserRemovedEvent($this, $user));
if ($this->emitter) {
$this->emitter->emit('\OC\Group', 'postRemoveUser', [$this, $user]);
}
@@ -352,7 +340,7 @@ class Group implements IGroup {
}
$result = false;
- $this->dispatcher->dispatch(IGroup::class . '::preDelete', new GenericEvent($this));
+ $this->dispatcher->dispatchTyped(new BeforeGroupDeletedEvent($this));
if ($this->emitter) {
$this->emitter->emit('\OC\Group', 'preDelete', [$this]);
}
@@ -362,7 +350,7 @@ class Group implements IGroup {
}
}
if ($result) {
- $this->dispatcher->dispatch(IGroup::class . '::postDelete', new GenericEvent($this));
+ $this->dispatcher->dispatchTyped(new GroupDeletedEvent($this));
if ($this->emitter) {
$this->emitter->emit('\OC\Group', 'postDelete', [$this]);
}
diff --git a/lib/private/Group/Manager.php b/lib/private/Group/Manager.php
index 0672e519e36..47475121ea0 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,13 +42,16 @@ 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;
use OCP\ICacheFactory;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IUser;
use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Class Manager
@@ -70,14 +74,13 @@ class Manager extends PublicEmitter implements IGroupManager {
/** @var \OC\User\Manager */
private $userManager;
- /** @var EventDispatcherInterface */
- private $dispatcher;
+ 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,7 +89,7 @@ class Manager extends PublicEmitter implements IGroupManager {
private DisplayNameCache $displayNameCache;
public function __construct(\OC\User\Manager $userManager,
- EventDispatcherInterface $dispatcher,
+ IEventDispatcher $dispatcher,
LoggerInterface $logger,
ICacheFactory $cacheFactory) {
$this->userManager = $userManager;
@@ -185,7 +188,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 +201,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
*/
@@ -220,11 +281,13 @@ class Manager extends PublicEmitter implements IGroupManager {
} elseif ($group = $this->get($gid)) {
return $group;
} else {
+ $this->dispatcher->dispatchTyped(new BeforeGroupCreatedEvent($gid));
$this->emit('\OC\Group', 'preCreate', [$gid]);
foreach ($this->backends as $backend) {
if ($backend->implementsActions(Backend::CREATE_GROUP)) {
if ($backend->createGroup($gid)) {
$group = $this->getGroupObject($gid);
+ $this->dispatcher->dispatchTyped(new GroupCreatedEvent($group));
$this->emit('\OC\Group', 'postCreate', [$group]);
return $group;
}
@@ -244,13 +307,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);
@@ -424,7 +483,7 @@ class Manager extends PublicEmitter implements IGroupManager {
$this->userManager,
$this,
\OC::$server->getDatabaseConnection(),
- \OC::$server->get(IEventDispatcher::class)
+ $this->dispatcher
);
}
diff --git a/lib/private/Http/Client/Client.php b/lib/private/Http/Client/Client.php
index 298749d52e1..3bf43e6c07e 100644
--- a/lib/private/Http/Client/Client.php
+++ b/lib/private/Http/Client/Client.php
@@ -34,13 +34,16 @@ declare(strict_types=1);
namespace OC\Http\Client;
use GuzzleHttp\Client as GuzzleClient;
+use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\RequestOptions;
use OCP\Http\Client\IClient;
+use OCP\Http\Client\IPromise;
use OCP\Http\Client\IResponse;
use OCP\Http\Client\LocalServerException;
use OCP\ICertificateManager;
use OCP\IConfig;
use OCP\Security\IRemoteHostValidator;
+use Psr\Log\LoggerInterface;
use function parse_url;
/**
@@ -61,7 +64,8 @@ class Client implements IClient {
IConfig $config,
ICertificateManager $certificateManager,
GuzzleClient $client,
- IRemoteHostValidator $remoteHostValidator
+ IRemoteHostValidator $remoteHostValidator,
+ protected LoggerInterface $logger,
) {
$this->config = $config;
$this->client = $client;
@@ -205,7 +209,7 @@ class Client implements IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -236,7 +240,7 @@ class Client implements IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -271,7 +275,7 @@ class Client implements IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -312,7 +316,7 @@ class Client implements IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -347,7 +351,7 @@ class Client implements IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -370,7 +374,7 @@ class Client implements IClient {
}
/**
- * Sends a options request
+ * Sends an OPTIONS request
*
* @param string $uri
* @param array $options Array such as
@@ -382,7 +386,7 @@ class Client implements IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -403,4 +407,215 @@ class Client implements IClient {
$response = $this->client->request('options', $uri, $this->buildRequestOptions($options));
return new Response($response);
}
+
+ protected function wrapGuzzlePromise(PromiseInterface $promise): IPromise {
+ return new GuzzlePromiseAdapter(
+ $promise,
+ $this->logger
+ );
+ }
+
+ /**
+ * Sends an asynchronous GET request
+ *
+ * @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 IPromise
+ */
+ public function getAsync(string $uri, array $options = []): IPromise {
+ $this->preventLocalAddress($uri, $options);
+ $response = $this->client->requestAsync('get', $uri, $this->buildRequestOptions($options));
+ return $this->wrapGuzzlePromise($response);
+ }
+
+ /**
+ * Sends an asynchronous HEAD request
+ *
+ * @param string $uri
+ * @param array $options Array such as
+ * '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 IPromise
+ */
+ public function headAsync(string $uri, array $options = []): IPromise {
+ $this->preventLocalAddress($uri, $options);
+ $response = $this->client->requestAsync('head', $uri, $this->buildRequestOptions($options));
+ return $this->wrapGuzzlePromise($response);
+ }
+
+ /**
+ * Sends an asynchronous POST request
+ *
+ * @param string $uri
+ * @param array $options Array such as
+ * 'body' => [
+ * '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 IPromise
+ */
+ public function postAsync(string $uri, array $options = []): IPromise {
+ $this->preventLocalAddress($uri, $options);
+
+ if (isset($options['body']) && is_array($options['body'])) {
+ $options['form_params'] = $options['body'];
+ unset($options['body']);
+ }
+
+ return $this->wrapGuzzlePromise($this->client->requestAsync('post', $uri, $this->buildRequestOptions($options)));
+ }
+
+ /**
+ * Sends an asynchronous PUT request
+ *
+ * @param string $uri
+ * @param array $options Array such as
+ * 'body' => [
+ * '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 IPromise
+ */
+ public function putAsync(string $uri, array $options = []): IPromise {
+ $this->preventLocalAddress($uri, $options);
+ $response = $this->client->requestAsync('put', $uri, $this->buildRequestOptions($options));
+ return $this->wrapGuzzlePromise($response);
+ }
+
+ /**
+ * Sends an asynchronous DELETE request
+ *
+ * @param string $uri
+ * @param array $options Array such as
+ * 'body' => [
+ * '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 IPromise
+ */
+ public function deleteAsync(string $uri, array $options = []): IPromise {
+ $this->preventLocalAddress($uri, $options);
+ $response = $this->client->requestAsync('delete', $uri, $this->buildRequestOptions($options));
+ return $this->wrapGuzzlePromise($response);
+ }
+
+ /**
+ * Sends an asynchronous OPTIONS request
+ *
+ * @param string $uri
+ * @param array $options Array such as
+ * 'body' => [
+ * '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 IPromise
+ */
+ public function optionsAsync(string $uri, array $options = []): IPromise {
+ $this->preventLocalAddress($uri, $options);
+ $response = $this->client->requestAsync('options', $uri, $this->buildRequestOptions($options));
+ return $this->wrapGuzzlePromise($response);
+ }
}
diff --git a/lib/private/Http/Client/ClientService.php b/lib/private/Http/Client/ClientService.php
index d0640680124..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;
@@ -37,6 +37,7 @@ use OCP\ICertificateManager;
use OCP\IConfig;
use OCP\Security\IRemoteHostValidator;
use Psr\Http\Message\RequestInterface;
+use Psr\Log\LoggerInterface;
/**
* Class ClientService
@@ -59,6 +60,7 @@ class ClientService implements IClientService {
DnsPinMiddleware $dnsPinMiddleware,
IRemoteHostValidator $remoteHostValidator,
IEventLogger $eventLogger,
+ protected LoggerInterface $logger,
) {
$this->config = $config;
$this->certificateManager = $certificateManager;
@@ -73,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 () {
@@ -87,6 +91,7 @@ class ClientService implements IClientService {
$this->certificateManager,
$client,
$this->remoteHostValidator,
+ $this->logger,
);
}
}
diff --git a/lib/private/Http/Client/DnsPinMiddleware.php b/lib/private/Http/Client/DnsPinMiddleware.php
index c6a58972fdd..aecccc6ce97 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) {
diff --git a/lib/private/Http/Client/GuzzlePromiseAdapter.php b/lib/private/Http/Client/GuzzlePromiseAdapter.php
new file mode 100644
index 00000000000..9d0b89bfd17
--- /dev/null
+++ b/lib/private/Http/Client/GuzzlePromiseAdapter.php
@@ -0,0 +1,139 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023, 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\Http\Client;
+
+use Exception;
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\Promise\PromiseInterface;
+use LogicException;
+use OCP\Http\Client\IPromise;
+use OCP\Http\Client\IResponse;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * A wrapper around Guzzle's PromiseInterface
+ *
+ * @see \GuzzleHttp\Promise\PromiseInterface
+ * @since 28.0.0
+ */
+class GuzzlePromiseAdapter implements IPromise {
+ public function __construct(
+ protected PromiseInterface $promise,
+ protected LoggerInterface $logger,
+ ) {
+ }
+
+ /**
+ * Appends fulfillment and rejection handlers to the promise, and returns
+ * a new promise resolving to the return value of the called handler.
+ *
+ * @param ?callable(IResponse): void $onFulfilled Invoked when the promise fulfills. Gets an \OCP\Http\Client\IResponse passed in as argument
+ * @param ?callable(Exception): void $onRejected Invoked when the promise is rejected. Gets an \Exception passed in as argument
+ *
+ * @return IPromise
+ * @since 28.0.0
+ */
+ public function then(
+ ?callable $onFulfilled = null,
+ ?callable $onRejected = null,
+ ): IPromise {
+ if ($onFulfilled !== null) {
+ $wrappedOnFulfilled = static function (ResponseInterface $response) use ($onFulfilled) {
+ $onFulfilled(new Response($response));
+ };
+ } else {
+ $wrappedOnFulfilled = null;
+ }
+
+ if ($onRejected !== null) {
+ $wrappedOnRejected = static function (RequestException $e) use ($onRejected) {
+ $onRejected($e);
+ };
+ } else {
+ $wrappedOnRejected = null;
+ }
+
+ $this->promise->then($wrappedOnFulfilled, $wrappedOnRejected);
+ return $this;
+ }
+
+ /**
+ * Get the state of the promise ("pending", "rejected", or "fulfilled").
+ *
+ * The three states can be checked against the constants defined:
+ * STATE_PENDING, STATE_FULFILLED, and STATE_REJECTED.
+ *
+ * @return IPromise::STATE_*
+ * @since 28.0.0
+ */
+ public function getState(): string {
+ $state = $this->promise->getState();
+ if ($state === PromiseInterface::FULFILLED) {
+ return self::STATE_FULFILLED;
+ }
+ if ($state === PromiseInterface::REJECTED) {
+ return self::STATE_REJECTED;
+ }
+ if ($state === PromiseInterface::PENDING) {
+ return self::STATE_PENDING;
+ }
+
+ $this->logger->error('Unexpected promise state "{state}" returned by Guzzle', [
+ 'state' => $state,
+ ]);
+ return self::STATE_PENDING;
+ }
+
+ /**
+ * Cancels the promise if possible.
+ *
+ * @link https://github.com/promises-aplus/cancellation-spec/issues/7
+ * @since 28.0.0
+ */
+ public function cancel(): void {
+ $this->promise->cancel();
+ }
+
+ /**
+ * Waits until the promise completes if possible.
+ *
+ * Pass $unwrap as true to unwrap the result of the promise, either
+ * returning the resolved value or throwing the rejected exception.
+ *
+ * If the promise cannot be waited on, then the promise will be rejected.
+ *
+ * @param bool $unwrap
+ *
+ * @return mixed
+ *
+ * @throws LogicException if the promise has no wait function or if the
+ * promise does not settle after waiting.
+ * @since 28.0.0
+ */
+ public function wait(bool $unwrap = true): mixed {
+ return $this->promise->wait($unwrap);
+ }
+}
diff --git a/lib/private/Installer.php b/lib/private/Installer.php
index 9b286cc85b0..dc81135b644 100644
--- a/lib/private/Installer.php
+++ b/lib/private/Installer.php
@@ -334,10 +334,10 @@ class Installer {
// Check if appinfo/info.xml has the same app ID as well
if ((PHP_VERSION_ID < 80000)) {
$loadEntities = libxml_disable_entity_loader(false);
- $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
+ $xml = simplexml_load_string(file_get_contents($extractDir . '/' . $folders[0] . '/appinfo/info.xml'));
libxml_disable_entity_loader($loadEntities);
} else {
- $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
+ $xml = simplexml_load_string(file_get_contents($extractDir . '/' . $folders[0] . '/appinfo/info.xml'));
}
if ((string)$xml->id !== $appId) {
throw new \Exception(
diff --git a/lib/private/Log.php b/lib/private/Log.php
index 1f248be1410..d6750491d92 100644
--- a/lib/private/Log.php
+++ b/lib/private/Log.php
@@ -38,17 +38,18 @@ namespace OC;
use Exception;
use Nextcloud\LogNormalizer\Normalizer;
-use OC\AppFramework\Bootstrap\Coordinator;
use OCP\EventDispatcher\IEventDispatcher;
+use OCP\ILogger;
+use OCP\IUserSession;
use OCP\Log\BeforeMessageLoggedEvent;
use OCP\Log\IDataLogger;
-use Throwable;
-use function array_merge;
-use OC\Log\ExceptionSerializer;
-use OCP\ILogger;
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;
/**
@@ -220,6 +221,12 @@ class Log implements ILogger, IDataLogger {
$this->eventDispatcher->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $entry));
}
+ $hasBacktrace = isset($entry['exception']);
+ $logBacktrace = $this->config->getValue('log.backtrace', false);
+ if (!$hasBacktrace && $logBacktrace) {
+ $entry['backtrace'] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ }
+
try {
if ($level >= $minLevel) {
$this->writeLog($app, $entry, $level);
@@ -274,10 +281,13 @@ class Log implements ILogger, IDataLogger {
// check for user
if (isset($logCondition['users'])) {
- $user = \OC::$server->getUserSession()->getUser();
+ $user = \OCP\Server::get(IUserSession::class)->getUser();
- // if the user matches set the log condition to satisfied
- if ($user !== null && in_array($user->getUID(), $logCondition['users'], true)) {
+ if ($user === null) {
+ // User is not known for this request yet
+ $this->logConditionSatisfied = null;
+ } elseif (in_array($user->getUID(), $logCondition['users'], true)) {
+ // if the user matches set the log condition to satisfied
$this->logConditionSatisfied = true;
}
}
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..ec88aa767fb 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 {
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..4c0e258b2f9 100644
--- a/lib/private/Log/Rotate.php
+++ b/lib/private/Log/Rotate.php
@@ -35,7 +35,7 @@ use OCP\Log\RotationTrait;
class Rotate extends \OCP\BackgroundJob\Job {
use RotationTrait;
- public function run($dummy) {
+ public function run($dummy): void {
$systemConfig = \OC::$server->getSystemConfig();
$this->filePath = $systemConfig->getValue('logfile', $systemConfig->getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/nextcloud.log');
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/Attachment.php b/lib/private/Mail/Attachment.php
index 5bfe0dd0522..a39161b2505 100644
--- a/lib/private/Mail/Attachment.php
+++ b/lib/private/Mail/Attachment.php
@@ -36,25 +36,15 @@ use Symfony\Component\Mime\Email;
* @since 13.0.0
*/
class Attachment implements IAttachment {
- private ?string $body;
- private ?string $name;
- private ?string $contentType;
- private ?string $path;
-
public function __construct(
- ?string $body,
- ?string $name,
- ?string $contentType,
- ?string $path = null
+ private ?string $body,
+ private ?string $name,
+ private ?string $contentType,
+ private ?string $path = null
) {
- $this->body = $body;
- $this->name = $name;
- $this->contentType = $contentType;
- $this->path = $path;
}
/**
- * @param string $filename
* @return $this
* @since 13.0.0
*/
@@ -64,7 +54,6 @@ class Attachment implements IAttachment {
}
/**
- * @param string $contentType
* @return $this
* @since 13.0.0
*/
@@ -74,7 +63,6 @@ class Attachment implements IAttachment {
}
/**
- * @param string $body
* @return $this
* @since 13.0.0
*/
diff --git a/lib/private/Mail/EMailTemplate.php b/lib/private/Mail/EMailTemplate.php
index 40738623c19..bb60f761450 100644
--- a/lib/private/Mail/EMailTemplate.php
+++ b/lib/private/Mail/EMailTemplate.php
@@ -52,33 +52,19 @@ use OCP\Mail\IEMailTemplate;
* @package OC\Mail
*/
class EMailTemplate implements IEMailTemplate {
- /** @var Defaults */
- protected $themingDefaults;
- /** @var IURLGenerator */
- protected $urlGenerator;
- /** @var IFactory */
- protected $l10nFactory;
- /** @var string */
- protected $emailId;
- /** @var array */
- protected $data;
-
- /** @var string */
- protected $subject = '';
- /** @var string */
- protected $htmlBody = '';
- /** @var string */
- protected $plainBody = '';
- /** @var bool indicated if the footer is added */
- protected $headerAdded = false;
- /** @var bool indicated if the body is already opened */
- protected $bodyOpened = false;
- /** @var bool indicated if there is a list open in the body */
- protected $bodyListOpened = false;
- /** @var bool indicated if the footer is added */
- protected $footerAdded = false;
-
- protected $head = <<<EOF
+ protected string $subject = '';
+ protected string $htmlBody = '';
+ protected string $plainBody = '';
+ /** indicated if the header is added */
+ protected bool $headerAdded = false;
+ /** indicated if the body is already opened */
+ protected bool $bodyOpened = false;
+ /** indicated if there is a list open in the body */
+ protected bool $bodyListOpened = false;
+ /** indicated if the footer is added */
+ protected bool $footerAdded = false;
+
+ protected string $head = <<<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" style="-webkit-font-smoothing:antialiased;background:#fff!important">
<head>
@@ -96,7 +82,7 @@ class EMailTemplate implements IEMailTemplate {
<center data-parsed="" style="min-width:580px;width:100%">
EOF;
- protected $tail = <<<EOF
+ protected string $tail = <<<EOF
</center>
</td>
</tr>
@@ -108,7 +94,7 @@ EOF;
EOF;
- protected $header = <<<EOF
+ protected string $header = <<<EOF
<table align="center" class="wrapper header float-center" style="Margin:0 auto;background:#fff;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
<tr style="padding:0;text-align:left;vertical-align:top">
<td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',Arial,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:20px;text-align:left;vertical-align:top;word-wrap:break-word">
@@ -141,7 +127,7 @@ EOF;
</table>
EOF;
- protected $heading = <<<EOF
+ protected string $heading = <<<EOF
<table align="center" class="container main-heading float-center" style="Margin:0 auto;background:0 0!important;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:580px">
<tbody>
<tr style="padding:0;text-align:left;vertical-align:top">
@@ -160,7 +146,7 @@ EOF;
</table>
EOF;
- protected $bodyBegin = <<<EOF
+ protected string $bodyBegin = <<<EOF
<table align="center" class="wrapper content float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%">
<tr style="padding:0;text-align:left;vertical-align:top">
<td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',Arial,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
@@ -170,7 +156,7 @@ EOF;
<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',Arial,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
EOF;
- protected $bodyText = <<<EOF
+ protected string $bodyText = <<<EOF
<table class="row description" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
<tbody>
<tr style="padding:0;text-align:left;vertical-align:top">
@@ -190,7 +176,7 @@ EOF;
EOF;
// note: listBegin (like bodyBegin) is not processed through sprintf, so "%" is not escaped as "%%". (bug #12151)
- protected $listBegin = <<<EOF
+ protected string $listBegin = <<<EOF
<table class="row description" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%">
<tbody>
<tr style="padding:0;text-align:left;vertical-align:top">
@@ -198,7 +184,7 @@ EOF;
<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%">
EOF;
- protected $listItem = <<<EOF
+ protected string $listItem = <<<EOF
<tr style="padding:0;text-align:left;vertical-align:top">
<td style="Margin:0;color:#0a0a0a;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',Arial,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left;width:15px;">
<p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',Arial,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;padding-left:10px;text-align:left">%s</p>
@@ -210,7 +196,7 @@ EOF;
</tr>
EOF;
- protected $listEnd = <<<EOF
+ protected string $listEnd = <<<EOF
</table>
</th>
</tr>
@@ -218,7 +204,7 @@ EOF;
</table>
EOF;
- protected $buttonGroup = <<<EOF
+ protected string $buttonGroup = <<<EOF
<table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
<tbody>
<tr style="padding:0;text-align:left;vertical-align:top">
@@ -271,7 +257,7 @@ EOF;
</table>
EOF;
- protected $button = <<<EOF
+ protected string $button = <<<EOF
<table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
<tbody>
<tr style="padding:0;text-align:left;vertical-align:top">
@@ -311,7 +297,7 @@ EOF;
</table>
EOF;
- protected $bodyEnd = <<<EOF
+ protected string $bodyEnd = <<<EOF
</td>
</tr>
@@ -322,7 +308,7 @@ EOF;
</table>
EOF;
- protected $footer = <<<EOF
+ protected string $footer = <<<EOF
<table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
<tbody>
<tr style="padding:0;text-align:left;vertical-align:top">
@@ -348,32 +334,27 @@ EOF;
</table>
EOF;
- public function __construct(Defaults $themingDefaults,
- IURLGenerator $urlGenerator,
- IFactory $l10nFactory,
- $emailId,
- array $data) {
- $this->themingDefaults = $themingDefaults;
- $this->urlGenerator = $urlGenerator;
- $this->l10nFactory = $l10nFactory;
+ public function __construct(
+ protected Defaults $themingDefaults,
+ protected IURLGenerator $urlGenerator,
+ protected IFactory $l10nFactory,
+ protected string $emailId,
+ protected array $data,
+ ) {
$this->htmlBody .= $this->head;
- $this->emailId = $emailId;
- $this->data = $data;
}
/**
* Sets the subject of the email
- *
- * @param string $subject
*/
- public function setSubject(string $subject) {
+ public function setSubject(string $subject): void {
$this->subject = $subject;
}
/**
* Adds a header to the email
*/
- public function addHeader() {
+ public function addHeader(): void {
if ($this->headerAdded) {
return;
}
@@ -386,11 +367,10 @@ EOF;
/**
* Adds a heading to the email
*
- * @param string $title
* @param string|bool $plainTitle Title that is used in the plain text email
* if empty the $title is used, if false none will be used
*/
- public function addHeading(string $title, $plainTitle = '') {
+ public function addHeading(string $title, $plainTitle = ''): void {
if ($this->footerAdded) {
return;
}
@@ -407,7 +387,7 @@ EOF;
/**
* Open the HTML body when it is not already
*/
- protected function ensureBodyIsOpened() {
+ protected function ensureBodyIsOpened(): void {
if ($this->bodyOpened) {
return;
}
@@ -423,7 +403,7 @@ EOF;
* @param string|bool $plainText Text that is used in the plain text email
* if empty the $text is used, if false none will be used
*/
- public function addBodyText(string $text, $plainText = '') {
+ public function addBodyText(string $text, $plainText = ''): void {
if ($this->footerAdded) {
return;
}
@@ -451,10 +431,17 @@ EOF;
* if empty or true the $text is used, if false none will be used
* @param string|bool $plainMetaInfo Meta info that is used in the plain text email
* if empty or true the $metaInfo is used, if false none will be used
- * @param integer plainIndent If > 0, Indent plainText by this amount.
+ * @param integer $plainIndent plainIndent If > 0, Indent plainText by this amount.
* @since 12.0.0
*/
- public function addBodyListItem(string $text, string $metaInfo = '', string $icon = '', $plainText = '', $plainMetaInfo = '', $plainIndent = 0) {
+ public function addBodyListItem(
+ string $text,
+ string $metaInfo = '',
+ string $icon = '',
+ $plainText = '',
+ $plainMetaInfo = '',
+ $plainIndent = 0,
+ ): void {
$this->ensureBodyListOpened();
if ($plainText === '' || $plainText === true) {
@@ -504,7 +491,7 @@ EOF;
}
}
- protected function ensureBodyListOpened() {
+ protected function ensureBodyListOpened(): void {
if ($this->bodyListOpened) {
return;
}
@@ -514,7 +501,7 @@ EOF;
$this->htmlBody .= $this->listBegin;
}
- protected function ensureBodyListClosed() {
+ protected function ensureBodyListClosed(): void {
if (!$this->bodyListOpened) {
return;
}
@@ -533,12 +520,14 @@ EOF;
* @param string $plainTextLeft Text of left button that is used in the plain text version - if unset the $textLeft is used
* @param string $plainTextRight Text of right button that is used in the plain text version - if unset the $textRight is used
*/
- public function addBodyButtonGroup(string $textLeft,
- string $urlLeft,
- string $textRight,
- string $urlRight,
- string $plainTextLeft = '',
- string $plainTextRight = '') {
+ public function addBodyButtonGroup(
+ string $textLeft,
+ string $urlLeft,
+ string $textRight,
+ string $urlRight,
+ string $plainTextLeft = '',
+ string $plainTextRight = '',
+ ): void {
if ($this->footerAdded) {
return;
}
@@ -573,7 +562,7 @@ EOF;
*
* @since 12.0.0
*/
- public function addBodyButton(string $text, string $url, $plainText = '') {
+ public function addBodyButton(string $text, string $url, $plainText = ''): void {
if ($this->footerAdded) {
return;
}
@@ -600,7 +589,7 @@ EOF;
/**
* Close the HTML body when it is open
*/
- protected function ensureBodyIsClosed() {
+ protected function ensureBodyIsClosed(): void {
if (!$this->bodyOpened) {
return;
}
@@ -616,7 +605,7 @@ EOF;
*
* @param string $text If the text is empty the default "Name - Slogan<br>This is an automatically sent email" will be used
*/
- public function addFooter(string $text = '', ?string $lang = null) {
+ public function addFooter(string $text = '', ?string $lang = null): void {
if ($text === '') {
$l10n = $this->l10nFactory->get('lib', $lang);
$slogan = $this->themingDefaults->getSlogan($lang);
@@ -641,8 +630,6 @@ EOF;
/**
* Returns the rendered email subject as string
- *
- * @return string
*/
public function renderSubject(): string {
return $this->subject;
@@ -650,8 +637,6 @@ EOF;
/**
* Returns the rendered HTML email as string
- *
- * @return string
*/
public function renderHtml(): string {
if (!$this->footerAdded) {
@@ -664,8 +649,6 @@ EOF;
/**
* Returns the rendered plain text email as string
- *
- * @return string
*/
public function renderText(): string {
if (!$this->footerAdded) {
diff --git a/lib/private/Mail/Mailer.php b/lib/private/Mail/Mailer.php
index 5d838b2cdf1..9b7b3cf117b 100644
--- a/lib/private/Mail/Mailer.php
+++ b/lib/private/Mail/Mailer.php
@@ -79,34 +79,20 @@ use Symfony\Component\Mime\Exception\RfcComplianceException;
*/
class Mailer implements IMailer {
private ?MailerInterface $instance = null;
- private IConfig $config;
- private LoggerInterface $logger;
- private Defaults $defaults;
- private IURLGenerator $urlGenerator;
- private IL10N $l10n;
- private IEventDispatcher $dispatcher;
- private IFactory $l10nFactory;
-
- public function __construct(IConfig $config,
- LoggerInterface $logger,
- Defaults $defaults,
- IURLGenerator $urlGenerator,
- IL10N $l10n,
- IEventDispatcher $dispatcher,
- IFactory $l10nFactory) {
- $this->config = $config;
- $this->logger = $logger;
- $this->defaults = $defaults;
- $this->urlGenerator = $urlGenerator;
- $this->l10n = $l10n;
- $this->dispatcher = $dispatcher;
- $this->l10nFactory = $l10nFactory;
+
+ public function __construct(
+ private IConfig $config,
+ private LoggerInterface $logger,
+ private Defaults $defaults,
+ private IURLGenerator $urlGenerator,
+ private IL10N $l10n,
+ private IEventDispatcher $dispatcher,
+ private IFactory $l10nFactory,
+ ) {
}
/**
* Creates a new message object that can be passed to send()
- *
- * @return Message
*/
public function createMessage(): Message {
$plainTextOnly = $this->config->getSystemValueBool('mail_send_plaintext_only', false);
@@ -117,7 +103,6 @@ class Mailer implements IMailer {
* @param string|null $data
* @param string|null $filename
* @param string|null $contentType
- * @return IAttachment
* @since 13.0.0
*/
public function createAttachment($data = null, $filename = null, $contentType = null): IAttachment {
@@ -125,9 +110,7 @@ class Mailer implements IMailer {
}
/**
- * @param string $path
* @param string|null $contentType
- * @return IAttachment
* @since 13.0.0
*/
public function createAttachmentFromPath(string $path, $contentType = null): IAttachment {
@@ -137,9 +120,6 @@ class Mailer implements IMailer {
/**
* Creates a new email template object
*
- * @param string $emailId
- * @param array $data
- * @return IEMailTemplate
* @since 12.0.0
*/
public function createEMailTemplate(string $emailId, array $data = []): IEMailTemplate {
@@ -292,7 +272,7 @@ class Mailer implements IMailer {
// either null or true - if nothing is passed, let the symfony mailer figure out the configuration by itself
$mailSmtpsecure = ($this->config->getSystemValue('mail_smtpsecure', null) === 'ssl') ? true : null;
$transport = new EsmtpTransport(
- $this->config->getSystemValue('mail_smtphost', '127.0.0.1'),
+ $this->config->getSystemValueString('mail_smtphost', '127.0.0.1'),
$this->config->getSystemValueInt('mail_smtpport', 25),
$mailSmtpsecure,
null,
@@ -301,11 +281,11 @@ class Mailer implements IMailer {
/** @var SocketStream $stream */
$stream = $transport->getStream();
/** @psalm-suppress InternalMethod */
- $stream->setTimeout($this->config->getSystemValue('mail_smtptimeout', 10));
+ $stream->setTimeout($this->config->getSystemValueInt('mail_smtptimeout', 10));
if ($this->config->getSystemValueBool('mail_smtpauth', false)) {
- $transport->setUsername($this->config->getSystemValue('mail_smtpname', ''));
- $transport->setPassword($this->config->getSystemValue('mail_smtppassword', ''));
+ $transport->setUsername($this->config->getSystemValueString('mail_smtpname', ''));
+ $transport->setPassword($this->config->getSystemValueString('mail_smtppassword', ''));
}
$streamingOptions = $this->config->getSystemValue('mail_smtpstreamoptions', []);
@@ -350,14 +330,10 @@ class Mailer implements IMailer {
break;
}
- switch ($this->config->getSystemValueString('mail_sendmailmode', 'smtp')) {
- case 'pipe':
- $binaryParam = ' -t';
- break;
- default:
- $binaryParam = ' -bs';
- break;
- }
+ $binaryParam = match ($this->config->getSystemValueString('mail_sendmailmode', 'smtp')) {
+ 'pipe' => ' -t',
+ default => ' -bs',
+ };
return new SendmailTransport($binaryPath . $binaryParam, null, $this->logger);
}
diff --git a/lib/private/Mail/Message.php b/lib/private/Mail/Message.php
index 016340c9692..15d4da793dd 100644
--- a/lib/private/Mail/Message.php
+++ b/lib/private/Mail/Message.php
@@ -46,28 +46,21 @@ use Symfony\Component\Mime\Exception\RfcComplianceException;
* @package OC\Mail
*/
class Message implements IMessage {
- private Email $symfonyEmail;
- private bool $plainTextOnly;
-
- private array $to;
- private array $from;
- private array $replyTo;
- private array $cc;
- private array $bcc;
-
- public function __construct(Email $symfonyEmail, bool $plainTextOnly) {
- $this->symfonyEmail = $symfonyEmail;
- $this->plainTextOnly = $plainTextOnly;
- $this->to = [];
- $this->from = [];
- $this->replyTo = [];
- $this->cc = [];
- $this->bcc = [];
+ private array $to = [];
+ private array $from = [];
+ private array $replyTo = [];
+ private array $cc = [];
+ private array $bcc = [];
+
+ public function __construct(
+ private Email $symfonyEmail,
+ private bool $plainTextOnly,
+ ) {
}
/**
- * @return $this
* @since 13.0.0
+ * @return $this
*/
public function attach(IAttachment $attachment): IMessage {
/** @var Attachment $attachment */
@@ -138,7 +131,6 @@ class Message implements IMessage {
/**
* Set the Reply-To address of this message
- *
* @return $this
*/
public function setReplyTo(array $addresses): IMessage {
@@ -207,6 +199,9 @@ class Message implements IMessage {
return $this->bcc;
}
+ /**
+ * @return $this
+ */
public function setSubject(string $subject): IMessage {
$this->symfonyEmail->subject($subject);
return $this;
@@ -219,6 +214,9 @@ class Message implements IMessage {
return $this->symfonyEmail->getSubject() ?? '';
}
+ /**
+ * @return $this
+ */
public function setPlainBody(string $body): IMessage {
$this->symfonyEmail->text($body);
return $this;
@@ -233,6 +231,9 @@ class Message implements IMessage {
return $body;
}
+ /**
+ * @return $this
+ */
public function setHtmlBody(string $body): IMessage {
if (!$this->plainTextOnly) {
$this->symfonyEmail->html($body);
@@ -241,7 +242,7 @@ class Message implements IMessage {
}
/**
- * Set the underlying Email intance
+ * Set the underlying Email instance
*/
public function setSymfonyEmail(Email $symfonyEmail): void {
$this->symfonyEmail = $symfonyEmail;
@@ -284,10 +285,9 @@ class Message implements IMessage {
* we wrap the calls here. We then have the validation errors all in one place and can
* throw shortly before \OC\Mail\Mailer::send
*
- * @return void
* @throws InvalidArgumentException|RfcComplianceException
*/
- public function setRecipients() {
+ public function setRecipients(): void {
$this->symfonyEmail->to(...$this->convertAddresses($this->getTo()));
$this->symfonyEmail->from(...$this->convertAddresses($this->getFrom()));
$this->symfonyEmail->replyTo(...$this->convertAddresses($this->getReplyTo()));
@@ -335,8 +335,6 @@ class Message implements IMessage {
/**
* Get the current value of the Auto-Submitted header. Defaults to "no"
* which is equivalent to the header not existing at all
- *
- * @return string
*/
public function getAutoSubmitted(): string {
$headers = $this->symfonyEmail->getHeaders();
diff --git a/lib/private/Memcache/APCu.php b/lib/private/Memcache/APCu.php
index 957926ab848..f3221fc7b77 100644
--- a/lib/private/Memcache/APCu.php
+++ b/lib/private/Memcache/APCu.php
@@ -155,10 +155,7 @@ class APCu extends Cache implements IMemcache {
return false;
} elseif (!\OC::$server->get(IniGetWrapper::class)->getBool('apc.enable_cli') && \OC::$CLI) {
return false;
- } elseif (
- version_compare(phpversion('apc') ?: '0.0.0', '4.0.6') === -1 &&
- version_compare(phpversion('apcu') ?: '0.0.0', '5.1.0') === -1
- ) {
+ } elseif (version_compare(phpversion('apcu') ?: '0.0.0', '5.1.0') === -1) {
return false;
} else {
return true;
diff --git a/lib/private/Memcache/Factory.php b/lib/private/Memcache/Factory.php
index 604f764c03c..788a7c2e8c9 100644
--- a/lib/private/Memcache/Factory.php
+++ b/lib/private/Memcache/Factory.php
@@ -73,16 +73,17 @@ class Factory implements ICacheFactory {
*/
public function __construct(string $globalPrefix, LoggerInterface $logger, IProfiler $profiler,
?string $localCacheClass = null, ?string $distributedCacheClass = null, ?string $lockingCacheClass = null, string $logFile = '') {
- $this->logger = $logger;
$this->logFile = $logFile;
$this->globalPrefix = $globalPrefix;
if (!$localCacheClass) {
$localCacheClass = self::NULL_CACHE;
}
+ $localCacheClass = ltrim($localCacheClass, '\\');
if (!$distributedCacheClass) {
$distributedCacheClass = $localCacheClass;
}
+ $distributedCacheClass = ltrim($distributedCacheClass, '\\');
$missingCacheMessage = 'Memcache {class} not available for {use} cache';
$missingCacheHint = 'Is the matching PHP module installed and enabled?';
@@ -97,9 +98,10 @@ class Factory implements ICacheFactory {
]), $missingCacheHint);
}
if (!($lockingCacheClass && class_exists($lockingCacheClass) && $lockingCacheClass::isAvailable())) {
- // don't fallback since the fallback might not be suitable for storing lock
+ // don't fall back since the fallback might not be suitable for storing lock
$lockingCacheClass = self::NULL_CACHE;
}
+ $lockingCacheClass = ltrim($lockingCacheClass, '\\');
$this->localCacheClass = $localCacheClass;
$this->distributedCacheClass = $distributedCacheClass;
@@ -116,7 +118,7 @@ class Factory implements ICacheFactory {
public function createLocking(string $prefix = ''): IMemcache {
assert($this->lockingCacheClass !== null);
$cache = new $this->lockingCacheClass($this->globalPrefix . '/' . $prefix);
- if ($this->profiler->isEnabled() && $this->lockingCacheClass === '\OC\Memcache\Redis') {
+ if ($this->lockingCacheClass === Redis::class && $this->profiler->isEnabled()) {
// We only support the profiler with Redis
$cache = new ProfilerWrapperCache($cache, 'Locking');
$this->profiler->add($cache);
@@ -138,7 +140,7 @@ class Factory implements ICacheFactory {
public function createDistributed(string $prefix = ''): ICache {
assert($this->distributedCacheClass !== null);
$cache = new $this->distributedCacheClass($this->globalPrefix . '/' . $prefix);
- if ($this->profiler->isEnabled() && $this->distributedCacheClass === '\OC\Memcache\Redis') {
+ if ($this->distributedCacheClass === Redis::class && $this->profiler->isEnabled()) {
// We only support the profiler with Redis
$cache = new ProfilerWrapperCache($cache, 'Distributed');
$this->profiler->add($cache);
@@ -160,7 +162,7 @@ class Factory implements ICacheFactory {
public function createLocal(string $prefix = ''): ICache {
assert($this->localCacheClass !== null);
$cache = new $this->localCacheClass($this->globalPrefix . '/' . $prefix);
- if ($this->profiler->isEnabled() && $this->localCacheClass === '\OC\Memcache\Redis') {
+ if ($this->localCacheClass === Redis::class && $this->profiler->isEnabled()) {
// We only support the profiler with Redis
$cache = new ProfilerWrapperCache($cache, 'Local');
$this->profiler->add($cache);
@@ -179,7 +181,7 @@ class Factory implements ICacheFactory {
* @return bool
*/
public function isAvailable(): bool {
- return ($this->distributedCacheClass !== self::NULL_CACHE);
+ return $this->distributedCacheClass !== self::NULL_CACHE;
}
/**
@@ -197,6 +199,6 @@ class Factory implements ICacheFactory {
* @return bool
*/
public function isLocalCacheAvailable(): bool {
- return ($this->localCacheClass !== self::NULL_CACHE);
+ return $this->localCacheClass !== self::NULL_CACHE;
}
}
diff --git a/lib/private/NavigationManager.php b/lib/private/NavigationManager.php
index 56f55e80331..ac6f16190dc 100644
--- a/lib/private/NavigationManager.php
+++ b/lib/private/NavigationManager.php
@@ -171,8 +171,8 @@ class NavigationManager implements INavigationManager {
/**
* @inheritDoc
*/
- public function setActiveEntry($id) {
- $this->activeEntry = $id;
+ public function setActiveEntry($appId) {
+ $this->activeEntry = $appId;
}
/**
diff --git a/lib/private/OCM/Model/OCMProvider.php b/lib/private/OCM/Model/OCMProvider.php
new file mode 100644
index 00000000000..44f4fbebc10
--- /dev/null
+++ b/lib/private/OCM/Model/OCMProvider.php
@@ -0,0 +1,211 @@
+<?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 JsonSerializable;
+use OCP\OCM\Exceptions\OCMArgumentException;
+use OCP\OCM\Exceptions\OCMProviderException;
+use OCP\OCM\IOCMProvider;
+
+/**
+ * @since 28.0.0
+ */
+class OCMProvider implements IOCMProvider, JsonSerializable {
+ private bool $enabled = false;
+ private string $apiVersion = '';
+ private string $endPoint = '';
+ /** @var OCMResource[] */
+ private array $resourceTypes = [];
+
+ /**
+ * @param bool $enabled
+ *
+ * @return OCMProvider
+ */
+ public function setEnabled(bool $enabled): self {
+ $this->enabled = $enabled;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isEnabled(): bool {
+ return $this->enabled;
+ }
+
+ /**
+ * @param string $apiVersion
+ *
+ * @return OCMProvider
+ */
+ public function setApiVersion(string $apiVersion): self {
+ $this->apiVersion = $apiVersion;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getApiVersion(): string {
+ return $this->apiVersion;
+ }
+
+ /**
+ * @param string $endPoint
+ *
+ * @return OCMProvider
+ */
+ public function setEndPoint(string $endPoint): self {
+ $this->endPoint = $endPoint;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getEndPoint(): string {
+ return $this->endPoint;
+ }
+
+ /**
+ * @param OCMResource $resource
+ *
+ * @return $this
+ */
+ public function addResourceType(OCMResource $resource): self {
+ $this->resourceTypes[] = $resource;
+
+ return $this;
+ }
+
+ /**
+ * @param OCMResource[] $resourceTypes
+ *
+ * @return OCMProvider
+ */
+ public function setResourceTypes(array $resourceTypes): self {
+ $this->resourceTypes = $resourceTypes;
+
+ return $this;
+ }
+
+ /**
+ * @return OCMResource[]
+ */
+ public function getResourceTypes(): array {
+ 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 self
+ * @throws OCMProviderException in case a descent provider cannot be generated from data
+ * @see self::jsonSerialize()
+ */
+ public function import(array $data): self {
+ $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..12948aa8949
--- /dev/null
+++ b/lib/private/OCM/Model/OCMResource.php
@@ -0,0 +1,125 @@
+<?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 JsonSerializable;
+use OCP\OCM\IOCMResource;
+
+/**
+ * @since 28.0.0
+ */
+class OCMResource implements IOCMResource, JsonSerializable {
+ private string $name = '';
+ /** @var string[] */
+ private array $shareTypes = [];
+ /** @var array<string, string> */
+ private array $protocols = [];
+
+ /**
+ * @param string $name
+ *
+ * @return OCMResource
+ */
+ public function setName(string $name): self {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName(): string {
+ return $this->name;
+ }
+
+ /**
+ * @param string[] $shareTypes
+ *
+ * @return OCMResource
+ */
+ public function setShareTypes(array $shareTypes): self {
+ $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): self {
+ $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 self
+ * @see self::jsonSerialize()
+ */
+ public function import(array $data): self {
+ 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..e3b1d350813
--- /dev/null
+++ b/lib/private/OCM/OCMDiscoveryService.php
@@ -0,0 +1,138 @@
+<?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 OC\OCM\Model\OCMProvider;
+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 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, '/');
+ $provider = new OCMProvider();
+
+ if (!$skipCache) {
+ try {
+ $provider->import(json_decode($this->cache->get($remote) ?? '', true, 8, JSON_THROW_ON_ERROR) ?? []);
+ if ($this->supportedAPIVersion($provider->getApiVersion())) {
+ return $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
+ $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($provider->getApiVersion())) {
+ throw new OCMProviderException('API version not supported');
+ }
+
+ return $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 2c630531b17..9cead57c6a3 100644
--- a/lib/private/OCS/CoreCapabilities.php
+++ b/lib/private/OCS/CoreCapabilities.php
@@ -44,8 +44,6 @@ class CoreCapabilities implements ICapability {
/**
* Return this classes capabilities
- *
- * @return array
*/
public function getCapabilities() {
return [
diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php
index 3ce44913498..b9ea5ea1a07 100644
--- a/lib/private/Preview/Generator.php
+++ b/lib/private/Preview/Generator.php
@@ -44,8 +44,6 @@ use OCP\IStreamImage;
use OCP\Preview\BeforePreviewFetchedEvent;
use OCP\Preview\IProviderV2;
use OCP\Preview\IVersionedPreviewFile;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
class Generator {
public const SEMAPHORE_ID_ALL = 0x0a11;
@@ -59,8 +57,6 @@ class Generator {
private $appData;
/** @var GeneratorHelper */
private $helper;
- /** @var EventDispatcherInterface */
- private $legacyEventDispatcher;
/** @var IEventDispatcher */
private $eventDispatcher;
@@ -69,14 +65,12 @@ class Generator {
IPreview $previewManager,
IAppData $appData,
GeneratorHelper $helper,
- EventDispatcherInterface $legacyEventDispatcher,
IEventDispatcher $eventDispatcher
) {
$this->config = $config;
$this->previewManager = $previewManager;
$this->appData = $appData;
$this->helper = $helper;
- $this->legacyEventDispatcher = $legacyEventDispatcher;
$this->eventDispatcher = $eventDispatcher;
}
@@ -91,7 +85,7 @@ class Generator {
* @param int $height
* @param bool $crop
* @param string $mode
- * @param string $mimeType
+ * @param string|null $mimeType
* @return ISimpleFile
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
@@ -104,12 +98,12 @@ class Generator {
'mode' => $mode,
];
- $this->legacyEventDispatcher->dispatch(
- IPreview::EVENT,
- new GenericEvent($file, $specification)
- );
$this->eventDispatcher->dispatchTyped(new BeforePreviewFetchedEvent(
- $file
+ $file,
+ $width,
+ $height,
+ $crop,
+ $mode,
));
// since we only ask for one preview, and the generate method return the last one it created, it returns the one we want
@@ -657,6 +651,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 74f04e09250..7184f7e9e76 100644
--- a/lib/private/Preview/Imaginary.php
+++ b/lib/private/Preview/Imaginary.php
@@ -106,6 +106,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 +130,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'),
@@ -148,14 +166,14 @@ class Imaginary extends ProviderV2 {
'connect_timeout' => 3,
]);
} catch (\Exception $e) {
- $this->logger->error('Imaginary preview generation failed: ' . $e->getMessage(), [
+ $this->logger->info('Imaginary preview generation failed: ' . $e->getMessage(), [
'exception' => $e,
]);
return null;
}
if ($response->getStatusCode() !== 200) {
- $this->logger->error('Imaginary preview generation failed: ' . json_decode($response->getBody())['message']);
+ $this->logger->info('Imaginary preview generation failed: ' . json_decode($response->getBody())['message']);
return null;
}
diff --git a/lib/private/Preview/MP3.php b/lib/private/Preview/MP3.php
index ff6ff86c966..4c5f932f477 100644
--- a/lib/private/Preview/MP3.php
+++ b/lib/private/Preview/MP3.php
@@ -28,11 +28,10 @@
*/
namespace OC\Preview;
-use ID3Parser\ID3Parser;
-
use OCP\Files\File;
use OCP\IImage;
use Psr\Log\LoggerInterface;
+use wapmorgan\Mp3Info\Mp3Info;
class MP3 extends ProviderV2 {
/**
@@ -46,11 +45,12 @@ class MP3 extends ProviderV2 {
* {@inheritDoc}
*/
public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
- $getID3 = new ID3Parser();
-
$tmpPath = $this->getLocalFile($file);
+
try {
- $tags = $getID3->analyze($tmpPath);
+ $audio = new Mp3Info($tmpPath, true);
+ /** @var string|null|false $picture */
+ $picture = $audio->getCover();
} catch (\Throwable $e) {
\OC::$server->get(LoggerInterface::class)->info($e->getMessage(), [
'exception' => $e,
@@ -61,12 +61,7 @@ class MP3 extends ProviderV2 {
$this->cleanTmpFiles();
}
- $picture = isset($tags['id3v2']['APIC'][0]['data']) ? $tags['id3v2']['APIC'][0]['data'] : null;
- if (is_null($picture) && isset($tags['id3v2']['PIC'][0]['data'])) {
- $picture = $tags['id3v2']['PIC'][0]['data'];
- }
-
- if (!is_null($picture)) {
+ if (is_string($picture)) {
$image = new \OCP\Image();
$image->loadFromData($picture);
diff --git a/lib/private/Preview/MimeIconProvider.php b/lib/private/Preview/MimeIconProvider.php
new file mode 100644
index 00000000000..80073c307c9
--- /dev/null
+++ b/lib/private/Preview/MimeIconProvider.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @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\Preview;
+
+use OCA\Theming\ThemingDefaults;
+use OCP\App\IAppManager;
+use OCP\Files\IMimeTypeDetector;
+use OCP\IConfig;
+use OCP\IURLGenerator;
+use OCP\Preview\IMimeIconProvider;
+
+class MimeIconProvider implements IMimeIconProvider {
+ public function __construct(
+ protected IMimeTypeDetector $mimetypeDetector,
+ protected IConfig $config,
+ protected IURLGenerator $urlGenerator,
+ protected IAppManager $appManager,
+ protected ThemingDefaults $themingDefaults,
+ ) {
+ }
+
+ public function getMimeIconUrl(string $mime): null|string {
+ if (!$mime) {
+ return null;
+ }
+
+ // Fetch all the aliases
+ $aliases = $this->mimetypeDetector->getAllAliases();
+
+ // Remove comments
+ $aliases = array_filter($aliases, static function ($key) {
+ return !($key === '' || $key[0] === '_');
+ }, ARRAY_FILTER_USE_KEY);
+
+ // Map all the aliases recursively
+ foreach ($aliases as $alias => $value) {
+ if ($alias === $mime) {
+ $mime = $value;
+ }
+ }
+
+ $fileName = str_replace('/', '-', $mime);
+ if ($url = $this->searchfileName($fileName)) {
+ return $url;
+ }
+
+ $mimeType = explode('/', $mime)[0];
+ if ($url = $this->searchfileName($mimeType)) {
+ return $url;
+ }
+
+ return null;
+ }
+
+ private function searchfileName(string $fileName): null|string {
+ // If the file exists in the current enabled legacy
+ // custom theme, let's return it
+ $theme = $this->config->getSystemValue('theme', '');
+ if (!empty($theme)) {
+ $path = "/themes/$theme/core/img/filetypes/$fileName.svg";
+ if (file_exists(\OC::$SERVERROOT . $path)) {
+ return $this->urlGenerator->getAbsoluteURL($path);
+ }
+ }
+
+ // Previously, we used to pass this through Theming
+ // But it was only used to colour icons containing
+ // 0082c9. Since with vue we moved to inline svg icons,
+ // we can just use the default core icons.
+
+ // Finally, if the file exists in core, let's return it
+ $path = "/core/img/filetypes/$fileName.svg";
+ if (file_exists(\OC::$SERVERROOT . $path)) {
+ return $this->urlGenerator->getAbsoluteURL($path);
+ }
+
+ return null;
+ }
+}
diff --git a/lib/private/Preview/WatcherConnector.php b/lib/private/Preview/WatcherConnector.php
index d0eafed42c1..ffbdf825211 100644
--- a/lib/private/Preview/WatcherConnector.php
+++ b/lib/private/Preview/WatcherConnector.php
@@ -52,7 +52,7 @@ class WatcherConnector {
* @return Watcher
*/
private function getWatcher(): Watcher {
- return \OC::$server->query(Watcher::class);
+ return \OCP\Server::get(Watcher::class);
}
public function connectWatcher() {
diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php
index 814235f4212..3af6848686e 100644
--- a/lib/private/PreviewManager.php
+++ b/lib/private/PreviewManager.php
@@ -46,7 +46,6 @@ use OCP\IConfig;
use OCP\IPreview;
use OCP\IServerContainer;
use OCP\Preview\IProviderV2;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use function array_key_exists;
class PreviewManager implements IPreview {
@@ -54,7 +53,6 @@ class PreviewManager implements IPreview {
protected IRootFolder $rootFolder;
protected IAppData $appData;
protected IEventDispatcher $eventDispatcher;
- protected EventDispatcherInterface $legacyEventDispatcher;
private ?Generator $generator = null;
private GeneratorHelper $helper;
protected bool $providerListDirty = false;
@@ -81,7 +79,6 @@ class PreviewManager implements IPreview {
IRootFolder $rootFolder,
IAppData $appData,
IEventDispatcher $eventDispatcher,
- EventDispatcherInterface $legacyEventDispatcher,
GeneratorHelper $helper,
?string $userId,
Coordinator $bootstrapCoordinator,
@@ -93,7 +90,6 @@ class PreviewManager implements IPreview {
$this->rootFolder = $rootFolder;
$this->appData = $appData;
$this->eventDispatcher = $eventDispatcher;
- $this->legacyEventDispatcher = $legacyEventDispatcher;
$this->helper = $helper;
$this->userId = $userId;
$this->bootstrapCoordinator = $bootstrapCoordinator;
@@ -161,7 +157,6 @@ class PreviewManager implements IPreview {
$this->rootFolder,
$this->config
),
- $this->legacyEventDispatcher,
$this->eventDispatcher
);
}
diff --git a/lib/private/Profile/ProfileManager.php b/lib/private/Profile/ProfileManager.php
index 8de48994ff7..f20ae74768e 100644
--- a/lib/private/Profile/ProfileManager.php
+++ b/lib/private/Profile/ProfileManager.php
@@ -169,7 +169,7 @@ class ProfileManager {
return;
}
if (!$this->appManager->isEnabledForUser($action->getAppId(), $visitingUser)) {
- $this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the visiting user: ' . $visitingUser->getUID());
+ $this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the visiting user: ' . ($visitingUser ? $visitingUser->getUID() : '(user not connected)'));
return;
}
}
diff --git a/lib/private/RedisFactory.php b/lib/private/RedisFactory.php
index 6b509b1c1a9..4903a8713df 100644
--- a/lib/private/RedisFactory.php
+++ b/lib/private/RedisFactory.php
@@ -59,17 +59,8 @@ class RedisFactory {
throw new \Exception('Redis Cluster support is not available');
}
- if (isset($config['timeout'])) {
- $timeout = $config['timeout'];
- } else {
- $timeout = 0.0;
- }
-
- if (isset($config['read_timeout'])) {
- $readTimeout = $config['read_timeout'];
- } else {
- $readTimeout = 0.0;
- }
+ $timeout = $config['timeout'] ?? 0.0;
+ $readTimeout = $config['read_timeout'] ?? 0.0;
$auth = null;
if (isset($config['password']) && (string)$config['password'] !== '') {
@@ -103,19 +94,8 @@ class RedisFactory {
} else {
$this->instance = new \Redis();
- if (isset($config['host'])) {
- $host = $config['host'];
- } else {
- $host = '127.0.0.1';
- }
-
- if (isset($config['port'])) {
- $port = $config['port'];
- } elseif ($host[0] !== '/') {
- $port = 6379;
- } else {
- $port = null;
- }
+ $host = $config['host'] ?? '127.0.0.1';
+ $port = $config['port'] ?? ($host[0] !== '/' ? 6379 : null);
$this->eventLogger->start('connect:redis', 'Connect to redis and send AUTH, SELECT');
// Support for older phpredis versions not supporting connectionParameters
diff --git a/lib/private/Repair.php b/lib/private/Repair.php
index 330fa241b1e..05624a2423a 100644
--- a/lib/private/Repair.php
+++ b/lib/private/Repair.php
@@ -34,6 +34,7 @@
*/
namespace OC;
+use OC\Repair\AddRemoveOldTasksBackgroundJob;
use OC\Repair\CleanUpAbandonedApps;
use OCP\AppFramework\QueryException;
use OCP\AppFramework\Utility\ITimeFactory;
@@ -191,14 +192,14 @@ class Repair implements IOutput {
new FixMountStorages(\OC::$server->getDatabaseConnection()),
new UpdateLanguageCodes(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig()),
new AddLogRotateJob(\OC::$server->getJobList()),
- new ClearFrontendCaches(\OC::$server->getMemCacheFactory(), \OC::$server->query(JSCombiner::class)),
+ new ClearFrontendCaches(\OC::$server->getMemCacheFactory(), \OCP\Server::get(JSCombiner::class)),
\OCP\Server::get(ClearGeneratedAvatarCache::class),
new AddPreviewBackgroundCleanupJob(\OC::$server->getJobList()),
new AddCleanupUpdaterBackupsJob(\OC::$server->getJobList()),
new CleanupCardDAVPhotoCache(\OC::$server->getConfig(), \OC::$server->getAppDataDir('dav-photocache'), \OC::$server->get(LoggerInterface::class)),
new AddClenupLoginFlowV2BackgroundJob(\OC::$server->getJobList()),
- new RemoveLinkShares(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig(), \OC::$server->getGroupManager(), \OC::$server->getNotificationManager(), \OC::$server->query(ITimeFactory::class)),
- new ClearCollectionsAccessCache(\OC::$server->getConfig(), \OC::$server->query(IManager::class)),
+ new RemoveLinkShares(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig(), \OC::$server->getGroupManager(), \OC::$server->getNotificationManager(), \OCP\Server::get(ITimeFactory::class)),
+ new ClearCollectionsAccessCache(\OC::$server->getConfig(), \OCP\Server::get(IManager::class)),
\OCP\Server::get(ResetGeneratedAvatarFlag::class),
\OCP\Server::get(EncryptionLegacyCipher::class),
\OCP\Server::get(EncryptionMigration::class),
@@ -210,6 +211,7 @@ class Repair implements IOutput {
\OCP\Server::get(AddTokenCleanupJob::class),
\OCP\Server::get(CleanUpAbandonedApps::class),
\OCP\Server::get(AddMissingSecretJob::class),
+ \OCP\Server::get(AddRemoveOldTasksBackgroundJob::class),
];
}
diff --git a/lib/private/Repair/AddRemoveOldTasksBackgroundJob.php b/lib/private/Repair/AddRemoveOldTasksBackgroundJob.php
new file mode 100644
index 00000000000..94ae39f2183
--- /dev/null
+++ b/lib/private/Repair/AddRemoveOldTasksBackgroundJob.php
@@ -0,0 +1,47 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 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\Repair;
+
+use OC\TextProcessing\RemoveOldTasksBackgroundJob;
+use OCP\BackgroundJob\IJobList;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class AddRemoveOldTasksBackgroundJob implements IRepairStep {
+ private IJobList $jobList;
+
+ public function __construct(IJobList $jobList) {
+ $this->jobList = $jobList;
+ }
+
+ public function getName(): string {
+ return 'Add language model tasks cleanup job';
+ }
+
+ public function run(IOutput $output) {
+ $this->jobList->add(RemoveOldTasksBackgroundJob::class);
+ }
+}
diff --git a/lib/private/Search/Provider/File.php b/lib/private/Search/Provider/File.php
index 7046fea33d2..5ec0132cc03 100644
--- a/lib/private/Search/Provider/File.php
+++ b/lib/private/Search/Provider/File.php
@@ -53,9 +53,9 @@ class File extends PagedProvider {
*/
public function search($query, int $limit = null, int $offset = null) {
/** @var IRootFolder $rootFolder */
- $rootFolder = \OC::$server->query(IRootFolder::class);
+ $rootFolder = \OCP\Server::get(IRootFolder::class);
/** @var IUserSession $userSession */
- $userSession = \OC::$server->query(IUserSession::class);
+ $userSession = \OCP\Server::get(IUserSession::class);
$user = $userSession->getUser();
if (!$user) {
return [];
diff --git a/lib/private/Security/Bruteforce/Backend/DatabaseBackend.php b/lib/private/Security/Bruteforce/Backend/DatabaseBackend.php
new file mode 100644
index 00000000000..04f2a7b6397
--- /dev/null
+++ b/lib/private/Security/Bruteforce/Backend/DatabaseBackend.php
@@ -0,0 +1,116 @@
+<?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\Security\Bruteforce\Backend;
+
+use OCP\IDBConnection;
+
+class DatabaseBackend implements IBackend {
+ private const TABLE_NAME = 'bruteforce_attempts';
+
+ public function __construct(
+ private IDBConnection $db,
+ ) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getAttempts(
+ string $ipSubnet,
+ int $maxAgeTimestamp,
+ ?string $action = null,
+ ?array $metadata = null,
+ ): int {
+ $query = $this->db->getQueryBuilder();
+ $query->select($query->func()->count('*', 'attempts'))
+ ->from(self::TABLE_NAME)
+ ->where($query->expr()->gt('occurred', $query->createNamedParameter($maxAgeTimestamp)))
+ ->andWhere($query->expr()->eq('subnet', $query->createNamedParameter($ipSubnet)));
+
+ if ($action !== null) {
+ $query->andWhere($query->expr()->eq('action', $query->createNamedParameter($action)));
+
+ if ($metadata !== null) {
+ $query->andWhere($query->expr()->eq('metadata', $query->createNamedParameter(json_encode($metadata))));
+ }
+ }
+
+ $result = $query->executeQuery();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ return (int) $row['attempts'];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function resetAttempts(
+ string $ipSubnet,
+ ?string $action = null,
+ ?array $metadata = null,
+ ): void {
+ $query = $this->db->getQueryBuilder();
+ $query->delete(self::TABLE_NAME)
+ ->where($query->expr()->eq('subnet', $query->createNamedParameter($ipSubnet)));
+
+ if ($action !== null) {
+ $query->andWhere($query->expr()->eq('action', $query->createNamedParameter($action)));
+
+ if ($metadata !== null) {
+ $query->andWhere($query->expr()->eq('metadata', $query->createNamedParameter(json_encode($metadata))));
+ }
+ }
+
+ $query->executeStatement();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function registerAttempt(
+ string $ip,
+ string $ipSubnet,
+ int $timestamp,
+ string $action,
+ array $metadata = [],
+ ): void {
+ $values = [
+ 'ip' => $ip,
+ 'subnet' => $ipSubnet,
+ 'action' => $action,
+ 'metadata' => json_encode($metadata),
+ 'occurred' => $timestamp,
+ ];
+
+ $qb = $this->db->getQueryBuilder();
+ $qb->insert(self::TABLE_NAME);
+ foreach ($values as $column => $value) {
+ $qb->setValue($column, $qb->createNamedParameter($value));
+ }
+ $qb->executeStatement();
+ }
+}
diff --git a/lib/private/Security/Bruteforce/Backend/IBackend.php b/lib/private/Security/Bruteforce/Backend/IBackend.php
new file mode 100644
index 00000000000..4b40262e645
--- /dev/null
+++ b/lib/private/Security/Bruteforce/Backend/IBackend.php
@@ -0,0 +1,82 @@
+<?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\Security\Bruteforce\Backend;
+
+/**
+ * Interface IBackend defines a storage backend for the bruteforce data. It
+ * should be noted that writing and reading brute force data is an expensive
+ * operation and one should thus make sure to only use sufficient fast backends.
+ */
+interface IBackend {
+ /**
+ * Gets the number of attempts for the specified subnet (and further filters)
+ *
+ * @param string $ipSubnet
+ * @param int $maxAgeTimestamp
+ * @param ?string $action Optional action to further limit attempts
+ * @param ?array $metadata Optional metadata stored to further limit attempts (Only considered when $action is set)
+ * @return int
+ * @since 28.0.0
+ */
+ public function getAttempts(
+ string $ipSubnet,
+ int $maxAgeTimestamp,
+ ?string $action = null,
+ ?array $metadata = null,
+ ): int;
+
+ /**
+ * Reset the attempts for the specified subnet (and further filters)
+ *
+ * @param string $ipSubnet
+ * @param ?string $action Optional action to further limit attempts
+ * @param ?array $metadata Optional metadata stored to further limit attempts(Only considered when $action is set)
+ * @since 28.0.0
+ */
+ public function resetAttempts(
+ string $ipSubnet,
+ ?string $action = null,
+ ?array $metadata = null,
+ ): void;
+
+ /**
+ * Register a failed attempt to bruteforce a security control
+ *
+ * @param string $ip
+ * @param string $ipSubnet
+ * @param int $timestamp
+ * @param string $action
+ * @param array $metadata Optional metadata stored to further limit attempts when getting
+ * @since 28.0.0
+ */
+ public function registerAttempt(
+ string $ip,
+ string $ipSubnet,
+ int $timestamp,
+ string $action,
+ array $metadata = [],
+ ): void;
+}
diff --git a/lib/private/Security/Bruteforce/Backend/MemoryCacheBackend.php b/lib/private/Security/Bruteforce/Backend/MemoryCacheBackend.php
new file mode 100644
index 00000000000..432e99700fe
--- /dev/null
+++ b/lib/private/Security/Bruteforce/Backend/MemoryCacheBackend.php
@@ -0,0 +1,161 @@
+<?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\Security\Bruteforce\Backend;
+
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\ICache;
+use OCP\ICacheFactory;
+
+class MemoryCacheBackend implements IBackend {
+ private ICache $cache;
+
+ public function __construct(
+ ICacheFactory $cacheFactory,
+ private ITimeFactory $timeFactory,
+ ) {
+ $this->cache = $cacheFactory->createDistributed(__CLASS__);
+ }
+
+ private function hash(
+ null|string|array $data,
+ ): ?string {
+ if ($data === null) {
+ return null;
+ }
+ if (!is_string($data)) {
+ $data = json_encode($data);
+ }
+ return hash('sha1', $data);
+ }
+
+ private function getExistingAttempts(string $identifier): array {
+ $cachedAttempts = $this->cache->get($identifier);
+ if ($cachedAttempts === null) {
+ return [];
+ }
+
+ $cachedAttempts = json_decode($cachedAttempts, true);
+ if (\is_array($cachedAttempts)) {
+ return $cachedAttempts;
+ }
+
+ return [];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getAttempts(
+ string $ipSubnet,
+ int $maxAgeTimestamp,
+ ?string $action = null,
+ ?array $metadata = null,
+ ): int {
+ $identifier = $this->hash($ipSubnet);
+ $actionHash = $this->hash($action);
+ $metadataHash = $this->hash($metadata);
+ $existingAttempts = $this->getExistingAttempts($identifier);
+
+ $count = 0;
+ foreach ($existingAttempts as $info) {
+ [$occurredTime, $attemptAction, $attemptMetadata] = explode('#', $info, 3);
+ if ($action === null || $attemptAction === $actionHash) {
+ if ($metadata === null || $attemptMetadata === $metadataHash) {
+ if ($occurredTime > $maxAgeTimestamp) {
+ $count++;
+ }
+ }
+ }
+ }
+
+ return $count;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function resetAttempts(
+ string $ipSubnet,
+ ?string $action = null,
+ ?array $metadata = null,
+ ): void {
+ $identifier = $this->hash($ipSubnet);
+ if ($action === null) {
+ $this->cache->remove($identifier);
+ } else {
+ $actionHash = $this->hash($action);
+ $metadataHash = $this->hash($metadata);
+ $existingAttempts = $this->getExistingAttempts($identifier);
+ $maxAgeTimestamp = $this->timeFactory->getTime() - 12 * 3600;
+
+ foreach ($existingAttempts as $key => $info) {
+ [$occurredTime, $attemptAction, $attemptMetadata] = explode('#', $info, 3);
+ if ($attemptAction === $actionHash) {
+ if ($metadata === null || $attemptMetadata === $metadataHash) {
+ unset($existingAttempts[$key]);
+ } elseif ($occurredTime < $maxAgeTimestamp) {
+ unset($existingAttempts[$key]);
+ }
+ }
+ }
+
+ if (!empty($existingAttempts)) {
+ $this->cache->set($identifier, json_encode($existingAttempts), 12 * 3600);
+ } else {
+ $this->cache->remove($identifier);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function registerAttempt(
+ string $ip,
+ string $ipSubnet,
+ int $timestamp,
+ string $action,
+ array $metadata = [],
+ ): void {
+ $identifier = $this->hash($ipSubnet);
+ $existingAttempts = $this->getExistingAttempts($identifier);
+ $maxAgeTimestamp = $this->timeFactory->getTime() - 12 * 3600;
+
+ // Unset all attempts that are already expired
+ foreach ($existingAttempts as $key => $info) {
+ [$occurredTime,] = explode('#', $info, 3);
+ if ($occurredTime < $maxAgeTimestamp) {
+ unset($existingAttempts[$key]);
+ }
+ }
+ $existingAttempts = array_values($existingAttempts);
+
+ // Store the new attempt
+ $existingAttempts[] = $timestamp . '#' . $this->hash($action) . '#' . $this->hash($metadata);
+
+ $this->cache->set($identifier, json_encode($existingAttempts), 12 * 3600);
+ }
+}
diff --git a/lib/private/Security/Bruteforce/Capabilities.php b/lib/private/Security/Bruteforce/Capabilities.php
index 60cf3086f2d..b50eea0b7af 100644
--- a/lib/private/Security/Bruteforce/Capabilities.php
+++ b/lib/private/Security/Bruteforce/Capabilities.php
@@ -3,9 +3,11 @@
declare(strict_types=1);
/**
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
* @copyright Copyright (c) 2017 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author J0WI <J0WI@users.noreply.github.com>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -30,35 +32,24 @@ namespace OC\Security\Bruteforce;
use OCP\Capabilities\IPublicCapability;
use OCP\Capabilities\IInitialStateExcludedCapability;
use OCP\IRequest;
+use OCP\Security\Bruteforce\IThrottler;
class Capabilities implements IPublicCapability, IInitialStateExcludedCapability {
- /** @var IRequest */
- private $request;
-
- /** @var Throttler */
- private $throttler;
+ public function __construct(
+ private IRequest $request,
+ private IThrottler $throttler,
+ ) {
+ }
/**
- * Capabilities constructor.
- *
- * @param IRequest $request
- * @param Throttler $throttler
+ * @return array{bruteforce: array{delay: int, allow-listed: bool}}
*/
- public function __construct(IRequest $request,
- Throttler $throttler) {
- $this->request = $request;
- $this->throttler = $throttler;
- }
-
public function getCapabilities(): array {
- if (version_compare(\OC::$server->getConfig()->getSystemValueString('version', '0.0.0.0'), '12.0.0.0', '<')) {
- return [];
- }
-
return [
'bruteforce' => [
- 'delay' => $this->throttler->getDelay($this->request->getRemoteAddress())
- ]
+ 'delay' => $this->throttler->getDelay($this->request->getRemoteAddress()),
+ 'allow-listed' => $this->throttler->isBypassListed($this->request->getRemoteAddress()),
+ ],
];
}
}
diff --git a/lib/private/Security/Bruteforce/Throttler.php b/lib/private/Security/Bruteforce/Throttler.php
index 8c0f6f3d1a9..2803373e8ba 100644
--- a/lib/private/Security/Bruteforce/Throttler.php
+++ b/lib/private/Security/Bruteforce/Throttler.php
@@ -3,6 +3,7 @@
declare(strict_types=1);
/**
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
* @author Bjoern Schiessle <bjoern@schiessle.org>
@@ -32,10 +33,10 @@ declare(strict_types=1);
*/
namespace OC\Security\Bruteforce;
+use OC\Security\Bruteforce\Backend\IBackend;
use OC\Security\Normalizer\IpAddress;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
-use OCP\IDBConnection;
use OCP\Security\Bruteforce\IThrottler;
use OCP\Security\Bruteforce\MaxDelayReached;
use Psr\Log\LoggerInterface;
@@ -54,59 +55,21 @@ use Psr\Log\LoggerInterface;
* @package OC\Security\Bruteforce
*/
class Throttler implements IThrottler {
- public const LOGIN_ACTION = 'login';
-
- /** @var IDBConnection */
- private $db;
- /** @var ITimeFactory */
- private $timeFactory;
- private LoggerInterface $logger;
- /** @var IConfig */
- private $config;
/** @var bool[] */
- private $hasAttemptsDeleted = [];
-
- public function __construct(IDBConnection $db,
- ITimeFactory $timeFactory,
- LoggerInterface $logger,
- IConfig $config) {
- $this->db = $db;
- $this->timeFactory = $timeFactory;
- $this->logger = $logger;
- $this->config = $config;
- }
-
- /**
- * Convert a number of seconds into the appropriate DateInterval
- *
- * @param int $expire
- * @return \DateInterval
- */
- private function getCutoff(int $expire): \DateInterval {
- $d1 = new \DateTime();
- $d2 = clone $d1;
- $d2->sub(new \DateInterval('PT' . $expire . 'S'));
- return $d2->diff($d1);
- }
-
- /**
- * Calculate the cut off timestamp
- *
- * @param float $maxAgeHours
- * @return int
- */
- private function getCutoffTimestamp(float $maxAgeHours = 12.0): int {
- return (new \DateTime())
- ->sub($this->getCutoff((int) ($maxAgeHours * 3600)))
- ->getTimestamp();
+ private array $hasAttemptsDeleted = [];
+ /** @var bool[] */
+ private array $ipIsWhitelisted = [];
+
+ public function __construct(
+ private ITimeFactory $timeFactory,
+ private LoggerInterface $logger,
+ private IConfig $config,
+ private IBackend $backend,
+ ) {
}
/**
- * Register a failed attempt to bruteforce a security control
- *
- * @param string $action
- * @param string $ip
- * @param array $metadata Optional metadata logged to the database
+ * {@inheritDoc}
*/
public function registerAttempt(string $action,
string $ip,
@@ -117,13 +80,9 @@ class Throttler implements IThrottler {
}
$ipAddress = new IpAddress($ip);
- $values = [
- 'action' => $action,
- 'occurred' => $this->timeFactory->getTime(),
- 'ip' => (string)$ipAddress,
- 'subnet' => $ipAddress->getSubnet(),
- 'metadata' => json_encode($metadata),
- ];
+ if ($this->isBypassListed((string)$ipAddress)) {
+ return;
+ }
$this->logger->notice(
sprintf(
@@ -136,12 +95,13 @@ class Throttler implements IThrottler {
]
);
- $qb = $this->db->getQueryBuilder();
- $qb->insert('bruteforce_attempts');
- foreach ($values as $column => $value) {
- $qb->setValue($column, $qb->createNamedParameter($value));
- }
- $qb->execute();
+ $this->backend->registerAttempt(
+ (string)$ipAddress,
+ $ipAddress->getSubnet(),
+ $this->timeFactory->getTime(),
+ $action,
+ $metadata
+ );
}
/**
@@ -150,8 +110,13 @@ class Throttler implements IThrottler {
* @param string $ip
* @return bool
*/
- private function isIPWhitelisted(string $ip): bool {
+ public function isBypassListed(string $ip): bool {
+ if (isset($this->ipIsWhitelisted[$ip])) {
+ return $this->ipIsWhitelisted[$ip];
+ }
+
if (!$this->config->getSystemValueBool('auth.bruteforce.protection.enabled', true)) {
+ $this->ipIsWhitelisted[$ip] = true;
return true;
}
@@ -165,6 +130,7 @@ class Throttler implements IThrottler {
} elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$type = 6;
} else {
+ $this->ipIsWhitelisted[$ip] = false;
return false;
}
@@ -202,20 +168,26 @@ class Throttler implements IThrottler {
}
if ($valid === true) {
+ $this->ipIsWhitelisted[$ip] = true;
return true;
}
}
+ $this->ipIsWhitelisted[$ip] = false;
return false;
}
/**
- * Get the throttling delay (in milliseconds)
- *
- * @param string $ip
- * @param string $action optionally filter by action
- * @param float $maxAgeHours
- * @return int
+ * {@inheritDoc}
+ */
+ public function showBruteforceWarning(string $ip, string $action = ''): bool {
+ $attempts = $this->getAttempts($ip, $action);
+ // 4 failed attempts is the last delay below 5 seconds
+ return $attempts >= 4;
+ }
+
+ /**
+ * {@inheritDoc}
*/
public function getAttempts(string $ip, string $action = '', float $maxAgeHours = 12): int {
if ($maxAgeHours > 48) {
@@ -228,35 +200,21 @@ class Throttler implements IThrottler {
}
$ipAddress = new IpAddress($ip);
- if ($this->isIPWhitelisted((string)$ipAddress)) {
+ if ($this->isBypassListed((string)$ipAddress)) {
return 0;
}
- $cutoffTime = $this->getCutoffTimestamp($maxAgeHours);
-
- $qb = $this->db->getQueryBuilder();
- $qb->select($qb->func()->count('*', 'attempts'))
- ->from('bruteforce_attempts')
- ->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime)))
- ->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($ipAddress->getSubnet())));
-
- if ($action !== '') {
- $qb->andWhere($qb->expr()->eq('action', $qb->createNamedParameter($action)));
- }
-
- $result = $qb->execute();
- $row = $result->fetch();
- $result->closeCursor();
+ $maxAgeTimestamp = (int) ($this->timeFactory->getTime() - 3600 * $maxAgeHours);
- return (int) $row['attempts'];
+ return $this->backend->getAttempts(
+ $ipAddress->getSubnet(),
+ $maxAgeTimestamp,
+ $action !== '' ? $action : null,
+ );
}
/**
- * Get the throttling delay (in milliseconds)
- *
- * @param string $ip
- * @param string $action optionally filter by action
- * @return int
+ * {@inheritDoc}
*/
public function getDelay(string $ip, string $action = ''): int {
$attempts = $this->getAttempts($ip, $action);
@@ -278,69 +236,58 @@ class Throttler implements IThrottler {
}
/**
- * Reset the throttling delay for an IP address, action and metadata
- *
- * @param string $ip
- * @param string $action
- * @param array $metadata
+ * {@inheritDoc}
*/
public function resetDelay(string $ip, string $action, array $metadata): void {
- $ipAddress = new IpAddress($ip);
- if ($this->isIPWhitelisted((string)$ipAddress)) {
+ // No need to log if the bruteforce protection is disabled
+ if (!$this->config->getSystemValueBool('auth.bruteforce.protection.enabled', true)) {
return;
}
- $cutoffTime = $this->getCutoffTimestamp();
-
- $qb = $this->db->getQueryBuilder();
- $qb->delete('bruteforce_attempts')
- ->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime)))
- ->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($ipAddress->getSubnet())))
- ->andWhere($qb->expr()->eq('action', $qb->createNamedParameter($action)))
- ->andWhere($qb->expr()->eq('metadata', $qb->createNamedParameter(json_encode($metadata))));
+ $ipAddress = new IpAddress($ip);
+ if ($this->isBypassListed((string)$ipAddress)) {
+ return;
+ }
- $qb->executeStatement();
+ $this->backend->resetAttempts(
+ $ipAddress->getSubnet(),
+ $action,
+ $metadata,
+ );
$this->hasAttemptsDeleted[$action] = true;
}
/**
- * Reset the throttling delay for an IP address
- *
- * @param string $ip
+ * {@inheritDoc}
*/
public function resetDelayForIP(string $ip): void {
- $cutoffTime = $this->getCutoffTimestamp();
+ // No need to log if the bruteforce protection is disabled
+ if (!$this->config->getSystemValueBool('auth.bruteforce.protection.enabled', true)) {
+ return;
+ }
- $qb = $this->db->getQueryBuilder();
- $qb->delete('bruteforce_attempts')
- ->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime)))
- ->andWhere($qb->expr()->eq('ip', $qb->createNamedParameter($ip)));
+ $ipAddress = new IpAddress($ip);
+ if ($this->isBypassListed((string)$ipAddress)) {
+ return;
+ }
- $qb->execute();
+ $this->backend->resetAttempts($ipAddress->getSubnet());
}
/**
- * Will sleep for the defined amount of time
- *
- * @param string $ip
- * @param string $action optionally filter by action
- * @return int the time spent sleeping
+ * {@inheritDoc}
*/
public function sleepDelay(string $ip, string $action = ''): int {
$delay = $this->getDelay($ip, $action);
- usleep($delay * 1000);
+ if (!$this->config->getSystemValueBool('auth.bruteforce.protection.testing')) {
+ usleep($delay * 1000);
+ }
return $delay;
}
/**
- * Will sleep for the defined amount of time unless maximum was reached in the last 30 minutes
- * In this case a "429 Too Many Request" exception is thrown
- *
- * @param string $ip
- * @param string $action optionally filter by action
- * @return int the time spent sleeping
- * @throws MaxDelayReached when reached the maximum
+ * {@inheritDoc}
*/
public function sleepDelayOrThrowOnMax(string $ip, string $action = ''): int {
$delay = $this->getDelay($ip, $action);
@@ -359,7 +306,9 @@ class Throttler implements IThrottler {
'delay' => $delay,
]);
}
- usleep($delay * 1000);
+ if (!$this->config->getSystemValueBool('auth.bruteforce.protection.testing')) {
+ usleep($delay * 1000);
+ }
return $delay;
}
}
diff --git a/lib/private/Security/CSP/ContentSecurityPolicy.php b/lib/private/Security/CSP/ContentSecurityPolicy.php
index 8d9551c8978..e2d115cf34e 100644
--- a/lib/private/Security/CSP/ContentSecurityPolicy.php
+++ b/lib/private/Security/CSP/ContentSecurityPolicy.php
@@ -64,6 +64,14 @@ class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy
$this->evalScriptAllowed = $evalScriptAllowed;
}
+ public function isEvalWasmAllowed(): ?bool {
+ return $this->evalWasmAllowed;
+ }
+
+ public function setEvalWasmAllowed(bool $evalWasmAllowed): void {
+ $this->evalWasmAllowed = $evalWasmAllowed;
+ }
+
/**
* @return array
*/
diff --git a/lib/private/Security/IdentityProof/Key.php b/lib/private/Security/IdentityProof/Key.php
index 349ffd3c15a..bde828a3859 100644
--- a/lib/private/Security/IdentityProof/Key.php
+++ b/lib/private/Security/IdentityProof/Key.php
@@ -27,18 +27,10 @@ declare(strict_types=1);
namespace OC\Security\IdentityProof;
class Key {
- /** @var string */
- private $publicKey;
- /** @var string */
- private $privateKey;
-
- /**
- * @param string $publicKey
- * @param string $privateKey
- */
- public function __construct(string $publicKey, string $privateKey) {
- $this->publicKey = $publicKey;
- $this->privateKey = $privateKey;
+ public function __construct(
+ private string $publicKey,
+ private string $privateKey,
+ ) {
}
public function getPrivate(): string {
diff --git a/lib/private/Security/IdentityProof/Manager.php b/lib/private/Security/IdentityProof/Manager.php
index c92d7390969..49b9bb10c3e 100644
--- a/lib/private/Security/IdentityProof/Manager.php
+++ b/lib/private/Security/IdentityProof/Manager.php
@@ -37,23 +37,15 @@ use OCP\Security\ICrypto;
use Psr\Log\LoggerInterface;
class Manager {
- /** @var IAppData */
- private $appData;
- /** @var ICrypto */
- private $crypto;
- /** @var IConfig */
- private $config;
- private LoggerInterface $logger;
-
- public function __construct(Factory $appDataFactory,
- ICrypto $crypto,
- IConfig $config,
- LoggerInterface $logger
+ private IAppData $appData;
+
+ public function __construct(
+ Factory $appDataFactory,
+ private ICrypto $crypto,
+ private IConfig $config,
+ private LoggerInterface $logger,
) {
$this->appData = $appDataFactory->get('identityproof');
- $this->crypto = $crypto;
- $this->config = $config;
- $this->logger = $logger;
}
/**
@@ -94,7 +86,6 @@ class Manager {
* Note: If a key already exists it will be overwritten
*
* @param string $id key id
- * @return Key
* @throws \RuntimeException
*/
protected function generateKey(string $id): Key {
@@ -117,8 +108,6 @@ class Manager {
/**
* Get key for a specific id
*
- * @param string $id
- * @return Key
* @throws \RuntimeException
*/
protected function retrieveKey(string $id): Key {
@@ -137,8 +126,6 @@ class Manager {
/**
* Get public and private key for $user
*
- * @param IUser $user
- * @return Key
* @throws \RuntimeException
*/
public function getKey(IUser $user): Key {
@@ -149,7 +136,6 @@ class Manager {
/**
* Get instance wide public and private key
*
- * @return Key
* @throws \RuntimeException
*/
public function getSystemKey(): Key {
diff --git a/lib/private/Security/IdentityProof/Signer.php b/lib/private/Security/IdentityProof/Signer.php
index 7431bfe815f..1458390c327 100644
--- a/lib/private/Security/IdentityProof/Signer.php
+++ b/lib/private/Security/IdentityProof/Signer.php
@@ -32,32 +32,16 @@ use OCP\IUser;
use OCP\IUserManager;
class Signer {
- /** @var Manager */
- private $keyManager;
- /** @var ITimeFactory */
- private $timeFactory;
- /** @var IUserManager */
- private $userManager;
-
- /**
- * @param Manager $keyManager
- * @param ITimeFactory $timeFactory
- * @param IUserManager $userManager
- */
- public function __construct(Manager $keyManager,
- ITimeFactory $timeFactory,
- IUserManager $userManager) {
- $this->keyManager = $keyManager;
- $this->timeFactory = $timeFactory;
- $this->userManager = $userManager;
+ public function __construct(
+ private Manager $keyManager,
+ private ITimeFactory $timeFactory,
+ private IUserManager $userManager,
+ ) {
}
/**
* Returns a signed blob for $data
*
- * @param string $type
- * @param array $data
- * @param IUser $user
* @return array ['message', 'signature']
*/
public function sign(string $type, array $data, IUser $user): array {
@@ -79,13 +63,10 @@ class Signer {
/**
* Whether the data is signed properly
*
- * @param array $data
- * @return bool
*/
public function verify(array $data): bool {
- if (isset($data['message'])
+ if (isset($data['message']['signer'])
&& isset($data['signature'])
- && isset($data['message']['signer'])
) {
$location = strrpos($data['message']['signer'], '@');
$userId = substr($data['message']['signer'], 0, $location);
diff --git a/lib/private/Security/RateLimiting/Backend/DatabaseBackend.php b/lib/private/Security/RateLimiting/Backend/DatabaseBackend.php
index d1631a8d0ae..41f50a90b5c 100644
--- a/lib/private/Security/RateLimiting/Backend/DatabaseBackend.php
+++ b/lib/private/Security/RateLimiting/Backend/DatabaseBackend.php
@@ -28,6 +28,7 @@ declare(strict_types=1);
namespace OC\Security\RateLimiting\Backend;
use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
use OCP\IDBConnection;
@@ -35,38 +36,22 @@ use OCP\IDBConnection;
class DatabaseBackend implements IBackend {
private const TABLE_NAME = 'ratelimit_entries';
- /** @var IConfig */
- private $config;
- /** @var IDBConnection */
- private $dbConnection;
- /** @var ITimeFactory */
- private $timeFactory;
-
public function __construct(
- IConfig $config,
- IDBConnection $dbConnection,
- ITimeFactory $timeFactory
+ private IConfig $config,
+ private IDBConnection $dbConnection,
+ private ITimeFactory $timeFactory
) {
- $this->config = $config;
- $this->dbConnection = $dbConnection;
- $this->timeFactory = $timeFactory;
}
- /**
- * @param string $methodIdentifier
- * @param string $userIdentifier
- * @return string
- */
- private function hash(string $methodIdentifier,
- string $userIdentifier): string {
+ private function hash(
+ string $methodIdentifier,
+ string $userIdentifier,
+ ): string {
return hash('sha512', $methodIdentifier . $userIdentifier);
}
/**
- * @param string $identifier
- * @param int $seconds
- * @return int
- * @throws \OCP\DB\Exception
+ * @throws Exception
*/
private function getExistingAttemptCount(
string $identifier
@@ -97,8 +82,10 @@ class DatabaseBackend implements IBackend {
/**
* {@inheritDoc}
*/
- public function getAttempts(string $methodIdentifier,
- string $userIdentifier): int {
+ public function getAttempts(
+ string $methodIdentifier,
+ string $userIdentifier,
+ ): int {
$identifier = $this->hash($methodIdentifier, $userIdentifier);
return $this->getExistingAttemptCount($identifier);
}
@@ -106,9 +93,11 @@ class DatabaseBackend implements IBackend {
/**
* {@inheritDoc}
*/
- public function registerAttempt(string $methodIdentifier,
- string $userIdentifier,
- int $period) {
+ public function registerAttempt(
+ string $methodIdentifier,
+ string $userIdentifier,
+ int $period,
+ ): void {
$identifier = $this->hash($methodIdentifier, $userIdentifier);
$deleteAfter = $this->timeFactory->getDateTime()->add(new \DateInterval("PT{$period}S"));
diff --git a/lib/private/Security/RateLimiting/Backend/IBackend.php b/lib/private/Security/RateLimiting/Backend/IBackend.php
index 960bfd2d159..24715391a96 100644
--- a/lib/private/Security/RateLimiting/Backend/IBackend.php
+++ b/lib/private/Security/RateLimiting/Backend/IBackend.php
@@ -39,10 +39,11 @@ interface IBackend {
*
* @param string $methodIdentifier Identifier for the method
* @param string $userIdentifier Identifier for the user
- * @return int
*/
- public function getAttempts(string $methodIdentifier,
- string $userIdentifier): int;
+ public function getAttempts(
+ string $methodIdentifier,
+ string $userIdentifier,
+ ): int;
/**
* Registers an attempt
@@ -51,7 +52,9 @@ interface IBackend {
* @param string $userIdentifier Identifier for the user
* @param int $period Period in seconds how long this attempt should be stored
*/
- public function registerAttempt(string $methodIdentifier,
- string $userIdentifier,
- int $period);
+ public function registerAttempt(
+ string $methodIdentifier,
+ string $userIdentifier,
+ int $period,
+ );
}
diff --git a/lib/private/Security/RateLimiting/Backend/MemoryCacheBackend.php b/lib/private/Security/RateLimiting/Backend/MemoryCacheBackend.php
index 4bcb459c64e..b59178c7d7b 100644
--- a/lib/private/Security/RateLimiting/Backend/MemoryCacheBackend.php
+++ b/lib/private/Security/RateLimiting/Backend/MemoryCacheBackend.php
@@ -42,36 +42,23 @@ use OCP\IConfig;
* @package OC\Security\RateLimiting\Backend
*/
class MemoryCacheBackend implements IBackend {
- /** @var IConfig */
- private $config;
- /** @var ICache */
- private $cache;
- /** @var ITimeFactory */
- private $timeFactory;
+ private ICache $cache;
public function __construct(
- IConfig $config,
+ private IConfig $config,
ICacheFactory $cacheFactory,
- ITimeFactory $timeFactory) {
- $this->config = $config;
+ private ITimeFactory $timeFactory,
+ ) {
$this->cache = $cacheFactory->createDistributed(__CLASS__);
- $this->timeFactory = $timeFactory;
}
- /**
- * @param string $methodIdentifier
- * @param string $userIdentifier
- * @return string
- */
- private function hash(string $methodIdentifier,
- string $userIdentifier): string {
+ private function hash(
+ string $methodIdentifier,
+ string $userIdentifier,
+ ): string {
return hash('sha512', $methodIdentifier . $userIdentifier);
}
- /**
- * @param string $identifier
- * @return array
- */
private function getExistingAttempts(string $identifier): array {
$cachedAttempts = $this->cache->get($identifier);
if ($cachedAttempts === null) {
@@ -89,8 +76,10 @@ class MemoryCacheBackend implements IBackend {
/**
* {@inheritDoc}
*/
- public function getAttempts(string $methodIdentifier,
- string $userIdentifier): int {
+ public function getAttempts(
+ string $methodIdentifier,
+ string $userIdentifier,
+ ): int {
$identifier = $this->hash($methodIdentifier, $userIdentifier);
$existingAttempts = $this->getExistingAttempts($identifier);
@@ -108,9 +97,11 @@ class MemoryCacheBackend implements IBackend {
/**
* {@inheritDoc}
*/
- public function registerAttempt(string $methodIdentifier,
- string $userIdentifier,
- int $period) {
+ public function registerAttempt(
+ string $methodIdentifier,
+ string $userIdentifier,
+ int $period,
+ ): void {
$identifier = $this->hash($methodIdentifier, $userIdentifier);
$existingAttempts = $this->getExistingAttempts($identifier);
$currentTime = $this->timeFactory->getTime();
diff --git a/lib/private/Security/RateLimiting/Limiter.php b/lib/private/Security/RateLimiting/Limiter.php
index 7848a5b75a7..c8c0e2ce101 100644
--- a/lib/private/Security/RateLimiting/Limiter.php
+++ b/lib/private/Security/RateLimiting/Limiter.php
@@ -32,27 +32,21 @@ use OC\Security\RateLimiting\Exception\RateLimitExceededException;
use OCP\IUser;
class Limiter {
- /** @var IBackend */
- private $backend;
-
- /**
- * @param IBackend $backend
- */
- public function __construct(IBackend $backend) {
- $this->backend = $backend;
+ public function __construct(
+ private IBackend $backend,
+ ) {
}
/**
- * @param string $methodIdentifier
- * @param string $userIdentifier
* @param int $period in seconds
- * @param int $limit
* @throws RateLimitExceededException
*/
- private function register(string $methodIdentifier,
- string $userIdentifier,
- int $period,
- int $limit): void {
+ private function register(
+ string $methodIdentifier,
+ string $userIdentifier,
+ int $period,
+ int $limit,
+ ): void {
$existingAttempts = $this->backend->getAttempts($methodIdentifier, $userIdentifier);
if ($existingAttempts >= $limit) {
throw new RateLimitExceededException();
@@ -64,16 +58,15 @@ class Limiter {
/**
* Registers attempt for an anonymous request
*
- * @param string $identifier
- * @param int $anonLimit
* @param int $anonPeriod in seconds
- * @param string $ip
* @throws RateLimitExceededException
*/
- public function registerAnonRequest(string $identifier,
- int $anonLimit,
- int $anonPeriod,
- string $ip): void {
+ public function registerAnonRequest(
+ string $identifier,
+ int $anonLimit,
+ int $anonPeriod,
+ string $ip,
+ ): void {
$ipSubnet = (new IpAddress($ip))->getSubnet();
$anonHashIdentifier = hash('sha512', 'anon::' . $identifier . $ipSubnet);
@@ -83,16 +76,15 @@ class Limiter {
/**
* Registers attempt for an authenticated request
*
- * @param string $identifier
- * @param int $userLimit
* @param int $userPeriod in seconds
- * @param IUser $user
* @throws RateLimitExceededException
*/
- public function registerUserRequest(string $identifier,
- int $userLimit,
- int $userPeriod,
- IUser $user): void {
+ public function registerUserRequest(
+ string $identifier,
+ int $userLimit,
+ int $userPeriod,
+ IUser $user,
+ ): void {
$userHashIdentifier = hash('sha512', 'user::' . $identifier . $user->getUID());
$this->register($identifier, $userHashIdentifier, $userPeriod, $userLimit);
}
diff --git a/lib/private/Security/VerificationToken/CleanUpJob.php b/lib/private/Security/VerificationToken/CleanUpJob.php
index 4510dcffe0a..1f4af046451 100644
--- a/lib/private/Security/VerificationToken/CleanUpJob.php
+++ b/lib/private/Security/VerificationToken/CleanUpJob.php
@@ -39,18 +39,17 @@ class CleanUpJob extends Job {
protected ?string $userId = null;
protected ?string $subject = null;
protected ?string $pwdPrefix = null;
- private IConfig $config;
- private IVerificationToken $verificationToken;
- private IUserManager $userManager;
- public function __construct(ITimeFactory $time, IConfig $config, IVerificationToken $verificationToken, IUserManager $userManager) {
+ public function __construct(
+ ITimeFactory $time,
+ private IConfig $config,
+ private IVerificationToken $verificationToken,
+ private IUserManager $userManager,
+ ) {
parent::__construct($time);
- $this->config = $config;
- $this->verificationToken = $verificationToken;
- $this->userManager = $userManager;
}
- public function setArgument($argument) {
+ public function setArgument($argument): void {
parent::setArgument($argument);
$args = \json_decode($argument, true);
$this->userId = (string)$args['userId'];
@@ -59,7 +58,7 @@ class CleanUpJob extends Job {
$this->runNotBefore = (int)$args['notBefore'];
}
- protected function run($argument) {
+ protected function run($argument): void {
try {
$user = $this->userManager->get($this->userId);
if ($user === null) {
diff --git a/lib/private/Security/VerificationToken/VerificationToken.php b/lib/private/Security/VerificationToken/VerificationToken.php
index 52c3f62b813..5f606d0e049 100644
--- a/lib/private/Security/VerificationToken/VerificationToken.php
+++ b/lib/private/Security/VerificationToken/VerificationToken.php
@@ -39,29 +39,13 @@ use function json_encode;
class VerificationToken implements IVerificationToken {
protected const TOKEN_LIFETIME = 60 * 60 * 24 * 7;
- /** @var IConfig */
- private $config;
- /** @var ICrypto */
- private $crypto;
- /** @var ITimeFactory */
- private $timeFactory;
- /** @var ISecureRandom */
- private $secureRandom;
- /** @var IJobList */
- private $jobList;
-
public function __construct(
- IConfig $config,
- ICrypto $crypto,
- ITimeFactory $timeFactory,
- ISecureRandom $secureRandom,
- IJobList $jobList
+ private IConfig $config,
+ private ICrypto $crypto,
+ private ITimeFactory $timeFactory,
+ private ISecureRandom $secureRandom,
+ private IJobList $jobList
) {
- $this->config = $config;
- $this->crypto = $crypto;
- $this->timeFactory = $timeFactory;
- $this->secureRandom = $secureRandom;
- $this->jobList = $jobList;
}
/**
@@ -71,7 +55,13 @@ class VerificationToken implements IVerificationToken {
throw new InvalidTokenException($code);
}
- public function check(string $token, ?IUser $user, string $subject, string $passwordPrefix = '', bool $expiresWithLogin = false): void {
+ public function check(
+ string $token,
+ ?IUser $user,
+ string $subject,
+ string $passwordPrefix = '',
+ bool $expiresWithLogin = false,
+ ): void {
if ($user === null || !$user->isEnabled()) {
$this->throwInvalidTokenException(InvalidTokenException::USER_UNKNOWN);
}
@@ -107,7 +97,11 @@ class VerificationToken implements IVerificationToken {
}
}
- public function create(IUser $user, string $subject, string $passwordPrefix = ''): string {
+ public function create(
+ IUser $user,
+ string $subject,
+ string $passwordPrefix = '',
+ ): string {
$token = $this->secureRandom->generate(
21,
ISecureRandom::CHAR_DIGITS.
diff --git a/lib/private/Server.php b/lib/private/Server.php
index f98ee051a32..40e5cabbbcc 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -82,7 +82,6 @@ use OC\DB\Connection;
use OC\DB\ConnectionAdapter;
use OC\Diagnostics\EventLogger;
use OC\Diagnostics\QueryLogger;
-use OC\EventDispatcher\SymfonyAdapter;
use OC\Federation\CloudFederationFactory;
use OC\Federation\CloudFederationProviderManager;
use OC\Federation\CloudIdManager;
@@ -125,9 +124,11 @@ use OC\Metadata\Capabilities as MetadataCapabilities;
use OC\Metadata\IMetadataManager;
use OC\Metadata\MetadataManager;
use OC\Notification\Manager;
+use OC\OCM\OCMDiscoveryService;
use OC\OCS\DiscoveryService;
use OC\Preview\GeneratorHelper;
use OC\Preview\IMagickSupport;
+use OC\Preview\MimeIconProvider;
use OC\Remote\Api\ApiFactory;
use OC\Remote\InstanceFactory;
use OC\RichObjectStrings\Validator;
@@ -147,6 +148,7 @@ use OC\Security\TrustedDomainHelper;
use OC\Security\VerificationToken\VerificationToken;
use OC\Session\CryptoWrapper;
use OC\Share20\ProviderFactory;
+use OC\Share20\ShareDisableChecker;
use OC\Share20\ShareHelper;
use OC\SpeechToText\SpeechToTextManager;
use OC\SystemTag\ManagerFactory as SystemTagManagerFactory;
@@ -192,14 +194,6 @@ use OCP\Files\Storage\IStorageFactory;
use OCP\Files\Template\ITemplateManager;
use OCP\FullTextSearch\IFullTextSearchManager;
use OCP\GlobalScale\IConfig;
-use OCP\Group\Events\BeforeGroupCreatedEvent;
-use OCP\Group\Events\BeforeGroupDeletedEvent;
-use OCP\Group\Events\BeforeUserAddedEvent;
-use OCP\Group\Events\BeforeUserRemovedEvent;
-use OCP\Group\Events\GroupCreatedEvent;
-use OCP\Group\Events\GroupDeletedEvent;
-use OCP\Group\Events\UserAddedEvent;
-use OCP\Group\Events\UserRemovedEvent;
use OCP\Group\ISubAdmin;
use OCP\Http\Client\IClientService;
use OCP\IAppConfig;
@@ -235,6 +229,7 @@ use OCP\Lock\ILockingProvider;
use OCP\Lockdown\ILockdownManager;
use OCP\Log\ILogFactory;
use OCP\Mail\IMailer;
+use OCP\OCM\IOCMDiscoveryService;
use OCP\Remote\Api\IApiFactory;
use OCP\Remote\IInstanceFactory;
use OCP\RichObjectStrings\IValidator;
@@ -253,12 +248,10 @@ use OCP\SystemTag\ISystemTagManager;
use OCP\SystemTag\ISystemTagObjectMapper;
use OCP\Talk\IBroker;
use OCP\Translation\ITranslationManager;
-use OCP\User\Events\BeforePasswordUpdatedEvent;
use OCP\User\Events\BeforeUserDeletedEvent;
use OCP\User\Events\BeforeUserLoggedInEvent;
use OCP\User\Events\BeforeUserLoggedInWithCookieEvent;
use OCP\User\Events\BeforeUserLoggedOutEvent;
-use OCP\User\Events\PasswordUpdatedEvent;
use OCP\User\Events\PostLoginEvent;
use OCP\User\Events\UserChangedEvent;
use OCP\User\Events\UserLoggedInEvent;
@@ -267,14 +260,13 @@ use OCP\User\Events\UserLoggedOutEvent;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
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
@@ -340,7 +332,6 @@ class Server extends ServerContainer implements IServerContainer {
$c->get(SystemConfig::class)
),
$c->get(IEventDispatcher::class),
- $c->get(SymfonyAdapter::class),
$c->get(GeneratorHelper::class),
$c->get(ISession::class)->get('user_id'),
$c->get(Coordinator::class),
@@ -351,6 +342,7 @@ class Server extends ServerContainer implements IServerContainer {
});
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('PreviewManager', IPreview::class);
+ $this->registerAlias(IMimeIconProvider::class, MimeIconProvider::class);
$this->registerService(\OC\Preview\Watcher::class, function (ContainerInterface $c) {
return new \OC\Preview\Watcher(
@@ -466,7 +458,6 @@ class Server extends ServerContainer implements IServerContainer {
return new HookConnector(
$c->get(IRootFolder::class),
new View(),
- $c->get(\OC\EventDispatcher\SymfonyAdapter::class),
$c->get(IEventDispatcher::class)
);
});
@@ -493,50 +484,10 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService(\OCP\IGroupManager::class, function (ContainerInterface $c) {
$groupManager = new \OC\Group\Manager(
$this->get(IUserManager::class),
- $c->get(SymfonyAdapter::class),
+ $this->get(IEventDispatcher::class),
$this->get(LoggerInterface::class),
$this->get(ICacheFactory::class)
);
- $groupManager->listen('\OC\Group', 'preCreate', function ($gid) {
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new BeforeGroupCreatedEvent($gid));
- });
- $groupManager->listen('\OC\Group', 'postCreate', function (\OC\Group\Group $group) {
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new GroupCreatedEvent($group));
- });
- $groupManager->listen('\OC\Group', 'preDelete', function (\OC\Group\Group $group) {
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new BeforeGroupDeletedEvent($group));
- });
- $groupManager->listen('\OC\Group', 'postDelete', function (\OC\Group\Group $group) {
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new GroupDeletedEvent($group));
- });
- $groupManager->listen('\OC\Group', 'preAddUser', function (\OC\Group\Group $group, \OC\User\User $user) {
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new BeforeUserAddedEvent($group, $user));
- });
- $groupManager->listen('\OC\Group', 'postAddUser', function (\OC\Group\Group $group, \OC\User\User $user) {
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new UserAddedEvent($group, $user));
- });
- $groupManager->listen('\OC\Group', 'preRemoveUser', function (\OC\Group\Group $group, \OC\User\User $user) {
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new BeforeUserRemovedEvent($group, $user));
- });
- $groupManager->listen('\OC\Group', 'postRemoveUser', function (\OC\Group\Group $group, \OC\User\User $user) {
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new UserRemovedEvent($group, $user));
- });
return $groupManager;
});
/** @deprecated 19.0.0 */
@@ -568,8 +519,6 @@ class Server extends ServerContainer implements IServerContainer {
$provider = null;
}
- $legacyDispatcher = $c->get(SymfonyAdapter::class);
-
$userSession = new \OC\User\Session(
$manager,
$session,
@@ -591,10 +540,9 @@ class Server extends ServerContainer implements IServerContainer {
\OC_Hook::emit('OC_User', 'post_createUser', ['uid' => $user->getUID(), 'password' => $password]);
});
/** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
- $userSession->listen('\OC\User', 'preDelete', function ($user) use ($legacyDispatcher) {
+ $userSession->listen('\OC\User', 'preDelete', function ($user) {
/** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'pre_deleteUser', ['run' => true, 'uid' => $user->getUID()]);
- $legacyDispatcher->dispatch('OCP\IUser::preDelete', new GenericEvent($user));
});
/** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
$userSession->listen('\OC\User', 'postDelete', function ($user) {
@@ -604,18 +552,10 @@ class Server extends ServerContainer implements IServerContainer {
$userSession->listen('\OC\User', 'preSetPassword', function ($user, $password, $recoveryPassword) {
/** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'pre_setPassword', ['run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword]);
-
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new BeforePasswordUpdatedEvent($user, $password, $recoveryPassword));
});
$userSession->listen('\OC\User', 'postSetPassword', function ($user, $password, $recoveryPassword) {
/** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'post_setPassword', ['run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword]);
-
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new PasswordUpdatedEvent($user, $password, $recoveryPassword));
});
$userSession->listen('\OC\User', 'preLogin', function ($uid, $password) {
\OC_Hook::emit('OC_User', 'pre_login', ['run' => true, 'uid' => $uid, 'password' => $password]);
@@ -660,10 +600,6 @@ class Server extends ServerContainer implements IServerContainer {
$userSession->listen('\OC\User', 'changeUser', function ($user, $feature, $value, $oldValue) {
/** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'changeUser', ['run' => true, 'user' => $user, 'feature' => $feature, 'value' => $value, 'old_value' => $oldValue]);
-
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->get(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new UserChangedEvent($user, $feature, $value, $oldValue));
});
return $userSession;
});
@@ -852,8 +788,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),
@@ -940,7 +876,6 @@ class Server extends ServerContainer implements IServerContainer {
$c->get(\OC\AppConfig::class),
$c->get(IGroupManager::class),
$c->get(ICacheFactory::class),
- $c->get(SymfonyAdapter::class),
$c->get(IEventDispatcher::class),
$c->get(LoggerInterface::class)
);
@@ -1018,6 +953,18 @@ class Server extends ServerContainer implements IServerContainer {
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Throttler', Throttler::class);
$this->registerAlias(IThrottler::class, Throttler::class);
+
+ $this->registerService(\OC\Security\Bruteforce\Backend\IBackend::class, function ($c) {
+ $config = $c->get(\OCP\IConfig::class);
+ if (ltrim($config->getSystemValueString('memcache.distributed', ''), '\\') === \OC\Memcache\Redis::class) {
+ $backend = $c->get(\OC\Security\Bruteforce\Backend\MemoryCacheBackend::class);
+ } else {
+ $backend = $c->get(\OC\Security\Bruteforce\Backend\DatabaseBackend::class);
+ }
+
+ return $backend;
+ });
+
$this->registerService('IntegrityCodeChecker', function (ContainerInterface $c) {
// IConfig and IAppManager requires a working database. This code
// might however be called when ownCloud is not yet setup.
@@ -1250,9 +1197,6 @@ class Server extends ServerContainer implements IServerContainer {
);
});
$this->registerAlias(\OCP\EventDispatcher\IEventDispatcher::class, \OC\EventDispatcher\EventDispatcher::class);
- /** @deprecated 19.0.0 */
- $this->registerDeprecatedAlias('EventDispatcher', \OC\EventDispatcher\SymfonyAdapter::class);
- $this->registerAlias(EventDispatcherInterface::class, \OC\EventDispatcher\SymfonyAdapter::class);
$this->registerService('CryptoWrapper', function (ContainerInterface $c) {
// FIXME: Instantiated here due to cyclic dependency
@@ -1306,13 +1250,13 @@ class Server extends ServerContainer implements IServerContainer {
$factory,
$c->get(IUserManager::class),
$c->get(IRootFolder::class),
- $c->get(SymfonyAdapter::class),
$c->get(IMailer::class),
$c->get(IURLGenerator::class),
$c->get('ThemingDefaults'),
$c->get(IEventDispatcher::class),
$c->get(IUserSession::class),
- $c->get(KnownUserService::class)
+ $c->get(KnownUserService::class),
+ $c->get(ShareDisableChecker::class)
);
return $manager;
@@ -1364,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(
@@ -1379,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)
);
});
@@ -1470,6 +1417,8 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerAlias(IEventSourceFactory::class, EventSourceFactory::class);
+ $this->registerAlias(\OCP\TextProcessing\IManager::class, \OC\TextProcessing\Manager::class);
+
$this->connectDispatcher();
}
@@ -2113,17 +2062,6 @@ class Server extends ServerContainer implements IServerContainer {
}
/**
- * Get the EventDispatcher
- *
- * @return EventDispatcherInterface
- * @since 8.2.0
- * @deprecated 18.0.0 use \OCP\EventDispatcher\IEventDispatcher
- */
- public function getEventDispatcher() {
- return $this->get(\OC\EventDispatcher\SymfonyAdapter::class);
- }
-
- /**
* Get the Notification Manager
*
* @return \OCP\Notification\IManager
@@ -2175,7 +2113,7 @@ class Server extends ServerContainer implements IServerContainer {
}
/**
- * @return Throttler
+ * @return IThrottler
* @deprecated 20.0.0
*/
public function getBruteForceThrottler() {
diff --git a/lib/private/Session/Internal.php b/lib/private/Session/Internal.php
index e0f92c2e887..e8e2a4f2d8e 100644
--- a/lib/private/Session/Internal.php
+++ b/lib/private/Session/Internal.php
@@ -149,7 +149,7 @@ class Internal extends Session {
$newId = $this->getId();
/** @var IProvider $tokenProvider */
- $tokenProvider = \OC::$server->query(IProvider::class);
+ $tokenProvider = \OCP\Server::get(IProvider::class);
try {
$tokenProvider->renewSessionToken($oldId, $newId);
diff --git a/lib/private/Setup.php b/lib/private/Setup.php
index 3a2e7614dd9..0993fe54f47 100644
--- a/lib/private/Setup.php
+++ b/lib/private/Setup.php
@@ -53,6 +53,7 @@ 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 OCP\AppFramework\Utility\ITimeFactory;
@@ -424,20 +425,20 @@ class Setup {
unlink(\OC::$configDir.'/CAN_INSTALL');
}
- $bootstrapCoordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class);
+ $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 $userSession User\Session */
$userSession = \OC::$server->getUserSession();
- $provider = \OC::$server->query(PublicKeyTokenProvider::class);
+ $provider = \OCP\Server::get(PublicKeyTokenProvider::class);
$userSession->setTokenProvider($provider);
$userSession->login($username, $password);
$userSession->createSessionToken($request, $userSession->getUser()->getUID(), $username, $password);
$session = $userSession->getSession();
- $session->set('last-password-confirm', \OC::$server->query(ITimeFactory::class)->getTime());
+ $session->set('last-password-confirm', \OCP\Server::get(ITimeFactory::class)->getTime());
// Set email for admin
if (!empty($options['adminemail'])) {
@@ -453,6 +454,7 @@ class Setup {
$jobList->add(TokenCleanupJob::class);
$jobList->add(Rotate::class);
$jobList->add(BackgroundCleanupJob::class);
+ $jobList->add(RemoveOldTasksBackgroundJob::class);
}
/**
@@ -506,10 +508,10 @@ class Setup {
$config,
\OC::$server->get(IniGetWrapper::class),
\OC::$server->getL10N('lib'),
- \OC::$server->query(Defaults::class),
+ \OCP\Server::get(Defaults::class),
\OC::$server->get(LoggerInterface::class),
\OC::$server->getSecureRandom(),
- \OC::$server->query(Installer::class)
+ \OCP\Server::get(Installer::class)
);
$htaccessContent = file_get_contents($setupHelper->pathToHtaccess());
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index 5201cf074b1..3f5d01618eb 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;
@@ -90,19 +90,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 +111,7 @@ class DefaultShareProvider implements IShareProvider {
$this->defaults = $defaults;
$this->l10nFactory = $l10nFactory;
$this->urlGenerator = $urlGenerator;
- $this->config = $config;
+ $this->timeFactory = $timeFactory;
}
/**
@@ -216,32 +216,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');
-
- // 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)));
+ $qb->executeStatement();
- $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;
}
diff --git a/lib/private/Share20/LegacyHooks.php b/lib/private/Share20/LegacyHooks.php
index feb4604e884..24d07167fbd 100644
--- a/lib/private/Share20/LegacyHooks.php
+++ b/lib/private/Share20/LegacyHooks.php
@@ -26,69 +26,58 @@
*/
namespace OC\Share20;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\File;
use OCP\Share;
+use OCP\Share\Events\BeforeShareCreatedEvent;
+use OCP\Share\Events\BeforeShareDeletedEvent;
+use OCP\Share\Events\ShareCreatedEvent;
+use OCP\Share\Events\ShareDeletedEvent;
+use OCP\Share\Events\ShareDeletedFromSelfEvent;
use OCP\Share\IShare;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
class LegacyHooks {
- /** @var EventDispatcherInterface */
+ /** @var IEventDispatcher */
private $eventDispatcher;
- /**
- * LegacyHooks constructor.
- *
- * @param EventDispatcherInterface $eventDispatcher
- */
- public function __construct(EventDispatcherInterface $eventDispatcher) {
+ public function __construct(IEventDispatcher $eventDispatcher) {
$this->eventDispatcher = $eventDispatcher;
- $this->eventDispatcher->addListener('OCP\Share::preUnshare', [$this, 'preUnshare']);
- $this->eventDispatcher->addListener('OCP\Share::postUnshare', [$this, 'postUnshare']);
- $this->eventDispatcher->addListener('OCP\Share::postUnshareFromSelf', [$this, 'postUnshareFromSelf']);
- $this->eventDispatcher->addListener('OCP\Share::preShare', [$this, 'preShare']);
- $this->eventDispatcher->addListener('OCP\Share::postShare', [$this, 'postShare']);
+ $this->eventDispatcher->addListener(BeforeShareDeletedEvent::class, function (BeforeShareDeletedEvent $event) {
+ $this->preUnshare($event);
+ });
+ $this->eventDispatcher->addListener(ShareDeletedEvent::class, function (ShareDeletedEvent $event) {
+ $this->postUnshare($event);
+ });
+ $this->eventDispatcher->addListener(ShareDeletedFromSelfEvent::class, function (ShareDeletedFromSelfEvent $event) {
+ $this->postUnshareFromSelf($event);
+ });
+ $this->eventDispatcher->addListener(BeforeShareCreatedEvent::class, function (BeforeShareCreatedEvent $event) {
+ $this->preShare($event);
+ });
+ $this->eventDispatcher->addListener(ShareCreatedEvent::class, function (ShareCreatedEvent $event) {
+ $this->postShare($event);
+ });
}
- /**
- * @param GenericEvent $e
- */
- public function preUnshare(GenericEvent $e) {
- /** @var IShare $share */
- $share = $e->getSubject();
+ public function preUnshare(BeforeShareDeletedEvent $e) {
+ $share = $e->getShare();
$formatted = $this->formatHookParams($share);
\OC_Hook::emit(Share::class, 'pre_unshare', $formatted);
}
- /**
- * @param GenericEvent $e
- */
- public function postUnshare(GenericEvent $e) {
- /** @var IShare $share */
- $share = $e->getSubject();
+ public function postUnshare(ShareDeletedEvent $e) {
+ $share = $e->getShare();
$formatted = $this->formatHookParams($share);
-
- /** @var IShare[] $deletedShares */
- $deletedShares = $e->getArgument('deletedShares');
-
- $formattedDeletedShares = array_map(function ($share) {
- return $this->formatHookParams($share);
- }, $deletedShares);
-
- $formatted['deletedShares'] = $formattedDeletedShares;
+ $formatted['deletedShares'] = [$formatted];
\OC_Hook::emit(Share::class, 'post_unshare', $formatted);
}
- /**
- * @param GenericEvent $e
- */
- public function postUnshareFromSelf(GenericEvent $e) {
- /** @var IShare $share */
- $share = $e->getSubject();
+ public function postUnshareFromSelf(ShareDeletedFromSelfEvent $e) {
+ $share = $e->getShare();
$formatted = $this->formatHookParams($share);
$formatted['itemTarget'] = $formatted['fileTarget'];
@@ -121,9 +110,8 @@ class LegacyHooks {
return $hookParams;
}
- public function preShare(GenericEvent $e) {
- /** @var IShare $share */
- $share = $e->getSubject();
+ public function preShare(BeforeShareCreatedEvent $e) {
+ $share = $e->getShare();
// Pre share hook
$run = true;
@@ -145,16 +133,15 @@ class LegacyHooks {
\OC_Hook::emit(Share::class, 'pre_shared', $preHookData);
if ($run === false) {
- $e->setArgument('error', $error);
+ $e->setError($error);
$e->stopPropagation();
}
return $e;
}
- public function postShare(GenericEvent $e) {
- /** @var IShare $share */
- $share = $e->getSubject();
+ public function postShare(ShareCreatedEvent $e) {
+ $share = $e->getShare();
$postHookData = [
'itemType' => $share->getNode() instanceof File ? 'file' : 'folder',
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index 732bd5bb97d..4606101b7e6 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;
@@ -67,6 +66,11 @@ use OCP\Security\Events\ValidatePasswordPolicyEvent;
use OCP\Security\IHasher;
use OCP\Security\ISecureRandom;
use OCP\Share;
+use OCP\Share\Events\BeforeShareDeletedEvent;
+use OCP\Share\Events\ShareAcceptedEvent;
+use OCP\Share\Events\ShareCreatedEvent;
+use OCP\Share\Events\ShareDeletedEvent;
+use OCP\Share\Events\ShareDeletedFromSelfEvent;
use OCP\Share\Exceptions\AlreadySharedException;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
@@ -75,8 +79,6 @@ use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
/**
* This class is the communication hub for all sharing related operations.
@@ -103,10 +105,6 @@ class Manager implements IManager {
private $userManager;
/** @var IRootFolder */
private $rootFolder;
- /** @var CappedMemoryCache */
- private $sharingDisabledForUsersCache;
- /** @var EventDispatcherInterface */
- private $legacyDispatcher;
/** @var LegacyHooks */
private $legacyHooks;
/** @var IMailer */
@@ -121,6 +119,7 @@ class Manager implements IManager {
private $userSession;
/** @var KnownUserService */
private $knownUserService;
+ private ShareDisableChecker $shareDisableChecker;
public function __construct(
LoggerInterface $logger,
@@ -134,13 +133,13 @@ class Manager implements IManager {
IProviderFactory $factory,
IUserManager $userManager,
IRootFolder $rootFolder,
- EventDispatcherInterface $legacyDispatcher,
IMailer $mailer,
IURLGenerator $urlGenerator,
\OC_Defaults $defaults,
IEventDispatcher $dispatcher,
IUserSession $userSession,
- KnownUserService $knownUserService
+ KnownUserService $knownUserService,
+ ShareDisableChecker $shareDisableChecker
) {
$this->logger = $logger;
$this->config = $config;
@@ -153,17 +152,16 @@ class Manager implements IManager {
$this->factory = $factory;
$this->userManager = $userManager;
$this->rootFolder = $rootFolder;
- $this->legacyDispatcher = $legacyDispatcher;
- $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($this->legacyDispatcher);
+ $this->legacyHooks = new LegacyHooks($dispatcher);
$this->mailer = $mailer;
$this->urlGenerator = $urlGenerator;
$this->defaults = $defaults;
$this->dispatcher = $dispatcher;
$this->userSession = $userSession;
$this->knownUserService = $knownUserService;
+ $this->shareDisableChecker = $shareDisableChecker;
}
/**
@@ -194,7 +192,7 @@ class Manager implements IManager {
// Let others verify the password
try {
- $this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
+ $this->dispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
} catch (HintException $e) {
throw new \Exception($e->getHint());
}
@@ -806,10 +804,10 @@ class Manager implements IManager {
$share->setTarget($target);
// Pre share event
- $event = new GenericEvent($share);
- $this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
- if ($event->isPropagationStopped() && $event->hasArgument('error')) {
- throw new \Exception($event->getArgument('error'));
+ $event = new Share\Events\BeforeShareCreatedEvent($share);
+ $this->dispatcher->dispatchTyped($event);
+ if ($event->isPropagationStopped() && $event->getError()) {
+ throw new \Exception($event->getError());
}
$oldShare = $share;
@@ -833,10 +831,7 @@ class Manager implements IManager {
}
// Post share event
- $event = new GenericEvent($share);
- $this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
-
- $this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
+ $this->dispatcher->dispatchTyped(new ShareCreatedEvent($share));
if ($this->config->getSystemValueBool('sharing.enable_share_mail', true)
&& $share->getShareType() === IShare::TYPE_USER) {
@@ -1122,8 +1117,9 @@ class Manager implements IManager {
throw new \InvalidArgumentException('Share provider does not support accepting');
}
$provider->acceptShare($share, $recipientId);
- $event = new GenericEvent($share);
- $this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
+
+ $event = new ShareAcceptedEvent($share);
+ $this->dispatcher->dispatchTyped($event);
return $share;
}
@@ -1206,11 +1202,13 @@ class Manager implements IManager {
$provider = $this->factory->getProviderForType($share->getShareType());
foreach ($provider->getChildren($share) as $child) {
+ $this->dispatcher->dispatchTyped(new BeforeShareDeletedEvent($child));
+
$deletedChildren = $this->deleteChildren($child);
$deletedShares = array_merge($deletedShares, $deletedChildren);
$provider->delete($child);
- $this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($child));
+ $this->dispatcher->dispatchTyped(new ShareDeletedEvent($child));
$deletedShares[] = $child;
}
@@ -1231,24 +1229,16 @@ class Manager implements IManager {
throw new \InvalidArgumentException('Share does not have a full id');
}
- $event = new GenericEvent($share);
- $this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
+ $this->dispatcher->dispatchTyped(new BeforeShareDeletedEvent($share));
// Get all children and delete them as well
- $deletedShares = $this->deleteChildren($share);
+ $this->deleteChildren($share);
// Do the actual delete
$provider = $this->factory->getProviderForType($share->getShareType());
$provider->delete($share);
- $this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($share));
-
- // All the deleted shares caused by this delete
- $deletedShares[] = $share;
-
- // Emit post hook
- $event->setArgument('deletedShares', $deletedShares);
- $this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
+ $this->dispatcher->dispatchTyped(new ShareDeletedEvent($share));
}
@@ -1266,8 +1256,8 @@ class Manager implements IManager {
$provider = $this->factory->getProvider($providerId);
$provider->deleteFromSelf($share, $recipientId);
- $event = new GenericEvent($share);
- $this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
+ $event = new ShareDeletedFromSelfEvent($share);
+ $this->dispatcher->dispatchTyped($event);
}
public function restoreShare(IShare $share, string $recipientId): IShare {
@@ -1352,7 +1342,7 @@ class Manager implements IManager {
$added = 0;
foreach ($shares as $share) {
try {
- $this->checkExpireDate($share);
+ $this->checkShare($share);
} catch (ShareNotFound $e) {
//Ignore since this basically means the share is deleted
continue;
@@ -1411,7 +1401,7 @@ class Manager implements IManager {
// remove all shares which are already expired
foreach ($shares as $key => $share) {
try {
- $this->checkExpireDate($share);
+ $this->checkShare($share);
} catch (ShareNotFound $e) {
unset($shares[$key]);
}
@@ -1457,7 +1447,7 @@ class Manager implements IManager {
$share = $provider->getShareById($id, $recipient);
- $this->checkExpireDate($share);
+ $this->checkShare($share);
return $share;
}
@@ -1541,7 +1531,7 @@ class Manager implements IManager {
throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
}
- $this->checkExpireDate($share);
+ $this->checkShare($share);
/*
* Reduce the permissions for link or email shares if public upload is not enabled
@@ -1554,11 +1544,25 @@ class Manager implements IManager {
return $share;
}
- protected function checkExpireDate($share) {
+ /**
+ * Check expire date and disabled owner
+ *
+ * @throws ShareNotFound
+ */
+ protected function checkShare(IShare $share): void {
if ($share->isExpired()) {
$this->deleteShare($share);
throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
}
+ if ($this->config->getAppValue('files_sharing', 'hide_disabled_user_shares', 'no') === 'yes') {
+ $uids = array_unique([$share->getShareOwner(),$share->getSharedBy()]);
+ foreach ($uids as $uid) {
+ $user = $this->userManager->get($uid);
+ if ($user?->isEnabled() === false) {
+ throw new ShareNotFound($this->l->t('The requested share comes from a disabled user'));
+ }
+ }
+ }
}
/**
@@ -2020,37 +2024,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 6abfb372a4d..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),
);
}
@@ -139,11 +140,11 @@ class ProviderFactory implements IProviderFactory {
$addressHandler,
$this->serverContainer->getHTTPClientService(),
$this->serverContainer->query(\OCP\OCS\IDiscoveryService::class),
- $this->serverContainer->getLogger(),
$this->serverContainer->getJobList(),
\OC::$server->getCloudFederationProviderManager(),
\OC::$server->getCloudFederationFactory(),
- $this->serverContainer->query(IEventDispatcher::class)
+ $this->serverContainer->query(IEventDispatcher::class),
+ $this->serverContainer->get(LoggerInterface::class),
);
$tokenHandler = new TokenHandler(
$this->serverContainer->getSecureRandom()
@@ -155,13 +156,13 @@ class ProviderFactory implements IProviderFactory {
$notifications,
$tokenHandler,
$l,
- $this->serverContainer->getLogger(),
$this->serverContainer->getLazyRootFolder(),
$this->serverContainer->getConfig(),
$this->serverContainer->getUserManager(),
$this->serverContainer->getCloudIdManager(),
$this->serverContainer->getGlobalScaleConfig(),
- $this->serverContainer->getCloudFederationProviderManager()
+ $this->serverContainer->getCloudFederationProviderManager(),
+ $this->serverContainer->get(LoggerInterface::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/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 757fc02485e..bdd04ad3651 100644
--- a/lib/private/SpeechToText/SpeechToTextManager.php
+++ b/lib/private/SpeechToText/SpeechToTextManager.php
@@ -34,6 +34,7 @@ use OCP\BackgroundJob\IJobList;
use OCP\Files\File;
use OCP\Files\InvalidPathException;
use OCP\Files\NotFoundException;
+use OCP\IConfig;
use OCP\IServerContainer;
use OCP\PreConditionNotMetException;
use OCP\SpeechToText\ISpeechToTextManager;
@@ -53,6 +54,7 @@ class SpeechToTextManager implements ISpeechToTextManager {
private Coordinator $coordinator,
private LoggerInterface $logger,
private IJobList $jobList,
+ private IConfig $config,
) {
}
@@ -111,7 +113,18 @@ class SpeechToTextManager implements ISpeechToTextManager {
throw new PreConditionNotMetException('No SpeechToText providers have been registered');
}
- foreach ($this->getProviders() as $provider) {
+ $providers = $this->getProviders();
+
+ $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));
+ if ($provider !== false) {
+ $providers = [$provider];
+ }
+ }
+
+ foreach ($providers as $provider) {
try {
return $provider->transcribeFile($file);
} catch (\Throwable $e) {
diff --git a/lib/private/Streamer.php b/lib/private/Streamer.php
index 52f824fedf8..aafd3d95dfb 100644
--- a/lib/private/Streamer.php
+++ b/lib/private/Streamer.php
@@ -36,6 +36,7 @@ use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\IRequest;
use ownCloud\TarStreamer\TarStreamer;
+use Psr\Log\LoggerInterface;
use ZipStreamer\ZipStreamer;
class Streamer {
@@ -122,10 +123,16 @@ class Streamer {
$dirNode = $userFolder->get($dir);
$files = $dirNode->getDirectoryListing();
+ /** @var LoggerInterface $logger */
+ $logger = \OC::$server->query(LoggerInterface::class);
foreach ($files as $file) {
if ($file instanceof File) {
try {
$fh = $file->fopen('r');
+ if ($fh === false) {
+ $logger->error('Unable to open file for stream: ' . print_r($file, true));
+ continue;
+ }
} catch (NotPermittedException $e) {
continue;
}
diff --git a/lib/private/SystemTag/ManagerFactory.php b/lib/private/SystemTag/ManagerFactory.php
index ca0508fe19b..6670922407e 100644
--- a/lib/private/SystemTag/ManagerFactory.php
+++ b/lib/private/SystemTag/ManagerFactory.php
@@ -26,6 +26,7 @@ declare(strict_types=1);
*/
namespace OC\SystemTag;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IServerContainer;
use OCP\SystemTag\ISystemTagManager;
use OCP\SystemTag\ISystemTagManagerFactory;
@@ -64,7 +65,7 @@ class ManagerFactory implements ISystemTagManagerFactory {
return new SystemTagManager(
$this->serverContainer->getDatabaseConnection(),
$this->serverContainer->getGroupManager(),
- $this->serverContainer->getEventDispatcher()
+ $this->serverContainer->get(IEventDispatcher::class),
);
}
@@ -79,7 +80,7 @@ class ManagerFactory implements ISystemTagManagerFactory {
return new SystemTagObjectMapper(
$this->serverContainer->getDatabaseConnection(),
$this->getManager(),
- $this->serverContainer->getEventDispatcher()
+ $this->serverContainer->get(IEventDispatcher::class),
);
}
}
diff --git a/lib/private/SystemTag/SystemTagManager.php b/lib/private/SystemTag/SystemTagManager.php
index 79c5adcf450..c52c350b6f8 100644
--- a/lib/private/SystemTag/SystemTagManager.php
+++ b/lib/private/SystemTag/SystemTagManager.php
@@ -31,6 +31,7 @@ namespace OC\SystemTag;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IUser;
@@ -39,7 +40,6 @@ use OCP\SystemTag\ISystemTagManager;
use OCP\SystemTag\ManagerEvent;
use OCP\SystemTag\TagAlreadyExistsException;
use OCP\SystemTag\TagNotFoundException;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Manager class for system tags
@@ -48,15 +48,6 @@ class SystemTagManager implements ISystemTagManager {
public const TAG_TABLE = 'systemtag';
public const TAG_GROUP_TABLE = 'systemtag_group';
- /** @var IDBConnection */
- protected $connection;
-
- /** @var EventDispatcherInterface */
- protected $dispatcher;
-
- /** @var IGroupManager */
- protected $groupManager;
-
/**
* Prepared query for selecting tags directly
*
@@ -64,22 +55,11 @@ class SystemTagManager implements ISystemTagManager {
*/
private $selectTagQuery;
- /**
- * Constructor.
- *
- * @param IDBConnection $connection database connection
- * @param IGroupManager $groupManager
- * @param EventDispatcherInterface $dispatcher
- */
public function __construct(
- IDBConnection $connection,
- IGroupManager $groupManager,
- EventDispatcherInterface $dispatcher
+ protected IDBConnection $connection,
+ protected IGroupManager $groupManager,
+ protected IEventDispatcher $dispatcher,
) {
- $this->connection = $connection;
- $this->groupManager = $groupManager;
- $this->dispatcher = $dispatcher;
-
$query = $this->connection->getQueryBuilder();
$this->selectTagQuery = $query->select('*')
->from(self::TAG_TABLE)
@@ -91,7 +71,7 @@ class SystemTagManager implements ISystemTagManager {
/**
* {@inheritdoc}
*/
- public function getTagsByIds($tagIds): array {
+ public function getTagsByIds($tagIds, ?IUser $user = null): array {
if (!\is_array($tagIds)) {
$tagIds = [$tagIds];
}
@@ -116,7 +96,12 @@ class SystemTagManager implements ISystemTagManager {
$result = $query->execute();
while ($row = $result->fetch()) {
- $tags[$row['id']] = $this->createSystemTagFromRow($row);
+ $tag = $this->createSystemTagFromRow($row);
+ if ($user && !$this->canUserSeeTag($tag, $user)) {
+ // if a user is given, hide invisible tags
+ continue;
+ }
+ $tags[$row['id']] = $tag;
}
$result->closeCursor();
@@ -172,8 +157,10 @@ class SystemTagManager implements ISystemTagManager {
* {@inheritdoc}
*/
public function getTag(string $tagName, bool $userVisible, bool $userAssignable): ISystemTag {
+ // Length of name column is 64
+ $truncatedTagName = substr($tagName, 0, 64);
$result = $this->selectTagQuery
- ->setParameter('name', $tagName)
+ ->setParameter('name', $truncatedTagName)
->setParameter('visibility', $userVisible ? 1 : 0)
->setParameter('editable', $userAssignable ? 1 : 0)
->execute();
@@ -182,7 +169,7 @@ class SystemTagManager implements ISystemTagManager {
$result->closeCursor();
if (!$row) {
throw new TagNotFoundException(
- 'Tag ("' . $tagName . '", '. $userVisible . ', ' . $userAssignable . ') does not exist'
+ 'Tag ("' . $truncatedTagName . '", '. $userVisible . ', ' . $userAssignable . ') does not exist'
);
}
@@ -242,9 +229,11 @@ class SystemTagManager implements ISystemTagManager {
}
$beforeUpdate = array_shift($tags);
+ // Length of name column is 64
+ $truncatedNewName = substr($newName, 0, 64);
$afterUpdate = new SystemTag(
$tagId,
- $newName,
+ $truncatedNewName,
$userVisible,
$userAssignable
);
@@ -255,7 +244,7 @@ class SystemTagManager implements ISystemTagManager {
->set('visibility', $query->createParameter('visibility'))
->set('editable', $query->createParameter('editable'))
->where($query->expr()->eq('id', $query->createParameter('tagid')))
- ->setParameter('name', $newName)
+ ->setParameter('name', $truncatedNewName)
->setParameter('visibility', $userVisible ? 1 : 0)
->setParameter('editable', $userAssignable ? 1 : 0)
->setParameter('tagid', $tagId);
diff --git a/lib/private/SystemTag/SystemTagObjectMapper.php b/lib/private/SystemTag/SystemTagObjectMapper.php
index b61a81a1fa7..66a21e58609 100644
--- a/lib/private/SystemTag/SystemTagObjectMapper.php
+++ b/lib/private/SystemTag/SystemTagObjectMapper.php
@@ -29,37 +29,22 @@ namespace OC\SystemTag;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IDBConnection;
use OCP\SystemTag\ISystemTag;
use OCP\SystemTag\ISystemTagManager;
use OCP\SystemTag\ISystemTagObjectMapper;
use OCP\SystemTag\MapperEvent;
use OCP\SystemTag\TagNotFoundException;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class SystemTagObjectMapper implements ISystemTagObjectMapper {
public const RELATION_TABLE = 'systemtag_object_mapping';
- /** @var ISystemTagManager */
- protected $tagManager;
-
- /** @var IDBConnection */
- protected $connection;
-
- /** @var EventDispatcherInterface */
- protected $dispatcher;
-
- /**
- * Constructor.
- *
- * @param IDBConnection $connection database connection
- * @param ISystemTagManager $tagManager system tag manager
- * @param EventDispatcherInterface $dispatcher
- */
- public function __construct(IDBConnection $connection, ISystemTagManager $tagManager, EventDispatcherInterface $dispatcher) {
- $this->connection = $connection;
- $this->tagManager = $tagManager;
- $this->dispatcher = $dispatcher;
+ public function __construct(
+ protected IDBConnection $connection,
+ protected ISystemTagManager $tagManager,
+ protected IEventDispatcher $dispatcher,
+ ) {
}
/**
@@ -135,6 +120,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper {
while ($row = $result->fetch()) {
$objectIds[] = $row['objectid'];
}
+ $result->closeCursor();
return $objectIds;
}
diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php
index 5c6488cbc0f..658a85152bf 100644
--- a/lib/private/TemplateLayout.php
+++ b/lib/private/TemplateLayout.php
@@ -190,7 +190,7 @@ class TemplateLayout extends \OC_Template {
$this->assign('bodyid', 'body-public');
/** @var IRegistry $subscription */
- $subscription = \OC::$server->query(IRegistry::class);
+ $subscription = \OCP\Server::get(IRegistry::class);
$showSimpleSignup = $this->config->getSystemValueBool('simpleSignUpLink.shown', true);
if ($showSimpleSignup && $subscription->delegateHasValidSubscription()) {
$showSimpleSignup = false;
@@ -226,7 +226,7 @@ class TemplateLayout extends \OC_Template {
// see https://github.com/nextcloud/server/pull/22636 for details
$jsConfigHelper = new JSConfigHelper(
\OC::$server->getL10N('lib'),
- \OC::$server->query(Defaults::class),
+ \OCP\Server::get(Defaults::class),
\OC::$server->getAppManager(),
\OC::$server->getSession(),
\OC::$server->getUserSession()->getUser(),
@@ -235,7 +235,7 @@ class TemplateLayout extends \OC_Template {
\OC::$server->get(IniGetWrapper::class),
\OC::$server->getURLGenerator(),
\OC::$server->getCapabilitiesManager(),
- \OC::$server->query(IInitialStateService::class)
+ \OCP\Server::get(IInitialStateService::class)
);
$config = $jsConfigHelper->getConfig();
if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
diff --git a/lib/private/TextProcessing/Db/Task.php b/lib/private/TextProcessing/Db/Task.php
new file mode 100644
index 00000000000..9c6f16d11ae
--- /dev/null
+++ b/lib/private/TextProcessing/Db/Task.php
@@ -0,0 +1,112 @@
+<?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\TextProcessing\Db;
+
+use OCP\AppFramework\Db\Entity;
+use OCP\TextProcessing\Task as OCPTask;
+
+/**
+ * @method setType(string $type)
+ * @method string getType()
+ * @method setLastUpdated(int $lastUpdated)
+ * @method int getLastUpdated()
+ * @method setInput(string $type)
+ * @method string getInput()
+ * @method setOutput(string $type)
+ * @method string getOutput()
+ * @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 getIdentifier()
+ */
+class Task extends Entity {
+ protected $lastUpdated;
+ protected $type;
+ protected $input;
+ protected $output;
+ protected $status;
+ protected $userId;
+ protected $appId;
+ protected $identifier;
+
+ /**
+ * @var string[]
+ */
+ public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'identifier'];
+
+ /**
+ * @var string[]
+ */
+ public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'identifier'];
+
+
+ public function __construct() {
+ // add types in constructor
+ $this->addType('id', 'integer');
+ $this->addType('lastUpdated', 'integer');
+ $this->addType('type', 'string');
+ $this->addType('input', 'string');
+ $this->addType('output', 'string');
+ $this->addType('status', 'integer');
+ $this->addType('userId', 'string');
+ $this->addType('appId', 'string');
+ $this->addType('identifier', 'string');
+ }
+
+ 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 $task */
+ $task = Task::fromParams([
+ 'id' => $task->getId(),
+ 'type' => $task->getType(),
+ 'lastUpdated' => time(),
+ 'status' => $task->getStatus(),
+ 'input' => $task->getInput(),
+ 'output' => $task->getOutput(),
+ 'userId' => $task->getUserId(),
+ 'appId' => $task->getAppId(),
+ 'identifier' => $task->getIdentifier(),
+ ]);
+ return $task;
+ }
+
+ public function toPublicTask(): OCPTask {
+ $task = new OCPTask($this->getType(), $this->getInput(), $this->getAppId(), $this->getuserId(), $this->getIdentifier());
+ $task->setId($this->getId());
+ $task->setStatus($this->getStatus());
+ $task->setOutput($this->getOutput());
+ return $task;
+ }
+}
diff --git a/lib/private/TextProcessing/Db/TaskMapper.php b/lib/private/TextProcessing/Db/TaskMapper.php
new file mode 100644
index 00000000000..62dabea544f
--- /dev/null
+++ b/lib/private/TextProcessing/Db/TaskMapper.php
@@ -0,0 +1,118 @@
+<?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\TextProcessing\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\IDBConnection;
+
+/**
+ * @extends QBMapper<Task>
+ */
+class TaskMapper extends QBMapper {
+ public function __construct(
+ IDBConnection $db,
+ private ITimeFactory $timeFactory,
+ ) {
+ parent::__construct($db, 'textprocessing_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 int the number of deleted tasks
+ * @throws Exception
+ */
+ public function deleteOlderThan(int $timeout): int {
+ $qb = $this->db->getQueryBuilder();
+ $qb->delete($this->tableName)
+ ->where($qb->expr()->lt('last_updated', $qb->createPositionalParameter(time() - $timeout)));
+ return $qb->executeStatement();
+ }
+
+ public function update(Entity $entity): Entity {
+ $entity->setLastUpdated($this->timeFactory->now()->getTimestamp());
+ return parent::update($entity);
+ }
+}
diff --git a/lib/private/TextProcessing/Manager.php b/lib/private/TextProcessing/Manager.php
new file mode 100644
index 00000000000..b9cb06c298e
--- /dev/null
+++ b/lib/private/TextProcessing/Manager.php
@@ -0,0 +1,256 @@
+<?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\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\IServerContainer;
+use OCP\TextProcessing\IManager;
+use OCP\TextProcessing\IProvider;
+use OCP\PreConditionNotMetException;
+use Psr\Log\LoggerInterface;
+use RuntimeException;
+use Throwable;
+
+class Manager implements IManager {
+ /** @var ?IProvider[] */
+ private ?array $providers = null;
+
+ public function __construct(
+ private IServerContainer $serverContainer,
+ private Coordinator $coordinator,
+ private LoggerInterface $logger,
+ private IJobList $jobList,
+ private TaskMapper $taskMapper,
+ private IConfig $config,
+ ) {
+ }
+
+ public function getProviders(): array {
+ $context = $this->coordinator->getRegistrationContext();
+ if ($context === null) {
+ return [];
+ }
+
+ if ($this->providers !== null) {
+ return $this->providers;
+ }
+
+ $this->providers = [];
+
+ foreach ($context->getTextProcessingProviders() as $providerServiceRegistration) {
+ $class = $providerServiceRegistration->getService();
+ try {
+ $this->providers[$class] = $this->serverContainer->get($class);
+ } catch (Throwable $e) {
+ $this->logger->error('Failed to load Text processing provider ' . $class, [
+ 'exception' => $e,
+ ]);
+ }
+ }
+
+ return $this->providers;
+ }
+
+ public function hasProviders(): bool {
+ $context = $this->coordinator->getRegistrationContext();
+ if ($context === null) {
+ return false;
+ }
+ return count($context->getTextProcessingProviders()) > 0;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getAvailableTaskTypes(): array {
+ $tasks = [];
+ foreach ($this->getProviders() as $provider) {
+ $tasks[$provider->getTaskType()] = true;
+ }
+ return array_keys($tasks);
+ }
+
+ public function canHandleTask(OCPTask $task): bool {
+ return in_array($task->getType(), $this->getAvailableTaskTypes());
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function runTask(OCPTask $task): string {
+ 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);
+ }
+ }
+ }
+
+ foreach ($providers as $provider) {
+ if (!$task->canUseProvider($provider)) {
+ continue;
+ }
+ try {
+ $task->setStatus(OCPTask::STATUS_RUNNING);
+ if ($task->getId() === null) {
+ $taskEntity = $this->taskMapper->insert(DbTask::fromPublicTask($task));
+ $task->setId($taskEntity->getId());
+ } else {
+ $this->taskMapper->update(DbTask::fromPublicTask($task));
+ }
+ $output = $task->visitProvider($provider);
+ $task->setOutput($output);
+ $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 RuntimeException('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);
+ $taskEntity = DbTask::fromPublicTask($task);
+ $this->taskMapper->insert($taskEntity);
+ $task->setId($taskEntity->getId());
+ $this->jobList->add(TaskBackgroundJob::class, [
+ 'taskId' => $task->getId()
+ ]);
+ }
+
+ /**
+ * @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 OCPTask
+ * @throws RuntimeException If the query failed
+ * @throws NotFoundException If the task could not be found
+ */
+ public function getTask(int $id): OCPTask {
+ try {
+ $taskEntity = $this->taskMapper->find($id);
+ return $taskEntity->toPublicTask();
+ } catch (DoesNotExistException $e) {
+ throw new NotFoundException('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 OCPTask
+ * @throws RuntimeException If the query failed
+ * @throws NotFoundException If the task could not be found
+ */
+ public function getUserTask(int $id, ?string $userId): OCPTask {
+ try {
+ $taskEntity = $this->taskMapper->findByIdAndUser($id, $userId);
+ return $taskEntity->toPublicTask();
+ } catch (DoesNotExistException $e) {
+ throw new NotFoundException('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 array
+ */
+ 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);
+ }
+ }
+}
diff --git a/lib/private/TextProcessing/RemoveOldTasksBackgroundJob.php b/lib/private/TextProcessing/RemoveOldTasksBackgroundJob.php
new file mode 100644
index 00000000000..89d329acfbb
--- /dev/null
+++ b/lib/private/TextProcessing/RemoveOldTasksBackgroundJob.php
@@ -0,0 +1,59 @@
+<?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\TextProcessing;
+
+use OC\TextProcessing\Db\TaskMapper;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\TimedJob;
+use OCP\DB\Exception;
+use Psr\Log\LoggerInterface;
+
+class RemoveOldTasksBackgroundJob extends TimedJob {
+ public const MAX_TASK_AGE_SECONDS = 60 * 50 * 24 * 7; // 1 week
+
+ public function __construct(
+ ITimeFactory $timeFactory,
+ private TaskMapper $taskMapper,
+ private LoggerInterface $logger,
+
+ ) {
+ parent::__construct($timeFactory);
+ $this->setInterval(60 * 60 * 24);
+ }
+
+ /**
+ * @param mixed $argument
+ * @inheritDoc
+ */
+ protected function run($argument) {
+ try {
+ $this->taskMapper->deleteOlderThan(self::MAX_TASK_AGE_SECONDS);
+ } catch (Exception $e) {
+ $this->logger->warning('Failed to delete stale language model tasks', ['exception' => $e]);
+ }
+ }
+}
diff --git a/lib/private/TextProcessing/TaskBackgroundJob.php b/lib/private/TextProcessing/TaskBackgroundJob.php
new file mode 100644
index 00000000000..4c24b3e531f
--- /dev/null
+++ b/lib/private/TextProcessing/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\TextProcessing;
+
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\QueuedJob;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\TextProcessing\Events\TaskFailedEvent;
+use OCP\TextProcessing\Events\TaskSuccessfulEvent;
+use OCP\TextProcessing\IManager;
+
+class TaskBackgroundJob extends QueuedJob {
+ public function __construct(
+ ITimeFactory $timeFactory,
+ private IManager $textProcessingManager,
+ 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->textProcessingManager->getTask($taskId);
+ try {
+ $this->textProcessingManager->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 8456c41cdfc..48a0e2cdebd 100644
--- a/lib/private/Translation/TranslationManager.php
+++ b/lib/private/Translation/TranslationManager.php
@@ -28,6 +28,7 @@ namespace OC\Translation;
use InvalidArgumentException;
use OC\AppFramework\Bootstrap\Coordinator;
+use OCP\IConfig;
use OCP\IServerContainer;
use OCP\PreConditionNotMetException;
use OCP\Translation\CouldNotTranslateException;
@@ -48,6 +49,7 @@ class TranslationManager implements ITranslationManager {
private IServerContainer $serverContainer,
private Coordinator $coordinator,
private LoggerInterface $logger,
+ private IConfig $config,
) {
}
@@ -64,8 +66,25 @@ class TranslationManager implements ITranslationManager {
throw new PreConditionNotMetException('No translation providers available');
}
+ $providers = $this->getProviders();
+ $json = $this->config->getAppValue('core', 'ai.translation_provider_preferences', '');
+
+ if ($json !== '') {
+ $precedence = json_decode($json, true);
+ $newProviders = [];
+ foreach ($precedence as $className) {
+ $provider = current(array_filter($providers, fn ($provider) => $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));
+ $providers = $newProviders;
+ }
+
if ($fromLanguage === null) {
- foreach ($this->getProviders() as $provider) {
+ foreach ($providers as $provider) {
if ($provider instanceof IDetectLanguageProvider) {
$fromLanguage = $provider->detectLanguage($text);
}
@@ -84,11 +103,11 @@ class TranslationManager implements ITranslationManager {
return $text;
}
- foreach ($this->getProviders() as $provider) {
+ foreach ($providers as $provider) {
try {
return $provider->translate($fromLanguage, $toLanguage, $text);
} catch (RuntimeException $e) {
- $this->logger->warning("Failed to translate from {$fromLanguage} to {$toLanguage}", ['exception' => $e]);
+ $this->logger->warning("Failed to translate from {$fromLanguage} to {$toLanguage} using provider {$provider->getName()}", ['exception' => $e]);
}
}
diff --git a/lib/private/Updater/ChangesCheck.php b/lib/private/Updater/ChangesCheck.php
index 2c1eb321ee0..ee4d1f1fcee 100644
--- a/lib/private/Updater/ChangesCheck.php
+++ b/lib/private/Updater/ChangesCheck.php
@@ -51,6 +51,7 @@ class ChangesCheck {
/**
* @throws DoesNotExistException
+ * @return array{changelogURL: string, whatsNew: array<string, array{admin: string[], regular: string[]}>}
*/
public function getChangesForVersion(string $version): array {
$version = $this->normalizeVersion($version);
diff --git a/lib/private/Updater/VersionCheck.php b/lib/private/Updater/VersionCheck.php
index a634ae4cc71..97f770b6998 100644
--- a/lib/private/Updater/VersionCheck.php
+++ b/lib/private/Updater/VersionCheck.php
@@ -28,23 +28,19 @@ namespace OC\Updater;
use OCP\Http\Client\IClientService;
use OCP\IConfig;
+use OCP\IUserManager;
+use OCP\Support\Subscription\IRegistry;
use OCP\Util;
+use Psr\Log\LoggerInterface;
class VersionCheck {
- /** @var IClientService */
- private $clientService;
-
- /** @var IConfig */
- private $config;
-
- /**
- * @param IClientService $clientService
- * @param IConfig $config
- */
- public function __construct(IClientService $clientService,
- IConfig $config) {
- $this->clientService = $clientService;
- $this->config = $config;
+ public function __construct(
+ private IClientService $clientService,
+ private IConfig $config,
+ private IUserManager $userManager,
+ private IRegistry $registry,
+ private LoggerInterface $logger,
+ ) {
}
@@ -81,6 +77,8 @@ class VersionCheck {
$version['php_major'] = PHP_MAJOR_VERSION;
$version['php_minor'] = PHP_MINOR_VERSION;
$version['php_release'] = PHP_RELEASE_VERSION;
+ $version['category'] = $this->computeCategory();
+ $version['isSubscriber'] = (int) $this->registry->delegateHasValidSubscription();
$versionString = implode('x', $version);
//fetch xml data from updater
@@ -90,6 +88,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;
}
@@ -130,4 +130,25 @@ class VersionCheck {
$response = $client->get($url);
return $response->getBody();
}
+
+ private function computeCategory(): int {
+ $categoryBoundaries = [
+ 100,
+ 500,
+ 1000,
+ 5000,
+ 10000,
+ 100000,
+ 1000000,
+ ];
+
+ $nbUsers = $this->userManager->countSeenUsers();
+ foreach ($categoryBoundaries as $categoryId => $boundary) {
+ if ($nbUsers <= $boundary) {
+ return $categoryId;
+ }
+ }
+
+ return count($categoryBoundaries);
+ }
}
diff --git a/lib/private/User/Database.php b/lib/private/User/Database.php
index 615c392395e..9ef1bc67a58 100644
--- a/lib/private/User/Database.php
+++ b/lib/private/User/Database.php
@@ -97,7 +97,7 @@ class Database extends ABackend implements
public function __construct($eventDispatcher = null, $table = 'users') {
$this->cache = new CappedMemoryCache();
$this->table = $table;
- $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->query(IEventDispatcher::class);
+ $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OCP\Server::get(IEventDispatcher::class);
}
/**
diff --git a/lib/private/User/DisplayNameCache.php b/lib/private/User/DisplayNameCache.php
index 5d1cc8940d7..6ee74cc9f6c 100644
--- a/lib/private/User/DisplayNameCache.php
+++ b/lib/private/User/DisplayNameCache.php
@@ -29,6 +29,7 @@ use OCP\ICache;
use OCP\ICacheFactory;
use OCP\IUserManager;
use OCP\User\Events\UserChangedEvent;
+use OCP\User\Events\UserDeletedEvent;
/**
* Class that cache the relation UserId -> Display name
@@ -81,5 +82,10 @@ class DisplayNameCache implements IEventListener {
$this->cache[$userId] = $newDisplayName;
$this->memCache->set($userId, $newDisplayName, 60 * 10); // 10 minutes
}
+ if ($event instanceof UserDeletedEvent) {
+ $userId = $event->getUser()->getUID();
+ unset($this->cache[$userId]);
+ $this->memCache->remove($userId);
+ }
}
}
diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php
index 60059d5badd..fb1afb65825 100644
--- a/lib/private/User/Manager.php
+++ b/lib/private/User/Manager.php
@@ -55,7 +55,6 @@ use OCP\User\Backend\ICountUsersBackend;
use OCP\User\Events\BeforeUserCreatedEvent;
use OCP\User\Events\UserCreatedEvent;
use OCP\UserInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Class Manager
@@ -88,9 +87,6 @@ class Manager extends PublicEmitter implements IUserManager {
/** @var IConfig */
private $config;
- /** @var EventDispatcherInterface */
- private $dispatcher;
-
/** @var ICache */
private $cache;
@@ -100,11 +96,9 @@ class Manager extends PublicEmitter implements IUserManager {
private DisplayNameCache $displayNameCache;
public function __construct(IConfig $config,
- EventDispatcherInterface $oldDispatcher,
ICacheFactory $cacheFactory,
IEventDispatcher $eventDispatcher) {
$this->config = $config;
- $this->dispatcher = $oldDispatcher;
$this->cache = new WithLocalCache($cacheFactory->createDistributed('user_backend_map'));
$cachedUsers = &$this->cachedUsers;
$this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
@@ -211,7 +205,7 @@ class Manager extends PublicEmitter implements IUserManager {
return $this->cachedUsers[$uid];
}
- $user = new User($uid, $backend, $this->dispatcher, $this, $this->config);
+ $user = new User($uid, $backend, $this->eventDispatcher, $this, $this->config);
if ($cacheUser) {
$this->cachedUsers[$uid] = $user;
}
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index 840a3c04373..82887f8d029 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -51,6 +51,7 @@ use OC_User;
use OC_Util;
use OCA\DAV\Connector\Sabre\Auth;
use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\EventDispatcher\GenericEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\NotPermittedException;
use OCP\IConfig;
@@ -63,9 +64,9 @@ use OCP\Security\Bruteforce\IThrottler;
use OCP\Security\ISecureRandom;
use OCP\Session\Exceptions\SessionNotAvailableException;
use OCP\User\Events\PostLoginEvent;
+use OCP\User\Events\UserFirstTimeLoggedInEvent;
use OCP\Util;
use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
/**
* Class Session
@@ -418,7 +419,7 @@ class Session implements IUserSession, Emitter {
* @param string $user
* @param string $password
* @param IRequest $request
- * @param OC\Security\Bruteforce\Throttler $throttler
+ * @param IThrottler $throttler
* @throws LoginException
* @throws PasswordLoginForbiddenException
* @return boolean
@@ -426,7 +427,7 @@ class Session implements IUserSession, Emitter {
public function logClientIn($user,
$password,
IRequest $request,
- OC\Security\Bruteforce\Throttler $throttler) {
+ IThrottler $throttler) {
$remoteAddress = $request->getRemoteAddress();
$currentDelay = $throttler->sleepDelayOrThrowOnMax($remoteAddress, 'login');
@@ -561,7 +562,8 @@ class Session implements IUserSession, Emitter {
}
// trigger any other initialization
- \OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
+ \OC::$server->get(IEventDispatcher::class)->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
+ \OC::$server->get(IEventDispatcher::class)->dispatchTyped(new UserFirstTimeLoggedInEvent($this->getUser()));
}
}
@@ -570,11 +572,11 @@ class Session implements IUserSession, Emitter {
*
* @todo do not allow basic auth if the user is 2FA enforced
* @param IRequest $request
- * @param OC\Security\Bruteforce\Throttler $throttler
+ * @param IThrottler $throttler
* @return boolean if the login was successful
*/
public function tryBasicAuthLogin(IRequest $request,
- OC\Security\Bruteforce\Throttler $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)) {
diff --git a/lib/private/User/User.php b/lib/private/User/User.php
index b7f3b0e3740..d1185e17aef 100644
--- a/lib/private/User/User.php
+++ b/lib/private/User/User.php
@@ -49,16 +49,18 @@ use OCP\IImage;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserBackend;
+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 Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
use function json_decode;
use function json_encode;
@@ -75,8 +77,6 @@ class User implements IUser {
/** @var UserInterface|null */
private $backend;
- /** @var EventDispatcherInterface */
- private $legacyDispatcher;
/** @var IEventDispatcher */
private $dispatcher;
@@ -102,10 +102,9 @@ class User implements IUser {
/** @var IURLGenerator */
private $urlGenerator;
- public function __construct(string $uid, ?UserInterface $backend, EventDispatcherInterface $dispatcher, $emitter = null, IConfig $config = null, $urlGenerator = null) {
+ public function __construct(string $uid, ?UserInterface $backend, IEventDispatcher $dispatcher, $emitter = null, IConfig $config = null, $urlGenerator = null) {
$this->uid = $uid;
$this->backend = $backend;
- $this->legacyDispatcher = $dispatcher;
$this->emitter = $emitter;
if (is_null($config)) {
$config = \OC::$server->getConfig();
@@ -115,8 +114,7 @@ class User implements IUser {
if (is_null($this->urlGenerator)) {
$this->urlGenerator = \OC::$server->getURLGenerator();
}
- // TODO: inject
- $this->dispatcher = \OC::$server->query(IEventDispatcher::class);
+ $this->dispatcher = $dispatcher;
}
/**
@@ -270,8 +268,6 @@ class User implements IUser {
* @return bool
*/
public function delete() {
- /** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
- $this->legacyDispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
if ($this->emitter) {
/** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
$this->emitter->emit('\OC\User', 'preDelete', [$this]);
@@ -298,7 +294,7 @@ class User implements IUser {
\OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
/** @var AvatarManager $avatarManager */
- $avatarManager = \OC::$server->query(AvatarManager::class);
+ $avatarManager = \OCP\Server::get(AvatarManager::class);
$avatarManager->deleteUserAvatar($this->uid);
$notification = \OC::$server->getNotificationManager()->createNotification();
@@ -306,11 +302,9 @@ class User implements IUser {
\OC::$server->getNotificationManager()->markProcessed($notification);
/** @var AccountManager $accountManager */
- $accountManager = \OC::$server->query(AccountManager::class);
+ $accountManager = \OCP\Server::get(AccountManager::class);
$accountManager->deleteUser($this);
- /** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
- $this->legacyDispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
if ($this->emitter) {
/** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
$this->emitter->emit('\OC\User', 'postDelete', [$this]);
@@ -328,10 +322,7 @@ class User implements IUser {
* @return bool
*/
public function setPassword($password, $recoveryPassword = null) {
- $this->legacyDispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
- 'password' => $password,
- 'recoveryPassword' => $recoveryPassword,
- ]));
+ $this->dispatcher->dispatchTyped(new BeforePasswordUpdatedEvent($this, $password, $recoveryPassword));
if ($this->emitter) {
$this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
}
@@ -341,10 +332,7 @@ class User implements IUser {
$result = $backend->setPassword($this->uid, $password);
if ($result !== false) {
- $this->legacyDispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
- 'password' => $password,
- 'recoveryPassword' => $recoveryPassword,
- ]));
+ $this->dispatcher->dispatchTyped(new PasswordUpdatedEvent($this, $password, $recoveryPassword));
if ($this->emitter) {
$this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
}
@@ -432,25 +420,46 @@ class User implements IUser {
* @return bool
*/
public function isEnabled() {
- if ($this->enabled === null) {
- $enabled = $this->config->getUserValue($this->uid, 'core', 'enabled', 'true');
- $this->enabled = $enabled === 'true';
+ $queryDatabaseValue = function (): bool {
+ if ($this->enabled === null) {
+ $enabled = $this->config->getUserValue($this->uid, 'core', 'enabled', 'true');
+ $this->enabled = $enabled === 'true';
+ }
+ return $this->enabled;
+ };
+ if ($this->backend instanceof IProvideEnabledStateBackend) {
+ return $this->backend->isUserEnabled($this->uid, $queryDatabaseValue);
+ } else {
+ return $queryDatabaseValue();
}
- return (bool) $this->enabled;
}
/**
* set the enabled status for the user
*
- * @param bool $enabled
+ * @return void
*/
public function setEnabled(bool $enabled = true) {
$oldStatus = $this->isEnabled();
- $this->enabled = $enabled;
- if ($oldStatus !== $this->enabled) {
- // TODO: First change the value, then trigger the event as done for all other properties.
- $this->triggerChange('enabled', $enabled, $oldStatus);
+ $setDatabaseValue = function (bool $enabled): void {
$this->config->setUserValue($this->uid, 'core', 'enabled', $enabled ? 'true' : 'false');
+ $this->enabled = $enabled;
+ };
+ if ($this->backend instanceof IProvideEnabledStateBackend) {
+ $queryDatabaseValue = function (): bool {
+ if ($this->enabled === null) {
+ $enabled = $this->config->getUserValue($this->uid, 'core', 'enabled', 'true');
+ $this->enabled = $enabled === 'true';
+ }
+ return $this->enabled;
+ };
+ $enabled = $this->backend->setUserEnabled($this->uid, $enabled, $queryDatabaseValue, $setDatabaseValue);
+ if ($oldStatus !== $enabled) {
+ $this->triggerChange('enabled', $enabled, $oldStatus);
+ }
+ } elseif ($oldStatus !== $enabled) {
+ $setDatabaseValue($enabled);
+ $this->triggerChange('enabled', $enabled, $oldStatus);
}
}
@@ -604,11 +613,7 @@ class User implements IUser {
}
public function triggerChange($feature, $value = null, $oldValue = null) {
- $this->legacyDispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
- 'feature' => $feature,
- 'value' => $value,
- 'oldValue' => $oldValue,
- ]));
+ $this->dispatcher->dispatchTyped(new UserChangedEvent($this, $feature, $value, $oldValue));
if ($this->emitter) {
$this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
}
diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php
index a1aeb50bbf4..ac449a62a4f 100644
--- a/lib/private/legacy/OC_App.php
+++ b/lib/private/legacy/OC_App.php
@@ -52,7 +52,6 @@ declare(strict_types=1);
*/
use OCP\App\Events\AppUpdateEvent;
-use OCP\AppFramework\QueryException;
use OCP\App\IAppManager;
use OCP\App\ManagerEvent;
use OCP\Authentication\IAlternativeLogin;
@@ -65,6 +64,7 @@ use OC\DB\MigrationService;
use OC\Installer;
use OC\Repair;
use OC\Repair\Events\RepairErrorEvent;
+use Psr\Container\ContainerExceptionInterface;
use Psr\Log\LoggerInterface;
/**
@@ -255,7 +255,7 @@ class OC_App {
array $groups = []) {
// Check if app is already downloaded
/** @var Installer $installer */
- $installer = \OC::$server->query(Installer::class);
+ $installer = \OCP\Server::get(Installer::class);
$isDownloaded = $installer->isDownloaded($appId);
if (!$isDownloaded) {
@@ -463,7 +463,7 @@ class OC_App {
*/
public static function getAlternativeLogIns(): array {
/** @var Coordinator $bootstrapCoordinator */
- $bootstrapCoordinator = \OC::$server->query(Coordinator::class);
+ $bootstrapCoordinator = \OCP\Server::get(Coordinator::class);
foreach ($bootstrapCoordinator->getRegistrationContext()->getAlternativeLogins() as $registration) {
if (!in_array(IAlternativeLogin::class, class_implements($registration->getService()), true)) {
@@ -477,8 +477,8 @@ class OC_App {
try {
/** @var IAlternativeLogin $provider */
- $provider = \OC::$server->query($registration->getService());
- } catch (QueryException $e) {
+ $provider = \OCP\Server::get($registration->getService());
+ } catch (ContainerExceptionInterface $e) {
\OC::$server->getLogger()->logException($e, [
'message' => 'Alternative login option {option} can not be initialised.',
'option' => $registration->getService(),
@@ -543,7 +543,7 @@ class OC_App {
*/
public function getSupportedApps(): array {
/** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
- $subscriptionRegistry = \OC::$server->query(\OCP\Support\Subscription\IRegistry::class);
+ $subscriptionRegistry = \OCP\Server::get(\OCP\Support\Subscription\IRegistry::class);
$supportedApps = $subscriptionRegistry->delegateGetSupportedApps();
return $supportedApps;
}
@@ -802,7 +802,7 @@ class OC_App {
\OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
\OC::$server->get(IEventDispatcher::class)->dispatchTyped(new AppUpdateEvent($appId));
- \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
+ \OC::$server->get(IEventDispatcher::class)->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
ManagerEvent::EVENT_APP_UPDATE, $appId
));
diff --git a/lib/private/legacy/OC_Files.php b/lib/private/legacy/OC_Files.php
index b6c45e164ef..911c713f840 100644
--- a/lib/private/legacy/OC_Files.php
+++ b/lib/private/legacy/OC_Files.php
@@ -230,6 +230,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);
@@ -333,7 +337,7 @@ class OC_Files {
$rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), $fileSize);
}
- $dispatcher = \OC::$server->query(IEventDispatcher::class);
+ $dispatcher = \OCP\Server::get(IEventDispatcher::class);
$event = new BeforeDirectFileDownloadEvent($filename);
$dispatcher->dispatchTyped($event);
diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php
index 8c8be0e1069..cf39d045ae9 100644
--- a/lib/private/legacy/OC_Helper.php
+++ b/lib/private/legacy/OC_Helper.php
@@ -54,9 +54,23 @@ use Psr\Log\LoggerInterface;
/**
* Collection of useful functions
+ *
+ * @psalm-type StorageInfo = array{
+ * free: float|int,
+ * mountPoint: string,
+ * mountType: string,
+ * owner: string,
+ * ownerDisplayName: string,
+ * quota: float|int,
+ * relative: float|int,
+ * total: float|int,
+ * used: float|int,
+ * }
*/
class OC_Helper {
private static $templateManager;
+ private static ?ICacheFactory $cacheFactory = null;
+ private static ?bool $quotaIncludeExternalStorage = null;
/**
* Make a human file size
@@ -458,16 +472,20 @@ class OC_Helper {
* @param \OCP\Files\FileInfo $rootInfo (optional)
* @param bool $includeMountPoints whether to include mount points in the size calculation
* @param bool $useCache whether to use the cached quota values
- * @return array
+ * @psalm-suppress LessSpecificReturnStatement Legacy code outputs weird types - manually validated that they are correct
+ * @return StorageInfo
* @throws \OCP\Files\NotFoundException
*/
public static function getStorageInfo($path, $rootInfo = null, $includeMountPoints = true, $useCache = true) {
- /** @var ICacheFactory $cacheFactory */
- $cacheFactory = \OC::$server->get(ICacheFactory::class);
- $memcache = $cacheFactory->createLocal('storage_info');
+ if (!self::$cacheFactory) {
+ self::$cacheFactory = \OC::$server->get(ICacheFactory::class);
+ }
+ $memcache = self::$cacheFactory->createLocal('storage_info');
// return storage info without adding mount points
- $includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
+ if (self::$quotaIncludeExternalStorage === null) {
+ self::$quotaIncludeExternalStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
+ }
$view = Filesystem::getView();
if (!$view) {
@@ -484,23 +502,24 @@ class OC_Helper {
}
if (!$rootInfo) {
- $rootInfo = \OC\Files\Filesystem::getFileInfo($path, $includeExtStorage ? 'ext' : false);
+ $rootInfo = \OC\Files\Filesystem::getFileInfo($path, self::$quotaIncludeExternalStorage ? 'ext' : false);
}
if (!$rootInfo instanceof \OCP\Files\FileInfo) {
throw new \OCP\Files\NotFoundException('The root directory of the user\'s files is missing');
}
$used = $rootInfo->getSize($includeMountPoints);
if ($used < 0) {
- $used = 0;
+ $used = 0.0;
}
+ /** @var int|float $quota */
$quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
$mount = $rootInfo->getMountPoint();
$storage = $mount->getStorage();
$sourceStorage = $storage;
if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
- $includeExtStorage = false;
+ self::$quotaIncludeExternalStorage = false;
}
- if ($includeExtStorage) {
+ if (self::$quotaIncludeExternalStorage) {
if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
) {
@@ -523,6 +542,9 @@ class OC_Helper {
}
try {
$free = $sourceStorage->free_space($rootInfo->getInternalPath());
+ if (is_bool($free)) {
+ $free = 0.0;
+ }
} catch (\Exception $e) {
if ($path === "") {
throw $e;
@@ -549,6 +571,7 @@ class OC_Helper {
$relative = 0;
}
+ /** @var string $ownerId */
$ownerId = $storage->getOwner($path);
$ownerDisplayName = '';
if ($ownerId) {
@@ -580,15 +603,20 @@ class OC_Helper {
/**
* Get storage info including all mount points and quota
+ *
+ * @psalm-suppress LessSpecificReturnStatement Legacy code outputs weird types - manually validated that they are correct
+ * @return StorageInfo
*/
private static function getGlobalStorageInfo(int|float $quota, IUser $user, IMountPoint $mount): array {
$rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
+ /** @var int|float $used */
$used = $rootInfo['size'];
if ($used < 0) {
- $used = 0;
+ $used = 0.0;
}
$total = $quota;
+ /** @var int|float $free */
$free = $quota - $used;
if ($total > 0) {
@@ -598,7 +626,7 @@ class OC_Helper {
// prevent division by zero or error codes (negative values)
$relative = round(($used / $total) * 10000) / 100;
} else {
- $relative = 0;
+ $relative = 0.0;
}
if (substr_count($mount->getMountPoint(), '/') < 3) {
diff --git a/lib/private/legacy/OC_Image.php b/lib/private/legacy/OC_Image.php
index 74e82e62b16..aac0c496734 100644
--- a/lib/private/legacy/OC_Image.php
+++ b/lib/private/legacy/OC_Image.php
@@ -758,7 +758,7 @@ class OC_Image implements \OCP\IImage {
if (!$this->checkImageDataSize($data)) {
return false;
}
- $this->resource = imagecreatefromstring($data);
+ $this->resource = @imagecreatefromstring($data);
$iType = IMAGETYPE_PNG;
$this->logger->debug('OC_Image->loadFromFile, Default', ['app' => 'core']);
break;
diff --git a/lib/private/legacy/OC_Template.php b/lib/private/legacy/OC_Template.php
index 0c9fa1ccc0c..974f26fa381 100644
--- a/lib/private/legacy/OC_Template.php
+++ b/lib/private/legacy/OC_Template.php
@@ -39,7 +39,6 @@
*/
use OC\TemplateLayout;
use OCP\AppFramework\Http\TemplateResponse;
-use OCP\Util;
require_once __DIR__.'/template/functions.php';
@@ -59,8 +58,6 @@ class OC_Template extends \OC\Template\Base {
/** @var string */
protected $app; // app id
- protected static $initTemplateEngineFirstRun = true;
-
/**
* Constructor
*
@@ -73,9 +70,6 @@ class OC_Template extends \OC\Template\Base {
* @param bool $registerCall = true
*/
public function __construct($app, $name, $renderAs = TemplateResponse::RENDER_AS_BLANK, $registerCall = true) {
- // Read the selected theme from the config file
- self::initTemplateEngine($renderAs);
-
$theme = OC_Util::getTheme();
$requestToken = (OC::$server->getSession() && $registerCall) ? \OCP\Util::callRegister() : '';
@@ -83,7 +77,7 @@ class OC_Template extends \OC\Template\Base {
$parts = explode('/', $app); // fix translation when app is something like core/lostpassword
$l10n = \OC::$server->getL10N($parts[0]);
/** @var \OCP\Defaults $themeDefaults */
- $themeDefaults = \OC::$server->query(\OCP\Defaults::class);
+ $themeDefaults = \OCP\Server::get(\OCP\Defaults::class);
[$path, $template] = $this->findTemplate($theme, $app, $name);
@@ -95,40 +89,6 @@ class OC_Template extends \OC\Template\Base {
parent::__construct($template, $requestToken, $l10n, $themeDefaults);
}
- /**
- * @param string $renderAs
- */
- public static function initTemplateEngine($renderAs) {
- if (self::$initTemplateEngineFirstRun) {
- // apps that started before the template initialization can load their own scripts/styles
- // so to make sure this scripts/styles here are loaded first we put all core scripts first
- // check lib/public/Util.php
- OC_Util::addStyle('server', null, true);
-
- // include common nextcloud webpack bundle
- Util::addScript('core', 'common');
- Util::addScript('core', 'main');
- Util::addTranslations('core');
-
- if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
- Util::addScript('core', 'files_fileinfo');
- Util::addScript('core', 'files_client');
- Util::addScript('core', 'merged-template-prepend');
- }
-
- // If installed and background job is set to ajax, add dedicated script
- if (\OC::$server->getSystemConfig()->getValue('installed', false)
- && $renderAs !== TemplateResponse::RENDER_AS_ERROR
- && !\OCP\Util::needUpgrade()) {
- if (\OC::$server->getConfig()->getAppValue('core', 'backgroundjobs_mode', 'ajax') == 'ajax') {
- Util::addScript('core', 'backgroundjobs');
- }
- }
-
- self::$initTemplateEngineFirstRun = false;
- }
- }
-
/**
* find the template with the given name
diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php
index 63599ff833b..f82ddcc78ee 100644
--- a/lib/private/legacy/OC_Util.php
+++ b/lib/private/legacy/OC_Util.php
@@ -68,7 +68,6 @@ use bantu\IniGetWrapper\IniGetWrapper;
use OC\Files\SetupManager;
use OCP\Files\Template\ITemplateManager;
use OCP\IConfig;
-use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IURLGenerator;
use OCP\IUser;
@@ -326,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 */
@@ -715,8 +715,6 @@ class OC_Util {
}
}
- $errors = array_merge($errors, self::checkDatabaseVersion());
-
// Cache the result of this function
\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
@@ -724,43 +722,6 @@ class OC_Util {
}
/**
- * Check the database version
- *
- * @return array errors array
- */
- public static function checkDatabaseVersion() {
- $l = \OC::$server->getL10N('lib');
- $errors = [];
- $dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
- if ($dbType === 'pgsql') {
- // check PostgreSQL version
- // TODO latest postgresql 8 released was 8 years ago, maybe remove the
- // check completely?
- try {
- /** @var IDBConnection $connection */
- $connection = \OC::$server->get(IDBConnection::class);
- $result = $connection->executeQuery('SHOW SERVER_VERSION');
- $data = $result->fetch();
- $result->closeCursor();
- if (isset($data['server_version'])) {
- $version = $data['server_version'];
- if (version_compare($version, '9.0.0', '<')) {
- $errors[] = [
- 'error' => $l->t('PostgreSQL >= 9 required.'),
- 'hint' => $l->t('Please upgrade your database version.')
- ];
- }
- }
- } catch (\Doctrine\DBAL\Exception $e) {
- $logger = \OC::$server->getLogger();
- $logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
- $logger->logException($e);
- }
- }
- return $errors;
- }
-
- /**
* Check for correct file permissions of data directory
*
* @param string $dataDirectory
diff --git a/lib/private/legacy/template/functions.php b/lib/private/legacy/template/functions.php
index 7081bd4f743..bcc0906dcdf 100644
--- a/lib/private/legacy/template/functions.php
+++ b/lib/private/legacy/template/functions.php
@@ -101,7 +101,8 @@ function emit_script_tag(string $src, string $script_content = '', string $conte
*/
function emit_script_loading_tags($obj) {
foreach ($obj['jsfiles'] as $jsfile) {
- $type = str_ends_with($jsfile, '.mjs') ? 'module' : '';
+ $fileName = explode('?', $jsfile, 2)[0];
+ $type = str_ends_with($fileName, '.mjs') ? 'module' : '';
emit_script_tag($jsfile, '', $type);
}
if (!empty($obj['inline_ocjs'])) {
@@ -308,7 +309,7 @@ function strip_time($timestamp) {
*/
function relative_modified_date($timestamp, $fromTime = null, $dateOnly = false) {
/** @var \OC\DateTimeFormatter $formatter */
- $formatter = \OC::$server->query('DateTimeFormatter');
+ $formatter = \OCP\Server::get('DateTimeFormatter');
if ($dateOnly) {
return $formatter->formatDateSpan($timestamp, $fromTime);
diff --git a/lib/public/Accounts/UserUpdatedEvent.php b/lib/public/Accounts/UserUpdatedEvent.php
new file mode 100644
index 00000000000..e6c73f1d1c1
--- /dev/null
+++ b/lib/public/Accounts/UserUpdatedEvent.php
@@ -0,0 +1,58 @@
+<?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\Accounts;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+class UserUpdatedEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ protected IUser $user,
+ protected array $data,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getData(): array {
+ return $this->data;
+ }
+}
diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php
index 66cf1ef2306..720803a78d1 100644
--- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php
+++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php
@@ -37,6 +37,7 @@ 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;
@@ -220,6 +221,16 @@ interface IRegistrationContext {
public function registerSpeechToTextProvider(string $providerClass): void;
/**
+ * Register a custom text processing provider class that provides a promptable language model
+ * through the OCP\TextProcessing APIs
+ *
+ * @param string $providerClass
+ * @psalm-param class-string<ITextProcessingProvider> $providerClass
+ * @since 27.1.0
+ */
+ public function registerTextProcessingProvider(string $providerClass): void;
+
+ /**
* Register a custom template provider class that is able to inject custom templates
* in addition to the user defined ones
*
diff --git a/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php b/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php
new file mode 100644
index 00000000000..31ccd014321
--- /dev/null
+++ b/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php
@@ -0,0 +1,37 @@
+<?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\AppFramework\Http\Attribute;
+
+use Attribute;
+
+/**
+ * Attribute for controller methods that should be ignored when generating OpenAPI documentation
+ *
+ * @since 28.0.0
+ */
+#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)]
+class IgnoreOpenAPI {
+}
diff --git a/lib/public/AppFramework/Http/ContentSecurityPolicy.php b/lib/public/AppFramework/Http/ContentSecurityPolicy.php
index 0e3a6a705d5..f17dd9bd270 100644
--- a/lib/public/AppFramework/Http/ContentSecurityPolicy.php
+++ b/lib/public/AppFramework/Http/ContentSecurityPolicy.php
@@ -44,6 +44,8 @@ class ContentSecurityPolicy extends EmptyContentSecurityPolicy {
protected $inlineScriptAllowed = false;
/** @var bool Whether eval in JS scripts is allowed */
protected $evalScriptAllowed = false;
+ /** @var bool Whether WebAssembly compilation is allowed */
+ protected ?bool $evalWasmAllowed = false;
/** @var bool Whether strict-dynamic should be set */
protected $strictDynamicAllowed = false;
/** @var array Domains from which scripts can get loaded */
diff --git a/lib/public/AppFramework/Http/DataDisplayResponse.php b/lib/public/AppFramework/Http/DataDisplayResponse.php
index 78ab343abd6..be2ade50bb5 100644
--- a/lib/public/AppFramework/Http/DataDisplayResponse.php
+++ b/lib/public/AppFramework/Http/DataDisplayResponse.php
@@ -6,6 +6,7 @@
* @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -30,6 +31,9 @@ use OCP\AppFramework\Http;
* Class DataDisplayResponse
*
* @since 8.1.0
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class DataDisplayResponse extends Response {
/**
@@ -41,17 +45,14 @@ class DataDisplayResponse extends Response {
/**
* @param string $data the data to display
- * @param int $statusCode the Http status code, defaults to 200
- * @param array $headers additional key value based headers
+ * @param S $statusCode the Http status code, defaults to 200
+ * @param H $headers additional key value based headers
* @since 8.1.0
*/
- public function __construct($data = '', $statusCode = Http::STATUS_OK,
- $headers = []) {
- parent::__construct();
+ public function __construct(string $data = '', int $statusCode = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($statusCode, $headers);
$this->data = $data;
- $this->setStatus($statusCode);
- $this->setHeaders(array_merge($this->getHeaders(), $headers));
$this->addHeader('Content-Disposition', 'inline; filename=""');
}
diff --git a/lib/public/AppFramework/Http/DataDownloadResponse.php b/lib/public/AppFramework/Http/DataDownloadResponse.php
index 7f2bc73f6e2..f7005604795 100644
--- a/lib/public/AppFramework/Http/DataDownloadResponse.php
+++ b/lib/public/AppFramework/Http/DataDownloadResponse.php
@@ -5,6 +5,7 @@
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -23,10 +24,16 @@
*/
namespace OCP\AppFramework\Http;
+use OCP\AppFramework\Http;
+
/**
* Class DataDownloadResponse
*
* @since 8.0.0
+ * @template S of int
+ * @template C of string
+ * @template H of array<string, mixed>
+ * @template-extends DownloadResponse<int, string, array<string, mixed>>
*/
class DataDownloadResponse extends DownloadResponse {
/**
@@ -38,12 +45,14 @@ class DataDownloadResponse extends DownloadResponse {
* Creates a response that prompts the user to download the text
* @param string $data text to be downloaded
* @param string $filename the name that the downloaded file should have
- * @param string $contentType the mimetype that the downloaded file should have
+ * @param C $contentType the mimetype that the downloaded file should have
+ * @param S $status
+ * @param H $headers
* @since 8.0.0
*/
- public function __construct($data, $filename, $contentType) {
+ public function __construct(string $data, string $filename, string $contentType, int $status = Http::STATUS_OK, array $headers = []) {
$this->data = $data;
- parent::__construct($filename, $contentType);
+ parent::__construct($filename, $contentType, $status, $headers);
}
/**
diff --git a/lib/public/AppFramework/Http/DataResponse.php b/lib/public/AppFramework/Http/DataResponse.php
index e329b9c2975..1a56847d63d 100644
--- a/lib/public/AppFramework/Http/DataResponse.php
+++ b/lib/public/AppFramework/Http/DataResponse.php
@@ -6,6 +6,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -30,34 +31,37 @@ use OCP\AppFramework\Http;
* A generic DataResponse class that is used to return generic data responses
* for responders to transform
* @since 8.0.0
+ * @psalm-type DataResponseType = array|int|float|string|bool|object|null|\stdClass|\JsonSerializable
+ * @template S of int
+ * @template-covariant T of DataResponseType
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class DataResponse extends Response {
/**
* response data
- * @var array|int|float|string|bool|object
+ * @var T
*/
protected $data;
/**
- * @param array|int|float|string|bool|object $data the object or array that should be transformed
- * @param int $statusCode the Http status code, defaults to 200
- * @param array $headers additional key value based headers
+ * @param T $data the object or array that should be transformed
+ * @param S $statusCode the Http status code, defaults to 200
+ * @param H $headers additional key value based headers
* @since 8.0.0
*/
- public function __construct($data = [], $statusCode = Http::STATUS_OK,
- array $headers = []) {
- parent::__construct();
+ public function __construct(mixed $data = [], int $statusCode = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($statusCode, $headers);
$this->data = $data;
- $this->setStatus($statusCode);
- $this->setHeaders(array_merge($this->getHeaders(), $headers));
}
/**
* Sets values in the data json array
- * @param array|int|float|string|object $data an array or object which will be transformed
+ * @psalm-suppress InvalidTemplateParam
+ * @param T $data an array or object which will be transformed
* @return DataResponse Reference to this object
* @since 8.0.0
*/
@@ -70,7 +74,7 @@ class DataResponse extends Response {
/**
* Used to get the set parameters
- * @return array|int|float|string|bool|object the data
+ * @return T the data
* @since 8.0.0
*/
public function getData() {
diff --git a/lib/public/AppFramework/Http/DownloadResponse.php b/lib/public/AppFramework/Http/DownloadResponse.php
index b80f03958c0..5b3a235d444 100644
--- a/lib/public/AppFramework/Http/DownloadResponse.php
+++ b/lib/public/AppFramework/Http/DownloadResponse.php
@@ -7,6 +7,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @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
*
@@ -25,19 +26,27 @@
*/
namespace OCP\AppFramework\Http;
+use OCP\AppFramework\Http;
+
/**
* Prompts the user to download the a file
* @since 7.0.0
+ * @template S of int
+ * @template C of string
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class DownloadResponse extends Response {
/**
* Creates a response that prompts the user to download the file
* @param string $filename the name that the downloaded file should have
- * @param string $contentType the mimetype that the downloaded file should have
+ * @param C $contentType the mimetype that the downloaded file should have
+ * @param S $status
+ * @param H $headers
* @since 7.0.0
*/
- public function __construct(string $filename, string $contentType) {
- parent::__construct();
+ public function __construct(string $filename, string $contentType, int $status = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($status, $headers);
$filename = strtr($filename, ['"' => '\\"', '\\' => '\\\\']);
diff --git a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php
index 035b4f01f60..7e1de2ef2eb 100644
--- a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php
+++ b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php
@@ -47,6 +47,8 @@ class EmptyContentSecurityPolicy {
* @link https://github.com/owncloud/core/issues/11925
*/
protected $evalScriptAllowed = null;
+ /** @var bool Whether WebAssembly compilation is allowed */
+ protected ?bool $evalWasmAllowed = null;
/** @var array Domains from which scripts can get loaded */
protected $allowedScriptDomains = null;
/**
@@ -117,6 +119,17 @@ class EmptyContentSecurityPolicy {
}
/**
+ * Whether WebAssembly compilation is allowed or forbidden
+ * @param bool $state
+ * @return $this
+ * @since 28.0.0
+ */
+ public function allowEvalWasm(bool $state = true) {
+ $this->evalWasmAllowed = $state;
+ return $this;
+ }
+
+ /**
* Allows to execute JavaScript files from a specific domain. Use * to
* allow JavaScript from all domains.
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
@@ -433,7 +446,7 @@ class EmptyContentSecurityPolicy {
$policy .= "base-uri 'none';";
$policy .= "manifest-src 'self';";
- if (!empty($this->allowedScriptDomains) || $this->evalScriptAllowed) {
+ if (!empty($this->allowedScriptDomains) || $this->evalScriptAllowed || $this->evalWasmAllowed) {
$policy .= 'script-src ';
if (is_string($this->useJsNonce)) {
if ($this->strictDynamicAllowed) {
@@ -453,6 +466,9 @@ class EmptyContentSecurityPolicy {
if ($this->evalScriptAllowed) {
$policy .= ' \'unsafe-eval\'';
}
+ if ($this->evalWasmAllowed) {
+ $policy .= ' \'wasm-unsafe-eval\'';
+ }
$policy .= ';';
}
diff --git a/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php b/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php
new file mode 100644
index 00000000000..99c1275f3ff
--- /dev/null
+++ b/lib/public/AppFramework/Http/Events/BeforeLoginTemplateRenderedEvent.php
@@ -0,0 +1,52 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @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\AppFramework\Http\Events;
+
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\EventDispatcher\Event;
+
+/**
+ * Emitted before the rendering step of the login TemplateResponse.
+ *
+ * @since 28.0.0
+ */
+class BeforeLoginTemplateRenderedEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(private TemplateResponse $response) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getResponse(): TemplateResponse {
+ return $this->response;
+ }
+}
diff --git a/lib/public/AppFramework/Http/FileDisplayResponse.php b/lib/public/AppFramework/Http/FileDisplayResponse.php
index 41b452b5553..f194a23f1fe 100644
--- a/lib/public/AppFramework/Http/FileDisplayResponse.php
+++ b/lib/public/AppFramework/Http/FileDisplayResponse.php
@@ -4,6 +4,7 @@
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -24,31 +25,33 @@
namespace OCP\AppFramework\Http;
use OCP\AppFramework\Http;
+use OCP\Files\File;
+use OCP\Files\SimpleFS\ISimpleFile;
/**
* Class FileDisplayResponse
*
* @since 11.0.0
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class FileDisplayResponse extends Response implements ICallbackResponse {
- /** @var \OCP\Files\File|\OCP\Files\SimpleFS\ISimpleFile */
+ /** @var File|ISimpleFile */
private $file;
/**
* FileDisplayResponse constructor.
*
- * @param \OCP\Files\File|\OCP\Files\SimpleFS\ISimpleFile $file
- * @param int $statusCode
- * @param array $headers
+ * @param File|ISimpleFile $file
+ * @param S $statusCode
+ * @param H $headers
* @since 11.0.0
*/
- public function __construct($file, $statusCode = Http::STATUS_OK,
- $headers = []) {
- parent::__construct();
+ public function __construct(File|ISimpleFile $file, int $statusCode = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($statusCode, $headers);
$this->file = $file;
- $this->setStatus($statusCode);
- $this->setHeaders(array_merge($this->getHeaders(), $headers));
$this->addHeader('Content-Disposition', 'inline; filename="' . rawurldecode($file->getName()) . '"');
$this->setETag($file->getEtag());
diff --git a/lib/public/AppFramework/Http/JSONResponse.php b/lib/public/AppFramework/Http/JSONResponse.php
index d31a2761673..f6004296323 100644
--- a/lib/public/AppFramework/Http/JSONResponse.php
+++ b/lib/public/AppFramework/Http/JSONResponse.php
@@ -9,6 +9,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -32,26 +33,30 @@ use OCP\AppFramework\Http;
/**
* A renderer for JSON calls
* @since 6.0.0
+ * @template S of int
+ * @template-covariant T of array|object|\stdClass|\JsonSerializable
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class JSONResponse extends Response {
/**
* response data
- * @var array|object
+ * @var T
*/
protected $data;
/**
* constructor of JSONResponse
- * @param array|object $data the object or array that should be transformed
- * @param int $statusCode the Http status code, defaults to 200
+ * @param T $data the object or array that should be transformed
+ * @param S $statusCode the Http status code, defaults to 200
+ * @param H $headers
* @since 6.0.0
*/
- public function __construct($data = [], $statusCode = Http::STATUS_OK) {
- parent::__construct();
+ public function __construct(mixed $data = [], int $statusCode = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($statusCode, $headers);
$this->data = $data;
- $this->setStatus($statusCode);
$this->addHeader('Content-Type', 'application/json; charset=utf-8');
}
@@ -68,7 +73,8 @@ class JSONResponse extends Response {
/**
* Sets values in the data json array
- * @param array|object $data an array or object which will be transformed
+ * @psalm-suppress InvalidTemplateParam
+ * @param T $data an array or object which will be transformed
* to JSON
* @return JSONResponse Reference to this object
* @since 6.0.0 - return value was added in 7.0.0
@@ -81,8 +87,7 @@ class JSONResponse extends Response {
/**
- * Used to get the set parameters
- * @return array the data
+ * @return T the data
* @since 6.0.0
*/
public function getData() {
diff --git a/lib/public/AppFramework/Http/NotFoundResponse.php b/lib/public/AppFramework/Http/NotFoundResponse.php
index 34b74d353db..d6df0f60467 100644
--- a/lib/public/AppFramework/Http/NotFoundResponse.php
+++ b/lib/public/AppFramework/Http/NotFoundResponse.php
@@ -6,6 +6,7 @@
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -24,18 +25,24 @@
*/
namespace OCP\AppFramework\Http;
+use OCP\AppFramework\Http;
+
/**
* A generic 404 response showing an 404 error page as well to the end-user
* @since 8.1.0
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends TemplateResponse<int, array<string, mixed>>
*/
class NotFoundResponse extends TemplateResponse {
/**
+ * @param S $status
+ * @param H $headers
* @since 8.1.0
*/
- public function __construct() {
- parent::__construct('core', '404', [], 'guest');
+ public function __construct(int $status = Http::STATUS_NOT_FOUND, array $headers = []) {
+ parent::__construct('core', '404', [], 'guest', $status, $headers);
$this->setContentSecurityPolicy(new ContentSecurityPolicy());
- $this->setStatus(404);
}
}
diff --git a/lib/public/AppFramework/Http/RedirectResponse.php b/lib/public/AppFramework/Http/RedirectResponse.php
index 87853391e86..b6916195954 100644
--- a/lib/public/AppFramework/Http/RedirectResponse.php
+++ b/lib/public/AppFramework/Http/RedirectResponse.php
@@ -7,6 +7,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author v1r0x <vinzenz.rosenkranz@gmail.com>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -30,6 +31,9 @@ use OCP\AppFramework\Http;
/**
* Redirects to a different URL
* @since 7.0.0
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class RedirectResponse extends Response {
private $redirectURL;
@@ -37,13 +41,14 @@ class RedirectResponse extends Response {
/**
* Creates a response that redirects to a url
* @param string $redirectURL the url to redirect to
+ * @param S $status
+ * @param H $headers
* @since 7.0.0
*/
- public function __construct($redirectURL) {
- parent::__construct();
+ public function __construct(string $redirectURL, int $status = Http::STATUS_SEE_OTHER, array $headers = []) {
+ parent::__construct($status, $headers);
$this->redirectURL = $redirectURL;
- $this->setStatus(Http::STATUS_SEE_OTHER);
$this->addHeader('Location', $redirectURL);
}
diff --git a/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php b/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php
index ad11b53637b..7a1bfdbaf8f 100644
--- a/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php
+++ b/lib/public/AppFramework/Http/RedirectToDefaultAppResponse.php
@@ -7,6 +7,7 @@ declare(strict_types=1);
*
* @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -26,6 +27,7 @@ declare(strict_types=1);
*/
namespace OCP\AppFramework\Http;
+use OCP\AppFramework\Http;
use OCP\IURLGenerator;
/**
@@ -33,17 +35,22 @@ use OCP\IURLGenerator;
*
* @since 16.0.0
* @deprecated 23.0.0 Use RedirectResponse() with IURLGenerator::linkToDefaultPageUrl() instead
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends RedirectResponse<int, array<string, mixed>>
*/
class RedirectToDefaultAppResponse extends RedirectResponse {
/**
* Creates a response that redirects to the default app
*
+ * @param S $status
+ * @param H $headers
* @since 16.0.0
* @deprecated 23.0.0 Use RedirectResponse() with IURLGenerator::linkToDefaultPageUrl() instead
*/
- public function __construct() {
+ public function __construct(int $status = Http::STATUS_SEE_OTHER, array $headers = []) {
/** @var IURLGenerator $urlGenerator */
$urlGenerator = \OC::$server->get(IURLGenerator::class);
- parent::__construct($urlGenerator->linkToDefaultPageUrl());
+ parent::__construct($urlGenerator->linkToDefaultPageUrl(), $status, $headers);
}
}
diff --git a/lib/public/AppFramework/Http/Response.php b/lib/public/AppFramework/Http/Response.php
index 152f8c4a3c5..dd4f2c53418 100644
--- a/lib/public/AppFramework/Http/Response.php
+++ b/lib/public/AppFramework/Http/Response.php
@@ -12,6 +12,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -41,15 +42,15 @@ use Psr\Log\LoggerInterface;
*
* It handles headers, HTTP status code, last modified and ETag.
* @since 6.0.0
+ * @template S of int
+ * @template H of array<string, mixed>
*/
class Response {
/**
- * Headers - defaults to ['Cache-Control' => 'no-cache, no-store, must-revalidate']
- * @var array
+ * Headers
+ * @var H
*/
- private $headers = [
- 'Cache-Control' => 'no-cache, no-store, must-revalidate'
- ];
+ private $headers;
/**
@@ -61,9 +62,9 @@ class Response {
/**
* HTTP status code - defaults to STATUS OK
- * @var int
+ * @var S
*/
- private $status = Http::STATUS_OK;
+ private $status;
/**
@@ -91,15 +92,13 @@ class Response {
private $throttleMetadata = [];
/**
+ * @param S $status
+ * @param H $headers
* @since 17.0.0
*/
- public function __construct() {
- /** @var IRequest $request */
- /**
- * @psalm-suppress UndefinedClass
- */
- $request = \OC::$server->get(IRequest::class);
- $this->addHeader("X-Request-Id", $request->getId());
+ public function __construct(int $status = Http::STATUS_OK, array $headers = []) {
+ $this->setStatus($status);
+ $this->setHeaders($headers);
}
/**
@@ -120,7 +119,7 @@ class Response {
// Set expires header
$expires = new \DateTime();
/** @var ITimeFactory $time */
- $time = \OC::$server->query(ITimeFactory::class);
+ $time = \OCP\Server::get(ITimeFactory::class);
$expires->setTimestamp($time->getTime());
$expires->add(new \DateInterval('PT'.$cacheSeconds.'S'));
$this->addHeader('Expires', $expires->format(\DateTimeInterface::RFC2822));
@@ -231,11 +230,14 @@ class Response {
/**
* Set the headers
- * @param array $headers value header pairs
- * @return $this
+ * @template NewH as array<string, mixed>
+ * @param NewH $headers value header pairs
+ * @psalm-this-out static<S, NewH>
+ * @return static
* @since 8.0.0
*/
- public function setHeaders(array $headers) {
+ public function setHeaders(array $headers): static {
+ /** @psalm-suppress InvalidPropertyAssignmentValue Expected due to @psalm-this-out */
$this->headers = $headers;
return $this;
@@ -244,21 +246,27 @@ class Response {
/**
* Returns the set headers
- * @return array the headers
+ * @return array{X-Request-Id: string, Cache-Control: string, Content-Security-Policy: string, Feature-Policy: string, X-Robots-Tag: string, Last-Modified?: string, ETag?: string, ...H} the headers
* @since 6.0.0
*/
public function getHeaders() {
- $mergeWith = [];
+ /** @var IRequest $request */
+ /**
+ * @psalm-suppress UndefinedClass
+ */
+ $request = \OC::$server->get(IRequest::class);
+ $mergeWith = [
+ 'X-Request-Id' => $request->getId(),
+ 'Cache-Control' => 'no-cache, no-store, must-revalidate',
+ 'Content-Security-Policy' => $this->getContentSecurityPolicy()->buildPolicy(),
+ 'Feature-Policy' => $this->getFeaturePolicy()->buildPolicy(),
+ 'X-Robots-Tag' => 'noindex, nofollow',
+ ];
if ($this->lastModified) {
- $mergeWith['Last-Modified'] =
- $this->lastModified->format(\DateTimeInterface::RFC2822);
+ $mergeWith['Last-Modified'] = $this->lastModified->format(\DateTimeInterface::RFC2822);
}
- $this->headers['Content-Security-Policy'] = $this->getContentSecurityPolicy()->buildPolicy();
- $this->headers['Feature-Policy'] = $this->getFeaturePolicy()->buildPolicy();
- $this->headers['X-Robots-Tag'] = 'noindex, nofollow';
-
if ($this->ETag) {
$mergeWith['ETag'] = '"' . $this->ETag . '"';
}
@@ -279,11 +287,14 @@ class Response {
/**
* Set response status
- * @param int $status a HTTP status code, see also the STATUS constants
- * @return Response Reference to this object
+ * @template NewS as int
+ * @param NewS $status a HTTP status code, see also the STATUS constants
+ * @psalm-this-out static<NewS, H>
+ * @return static
* @since 6.0.0 - return value was added in 7.0.0
*/
- public function setStatus($status) {
+ public function setStatus($status): static {
+ /** @psalm-suppress InvalidPropertyAssignmentValue Expected due to @psalm-this-out */
$this->status = $status;
return $this;
@@ -338,6 +349,7 @@ class Response {
/**
* Get response status
* @since 6.0.0
+ * @return S
*/
public function getStatus() {
return $this->status;
diff --git a/lib/public/AppFramework/Http/StandaloneTemplateResponse.php b/lib/public/AppFramework/Http/StandaloneTemplateResponse.php
index 35a48481333..8a39dca71e3 100644
--- a/lib/public/AppFramework/Http/StandaloneTemplateResponse.php
+++ b/lib/public/AppFramework/Http/StandaloneTemplateResponse.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -32,6 +33,9 @@ namespace OCP\AppFramework\Http;
* full nextcloud UI. Like the 2FA page, or the grant page in the login flow.
*
* @since 16.0.0
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends TemplateResponse<int, array<string, mixed>>
*/
class StandaloneTemplateResponse extends TemplateResponse {
}
diff --git a/lib/public/AppFramework/Http/StreamResponse.php b/lib/public/AppFramework/Http/StreamResponse.php
index 25ad37e5d9a..14394383ba1 100644
--- a/lib/public/AppFramework/Http/StreamResponse.php
+++ b/lib/public/AppFramework/Http/StreamResponse.php
@@ -8,6 +8,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -32,6 +33,9 @@ use OCP\AppFramework\Http;
* Class StreamResponse
*
* @since 8.1.0
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class StreamResponse extends Response implements ICallbackResponse {
/** @var string */
@@ -39,10 +43,12 @@ class StreamResponse extends Response implements ICallbackResponse {
/**
* @param string|resource $filePath the path to the file or a file handle which should be streamed
+ * @param S $status
+ * @param H $headers
* @since 8.1.0
*/
- public function __construct($filePath) {
- parent::__construct();
+ public function __construct(mixed $filePath, int $status = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($status, $headers);
$this->filePath = $filePath;
}
diff --git a/lib/public/AppFramework/Http/StrictContentSecurityPolicy.php b/lib/public/AppFramework/Http/StrictContentSecurityPolicy.php
index ed137bad930..96c03673d5c 100644
--- a/lib/public/AppFramework/Http/StrictContentSecurityPolicy.php
+++ b/lib/public/AppFramework/Http/StrictContentSecurityPolicy.php
@@ -46,6 +46,8 @@ class StrictContentSecurityPolicy extends EmptyContentSecurityPolicy {
protected $inlineScriptAllowed = false;
/** @var bool Whether eval in JS scripts is allowed */
protected $evalScriptAllowed = false;
+ /** @var bool Whether WebAssembly compilation is allowed */
+ protected ?bool $evalWasmAllowed = false;
/** @var array Domains from which scripts can get loaded */
protected $allowedScriptDomains = [
'\'self\'',
diff --git a/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php b/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php
index 1196c90935d..def25d01c51 100644
--- a/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php
+++ b/lib/public/AppFramework/Http/Template/PublicTemplateResponse.php
@@ -5,6 +5,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Julius Härtl <jus@bitgrid.net>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -25,12 +26,16 @@
namespace OCP\AppFramework\Http\Template;
use InvalidArgumentException;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\TemplateResponse;
/**
* Class PublicTemplateResponse
*
* @since 14.0.0
+ * @template H of array<string, mixed>
+ * @template S of int
+ * @template-extends TemplateResponse<int, array<string, mixed>>
*/
class PublicTemplateResponse extends TemplateResponse {
private $headerTitle = '';
@@ -44,10 +49,12 @@ class PublicTemplateResponse extends TemplateResponse {
* @param string $appName
* @param string $templateName
* @param array $params
+ * @param S $status
+ * @param H $headers
* @since 14.0.0
*/
- public function __construct(string $appName, string $templateName, array $params = []) {
- parent::__construct($appName, $templateName, $params, 'public');
+ public function __construct(string $appName, string $templateName, array $params = [], $status = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($appName, $templateName, $params, 'public', $status, $headers);
\OC_Util::addScript('core', 'public/publicpage');
}
diff --git a/lib/public/AppFramework/Http/TemplateResponse.php b/lib/public/AppFramework/Http/TemplateResponse.php
index 48097674fdf..627906fcc20 100644
--- a/lib/public/AppFramework/Http/TemplateResponse.php
+++ b/lib/public/AppFramework/Http/TemplateResponse.php
@@ -10,6 +10,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -28,9 +29,15 @@
*/
namespace OCP\AppFramework\Http;
+use OCP\AppFramework\Http;
+
/**
* Response for a normal template
* @since 6.0.0
+ *
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class TemplateResponse extends Response {
/**
@@ -59,15 +66,6 @@ class TemplateResponse extends Response {
public const RENDER_AS_PUBLIC = 'public';
/**
- * @deprecated 20.0.0 use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent
- */
- public const EVENT_LOAD_ADDITIONAL_SCRIPTS = self::class . '::loadAdditionalScripts';
- /**
- * @deprecated 20.0.0 use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent
- */
- public const EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN = self::class . '::loadAdditionalScriptsLoggedIn';
-
- /**
* name of the template
* @var string
*/
@@ -98,11 +96,12 @@ class TemplateResponse extends Response {
* @param array $params an array of parameters which should be passed to the
* template
* @param string $renderAs how the page should be rendered, defaults to user
+ * @param S $status
+ * @param H $headers
* @since 6.0.0 - parameters $params and $renderAs were added in 7.0.0
*/
- public function __construct($appName, $templateName, array $params = [],
- $renderAs = self::RENDER_AS_USER) {
- parent::__construct();
+ public function __construct(string $appName, string $templateName, array $params = [], string $renderAs = self::RENDER_AS_USER, int $status = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($status, $headers);
$this->templateName = $templateName;
$this->appName = $appName;
diff --git a/lib/public/AppFramework/Http/TextPlainResponse.php b/lib/public/AppFramework/Http/TextPlainResponse.php
index 93edf704863..7bcd353e102 100644
--- a/lib/public/AppFramework/Http/TextPlainResponse.php
+++ b/lib/public/AppFramework/Http/TextPlainResponse.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright 2021 Lukas Reschke <lukas@statuscode.ch>
*
* @author 2021 Lukas Reschke <lukas@statuscode.ch>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -30,6 +31,9 @@ use OCP\AppFramework\Http;
/**
* A renderer for text responses
* @since 22.0.0
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class TextPlainResponse extends Response {
/** @var string */
@@ -38,14 +42,14 @@ class TextPlainResponse extends Response {
/**
* constructor of TextPlainResponse
* @param string $text The text body
- * @param int $statusCode the Http status code, defaults to 200
+ * @param S $statusCode the Http status code, defaults to 200
+ * @param H $headers
* @since 22.0.0
*/
- public function __construct(string $text = '', int $statusCode = Http::STATUS_OK) {
- parent::__construct();
+ public function __construct(string $text = '', int $statusCode = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($statusCode, $headers);
$this->text = $text;
- $this->setStatus($statusCode);
$this->addHeader('Content-Type', 'text/plain');
}
diff --git a/lib/public/AppFramework/Http/TooManyRequestsResponse.php b/lib/public/AppFramework/Http/TooManyRequestsResponse.php
index caf565ee954..043ae0161e9 100644
--- a/lib/public/AppFramework/Http/TooManyRequestsResponse.php
+++ b/lib/public/AppFramework/Http/TooManyRequestsResponse.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.com>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -26,20 +27,25 @@ declare(strict_types=1);
namespace OCP\AppFramework\Http;
use OCP\Template;
+use OCP\AppFramework\Http;
/**
* A generic 429 response showing an 404 error page as well to the end-user
* @since 19.0.0
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class TooManyRequestsResponse extends Response {
/**
+ * @param S $status
+ * @param H $headers
* @since 19.0.0
*/
- public function __construct() {
- parent::__construct();
+ public function __construct(int $status = Http::STATUS_TOO_MANY_REQUESTS, array $headers = []) {
+ parent::__construct($status, $headers);
$this->setContentSecurityPolicy(new ContentSecurityPolicy());
- $this->setStatus(429);
}
/**
diff --git a/lib/public/AppFramework/Http/ZipResponse.php b/lib/public/AppFramework/Http/ZipResponse.php
index 23e9f1f7a94..cd7f71f858d 100644
--- a/lib/public/AppFramework/Http/ZipResponse.php
+++ b/lib/public/AppFramework/Http/ZipResponse.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
* @author Jakob Sack <mail@jakobsack.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -29,12 +30,16 @@ declare(strict_types=1);
namespace OCP\AppFramework\Http;
use OC\Streamer;
+use OCP\AppFramework\Http;
use OCP\IRequest;
/**
* Public library to send several files in one zip archive.
*
* @since 15.0.0
+ * @template S of int
+ * @template H of array<string, mixed>
+ * @template-extends Response<int, array<string, mixed>>
*/
class ZipResponse extends Response implements ICallbackResponse {
/** @var array{internalName: string, resource: resource, size: int, time: int}[] Files to be added to the zip response */
@@ -44,10 +49,12 @@ class ZipResponse extends Response implements ICallbackResponse {
private IRequest $request;
/**
+ * @param S $status
+ * @param H $headers
* @since 15.0.0
*/
- public function __construct(IRequest $request, string $name = 'output') {
- parent::__construct();
+ public function __construct(IRequest $request, string $name = 'output', int $status = Http::STATUS_OK, array $headers = []) {
+ parent::__construct($status, $headers);
$this->name = $name;
$this->request = $request;
diff --git a/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php b/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php
new file mode 100644
index 00000000000..1b661ed9943
--- /dev/null
+++ b/lib/public/AppFramework/OCS/OCSPreconditionFailedException.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 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\AppFramework\OCS;
+
+use Exception;
+use OCP\AppFramework\Http;
+
+/**
+ * Class OCSPreconditionFailedException
+ *
+ * @since 28.0.0
+ */
+class OCSPreconditionFailedException extends OCSException {
+ /**
+ * OCSPreconditionFailedException constructor.
+ *
+ * @param string $message
+ * @param Exception|null $previous
+ * @since 9.1.0
+ */
+ public function __construct($message = '', Exception $previous = null) {
+ parent::__construct($message, Http::STATUS_PRECONDITION_FAILED, $previous);
+ }
+}
diff --git a/lib/public/AppFramework/Utility/ITimeFactory.php b/lib/public/AppFramework/Utility/ITimeFactory.php
index 7a6acf97b2d..d4f74c9d107 100644
--- a/lib/public/AppFramework/Utility/ITimeFactory.php
+++ b/lib/public/AppFramework/Utility/ITimeFactory.php
@@ -41,7 +41,6 @@ interface ITimeFactory extends ClockInterface {
/**
* @return int the result of a call to time()
* @since 8.0.0
- * @deprecated 26.0.0 {@see ITimeFactory::now()}
*/
public function getTime(): int;
@@ -50,7 +49,6 @@ interface ITimeFactory extends ClockInterface {
* @param \DateTimeZone|null $timezone
* @return \DateTime
* @since 15.0.0
- * @deprecated 26.0.0 {@see ITimeFactory::now()}
*/
public function getDateTime(string $time = 'now', \DateTimeZone $timezone = null): \DateTime;
diff --git a/lib/public/Authentication/TwoFactorAuth/IProvider.php b/lib/public/Authentication/TwoFactorAuth/IProvider.php
index 09fa7a56f5c..7cb6c83bdf6 100644
--- a/lib/public/Authentication/TwoFactorAuth/IProvider.php
+++ b/lib/public/Authentication/TwoFactorAuth/IProvider.php
@@ -33,17 +33,6 @@ use OCP\Template;
*/
interface IProvider {
/**
- * @since 14.0.0
- * @deprecated 22.0.0
- */
- public const EVENT_SUCCESS = self::class . '::success';
-
- /**
- * @deprecated 22.0.0
- */
- public const EVENT_FAILED = self::class . '::failed';
-
- /**
* Get unique identifier of this 2FA provider
*
* @since 9.1.0
diff --git a/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php b/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php
index fcc7e5f9207..0e36699c4ae 100644
--- a/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php
+++ b/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php
@@ -31,13 +31,14 @@ use OCP\IUser;
/**
* @since 15.0.0
+ * @deprecated 28.0.0 Use TwoFactorProviderForUserRegistered or TwoFactorProviderForUserUnregistered instead
+ * @see \OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserRegistered
+ * @see \OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserUnregistered
*/
class RegistryEvent extends Event {
- /** @var IProvider */
- private $provider;
+ private IProvider $provider;
- /** @IUser */
- private $user;
+ private IUser $user;
/**
* @since 15.0.0
diff --git a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengeFailed.php b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengeFailed.php
new file mode 100644
index 00000000000..8152cd236b5
--- /dev/null
+++ b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengeFailed.php
@@ -0,0 +1,58 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2021 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @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\Authentication\TwoFactorAuth;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+class TwoFactorProviderChallengeFailed extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IUser $user,
+ private IProvider $provider) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getProvider(): IProvider {
+ return $this->provider;
+ }
+}
diff --git a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengePassed.php b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengePassed.php
new file mode 100644
index 00000000000..f0fd1439c1d
--- /dev/null
+++ b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengePassed.php
@@ -0,0 +1,58 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2021 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @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\Authentication\TwoFactorAuth;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+class TwoFactorProviderChallengePassed extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IUser $user,
+ private IProvider $provider) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getProvider(): IProvider {
+ return $this->provider;
+ }
+}
diff --git a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderDisabled.php b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderDisabled.php
index 20c9479a1a9..c31766c25e2 100644
--- a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderDisabled.php
+++ b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderDisabled.php
@@ -29,6 +29,8 @@ use OCP\EventDispatcher\Event;
/**
* @since 20.0.0
+ * @deprecated 28.0.0 Use \OCP\Authentication\TwoFactorAuth\TwoFactorProviderUserDeleted instead
+ * @see \OCP\Authentication\TwoFactorAuth\TwoFactorProviderUserDeleted
*/
final class TwoFactorProviderDisabled extends Event {
/** @var string */
diff --git a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserDisabled.php b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserDisabled.php
index 5a56adc3cc9..86cecb2e36b 100644
--- a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserDisabled.php
+++ b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserDisabled.php
@@ -30,6 +30,8 @@ use OCP\IUser;
/**
* @since 22.0.0
+ * @deprecated 28.0.0 Use \OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengeFailed instead
+ * @see \OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengeFailed
*/
class TwoFactorProviderForUserDisabled extends Event {
/** @var IProvider */
diff --git a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserEnabled.php b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserEnabled.php
index c577d1484a3..4ca791ebf7c 100644
--- a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserEnabled.php
+++ b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserEnabled.php
@@ -30,6 +30,8 @@ use OCP\IUser;
/**
* @since 22.0.0
+ * @deprecated 28.0.0 Use \OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengePassed instead
+ * @see \OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengePassed
*/
class TwoFactorProviderForUserEnabled extends Event {
/** @var IProvider */
diff --git a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserRegistered.php b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserRegistered.php
new file mode 100644
index 00000000000..f4893b0f845
--- /dev/null
+++ b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserRegistered.php
@@ -0,0 +1,58 @@
+<?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\Authentication\TwoFactorAuth;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+class TwoFactorProviderForUserRegistered extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IUser $user,
+ private IProvider $provider,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getProvider(): IProvider {
+ return $this->provider;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+}
diff --git a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserUnregistered.php b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserUnregistered.php
new file mode 100644
index 00000000000..42e10bc0a7d
--- /dev/null
+++ b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserUnregistered.php
@@ -0,0 +1,58 @@
+<?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\Authentication\TwoFactorAuth;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+class TwoFactorProviderForUserUnregistered extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IUser $user,
+ private IProvider $provider,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getProvider(): IProvider {
+ return $this->provider;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+}
diff --git a/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderUserDeleted.php b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderUserDeleted.php
new file mode 100644
index 00000000000..73aa6e72deb
--- /dev/null
+++ b/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderUserDeleted.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @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\Authentication\TwoFactorAuth;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+final class TwoFactorProviderUserDeleted extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IUser $user,
+ private string $providerId,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getProviderId(): string {
+ return $this->providerId;
+ }
+}
diff --git a/lib/public/BackgroundJob/Job.php b/lib/public/BackgroundJob/Job.php
index 455fb3d42e7..a574e90e1a0 100644
--- a/lib/public/BackgroundJob/Job.php
+++ b/lib/public/BackgroundJob/Job.php
@@ -75,11 +75,6 @@ abstract class Job implements IJob, IParallelAwareJob {
$jobList->setLastRun($this);
$logger = $this->logger ?? \OCP\Server::get(LoggerInterface::class);
- if (!$this->getAllowParallelRuns() && $jobList->hasReservedJob(get_class($this))) {
- $logger->debug('Skipping ' . get_class($this) . ' job with ID ' . $this->getId() . ' because another job with the same class is already running', ['app' => 'cron']);
- return;
- }
-
try {
$jobStartTime = $this->time->getTime();
$logger->debug('Run ' . get_class($this) . ' job with ID ' . $this->getId(), ['app' => 'cron']);
diff --git a/lib/public/BackgroundJob/TimedJob.php b/lib/public/BackgroundJob/TimedJob.php
index 9d6b599c21b..8fd8fadce4f 100644
--- a/lib/public/BackgroundJob/TimedJob.php
+++ b/lib/public/BackgroundJob/TimedJob.php
@@ -26,7 +26,6 @@ declare(strict_types=1);
*/
namespace OCP\BackgroundJob;
-use OC\BackgroundJob\JobList;
use OCP\ILogger;
/**
@@ -81,20 +80,20 @@ abstract class TimedJob extends Job {
}
/**
- * run the job if the last run is is more than the interval ago
+ * Run the job if the last run is more than the interval ago
*
- * @param JobList $jobList
+ * @param IJobList $jobList
* @param ILogger|null $logger
*
* @since 15.0.0
* @deprecated since 25.0.0 Use start() instead
*/
- final public function execute($jobList, ILogger $logger = null) {
+ final public function execute(IJobList $jobList, ILogger $logger = null) {
$this->start($jobList);
}
/**
- * Run the job if the last run is is more than the interval ago
+ * Run the job if the last run is more than the interval ago
*
* @since 25.0.0
*/
diff --git a/lib/public/Capabilities/ICapability.php b/lib/public/Capabilities/ICapability.php
index fed1dba49d1..2d3f5215736 100644
--- a/lib/public/Capabilities/ICapability.php
+++ b/lib/public/Capabilities/ICapability.php
@@ -25,11 +25,8 @@ namespace OCP\Capabilities;
* Minimal interface that has to be implemented for a class to be considered
* a capability.
*
- * In an application use:
- * $this->getContainer()->registerCapability('OCA\MY_APP\Capabilities');
- * To register capabilities.
- *
- * The class 'OCA\MY_APP\Capabilities' must then implement ICapability
+ * In an application use \OCP\AppFramework\Bootstrap\IRegistrationContext::registerCapability
+ * to register capabilities.
*
* @since 8.2.0
*/
@@ -37,7 +34,19 @@ interface ICapability {
/**
* Function an app uses to return the capabilities
*
- * @return array Array containing the apps capabilities
+ * ```php
+ * return [
+ * 'myapp' => [
+ * 'awesomefeature' => true,
+ * 'featureversion' => 3,
+ * ],
+ * 'morecomplex' => [
+ * 'a' => [1, 2],
+ * ],
+ * ];
+ * ```
+ *
+ * @return array<string, array<string, mixed>> Indexed array containing the app's capabilities
* @since 8.2.0
*/
public function getCapabilities();
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/Reference.php b/lib/public/Collaboration/Reference/Reference.php
index 6b92a0fae52..8dc88edbeac 100644
--- a/lib/public/Collaboration/Reference/Reference.php
+++ b/lib/public/Collaboration/Reference/Reference.php
@@ -27,6 +27,7 @@ namespace OCP\Collaboration\Reference;
/**
* @since 25.0.0
+ * @psalm-type OpenGraphObject = array{id: string, name: string, description: ?string, thumb: ?string, link: string}
*/
class Reference implements IReference {
protected string $reference;
@@ -176,6 +177,7 @@ class Reference implements IReference {
/**
* @inheritdoc
* @since 25.0.0
+ * @return array<string, mixed>
*/
public function getRichObject(): array {
if ($this->richObject === null) {
@@ -187,6 +189,7 @@ class Reference implements IReference {
/**
* @inheritdoc
* @since 25.0.0
+ * @return OpenGraphObject
*/
public function getOpenGraphObject(): array {
return [
@@ -237,8 +240,9 @@ class Reference implements IReference {
/**
* @inheritdoc
* @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 e4b4c78f03c..3336b80d6b5 100644
--- a/lib/public/Comments/CommentsEntityEvent.php
+++ b/lib/public/Comments/CommentsEntityEvent.php
@@ -29,26 +29,24 @@ use OCP\EventDispatcher\Event;
* Class CommentsEntityEvent
*
* @since 9.1.0
+ * @since 28.0.0 Dispatched as a typed event
*/
class CommentsEntityEvent extends Event {
/**
- * @deprecated 22.0.0
+ * @deprecated 22.0.0 - Listen to the typed event instead.
*/
public const EVENT_ENTITY = 'OCP\Comments\ICommentsManager::registerEntity';
- /** @var string */
- protected $event;
/** @var \Closure[] */
protected $collections;
/**
* DispatcherEvent constructor.
*
- * @param string $event
* @since 9.1.0
*/
- public function __construct($event) {
- $this->event = $event;
+ public function __construct() {
+ parent::__construct();
$this->collections = [];
}
diff --git a/lib/public/Common/Exception/NotFoundException.php b/lib/public/Common/Exception/NotFoundException.php
new file mode 100644
index 00000000000..a30e1c42b8b
--- /dev/null
+++ b/lib/public/Common/Exception/NotFoundException.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 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\Common\Exception;
+
+/**
+ * This is thrown whenever something was expected to exist but doesn't
+ *
+ * @since 27.1.0
+ */
+class NotFoundException extends \Exception {
+ /**
+ * Constructor
+ * @param string $msg the error message
+ * @since 27.1.0
+ */
+ public function __construct(string $msg) {
+ parent::__construct($msg);
+ }
+}
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/AddMissingColumnsEvent.php b/lib/public/DB/Events/AddMissingColumnsEvent.php
new file mode 100644
index 00000000000..1fb44e86842
--- /dev/null
+++ b/lib/public/DB/Events/AddMissingColumnsEvent.php
@@ -0,0 +1,60 @@
+<?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\DB\Events;
+
+/**
+ * Event to allow apps to register information about missing database columns
+ *
+ * This event will be dispatched for checking on the admin settings and when running
+ * occ db:add-missing-columns which will then create those columns
+ *
+ * @since 28.0.0
+ */
+class AddMissingColumnsEvent extends \OCP\EventDispatcher\Event {
+ /** @var array<array-key, array{tableName: string, columnName: string, typeName: string, options: array{}}> */
+ private array $missingColumns = [];
+
+ /**
+ * @param mixed[] $options
+ * @since 28.0.0
+ */
+ public function addMissingColumn(string $tableName, string $columnName, string $typeName, array $options): void {
+ $this->missingColumns[] = [
+ 'tableName' => $tableName,
+ 'columnName' => $columnName,
+ 'typeName' => $typeName,
+ 'options' => $options,
+ ];
+ }
+
+ /**
+ * @since 28.0.0
+ * @return array<array-key, array{tableName: string, columnName: string, typeName: string, options: array{}}>
+ */
+ public function getMissingColumns(): array {
+ return $this->missingColumns;
+ }
+}
diff --git a/lib/public/DB/Events/AddMissingIndicesEvent.php b/lib/public/DB/Events/AddMissingIndicesEvent.php
new file mode 100644
index 00000000000..dc942f3d63e
--- /dev/null
+++ b/lib/public/DB/Events/AddMissingIndicesEvent.php
@@ -0,0 +1,78 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
+ * @copyright Copyright (c) 2023 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ * @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\DB\Events;
+
+/**
+ * Event to allow apps to register information about missing database indices
+ *
+ * This event will be dispatched for checking on the admin settings and when running
+ * occ db:add-missing-indices which will then create those indices
+ *
+ * @since 28.0.0
+ */
+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 = [];
+
+ /**
+ * @param string[] $columns
+ * @since 28.0.0
+ */
+ public function addMissingIndex(string $tableName, string $indexName, array $columns, array $options = [], bool $dropUnnamedIndex = false): void {
+ $this->missingIndices[] = [
+ 'tableName' => $tableName,
+ 'indexName' => $indexName,
+ 'columns' => $columns,
+ 'options' => $options,
+ 'dropUnnamedIndex' => $dropUnnamedIndex,
+ 'uniqueIndex' => false,
+ ];
+ }
+ /**
+ * @param string[] $columns
+ * @since 28.0.0
+ */
+ public function addMissingUniqueIndex(string $tableName, string $indexName, array $columns, array $options = [], bool $dropUnnamedIndex = false): void {
+ $this->missingIndices[] = [
+ 'tableName' => $tableName,
+ 'indexName' => $indexName,
+ 'columns' => $columns,
+ 'options' => $options,
+ 'dropUnnamedIndex' => $dropUnnamedIndex,
+ 'uniqueIndex' => true,
+ ];
+ }
+
+ /**
+ * @since 28.0.0
+ * @return array<array-key, array{tableName: string, indexName: string, columns: string[], options: array{}, dropUnnamedIndex: bool, uniqueIndex: bool}>
+ */
+ public function getMissingIndices(): array {
+ return $this->missingIndices;
+ }
+}
diff --git a/lib/public/DB/Events/AddMissingPrimaryKeyEvent.php b/lib/public/DB/Events/AddMissingPrimaryKeyEvent.php
new file mode 100644
index 00000000000..ace55d7538b
--- /dev/null
+++ b/lib/public/DB/Events/AddMissingPrimaryKeyEvent.php
@@ -0,0 +1,60 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023 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\DB\Events;
+
+/**
+ * Event to allow apps to register information about missing database primary keys
+ *
+ * This event will be dispatched for checking on the admin settings and when running
+ * occ db:add-missing-primary-keys which will then create those keys
+ *
+ * @since 28.0.0
+ */
+class AddMissingPrimaryKeyEvent extends \OCP\EventDispatcher\Event {
+ /** @var array<array-key, array{tableName: string, primaryKeyName: string, columns: string[], formerIndex: null|string}> */
+ private array $missingPrimaryKeys = [];
+
+ /**
+ * @param string[] $columns
+ * @since 28.0.0
+ */
+ public function addMissingPrimaryKey(string $tableName, string $primaryKeyName, array $columns, ?string $formerIndex = null): void {
+ $this->missingPrimaryKeys[] = [
+ 'tableName' => $tableName,
+ 'primaryKeyName' => $primaryKeyName,
+ 'columns' => $columns,
+ 'formerIndex' => $formerIndex,
+ ];
+ }
+
+ /**
+ * @since 28.0.0
+ * @return array<array-key, array{tableName: string, primaryKeyName: string, columns: string[], formerIndex: null|string}>
+ */
+ public function getMissingPrimaryKeys(): array {
+ return $this->missingPrimaryKeys;
+ }
+}
diff --git a/lib/public/DB/QueryBuilder/IQueryBuilder.php b/lib/public/DB/QueryBuilder/IQueryBuilder.php
index 1f5c4307914..63fdfb65971 100644
--- a/lib/public/DB/QueryBuilder/IQueryBuilder.php
+++ b/lib/public/DB/QueryBuilder/IQueryBuilder.php
@@ -28,6 +28,7 @@
namespace OCP\DB\QueryBuilder;
use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\ParameterType;
use OCP\DB\Exception;
use OCP\DB\IResult;
@@ -41,23 +42,23 @@ interface IQueryBuilder {
/**
* @since 9.0.0
*/
- public const PARAM_NULL = \PDO::PARAM_NULL;
+ public const PARAM_NULL = ParameterType::NULL;
/**
* @since 9.0.0
*/
- public const PARAM_BOOL = \PDO::PARAM_BOOL;
+ public const PARAM_BOOL = ParameterType::BOOLEAN;
/**
* @since 9.0.0
*/
- public const PARAM_INT = \PDO::PARAM_INT;
+ public const PARAM_INT = ParameterType::INTEGER;
/**
* @since 9.0.0
*/
- public const PARAM_STR = \PDO::PARAM_STR;
+ public const PARAM_STR = ParameterType::STRING;
/**
* @since 9.0.0
*/
- public const PARAM_LOB = \PDO::PARAM_LOB;
+ public const PARAM_LOB = ParameterType::LARGE_OBJECT;
/**
* @since 9.0.0
*/
diff --git a/lib/public/Dashboard/IAPIWidgetV2.php b/lib/public/Dashboard/IAPIWidgetV2.php
new file mode 100644
index 00000000000..27cb6510c77
--- /dev/null
+++ b/lib/public/Dashboard/IAPIWidgetV2.php
@@ -0,0 +1,43 @@
+<?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\Dashboard;
+
+use OCP\Dashboard\Model\WidgetItems;
+
+/**
+ * Interface IAPIWidgetV2
+ *
+ * @since 27.1.0
+ */
+interface IAPIWidgetV2 extends IWidget {
+ /**
+ * Items to render in the widget
+ *
+ * @since 27.1.0
+ */
+ public function getItemsV2(string $userId, ?string $since = null, int $limit = 7): WidgetItems;
+}
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/IReloadableWidget.php b/lib/public/Dashboard/IReloadableWidget.php
new file mode 100644
index 00000000000..9f65653fbe6
--- /dev/null
+++ b/lib/public/Dashboard/IReloadableWidget.php
@@ -0,0 +1,41 @@
+<?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\Dashboard;
+
+/**
+ * Allow {@see IAPIWidgetV2} to reload their items
+ *
+ * @since 27.1.0
+ */
+interface IReloadableWidget extends IAPIWidgetV2 {
+ /**
+ * Periodic interval in seconds in which to reload the widget's items
+ *
+ * @since 27.1.0
+ */
+ public function getReloadInterval(): int;
+}
diff --git a/lib/public/Dashboard/Model/WidgetItem.php b/lib/public/Dashboard/Model/WidgetItem.php
index 2bea9b93226..1c54d2bd426 100644
--- a/lib/public/Dashboard/Model/WidgetItem.php
+++ b/lib/public/Dashboard/Model/WidgetItem.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright 2021, Julien Veyssier <eneiluj@posteo.net>
*
* @author Julien Veyssier <eneiluj@posteo.net>
+ * @author Richard Steinmetz <richard@steinmetz.cloud>
*
* @license GNU AGPL version 3 or any later version
*
@@ -33,7 +34,7 @@ use JsonSerializable;
*
* This class is used by IAPIWidget interface.
* It represents an widget item data that can be provided to clients via the Dashboard API
- * @see IAPIWidget::getWidgetItems
+ * @see IAPIWidget::getItems
*
* @since 22.0.0
*
@@ -56,24 +57,30 @@ final class WidgetItem implements JsonSerializable {
*/
private $sinceId = '';
+ /**
+ * Overlay icon to show in the bottom right corner of {@see $iconUrl}
+ *
+ * @since 27.1.0
+ */
+ private string $overlayIconUrl = '';
/**
* WidgetItem constructor
*
* @since 22.0.0
- *
- * @param string $type
*/
public function __construct(string $title = '',
string $subtitle = '',
string $link = '',
string $iconUrl = '',
- string $sinceId = '') {
+ string $sinceId = '',
+ string $overlayIconUrl = '') {
$this->title = $title;
$this->subtitle = $subtitle;
$this->iconUrl = $iconUrl;
$this->link = $link;
$this->sinceId = $sinceId;
+ $this->overlayIconUrl = $overlayIconUrl;
}
/**
@@ -133,6 +140,17 @@ final class WidgetItem implements JsonSerializable {
}
/**
+ * Get the overlay icon url
+ *
+ * @since 27.1.0
+ *
+ * @return string
+ */
+ public function getOverlayIconUrl(): string {
+ return $this->overlayIconUrl;
+ }
+
+ /**
* @since 22.0.0
*
* @return array
@@ -143,6 +161,7 @@ final class WidgetItem implements JsonSerializable {
'title' => $this->getTitle(),
'link' => $this->getLink(),
'iconUrl' => $this->getIconUrl(),
+ 'overlayIconUrl' => $this->getOverlayIconUrl(),
'sinceId' => $this->getSinceId(),
];
}
diff --git a/lib/public/Dashboard/Model/WidgetItems.php b/lib/public/Dashboard/Model/WidgetItems.php
new file mode 100644
index 00000000000..4bb51f2f9b6
--- /dev/null
+++ b/lib/public/Dashboard/Model/WidgetItems.php
@@ -0,0 +1,100 @@
+<?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\Dashboard\Model;
+
+use JsonSerializable;
+use OCP\Dashboard\IAPIWidgetV2;
+
+/**
+ * Interface WidgetItems
+ *
+ * This class is used by {@see IAPIWidgetV2} interface.
+ * It represents an array of widget items and additional context information that can be provided to clients via the Dashboard API
+ *
+ * @see IAPIWidgetV2::getItemsV2
+ *
+ * @since 27.1.0
+ */
+class WidgetItems implements JsonSerializable {
+ /**
+ * @param $items WidgetItem[]
+ *
+ * @since 27.1.0
+ */
+ public function __construct(
+ private array $items = [],
+ private string $emptyContentMessage = '',
+ private string $halfEmptyContentMessage = '',
+ ) {
+ }
+
+ /**
+ * Items to render in the widgets
+ *
+ * @since 27.1.0
+ *
+ * @return WidgetItem[]
+ */
+ public function getItems(): array {
+ return $this->items;
+ }
+
+ /**
+ * The "half" empty content message to show above the list of items.
+ *
+ * A non-empty string enables this feature.
+ * An empty string hides the message and disables this feature.
+ *
+ * @since 27.1.0
+ */
+ public function getEmptyContentMessage(): string {
+ return $this->emptyContentMessage;
+ }
+
+ /**
+ * The empty content message to show in case of no items at all
+ *
+ * @since 27.1.0
+ */
+ public function getHalfEmptyContentMessage(): string {
+ return $this->halfEmptyContentMessage;
+ }
+
+ /**
+ * @since 27.1.0
+ */
+ public function jsonSerialize(): array {
+ $items = array_map(static function (WidgetItem $item) {
+ return $item->jsonSerialize();
+ }, $this->getItems());
+ return [
+ 'items' => $items,
+ 'emptyContentMessage' => $this->getEmptyContentMessage(),
+ 'halfEmptyContentMessage' => $this->getHalfEmptyContentMessage(),
+ ];
+ }
+}
diff --git a/lib/public/Federation/ICloudFederationProvider.php b/lib/public/Federation/ICloudFederationProvider.php
index 7cb620848ef..121cb56bc4e 100644
--- a/lib/public/Federation/ICloudFederationProvider.php
+++ b/lib/public/Federation/ICloudFederationProvider.php
@@ -66,7 +66,7 @@ interface ICloudFederationProvider {
* @param string $notificationType (e.g SHARE_ACCEPTED)
* @param string $providerId share ID
* @param array $notification provider specific notification
- * @return array $data send back to sender
+ * @return array<string> $data send back to sender
*
* @throws ShareNotFound
* @throws ActionNotSupportedException
diff --git a/lib/public/Federation/ICloudIdManager.php b/lib/public/Federation/ICloudIdManager.php
index 1612c03ba4a..52920751739 100644
--- a/lib/public/Federation/ICloudIdManager.php
+++ b/lib/public/Federation/ICloudIdManager.php
@@ -62,4 +62,14 @@ interface ICloudIdManager {
* @since 12.0.0
*/
public function isValidCloudId(string $cloudId): bool;
+
+ /**
+ * remove scheme/protocol from an url
+ *
+ * @param string $url
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function removeProtocolFromUrl(string $url): 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/DavUtil.php b/lib/public/Files/DavUtil.php
index 343f3c2ac0f..89fd3b18643 100644
--- a/lib/public/Files/DavUtil.php
+++ b/lib/public/Files/DavUtil.php
@@ -32,6 +32,9 @@
namespace OCP\Files;
+use OCP\Constants;
+use OCP\Files\Mount\IMovableMount;
+
/**
* This class provides different helper functions related to WebDAV protocol
*
@@ -56,31 +59,43 @@ class DavUtil {
* @since 25.0.0
*/
public static function getDavPermissions(FileInfo $info): string {
+ $permissions = $info->getPermissions();
$p = '';
if ($info->isShared()) {
$p .= 'S';
}
- if ($info->isShareable()) {
+ if ($permissions & Constants::PERMISSION_SHARE) {
$p .= 'R';
}
if ($info->isMounted()) {
$p .= 'M';
}
- if ($info->isReadable()) {
+ if ($permissions & Constants::PERMISSION_READ) {
$p .= 'G';
}
- if ($info->isDeletable()) {
+ if ($permissions & Constants::PERMISSION_DELETE) {
$p .= 'D';
}
- if ($info->isUpdateable()) {
- $p .= 'NV'; // Renameable, Moveable
+ if ($permissions & Constants::PERMISSION_UPDATE) {
+ $p .= 'NV'; // Renameable, Movable
}
+
+ // since we always add update permissions for the root of movable mounts
+ // we need to check the shared cache item directly to determine if it's writable
+ $storage = $info->getStorage();
+ if ($info->getInternalPath() === '' && $info->getMountPoint() instanceof IMovableMount) {
+ $rootEntry = $storage->getCache()->get('');
+ $isWritable = $rootEntry->getPermissions() & Constants::PERMISSION_UPDATE;
+ } else {
+ $isWritable = $permissions & Constants::PERMISSION_UPDATE;
+ }
+
if ($info->getType() === FileInfo::TYPE_FILE) {
- if ($info->isUpdateable()) {
+ if ($isWritable) {
$p .= 'W';
}
} else {
- if ($info->isCreatable()) {
+ if ($permissions & Constants::PERMISSION_CREATE) {
$p .= 'CK';
}
}
diff --git a/lib/public/Files/Events/NodeAddedToFavorite.php b/lib/public/Files/Events/NodeAddedToFavorite.php
new file mode 100644
index 00000000000..d3f84582e46
--- /dev/null
+++ b/lib/public/Files/Events/NodeAddedToFavorite.php
@@ -0,0 +1,66 @@
+<?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\Files\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+class NodeAddedToFavorite extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ protected IUser $user,
+ protected int $fileId,
+ protected string $path,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getFileId(): int {
+ return $this->fileId;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getPath(): string {
+ return $this->path;
+ }
+}
diff --git a/lib/public/Files/Events/NodeRemovedFromFavorite.php b/lib/public/Files/Events/NodeRemovedFromFavorite.php
new file mode 100644
index 00000000000..72b43558bec
--- /dev/null
+++ b/lib/public/Files/Events/NodeRemovedFromFavorite.php
@@ -0,0 +1,66 @@
+<?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\Files\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+class NodeRemovedFromFavorite extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ protected IUser $user,
+ protected int $fileId,
+ protected string $path,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getFileId(): int {
+ return $this->fileId;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getPath(): string {
+ return $this->path;
+ }
+}
diff --git a/lib/public/Files/FileInfo.php b/lib/public/Files/FileInfo.php
index 83ae4adef92..da35f7f9028 100644
--- a/lib/public/Files/FileInfo.php
+++ b/lib/public/Files/FileInfo.php
@@ -299,4 +299,13 @@ 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;
}
diff --git a/lib/public/Files/Folder.php b/lib/public/Files/Folder.php
index 912c5472fac..eb81a2098ec 100644
--- a/lib/public/Files/Folder.php
+++ b/lib/public/Files/Folder.php
@@ -142,6 +142,16 @@ interface Folder extends Node {
public function searchByTag($tag, $userId);
/**
+ * search for files by system tag
+ *
+ * @param string|int $tag tag name
+ * @param string $userId user id to ensure access on returned nodes
+ * @return \OCP\Files\Node[]
+ * @since 28.0.0
+ */
+ 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
*
* This method could return multiple entries. For example once the file/folder
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/IMimeTypeDetector.php b/lib/public/Files/IMimeTypeDetector.php
index 11ba5cfc95f..9992c153edc 100644
--- a/lib/public/Files/IMimeTypeDetector.php
+++ b/lib/public/Files/IMimeTypeDetector.php
@@ -82,4 +82,10 @@ interface IMimeTypeDetector {
* @since 8.2.0
*/
public function mimeTypeIcon($mimeType);
+
+ /**
+ * @return string[]
+ * @since 28.0.0
+ */
+ public function getAllAliases(): array;
}
diff --git a/lib/public/Files/Mount/IMovableMount.php b/lib/public/Files/Mount/IMovableMount.php
new file mode 100644
index 00000000000..d3cabb92f15
--- /dev/null
+++ b/lib/public/Files/Mount/IMovableMount.php
@@ -0,0 +1,48 @@
+<?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 OCP\Files\Mount;
+
+/**
+ * Denotes that the mount point can be (re)moved by the user
+ *
+ * @since 28.0.0
+ */
+interface IMovableMount {
+ /**
+ * Move the mount point to $target
+ *
+ * @param string $target the target mount point
+ * @return bool
+ * @since 28.0.0
+ */
+ public function moveMount($target);
+
+ /**
+ * Remove the mount points
+ *
+ * @return bool
+ * @since 28.0.0
+ */
+ public function removeMount();
+}
diff --git a/lib/public/Files/Template/TemplateFileCreator.php b/lib/public/Files/Template/TemplateFileCreator.php
index 3a1e62c6f5c..43e96b6f21b 100644
--- a/lib/public/Files/Template/TemplateFileCreator.php
+++ b/lib/public/Files/Template/TemplateFileCreator.php
@@ -31,10 +31,13 @@ namespace OCP\Files\Template;
*/
final class TemplateFileCreator implements \JsonSerializable {
protected $appId;
+ /** @var string[] $mimetypes */
protected $mimetypes = [];
protected $actionName;
protected $fileExtension;
+ /** @var ?string $iconClass */
protected $iconClass;
+ /** @var ?float $ratio */
protected $ratio = null;
protected $order = 100;
/**
@@ -124,6 +127,7 @@ final class TemplateFileCreator implements \JsonSerializable {
/**
* @since 21.0.0
+ * @return array{app: string, label: string, extension: string, iconClass: ?string, mimetypes: string[], ratio: ?float, actionLabel: string}
*/
public function jsonSerialize(): array {
return [
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..599a0eb2ff0 100644
--- a/lib/public/GroupInterface.php
+++ b/lib/public/GroupInterface.php
@@ -86,7 +86,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 +99,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 d692edc5b71..fb1760c25f2 100644
--- a/lib/public/Http/Client/IClient.php
+++ b/lib/public/Http/Client/IClient.php
@@ -44,7 +44,7 @@ interface IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -69,7 +69,7 @@ interface IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -99,7 +99,7 @@ interface IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -129,7 +129,7 @@ interface IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -159,7 +159,7 @@ interface IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -178,7 +178,7 @@ interface IClient {
public function delete(string $uri, array $options = []): IResponse;
/**
- * Sends a options request
+ * Sends an OPTIONS request
* @param string $uri
* @param array $options Array such as
* 'body' => [
@@ -189,7 +189,7 @@ interface IClient {
* 'headers' => [
* 'foo' => 'bar',
* ],
- * 'cookies' => ['
+ * 'cookies' => [
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
@@ -206,4 +206,173 @@ interface IClient {
* @since 8.1.0
*/
public function options(string $uri, array $options = []): IResponse;
+
+ /**
+ * Sends an asynchronous GET request
+ * @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 IPromise
+ * @since 28.0.0
+ */
+ public function getAsync(string $uri, array $options = []): IPromise;
+
+ /**
+ * Sends an asynchronous HEAD request
+ * @param string $uri
+ * @param array $options Array such as
+ * '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 IPromise
+ * @since 28.0.0
+ */
+ public function headAsync(string $uri, array $options = []): IPromise;
+
+ /**
+ * Sends an asynchronous POST request
+ * @param string $uri
+ * @param array $options Array such as
+ * 'body' => [
+ * '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 IPromise
+ * @since 28.0.0
+ */
+ public function postAsync(string $uri, array $options = []): IPromise;
+
+ /**
+ * Sends an asynchronous PUT request
+ * @param string $uri
+ * @param array $options Array such as
+ * 'body' => [
+ * '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 IPromise
+ * @since 28.0.0
+ */
+ public function putAsync(string $uri, array $options = []): IPromise;
+
+ /**
+ * Sends an asynchronous DELETE request
+ * @param string $uri
+ * @param array $options Array such as
+ * 'body' => [
+ * '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 IPromise
+ * @since 28.0.0
+ */
+ public function deleteAsync(string $uri, array $options = []): IPromise;
+
+ /**
+ * Sends an asynchronous OPTIONS request
+ * @param string $uri
+ * @param array $options Array such as
+ * 'body' => [
+ * '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 IPromise
+ * @since 28.0.0
+ */
+ public function optionsAsync(string $uri, array $options = []): IPromise;
}
diff --git a/lib/public/Http/Client/IPromise.php b/lib/public/Http/Client/IPromise.php
new file mode 100644
index 00000000000..29e186d0168
--- /dev/null
+++ b/lib/public/Http/Client/IPromise.php
@@ -0,0 +1,100 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023, 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\Http\Client;
+
+use Exception;
+use LogicException;
+
+/**
+ * A wrapper around Guzzle's PromiseInterface
+ * @see \GuzzleHttp\Promise\PromiseInterface
+ * @since 28.0.0
+ */
+interface IPromise {
+ /**
+ * @since 28.0.0
+ */
+ public const STATE_PENDING = 'pending';
+ /**
+ * @since 28.0.0
+ */
+ public const STATE_FULFILLED = 'fulfilled';
+ /**
+ * @since 28.0.0
+ */
+ public const STATE_REJECTED = 'rejected';
+
+ /**
+ * Appends fulfillment and rejection handlers to the promise, and returns
+ * a new promise resolving to the return value of the called handler.
+ *
+ * @param ?callable(IResponse): void $onFulfilled Invoked when the promise fulfills. Gets an \OCP\Http\Client\IResponse passed in as argument
+ * @param ?callable(Exception): void $onRejected Invoked when the promise is rejected. Gets an \Exception passed in as argument
+ *
+ * @return IPromise
+ * @since 28.0.0
+ */
+ public function then(
+ ?callable $onFulfilled = null,
+ ?callable $onRejected = null,
+ ): IPromise;
+
+ /**
+ * Get the state of the promise ("pending", "rejected", or "fulfilled").
+ *
+ * The three states can be checked against the constants defined:
+ * STATE_PENDING, STATE_FULFILLED, and STATE_REJECTED.
+ *
+ * @return self::STATE_*
+ * @since 28.0.0
+ */
+ public function getState(): string;
+
+ /**
+ * Cancels the promise if possible.
+ *
+ * @link https://github.com/promises-aplus/cancellation-spec/issues/7
+ * @since 28.0.0
+ */
+ public function cancel(): void;
+
+ /**
+ * Waits until the promise completes if possible.
+ *
+ * Pass $unwrap as true to unwrap the result of the promise, either
+ * returning the resolved value or throwing the rejected exception.
+ *
+ * If the promise cannot be waited on, then the promise will be rejected.
+ *
+ * @param bool $unwrap
+ *
+ * @return mixed
+ *
+ * @throws LogicException if the promise has no wait function or if the
+ * promise does not settle after waiting.
+ * @since 28.0.0
+ */
+ public function wait(bool $unwrap = true): mixed;
+}
diff --git a/lib/public/IAppConfig.php b/lib/public/IAppConfig.php
index 7ab70fb04bf..cf387a8a44c 100644
--- a/lib/public/IAppConfig.php
+++ b/lib/public/IAppConfig.php
@@ -62,7 +62,7 @@ interface IAppConfig {
/**
* Get all apps using the config
- * @return array an array of app ids
+ * @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.
diff --git a/lib/public/IDBConnection.php b/lib/public/IDBConnection.php
index 69ede2c8438..a528bb1a57b 100644
--- a/lib/public/IDBConnection.php
+++ b/lib/public/IDBConnection.php
@@ -45,35 +45,17 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
* @since 6.0.0
*/
interface IDBConnection {
- /**
- * @deprecated 22.0.0 this is an internal event
- */
- public const ADD_MISSING_INDEXES_EVENT = self::class . '::ADD_MISSING_INDEXES';
+ /* @since 28.0.0 */
+ public const PLATFORM_MYSQL = 'mysql';
- /**
- * @deprecated 22.0.0 this is an internal event
- */
- public const CHECK_MISSING_INDEXES_EVENT = self::class . '::CHECK_MISSING_INDEXES';
+ /* @since 28.0.0 */
+ public const PLATFORM_ORACLE = 'oracle';
- /**
- * @deprecated 22.0.0 this is an internal event
- */
- public const ADD_MISSING_PRIMARY_KEYS_EVENT = self::class . '::ADD_MISSING_PRIMARY_KEYS';
+ /* @since 28.0.0 */
+ public const PLATFORM_POSTGRES = 'postgres';
- /**
- * @deprecated 22.0.0 this is an internal event
- */
- public const CHECK_MISSING_PRIMARY_KEYS_EVENT = self::class . '::CHECK_MISSING_PRIMARY_KEYS';
-
- /**
- * @deprecated 22.0.0 this is an internal event
- */
- public const ADD_MISSING_COLUMNS_EVENT = self::class . '::ADD_MISSING_COLUMNS';
-
- /**
- * @deprecated 22.0.0 this is an internal event
- */
- public const CHECK_MISSING_COLUMNS_EVENT = self::class . '::CHECK_MISSING_COLUMNS';
+ /* @since 28.0.0 */
+ public const PLATFORM_SQLITE = 'sqlite';
/**
* Gets the QueryBuilder for the connection.
@@ -369,4 +351,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/IPreview.php b/lib/public/IPreview.php
index 8483587d60e..2758eba8d63 100644
--- a/lib/public/IPreview.php
+++ b/lib/public/IPreview.php
@@ -38,12 +38,6 @@ use OCP\Files\SimpleFS\ISimpleFile;
* @since 6.0.0
*/
interface IPreview {
- /**
- * @since 9.2.0
- * @deprecated 22.0.0
- */
- public const EVENT = self::class . ':' . 'PreviewRequested';
-
public const MODE_FILL = 'fill';
public const MODE_COVER = 'cover';
diff --git a/lib/public/IRequest.php b/lib/public/IRequest.php
index 93f065500cb..bc1f88504a8 100644
--- a/lib/public/IRequest.php
+++ b/lib/public/IRequest.php
@@ -64,43 +64,51 @@ namespace OCP;
interface IRequest {
/**
* @since 9.1.0
+ * @since 28.0.0 The regex has a group matching the version number
*/
- public const USER_AGENT_CLIENT_ANDROID = '/^Mozilla\/5\.0 \(Android\) (ownCloud|Nextcloud)\-android.*$/';
+ public const USER_AGENT_CLIENT_ANDROID = '/^Mozilla\/5\.0 \(Android\) (?:ownCloud|Nextcloud)\-android\/([^ ]*).*$/';
/**
* @since 13.0.0
+ * @since 28.0.0 The regex has a group matching the version number
*/
- public const USER_AGENT_TALK_ANDROID = '/^Mozilla\/5\.0 \(Android\) Nextcloud\-Talk v.*$/';
+ public const USER_AGENT_TALK_ANDROID = '/^Mozilla\/5\.0 \(Android\) Nextcloud\-Talk v([^ ]*).*$/';
/**
* @since 9.1.0
+ * @since 28.0.0 The regex has a group matching the version number
*/
- public const USER_AGENT_CLIENT_DESKTOP = '/^Mozilla\/5\.0 \([A-Za-z ]+\) (mirall|csyncoC)\/.*$/';
+ public const USER_AGENT_CLIENT_DESKTOP = '/^Mozilla\/5\.0 \([A-Za-z ]+\) (?:mirall|csyncoC)\/([^ ]*).*$/';
/**
* @since 26.0.0
+ * @since 28.0.0 The regex has a group matching the version number
*/
- public const USER_AGENT_TALK_DESKTOP = '/^Mozilla\/5\.0 \((?!Android|iOS)[A-Za-z ]+\) Nextcloud\-Talk v.*$/';
+ public const USER_AGENT_TALK_DESKTOP = '/^Mozilla\/5\.0 \((?!Android|iOS)[A-Za-z ]+\) Nextcloud\-Talk v([^ ]*).*$/';
/**
* @since 9.1.0
+ * @since 28.0.0 The regex has a group matching the version number
*/
- public const USER_AGENT_CLIENT_IOS = '/^Mozilla\/5\.0 \(iOS\) (ownCloud|Nextcloud)\-iOS.*$/';
+ public const USER_AGENT_CLIENT_IOS = '/^Mozilla\/5\.0 \(iOS\) (?:ownCloud|Nextcloud)\-iOS\/([^ ]*).*$/';
/**
* @since 13.0.0
+ * @since 28.0.0 The regex has a group matching the version number
*/
- public const USER_AGENT_TALK_IOS = '/^Mozilla\/5\.0 \(iOS\) Nextcloud\-Talk v.*$/';
+ public const USER_AGENT_TALK_IOS = '/^Mozilla\/5\.0 \(iOS\) Nextcloud\-Talk v([^ ]*).*$/';
/**
* @since 13.0.1
+ * @since 28.0.0 The regex has a group matching the version number
*/
- public const USER_AGENT_OUTLOOK_ADDON = '/^Mozilla\/5\.0 \([A-Za-z ]+\) Nextcloud\-Outlook v.*$/';
+ public const USER_AGENT_OUTLOOK_ADDON = '/^Mozilla\/5\.0 \([A-Za-z ]+\) Nextcloud\-Outlook v([^ ]*).*$/';
/**
* @since 13.0.1
+ * @since 28.0.0 The regex has a group matching the version number
*/
- public const USER_AGENT_THUNDERBIRD_ADDON = '/^Mozilla\/5\.0 \([A-Za-z ]+\) Nextcloud\-Thunderbird v.*$/';
+ public const USER_AGENT_THUNDERBIRD_ADDON = '/^Mozilla\/5\.0 \([A-Za-z ]+\) Nextcloud\-Thunderbird v([^ ]*).*$/';
/**
* @since 26.0.0
diff --git a/lib/public/IServerContainer.php b/lib/public/IServerContainer.php
index f438838b98e..b66e1ecdf02 100644
--- a/lib/public/IServerContainer.php
+++ b/lib/public/IServerContainer.php
@@ -46,7 +46,6 @@ use OCP\Federation\ICloudFederationProviderManager;
use OCP\Log\ILogFactory;
use OCP\Security\IContentSecurityPolicyManager;
use Psr\Container\ContainerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* This is a tagging interface for the server container
@@ -517,15 +516,6 @@ interface IServerContainer extends ContainerInterface, IContainer {
public function getMimeTypeLoader();
/**
- * Get the EventDispatcher
- *
- * @return EventDispatcherInterface
- * @deprecated 20.0.0 use \OCP\EventDispatcher\IEventDispatcher
- * @since 8.2.0
- */
- public function getEventDispatcher();
-
- /**
* Get the Notification Manager
*
* @return \OCP\Notification\IManager
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..f99ccf1cd23
--- /dev/null
+++ b/lib/public/OCM/IOCMProvider.php
@@ -0,0 +1,143 @@
+<?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 OC\OCM\Model\OCMResource;
+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 {
+ /**
+ * enable OCM
+ *
+ * @param bool $enabled
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setEnabled(bool $enabled): self;
+
+ /**
+ * is set as enabled ?
+ *
+ * @return bool
+ * @since 28.0.0
+ */
+ public function isEnabled(): bool;
+
+ /**
+ * get set API Version
+ *
+ * @param string $apiVersion
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setApiVersion(string $apiVersion): self;
+
+ /**
+ * returns API version
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getApiVersion(): string;
+
+ /**
+ * configure endpoint
+ *
+ * @param string $endPoint
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setEndPoint(string $endPoint): self;
+
+ /**
+ * get configured endpoint
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getEndPoint(): string;
+
+ /**
+ * add a single resource to the object
+ *
+ * @param OCMResource $resource
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function addResourceType(OCMResource $resource): self;
+
+ /**
+ * set resources
+ *
+ * @param OCMResource[] $resourceTypes
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setResourceTypes(array $resourceTypes): self;
+
+ /**
+ * 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 self
+ * @throws OCMProviderException in case a descent provider cannot be generated from data
+ * @since 28.0.0
+ */
+ public function import(array $data): self;
+}
diff --git a/lib/public/OCM/IOCMResource.php b/lib/public/OCM/IOCMResource.php
new file mode 100644
index 00000000000..381af61cecc
--- /dev/null
+++ b/lib/public/OCM/IOCMResource.php
@@ -0,0 +1,99 @@
+<?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;
+
+/**
+ * Model based on the Open Cloud Mesh Discovery API
+ *
+ * @link https://github.com/cs3org/OCM-API/
+ * @since 28.0.0
+ */
+interface IOCMResource {
+ /**
+ * set name of the resource
+ *
+ * @param string $name
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setName(string $name): self;
+
+ /**
+ * get name of the resource
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getName(): string;
+
+ /**
+ * set share types
+ *
+ * @param string[] $shareTypes
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setShareTypes(array $shareTypes): self;
+
+ /**
+ * get share types
+ *
+ * @return string[]
+ * @since 28.0.0
+ */
+ public function getShareTypes(): array;
+
+ /**
+ * set available protocols
+ *
+ * @param array<string, string> $protocols
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setProtocols(array $protocols): self;
+
+ /**
+ * get configured protocols
+ *
+ * @return array<string, string>
+ * @since 28.0.0
+ */
+ public function getProtocols(): array;
+
+ /**
+ * import data from an array
+ *
+ * @param array $data
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function import(array $data): self;
+}
diff --git a/lib/public/Preview/BeforePreviewFetchedEvent.php b/lib/public/Preview/BeforePreviewFetchedEvent.php
index 37da63b95a1..19048e08620 100644
--- a/lib/public/Preview/BeforePreviewFetchedEvent.php
+++ b/lib/public/Preview/BeforePreviewFetchedEvent.php
@@ -27,19 +27,27 @@ declare(strict_types=1);
namespace OCP\Preview;
use OCP\Files\Node;
+use OCP\IPreview;
/**
* @since 25.0.1
*/
class BeforePreviewFetchedEvent extends \OCP\EventDispatcher\Event {
- private Node $node;
-
/**
* @since 25.0.1
*/
- public function __construct(Node $node) {
+ public function __construct(
+ private Node $node,
+ /** @deprecated 28.0.0 null deprecated **/
+ private ?int $width = null,
+ /** @deprecated 28.0.0 null deprecated **/
+ private ?int $height = null,
+ /** @deprecated 28.0.0 null deprecated **/
+ private ?bool $crop = null,
+ /** @deprecated 28.0.0 null deprecated **/
+ private ?string $mode = null,
+ ) {
parent::__construct();
- $this->node = $node;
}
/**
@@ -48,4 +56,33 @@ class BeforePreviewFetchedEvent extends \OCP\EventDispatcher\Event {
public function getNode(): Node {
return $this->node;
}
+
+ /**
+ * @since 28.0.0
+ */
+ public function getWidth(): ?int {
+ return $this->width;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getHeight(): ?int {
+ return $this->height;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function isCrop(): ?bool {
+ return $this->crop;
+ }
+
+ /**
+ * @since 28.0.0
+ * @return null|IPreview::MODE_FILL|IPreview::MODE_COVER
+ */
+ public function getMode(): ?string {
+ return $this->mode;
+ }
}
diff --git a/lib/public/Preview/IMimeIconProvider.php b/lib/public/Preview/IMimeIconProvider.php
new file mode 100644
index 00000000000..cb397ddfda7
--- /dev/null
+++ b/lib/public/Preview/IMimeIconProvider.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @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 OCP\Preview;
+
+/**
+ * Interface IMimeIconProvider
+ *
+ * @since 28.0.0
+ */
+interface IMimeIconProvider {
+ /**
+ * Get the URL to the icon for the given mime type
+ * Used by the preview provider to show a mime icon
+ * if no preview is available.
+ * @since 28.0.0
+ */
+ public function getMimeIconUrl(string $mime): string|null;
+}
diff --git a/lib/public/Security/Bruteforce/IThrottler.php b/lib/public/Security/Bruteforce/IThrottler.php
index 6f492d6c59d..620a53fd354 100644
--- a/lib/public/Security/Bruteforce/IThrottler.php
+++ b/lib/public/Security/Bruteforce/IThrottler.php
@@ -40,16 +40,19 @@ namespace OCP\Security\Bruteforce;
interface IThrottler {
/**
* @since 25.0.0
+ * @deprecated 28.0.0
*/
public const MAX_DELAY = 25;
/**
* @since 25.0.0
+ * @deprecated 28.0.0
*/
public const MAX_DELAY_MS = 25000; // in milliseconds
/**
* @since 25.0.0
+ * @deprecated 28.0.0
*/
public const MAX_ATTEMPTS = 10;
@@ -58,11 +61,21 @@ interface IThrottler {
*
* @param string $action
* @param string $ip
- * @param array $metadata Optional metadata logged to the database
+ * @param array $metadata Optional metadata logged with the attempt
* @since 25.0.0
*/
public function registerAttempt(string $action, string $ip, array $metadata = []): void;
+
+ /**
+ * Check if the IP is allowed to bypass the brute force protection
+ *
+ * @param string $ip
+ * @return bool
+ * @since 28.0.0
+ */
+ public function isBypassListed(string $ip): bool;
+
/**
* Get the throttling delay (in milliseconds)
*
@@ -71,16 +84,28 @@ interface IThrottler {
* @param float $maxAgeHours
* @return int
* @since 25.0.0
+ * @deprecated 28.0.0 This method is considered internal as of Nextcloud 28. Use {@see showBruteforceWarning()} to decide whether a warning should be shown.
*/
public function getAttempts(string $ip, string $action = '', float $maxAgeHours = 12): int;
/**
+ * Whether a warning should be shown about the throttle
+ *
+ * @param string $ip
+ * @param string $action optionally filter by action
+ * @return bool
+ * @since 28.0.0
+ */
+ public function showBruteforceWarning(string $ip, string $action = ''): bool;
+
+ /**
* Get the throttling delay (in milliseconds)
*
* @param string $ip
* @param string $action optionally filter by action
* @return int
* @since 25.0.0
+ * @deprecated 28.0.0 This method is considered internal as of Nextcloud 28. Use {@see showBruteforceWarning()} to decide whether a warning should be shown.
*/
public function getDelay(string $ip, string $action = ''): int;
@@ -99,6 +124,7 @@ interface IThrottler {
*
* @param string $ip
* @since 25.0.0
+ * @deprecated 28.0.0 This method is considered internal as of Nextcloud 28. Use {@see resetDelay()} and only reset the entries of your action and metadata
*/
public function resetDelayForIP(string $ip): void;
@@ -109,6 +135,7 @@ interface IThrottler {
* @param string $action optionally filter by action
* @return int the time spent sleeping
* @since 25.0.0
+ * @deprecated 28.0.0 Use {@see sleepDelayOrThrowOnMax()} instead and abort handling the request when it throws
*/
public function sleepDelay(string $ip, string $action = ''): int;
diff --git a/lib/public/Share/Events/BeforeShareCreatedEvent.php b/lib/public/Share/Events/BeforeShareCreatedEvent.php
new file mode 100644
index 00000000000..f69049b3e8d
--- /dev/null
+++ b/lib/public/Share/Events/BeforeShareCreatedEvent.php
@@ -0,0 +1,66 @@
+<?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\Share\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\Share\IShare;
+
+/**
+ * @since 28.0.0
+ */
+class BeforeShareCreatedEvent extends Event {
+ private ?string $error = null;
+
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IShare $share,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getShare(): IShare {
+ return $this->share;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function setError(string $error): void {
+ $this->error = $error;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getError(): ?string {
+ return $this->error;
+ }
+}
diff --git a/lib/public/Share/Events/BeforeShareDeletedEvent.php b/lib/public/Share/Events/BeforeShareDeletedEvent.php
new file mode 100644
index 00000000000..854d8d95b8d
--- /dev/null
+++ b/lib/public/Share/Events/BeforeShareDeletedEvent.php
@@ -0,0 +1,50 @@
+<?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\Share\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\Share\IShare;
+
+/**
+ * @since 28.0.0
+ */
+class BeforeShareDeletedEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IShare $share,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getShare(): IShare {
+ return $this->share;
+ }
+}
diff --git a/lib/public/Share/Events/ShareAcceptedEvent.php b/lib/public/Share/Events/ShareAcceptedEvent.php
new file mode 100644
index 00000000000..bf2b8084d8e
--- /dev/null
+++ b/lib/public/Share/Events/ShareAcceptedEvent.php
@@ -0,0 +1,50 @@
+<?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\Share\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\Share\IShare;
+
+/**
+ * @since 28.0.0
+ */
+class ShareAcceptedEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IShare $share,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getShare(): IShare {
+ return $this->share;
+ }
+}
diff --git a/lib/public/Share/Events/ShareDeletedFromSelfEvent.php b/lib/public/Share/Events/ShareDeletedFromSelfEvent.php
new file mode 100644
index 00000000000..0bcc7e8cf73
--- /dev/null
+++ b/lib/public/Share/Events/ShareDeletedFromSelfEvent.php
@@ -0,0 +1,50 @@
+<?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\Share\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\Share\IShare;
+
+/**
+ * @since 28.0.0
+ */
+class ShareDeletedFromSelfEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IShare $share,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getShare(): IShare {
+ return $this->share;
+ }
+}
diff --git a/lib/public/SpeechToText/ISpeechToTextManager.php b/lib/public/SpeechToText/ISpeechToTextManager.php
index eff00ec0fa1..96973cfca08 100644
--- a/lib/public/SpeechToText/ISpeechToTextManager.php
+++ b/lib/public/SpeechToText/ISpeechToTextManager.php
@@ -41,6 +41,12 @@ interface ISpeechToTextManager {
public function hasProviders(): bool;
/**
+ * @return ISpeechToTextProvider[]
+ * @since 27.1.0
+ */
+ public function getProviders(): array;
+
+ /**
* Will schedule a transcription process in the background. The result will become available
* with the \OCP\SpeechToText\Events\TranscriptionFinishedEvent
* You should add context information to the context array to re-identify the transcription result as
diff --git a/lib/public/SystemTag/ISystemTagManager.php b/lib/public/SystemTag/ISystemTagManager.php
index 1cf7263b456..0f5c373c49f 100644
--- a/lib/public/SystemTag/ISystemTagManager.php
+++ b/lib/public/SystemTag/ISystemTagManager.php
@@ -38,6 +38,7 @@ interface ISystemTagManager {
* Returns the tag objects matching the given tag ids.
*
* @param array|string $tagIds id or array of unique ids of the tag to retrieve
+ * @param ?IUser $user optional user to run a visibility check against for each tag
*
* @return ISystemTag[] array of system tags with tag id as key
*
@@ -45,9 +46,9 @@ interface ISystemTagManager {
* @throws TagNotFoundException if at least one given tag ids did no exist
* The message contains a json_encoded array of the ids that could not be found
*
- * @since 9.0.0
+ * @since 9.0.0, optional parameter $user added in 28.0.0
*/
- public function getTagsByIds($tagIds): array;
+ public function getTagsByIds($tagIds, ?IUser $user = null): array;
/**
* Returns the tag object matching the given attributes.
diff --git a/lib/public/SystemTag/SystemTagsEntityEvent.php b/lib/public/SystemTag/SystemTagsEntityEvent.php
index 4360d924c23..0ce679a3a43 100644
--- a/lib/public/SystemTag/SystemTagsEntityEvent.php
+++ b/lib/public/SystemTag/SystemTagsEntityEvent.php
@@ -33,26 +33,22 @@ use OCP\EventDispatcher\Event;
* Class SystemTagsEntityEvent
*
* @since 9.1.0
+ * @since 28.0.0 Dispatched as a typed event
*/
class SystemTagsEntityEvent extends Event {
/**
- * @deprecated 22.0.0
+ * @deprecated 22.0.0 Listen to the typed event instead
*/
public const EVENT_ENTITY = 'OCP\SystemTag\ISystemTagManager::registerEntity';
- /** @var string */
- protected $event;
/** @var \Closure[] */
protected $collections;
/**
- * SystemTagsEntityEvent constructor.
- *
- * @param string $event
* @since 9.1.0
*/
- public function __construct(string $event) {
- $this->event = $event;
+ public function __construct() {
+ parent::__construct();
$this->collections = [];
}
diff --git a/lib/public/TextProcessing/Events/AbstractTextProcessingEvent.php b/lib/public/TextProcessing/Events/AbstractTextProcessingEvent.php
new file mode 100644
index 00000000000..329889e61f0
--- /dev/null
+++ b/lib/public/TextProcessing/Events/AbstractTextProcessingEvent.php
@@ -0,0 +1,51 @@
+<?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\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\TextProcessing\Task;
+
+/**
+ * @since 27.1.0
+ */
+abstract class AbstractTextProcessingEvent extends Event {
+ /**
+ * @since 27.1.0
+ */
+ public function __construct(
+ private Task $task
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @return Task
+ * @since 27.1.0
+ */
+ public function getTask(): Task {
+ return $this->task;
+ }
+}
diff --git a/lib/public/TextProcessing/Events/TaskFailedEvent.php b/lib/public/TextProcessing/Events/TaskFailedEvent.php
new file mode 100644
index 00000000000..f9765e362dc
--- /dev/null
+++ b/lib/public/TextProcessing/Events/TaskFailedEvent.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace OCP\TextProcessing\Events;
+
+use OCP\TextProcessing\Task;
+
+/**
+ * @since 27.1.0
+ */
+class TaskFailedEvent extends AbstractTextProcessingEvent {
+ /**
+ * @param Task $task
+ * @param string $errorMessage
+ * @since 27.1.0
+ */
+ public function __construct(
+ Task $task,
+ private string $errorMessage,
+ ) {
+ parent::__construct($task);
+ }
+
+ /**
+ * @return string
+ * @since 27.1.0
+ */
+ public function getErrorMessage(): string {
+ return $this->errorMessage;
+ }
+}
diff --git a/lib/public/TextProcessing/Events/TaskSuccessfulEvent.php b/lib/public/TextProcessing/Events/TaskSuccessfulEvent.php
new file mode 100644
index 00000000000..df4d2ba6227
--- /dev/null
+++ b/lib/public/TextProcessing/Events/TaskSuccessfulEvent.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace OCP\TextProcessing\Events;
+
+/**
+ * @since 27.1.0
+ */
+class TaskSuccessfulEvent extends AbstractTextProcessingEvent {
+}
diff --git a/lib/public/TextProcessing/FreePromptTaskType.php b/lib/public/TextProcessing/FreePromptTaskType.php
new file mode 100644
index 00000000000..2cb8d6b7946
--- /dev/null
+++ b/lib/public/TextProcessing/FreePromptTaskType.php
@@ -0,0 +1,66 @@
+<?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;
+
+use OCP\IL10N;
+use OCP\L10N\IFactory;
+
+/**
+ * This is the text processing task type for free prompting
+ * @since 27.1.0
+ */
+class FreePromptTaskType implements ITaskType {
+ private IL10N $l;
+
+ /**
+ * Constructor for FreePromptTaskType
+ *
+ * @param IFactory $l10nFactory
+ * @since 27.1.0
+ */
+ public function __construct(
+ IFactory $l10nFactory,
+ ) {
+ $this->l = $l10nFactory->get('core');
+ }
+
+
+ /**
+ * @inheritDoc
+ * @since 27.1.0
+ */
+ public function getName(): string {
+ return $this->l->t('Free prompt');
+ }
+
+ /**
+ * @inheritDoc
+ * @since 27.1.0
+ */
+ public function getDescription(): string {
+ return $this->l->t('Runs an arbitrary prompt through the language model.');
+ }
+}
diff --git a/lib/public/TextProcessing/HeadlineTaskType.php b/lib/public/TextProcessing/HeadlineTaskType.php
new file mode 100644
index 00000000000..7061ca1d69b
--- /dev/null
+++ b/lib/public/TextProcessing/HeadlineTaskType.php
@@ -0,0 +1,66 @@
+<?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;
+
+use OCP\IL10N;
+use OCP\L10N\IFactory;
+
+/**
+ * This is the text processing task type for creating headline
+ * @since 27.1.0
+ */
+class HeadlineTaskType implements ITaskType {
+ private IL10N $l;
+
+ /**
+ * Constructor for HeadlineTaskType
+ *
+ * @param IFactory $l10nFactory
+ * @since 27.1.0
+ */
+ public function __construct(
+ IFactory $l10nFactory,
+ ) {
+ $this->l = $l10nFactory->get('core');
+ }
+
+
+ /**
+ * @inheritDoc
+ * @since 27.1.0
+ */
+ public function getName(): string {
+ return $this->l->t('Generate headline');
+ }
+
+ /**
+ * @inheritDoc
+ * @since 27.1.0
+ */
+ public function getDescription(): string {
+ return $this->l->t('Generates a possible headline for a text.');
+ }
+}
diff --git a/lib/public/TextProcessing/IManager.php b/lib/public/TextProcessing/IManager.php
new file mode 100644
index 00000000000..dec0baba4bb
--- /dev/null
+++ b/lib/public/TextProcessing/IManager.php
@@ -0,0 +1,110 @@
+<?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;
+
+use OCP\Common\Exception\NotFoundException;
+use OCP\PreConditionNotMetException;
+use RuntimeException;
+
+/**
+ * API surface for apps interacting with and making use of LanguageModel providers
+ * without known which providers are installed
+ * @since 27.1.0
+ */
+interface IManager {
+ /**
+ * @since 27.1.0
+ */
+ public function hasProviders(): bool;
+
+ /**
+ * @return IProvider[]
+ * @since 27.1.0
+ */
+ public function getProviders(): array;
+
+ /**
+ * @return class-string<ITaskType>[]
+ * @since 27.1.0
+ */
+ public function getAvailableTaskTypes(): 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 RuntimeException If something else failed
+ * @since 27.1.0
+ */
+ public function runTask(Task $task): string;
+
+ /**
+ * Will schedule an LLM inference process in the background. The result will become available
+ * with the \OCP\LanguageModel\Events\TaskSuccessfulEvent
+ * If inference fails a \OCP\LanguageModel\Events\TaskFailedEvent will be dispatched instead
+ *
+ * @param Task $task The task to schedule
+ * @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called
+ * @since 27.1.0
+ */
+ public function scheduleTask(Task $task) : void;
+
+ /**
+ * Delete a task that has been scheduled before
+ *
+ * @param Task $task The task to delete
+ * @since 27.1.0
+ */
+ public function deleteTask(Task $task): void;
+
+ /**
+ * @param int $id The id of the task
+ * @return Task
+ * @throws RuntimeException If the query failed
+ * @throws NotFoundException If the task could not be found
+ * @since 27.1.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 NotFoundException If the task could not be found
+ * @since 27.1.0
+ */
+ public function getUserTask(int $id, ?string $userId): Task;
+
+ /**
+ * @param string $userId
+ * @param string $appId
+ * @param string|null $identifier
+ * @return array
+ * @since 27.1.0
+ */
+ public function getUserTasksByApp(string $userId, string $appId, ?string $identifier = null): array;
+}
diff --git a/lib/public/TextProcessing/IProvider.php b/lib/public/TextProcessing/IProvider.php
new file mode 100644
index 00000000000..6132e60b493
--- /dev/null
+++ b/lib/public/TextProcessing/IProvider.php
@@ -0,0 +1,62 @@
+<?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;
+
+use RuntimeException;
+
+/**
+ * This is the interface that is implemented by apps that
+ * implement a text processing provider
+ * @template T of ITaskType
+ * @since 27.1.0
+ */
+interface IProvider {
+ /**
+ * The localized name of this provider
+ * @since 27.1.0
+ */
+ public function getName(): string;
+
+ /**
+ * Processes a text
+ *
+ * @param string $prompt The input text
+ * @return string the output text
+ * @since 27.1.0
+ * @throws RuntimeException If the text could not be processed
+ */
+ public function process(string $prompt): string;
+
+ /**
+ * Returns the task type class string of the task type, that this
+ * provider handles
+ *
+ * @since 27.1.0
+ * @return class-string<T>
+ */
+ public function getTaskType(): string;
+}
diff --git a/lib/public/TextProcessing/ITaskType.php b/lib/public/TextProcessing/ITaskType.php
new file mode 100644
index 00000000000..d08da3f7ac7
--- /dev/null
+++ b/lib/public/TextProcessing/ITaskType.php
@@ -0,0 +1,49 @@
+<?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 is a task type interface that is implemented by text processing
+ * task types
+ * @since 27.1.0
+ */
+interface ITaskType {
+ /**
+ * Returns the localized name of this task type
+ *
+ * @since 27.1.0
+ * @return string
+ */
+ public function getName(): string;
+
+ /**
+ * Returns the localized description of this task type
+ *
+ * @since 27.1.0
+ * @return string
+ */
+ public function getDescription(): string;
+}
diff --git a/lib/public/TextProcessing/SummaryTaskType.php b/lib/public/TextProcessing/SummaryTaskType.php
new file mode 100644
index 00000000000..670a7cb4da6
--- /dev/null
+++ b/lib/public/TextProcessing/SummaryTaskType.php
@@ -0,0 +1,66 @@
+<?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;
+
+use OCP\IL10N;
+use OCP\L10N\IFactory;
+
+/**
+ * This is the text processing task type for summaries
+ * @since 27.1.0
+ */
+class SummaryTaskType implements ITaskType {
+ private IL10N $l;
+
+ /**
+ * Constructor for SummaryTaskType
+ *
+ * @param IFactory $l10nFactory
+ * @since 27.1.0
+ */
+ public function __construct(
+ IFactory $l10nFactory,
+ ) {
+ $this->l = $l10nFactory->get('core');
+ }
+
+
+ /**
+ * @inheritDoc
+ * @since 27.1.0
+ */
+ public function getName(): string {
+ return $this->l->t('Summarize');
+ }
+
+ /**
+ * @inheritDoc
+ * @since 27.1.0
+ */
+ public function getDescription(): string {
+ return $this->l->t('Summarizes text by reducing its length without losing key information.');
+ }
+}
diff --git a/lib/public/TextProcessing/Task.php b/lib/public/TextProcessing/Task.php
new file mode 100644
index 00000000000..446e414cb04
--- /dev/null
+++ b/lib/public/TextProcessing/Task.php
@@ -0,0 +1,221 @@
+<?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 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>
+ */
+final class Task implements \JsonSerializable {
+ protected ?int $id = null;
+ protected ?string $output = null;
+
+ /**
+ * @since 27.1.0
+ */
+ public const TYPES = [
+ FreePromptTaskType::class,
+ SummaryTaskType::class,
+ HeadlineTaskType::class,
+ TopicsTaskType::class,
+ ];
+
+ /**
+ * @since 27.1.0
+ */
+ public const STATUS_FAILED = 4;
+ /**
+ * @since 27.1.0
+ */
+ public const STATUS_SUCCESSFUL = 3;
+ /**
+ * @since 27.1.0
+ */
+ public const STATUS_RUNNING = 2;
+ /**
+ * @since 27.1.0
+ */
+ public const STATUS_SCHEDULED = 1;
+ /**
+ * @since 27.1.0
+ */
+ public const STATUS_UNKNOWN = 0;
+
+ /**
+ * @psalm-var self::STATUS_*
+ */
+ protected int $status = self::STATUS_UNKNOWN;
+
+ /**
+ * @psalm-param S $type
+ * @param string $type
+ * @param string $input
+ * @param string $appId
+ * @param string|null $userId
+ * @param string $identifier An arbitrary identifier for this task. max length: 255 chars
+ * @since 27.1.0
+ */
+ final public function __construct(
+ protected string $type,
+ protected string $input,
+ protected string $appId,
+ protected ?string $userId,
+ protected string $identifier = '',
+ ) {
+ }
+
+ /**
+ * @psalm-param P $provider
+ * @param IProvider $provider
+ * @return string
+ * @since 27.1.0
+ */
+ public function visitProvider(IProvider $provider): string {
+ if ($this->canUseProvider($provider)) {
+ return $provider->process($this->getInput());
+ } else {
+ throw new \RuntimeException('Task of type ' . $this->getType() . ' cannot visit provider with task type ' . $provider->getTaskType());
+ }
+ }
+
+ /**
+ * @psalm-param P $provider
+ * @param IProvider $provider
+ * @return bool
+ * @since 27.1.0
+ */
+ public function canUseProvider(IProvider $provider): bool {
+ return $provider->getTaskType() === $this->getType();
+ }
+
+ /**
+ * @psalm-return S
+ * @since 27.1.0
+ */
+ final public function getType(): string {
+ return $this->type;
+ }
+
+ /**
+ * @return string|null
+ * @since 27.1.0
+ */
+ final public function getOutput(): ?string {
+ return $this->output;
+ }
+
+ /**
+ * @param string|null $output
+ * @since 27.1.0
+ */
+ final public function setOutput(?string $output): void {
+ $this->output = $output;
+ }
+
+ /**
+ * @psalm-return self::STATUS_*
+ * @since 27.1.0
+ */
+ final public function getStatus(): int {
+ return $this->status;
+ }
+
+ /**
+ * @psalm-param self::STATUS_* $status
+ * @since 27.1.0
+ */
+ final public function setStatus(int $status): void {
+ $this->status = $status;
+ }
+
+ /**
+ * @return int|null
+ * @since 27.1.0
+ */
+ final public function getId(): ?int {
+ return $this->id;
+ }
+
+ /**
+ * @param int|null $id
+ * @since 27.1.0
+ */
+ final public function setId(?int $id): void {
+ $this->id = $id;
+ }
+
+ /**
+ * @return string
+ * @since 27.1.0
+ */
+ final public function getInput(): string {
+ return $this->input;
+ }
+
+ /**
+ * @return string
+ * @since 27.1.0
+ */
+ final public function getAppId(): string {
+ return $this->appId;
+ }
+
+ /**
+ * @return string
+ * @since 27.1.0
+ */
+ final public function getIdentifier(): string {
+ return $this->identifier;
+ }
+
+ /**
+ * @return string|null
+ * @since 27.1.0
+ */
+ final public function getUserId(): ?string {
+ return $this->userId;
+ }
+
+ /**
+ * @psalm-return array{id: ?int, type: S, status: 0|1|2|3|4, userId: ?string, appId: string, input: string, output: ?string, identifier: string}
+ * @since 27.1.0
+ */
+ public function jsonSerialize(): array {
+ return [
+ 'id' => $this->getId(),
+ 'type' => $this->getType(),
+ 'status' => $this->getStatus(),
+ 'userId' => $this->getUserId(),
+ 'appId' => $this->getAppId(),
+ 'input' => $this->getInput(),
+ 'output' => $this->getOutput(),
+ 'identifier' => $this->getIdentifier(),
+ ];
+ }
+}
diff --git a/lib/public/TextProcessing/TopicsTaskType.php b/lib/public/TextProcessing/TopicsTaskType.php
new file mode 100644
index 00000000000..5a994a7a8d2
--- /dev/null
+++ b/lib/public/TextProcessing/TopicsTaskType.php
@@ -0,0 +1,66 @@
+<?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;
+
+use OCP\IL10N;
+use OCP\L10N\IFactory;
+
+/**
+ * This is the text processing task type for topics extraction
+ * @since 27.1.0
+ */
+class TopicsTaskType implements ITaskType {
+ private IL10N $l;
+
+ /**
+ * Constructor for TopicsTaskType
+ *
+ * @param IFactory $l10nFactory
+ * @since 27.1.0
+ */
+ public function __construct(
+ IFactory $l10nFactory,
+ ) {
+ $this->l = $l10nFactory->get('core');
+ }
+
+
+ /**
+ * @inheritDoc
+ * @since 27.1.0
+ */
+ public function getName(): string {
+ return $this->l->t('Extract topics');
+ }
+
+ /**
+ * @inheritDoc
+ * @since 27.1.0
+ */
+ public function getDescription(): string {
+ return $this->l->t('Extracts topics from a text and outputs them separated by commas.');
+ }
+}
diff --git a/lib/public/Translation/ITranslationManager.php b/lib/public/Translation/ITranslationManager.php
index 4450f19c424..5b342faea75 100644
--- a/lib/public/Translation/ITranslationManager.php
+++ b/lib/public/Translation/ITranslationManager.php
@@ -39,6 +39,12 @@ interface ITranslationManager {
public function hasProviders(): bool;
/**
+ * @return ITranslationProvider[]
+ * @since 27.1.0
+ */
+ public function getProviders(): array;
+
+ /**
* @since 26.0.0
*/
public function canDetectLanguage(): bool;
diff --git a/lib/public/Translation/LanguageTuple.php b/lib/public/Translation/LanguageTuple.php
index 9defb17e4b6..27f932f0a64 100644
--- a/lib/public/Translation/LanguageTuple.php
+++ b/lib/public/Translation/LanguageTuple.php
@@ -45,6 +45,7 @@ class LanguageTuple implements JsonSerializable {
/**
* @since 26.0.0
+ * @return array{from: string, fromLabel: string, to: string, toLabel: string}
*/
public function jsonSerialize(): array {
return [
diff --git a/lib/public/User/Backend/IProvideEnabledStateBackend.php b/lib/public/User/Backend/IProvideEnabledStateBackend.php
new file mode 100644
index 00000000000..d03beacd7b8
--- /dev/null
+++ b/lib/public/User/Backend/IProvideEnabledStateBackend.php
@@ -0,0 +1,56 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Côme Chilliet <come.chilliet@nextcloud.com>
+ *
+ * @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\User\Backend;
+
+/**
+ * @since 28.0.0
+ */
+interface IProvideEnabledStateBackend {
+ /**
+ * @since 28.0.0
+ *
+ * @param callable():bool $queryDatabaseValue A callable to query the enabled state from database
+ */
+ public function isUserEnabled(string $uid, callable $queryDatabaseValue): bool;
+
+ /**
+ * @since 28.0.0
+ *
+ * @param callable():bool $queryDatabaseValue A callable to query the enabled state from database
+ * @param callable(bool):void $setDatabaseValue A callable to set the enabled state in the database.
+ */
+ public function setUserEnabled(string $uid, bool $enabled, callable $queryDatabaseValue, callable $setDatabaseValue): bool;
+
+ /**
+ * Get the list of disabled users, to merge with the ones disabled in database
+ *
+ * @since 28.0.0
+ *
+ * @return string[]
+ */
+ public function getDisabledUserList(int $offset = 0, ?int $limit = null): array;
+}
diff --git a/lib/public/User/Events/UserFirstTimeLoggedInEvent.php b/lib/public/User/Events/UserFirstTimeLoggedInEvent.php
new file mode 100644
index 00000000000..06491f79109
--- /dev/null
+++ b/lib/public/User/Events/UserFirstTimeLoggedInEvent.php
@@ -0,0 +1,50 @@
+<?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\User\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+class UserFirstTimeLoggedInEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IUser $user,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+}
diff --git a/lib/public/Util.php b/lib/public/Util.php
index 5bb126d26b0..781aa87d66b 100644
--- a/lib/public/Util.php
+++ b/lib/public/Util.php
@@ -49,6 +49,8 @@ namespace OCP;
use OC\AppScriptDependency;
use OC\AppScriptSort;
use bantu\IniGetWrapper\IniGetWrapper;
+use OCP\Share\IManager;
+use Psr\Container\ContainerExceptionInterface;
/**
* This class provides different helper functions to make the life of a developer easier
@@ -56,17 +58,11 @@ use bantu\IniGetWrapper\IniGetWrapper;
* @since 4.0.0
*/
class Util {
- /** @var \OCP\Share\IManager */
- private static $shareManager;
+ private static ?IManager $shareManager = null;
- /** @var array */
- private static $scripts = [];
-
- /** @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
@@ -83,9 +79,9 @@ class Util {
public static function hasExtendedSupport(): bool {
try {
/** @var \OCP\Support\Subscription\IRegistry */
- $subscriptionRegistry = \OC::$server->query(\OCP\Support\Subscription\IRegistry::class);
+ $subscriptionRegistry = \OCP\Server::get(\OCP\Support\Subscription\IRegistry::class);
return $subscriptionRegistry->delegateHasExtendedSupport();
- } catch (AppFramework\QueryException $e) {
+ } catch (ContainerExceptionInterface $e) {
}
return \OC::$server->getConfig()->getSystemValueBool('extendedSupport', false);
}
@@ -163,14 +159,34 @@ 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";
+ }
+
+ self::$scriptsInit[] = $path;
+ }
+
+ /**
* add a javascript file
*
* @param string $application
* @param string|null $file
* @param string $afterAppId
+ * @param bool $prepend
* @since 4.0.0
*/
- public static function addScript(string $application, string $file = null, string $afterAppId = 'core'): void {
+ public static function addScript(string $application, string $file = null, string $afterAppId = 'core', bool $prepend = false): void {
if (!empty($application)) {
$path = "$application/js/$file";
} else {
@@ -193,7 +209,11 @@ class Util {
self::$scriptDeps[$application]->addDep($afterAppId);
}
- self::$scripts[$application][] = $path;
+ if ($prepend) {
+ array_unshift(self::$scripts[$application], $path);
+ } else {
+ self::$scripts[$application][] = $path;
+ }
}
/**
@@ -208,10 +228,16 @@ 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
- array_unshift($sortedScripts, 'core/js/common', 'core/js/main');
+ if (in_array('core/js/main', $sortedScripts)) {
+ array_unshift($sortedScripts, 'core/js/main');
+ }
+ if (in_array('core/js/common', $sortedScripts)) {
+ array_unshift($sortedScripts, 'core/js/common');
+ }
return array_unique($sortedScripts);
}
diff --git a/lib/public/WorkflowEngine/IManager.php b/lib/public/WorkflowEngine/IManager.php
index f09d51eb159..abdcdfa107a 100644
--- a/lib/public/WorkflowEngine/IManager.php
+++ b/lib/public/WorkflowEngine/IManager.php
@@ -45,21 +45,6 @@ interface IManager {
public const MAX_OPERATION_VALUE_BYTES = 4096;
/**
- * @deprecated 17.0.0 Will be removed in NC19. Use the dedicated events in OCP\WorkflowEngine\Events
- */
- public const EVENT_NAME_REG_OPERATION = 'OCP\WorkflowEngine::registerOperations';
-
- /**
- * @deprecated 17.0.0
- */
- public const EVENT_NAME_REG_ENTITY = 'OCP\WorkflowEngine::registerEntities';
-
- /**
- * @deprecated 17.0.0
- */
- public const EVENT_NAME_REG_CHECK = 'OCP\WorkflowEngine::registerChecks';
-
- /**
* Listen to `OCP\WorkflowEngine\Events\RegisterEntitiesEvent` at the
* IEventDispatcher for registering your entities.
*